【代码学习】lua+redis分布式锁代码实现实例
生活随笔
收集整理的這篇文章主要介紹了
【代码学习】lua+redis分布式锁代码实现实例
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 分布式鎖場景和介紹:
- 分布式鎖模板類:
- 鎖實現類
- lua腳本加鎖和解鎖
- 分布式速度限制
- 測試分布式鎖
分布式鎖場景和介紹:
分布式鎖演進-基本原理
分布式鎖演進-階段一
分布式鎖演進-階段二
分布式鎖演進-階段三
分布式鎖演進-階段四
分布式鎖演進-階段五
分布式鎖一般有如下的特點:
互斥性: 同一時刻只能有一個線程持有鎖
可重入性: 同一節點上的同一個線程如果獲取了鎖之后能夠再次獲取鎖
鎖超時:和J.U.C中的鎖一樣支持鎖超時,防止死鎖
高性能和高可用: 加鎖和解鎖需要高效,同時也需要保證高可用,防止分布式鎖失效
具備阻塞和非阻塞性:能夠及時從阻塞狀態中被喚醒
分布式鎖模板類:
/*** 分布式鎖模板類* Created by sunyujia@aliyun.com on 2016/2/23.*/ public interface DistributedLockTemplate {/**** @param lockId 鎖id(對應業務唯一ID)* @param timeout 單位毫秒* @param callback 回調函數* @return*/public Object execute(String lockId,int timeout,Callback callback); } public interface DistributedReentrantLock {public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException;public void unlock(); }回調接口:
/*** Created by sunyujia@aliyun.com on 2016/2/23.*/ public interface Callback {public Object onGetLock() throws InterruptedException;public Object onTimeout() throws InterruptedException; }鎖實現類
/*** Created by sunyujia@aliyun.com on 2016/2/26.*/ public class RedisDistributedLockTemplate implements DistributedLockTemplate {private static final org.slf4j.Logger log = LoggerFactory.getLogger(RedisDistributedLockTemplate.class);private JedisPool jedisPool;public RedisDistributedLockTemplate(JedisPool jedisPool) {this.jedisPool = jedisPool;}@Overridepublic Object execute(String lockId, int timeout, Callback callback) {RedisReentrantLock distributedReentrantLock = null;boolean getLock=false;try {distributedReentrantLock = new RedisReentrantLock(jedisPool,lockId);if(distributedReentrantLock.tryLock(new Long(timeout), TimeUnit.MILLISECONDS)){getLock=true;return callback.onGetLock();}else{return callback.onTimeout();}}catch(InterruptedException ex){log.error(ex.getMessage(), ex);Thread.currentThread().interrupt();}catch (Exception e) {log.error(e.getMessage(), e);}finally {if(getLock) {distributedReentrantLock.unlock();}}return null;} } /*** Created by sunyujia@aliyun.com on 2016/2/26.*/ public class HHRedisDistributedLockTemplate implements DistributedLockTemplate {private static final org.slf4j.Logger log = LoggerFactory.getLogger(HHRedisDistributedLockTemplate.class);private JedisPool jedisPool;private Jedis jedis ;public HHRedisDistributedLockTemplate(JedisPool jedisPool) {this.jedisPool = jedisPool;this.jedis = jedisPool.getResource();}public boolean tryLock(String key, String ran, int timout){System.out.println("tryLock key:"+key+"ran:"+ran);Long val = jedis.setnx(key, ran);System.out.println("tryLock key:"+key+"ran:"+ran+"val:"+val);jedis.pexpire(key,timout);return jedis.get(key).equals(ran);}public boolean unLock(String key, String value){if (value.equals(jedis.get(key))){jedis.del(key);System.out.println("unLock key:"+key+"val:"+value);}else{jedis.close();System.out.println("unlockERROR:"+"key:"+key+"expectVal:"+value+"val:"+jedis.get(key));return false;}jedis.close();return true;}@Overridepublic Object execute(String lockId, int timeout, Callback callback) {String ran = Thread.currentThread().getName();boolean getLock=false;try {if(tryLock(lockId,ran, timeout)){getLock=true;return callback.onGetLock();}else{return callback.onTimeout();}}catch(InterruptedException ex){log.error(ex.getMessage(), ex);Thread.currentThread().interrupt();}catch (Exception e) {log.error(e.getMessage(), e);}finally {if(getLock) {unLock(lockId,ran);}else{jedis.close();}}return null;} }lua腳本加鎖和解鎖
class RedisLockInternals {private static final org.slf4j.Logger log = LoggerFactory.getLogger(RedisLockInternals.class);private JedisPool jedisPool;/*** 重試等待時間*/private int retryAwait=300;private int lockTimeout=2000;RedisLockInternals(JedisPool jedisPool) {this.jedisPool = jedisPool;}String tryRedisLock(String lockId,long time, TimeUnit unit) {final long startMillis = System.currentTimeMillis();final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;String lockValue=null;while (lockValue==null){lockValue=createRedisKey(lockId);if(lockValue!=null){break;}if(System.currentTimeMillis()-startMillis-retryAwait>millisToWait){break;}LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(retryAwait));}return lockValue;}private String createRedisKey(String lockId) {Jedis jedis = null;boolean broken = false;try {String value=lockId+randomId(1);jedis = jedisPool.getResource();即: // - 獲取鎖(unique_value可以是UUID等) // SET resource_name unique_value NX PX 30000 // // - 釋放鎖(lua腳本中,一定要比較value,防止誤解鎖) // if redis.call("get",KEYS[1]) == ARGV[1] then // return redis.call("del",KEYS[1]) //else // return 0 // endString luaScript = ""+ "\nlocal r = tonumber(redis.call('SETNX', KEYS[1],ARGV[1]));"+ "\nredis.call('PEXPIRE',KEYS[1],ARGV[2]);"+ "\nreturn r";List<String> keys = new ArrayList<String>();keys.add(lockId);List<String> args = new ArrayList<String>();args.add(value);args.add(lockTimeout+"");Long ret = (Long) jedis.eval(luaScript, keys, args);if( new Long(1).equals(ret)){return value;}}finally {if(jedis!=null) jedis.close();}return null;}void unlockRedisLock(String key,String value) {Jedis jedis = null;boolean broken = false;try { //String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return //redis.call('del', KEYS[1]) else return 0 end";jedis = jedisPool.getResource();String luaScript=""+"\nlocal v = redis.call('GET', KEYS[1]);"+"\nlocal r= 0;"+"\nif v == ARGV[1] then"+"\nr =redis.call('DEL',KEYS[1]);"+"\nend"+"\nreturn r";List<String> keys = new ArrayList<String>();keys.add(key);List<String> args = new ArrayList<String>();args.add(value);Object r=jedis.eval(luaScript, keys, args);} finally {if(jedis!=null) jedis.close();}}private final static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l','m', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y','z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L','M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z'};private String randomId(int size) {char[] cs = new char[size];for (int i = 0; i < cs.length; i++) {cs[i] = digits[ThreadLocalRandom.current().nextInt(digits.length)];}return new String(cs);}public static void main(String[] args){System.out.println(System.currentTimeMillis());LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(300));System.out.println(System.currentTimeMillis());} }分布式速度限制
/*** 分布式速率限制 例如:限制n秒鐘請求x次*/ public class AccessSpeedLimit {private static final org.slf4j.Logger log = LoggerFactory.getLogger(AccessSpeedLimit.class);private JedisPool jedisPool;public AccessSpeedLimit(){}public AccessSpeedLimit(JedisPool jedisPool) {this.jedisPool = jedisPool;}public JedisPool getJedisPool() {return jedisPool;}public void setJedisPool(JedisPool jedisPool) {this.jedisPool = jedisPool;}/*** 針對資源key,每seconds秒最多訪問maxCount次,超過maxCount次返回false** @param key* @param seconds* @param limitCount* @return*/public boolean tryAccess(String key,int seconds,int limitCount){LimitRule limitRule=new LimitRule();limitRule.setLimitCount(limitCount);limitRule.setSeconds(seconds);return tryAccess(key,limitRule);}/*** 針對資源key,每limitRule.seconds秒最多訪問limitRule.limitCount,超過limitCount次返回false* 超過lockCount 鎖定lockTime* @param key* @param limitRule* @return*/public boolean tryAccess(String key,LimitRule limitRule){String newKey="Limit:"+key;Jedis jedis = null;boolean broken = false;long count=-1;try {jedis = jedisPool.getResource();List<String> keys = new ArrayList<String>();keys.add(newKey);List<String> args = new ArrayList<String>();args.add(Math.max(limitRule.getLimitCount(), limitRule.getLockCount())+"");args.add(limitRule.getSeconds()+"");args.add(limitRule.getLockCount()+"");args.add(limitRule.getLockTime()+"");count=Long.parseLong(jedis.eval(buildLuaScript(limitRule),keys,args)+"");return count<=limitRule.getLimitCount();} finally {if(jedis!=null)jedis.close();}}private String buildLuaScript(LimitRule limitRule){StringBuilder lua=new StringBuilder();lua.append("\nlocal c");lua.append("\nc = redis.call('get',KEYS[1])");lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");lua.append("\nreturn c;");lua.append("\nend");lua.append("\nc = redis.call('incr',KEYS[1])");lua.append("\nif tonumber(c) == 1 then");lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");lua.append("\nend");if(limitRule.enableLimitLock()){lua.append("\nif tonumber(c) > tonumber(ARGV[3]) then");lua.append("\nredis.call('expire',KEYS[1],ARGV[4])");lua.append("\nend");}lua.append("\nreturn c;");return lua.toString();} }測試分布式鎖
public class AccessSpeedLimitTest {@Testpublic void test1() throws InterruptedException {JedisPool jp=new JedisPool("localhost",6379);AccessSpeedLimit accessSpeedLimit=new AccessSpeedLimit(jp);SimpleDateFormat sdf=new SimpleDateFormat(" mm:ss");while(true){//10.0.0.1這個ip每1秒鐘最多訪問5次if塊內代碼.if(accessSpeedLimit.tryAccess("10.0.0.1", 1,5)){System.out.println("yes"+sdf.format(new Date()));}else{System.out.println("no"+sdf.format(new Date()));}Thread.sleep(100);}}@Testpublic void test2() throws InterruptedException {JedisPool jp=new JedisPool("127.0.0.1",6379);final RedisDistributedLockTemplate template=new RedisDistributedLockTemplate(jp);LimitRule limitRule=new LimitRule();limitRule.setSeconds(1);limitRule.setLimitCount(5);limitRule.setLockCount(7);limitRule.setLockTime(2);AccessSpeedLimit accessSpeedLimit=new AccessSpeedLimit(jp);SimpleDateFormat sdf=new SimpleDateFormat(" mm:ss");while(true){//10.0.0.1這個ip每1秒鐘最多訪問5次if塊內代碼.1秒超過10次后,鎖定2秒,2秒內無法訪問.if(accessSpeedLimit.tryAccess("10.0.0.1",limitRule)){System.out.println("yes"+sdf.format(new Date()));}else{System.out.println("no"+sdf.format(new Date()));}Thread.sleep(100);}} }
總結
以上是生活随笔為你收集整理的【代码学习】lua+redis分布式锁代码实现实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot使用j2cache框
- 下一篇: 用百度开放地图api在代码中获得两地距离