分佈式鎖

分佈式鎖的使用場景是什麼呢?redis

以前紅包需求的時候,有一個場景要用到分佈式鎖。同一個openid,最多隻能搶到一個子紅包。dom

一、先判斷這個openid在不在該紅包對應的已搶openid hash中分佈式

String hget(String key, String field);ui

二、若是在,就返回。若是不在,則加分佈式鎖,保證同一個openid,最多隻有一個請求能搶到紅包。這裏是怕有人用本身的openid刷接口,從而致使他本身搶了不少個紅包。lua

SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]spa

只有這個命令,能一邊設不存在時才set,一邊設置過時時間。code

SETNX key value,只能在不存在時才set,不能設置過時時間。blog

key是什麼?key是openid+redPacketId。繼承

value是什麼?value是一個uuid便可,後面還要依靠這個uuid去解鎖呢。對的,分佈式鎖加上以後,須要咱們在業務完成以後,手動解鎖。即del key,可是不能亂刪,不能是沒有獲取到鎖的客戶端把鎖解了,只能是獲取到鎖的客戶端才能解鎖。這就是uuid的好處,每一個請求生成的uuid是不同的,只有uuid是key的值時,才能解鎖。接口

僞代碼以下:

public Object getChildRedPacket() { JedisCommands jedisCommands = null; Jedis jedis = null; JedisCluster jedisCluster = null; String openid = "d"; String redPacketId = "ss"; String lockKey = openid + redPacketId; SetParams setParams = new SetParams(); setParams.nx(); setParams.ex(60 * 60); String uuid = UUID.randomUUID().toString(); String money = jedisCommands.hget(redPacketId, openid); if (StringUtils.isNotBlank(money)) { return ImmutableMap.of("money", money); } else { try { // 得到鎖
                if ("ok".equalsIgnoreCase(jedisCommands.set(lockKey, uuid, setParams))) { money = jedisCommands.lpop(redPacketId); if (StringUtils.isNotBlank(money)) { jedisCommands.hset(redPacketId, openid, money); return ImmutableMap.of("money", money); } else { return ImmutableMap.of("msg", "已搶完"); } } } finally { // 釋放鎖
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return end"; // jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uuid));
 jedisCluster.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uuid)); } } return null; }

Jedis常規的set、get、hset、hget方法都是從JedisCommands接口繼承的,JedisCluster常規的set、get、hset、hget方法都是從JedisClusterCommands接口繼承的。

Jedis的eval方法是從ScriptingCommands接口繼承的,JedisCluster的eval方法是從JedisClusterScriptingCommands接口繼承的。

注意以上代碼,在lua腳本中用了uuid的值,這就是約束了只有得到鎖的請求能解鎖,沒有得到鎖的請求不能解鎖,且釋放鎖代碼放在finally塊中。

加鎖時的過時時間怎麼定呢?只要是比業務代碼執行所需時間長就行了,長點無所謂。爲啥無所謂呢?由於鎖是一個openid對應一個redPacketId,鎖不釋放不會影響另外一個openid搶這個紅包,也不會影響這個openid搶另外一個紅包,只會影響這個openid再一次搶這個紅包。參考https://mp.weixin.qq.com/s/ceRwZdwOgmzRGqF9HZztKg

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息