这里主要记录项目中使用基于redis的分布式锁所遇到的问题及解决方案;redis
个人业务场景是这样的,咱们服务有库存模块,而个人服务又是多节点部署,要高峰期会存在库存差别,后面分析问题以后,打算采用redis实现分布式锁(主要的缘由是服务已经集成了redis,不须要作额外的配置) 算法
不要感受奇怪,分布式锁怎么会致使数据库事务超时呢?
个人代码大概是这样的:数据库
伪代码 @Transaction(readOnly=false) void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); } }while(true) }
当你的key长时间获取不到锁,而且数据库事务都有超时时间的限制,那么就会出现数据库事务超时问题;
解决方案并发
数据库事务改成手动提交事务;分布式
个人key的过时时间设置的是30s,若是30秒业务尚未执行完毕,锁就会自动释放,锁释放以后,其它线程又会去占用锁,一样会致使问题的发生;
解决方案ide
最简单的解决方案就是使用redisson;
若是非要用redis来解决的话,只能使用定时器去检测key,若是说key还有2秒就快过时了,那么再为key从新设置30秒的过时时间;线程
分布式锁刚加上以后,生产出现一个问题,就是:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
解决办法
开始查代码,发现是开发人员没有对链接进行释放; code
修复bug以后,又在线上跑了一段时间,又出现了redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
解决办法事务
void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); }else{ // 释放当前redis链接 // 因为咱们的业务场景属于比较耗时的业务型,因此在这里休眠1000毫秒 redis.close(); sleep(1000); } }while(true) }
1.当前请求获取锁,若是获取不到,则释放当前链接,并休眠一会;
2.合理配置redis链接池大小,主要参考具体业务场景的并发量来设置;开发
回顾一下加锁的参数:
set(key, vlue,"NX","PX", 30000);
其中:value,我使用它来表示加锁人,必须是一个惟一的标识
好比:
A线程 key=test value=01
B线程 key=test value=02若是A线程执行业务耗时超过了锁的持有时间,锁会自动释放;锁自动释放以后,线程B又加锁成功,可是,此时A线程执行完业务逻辑以后,去释放锁,但A线程的锁已经自动释放了,若是没有value来标识的话,它可能就会去释放B线程的锁;
这种状况我没有遇到,由于公司的redis集群作了改进;
先说一下这种问题产生的缘由:
若是master节点因为某缘由发生了主从切换,那么就会出现锁丢失的状况;
解决办法
须要经过使用redlock算法;或使用redisson,它有对redlock算法作封装;