易知上图的程序存在线程问题。
加同步锁可正常在单体架构上线程安全执行。
分布式集群的情况呢?
集群部署到多个集群,每个tomcat应用都是一个jvm进程,同步锁只能在jvm内部生效。
因此对于整个集群来说,存在了并发问题。并发量越高,问题场景越明显。
使用JMeter模拟高并发场景,会出现明确的并发场景。
解决这个问题,需要使用redis分布式锁。
SETNX命令: 只在键key不存在的情况下,将键key的值设置为value;
若key已存在,则SetNX命令不做任何动作。 set if not exsits;
redis是单线程模式。?
按照上图,一个最初级的分布式锁。解锁方式:手动释放锁。
异常死锁:如果程序过程中出现异常,无法释放锁。用try...finally{手动释放异常}。
宕机,重启应用情况死锁:设置redis锁的超时时间。
上述两行代码,如果第一行获取锁完成,执行设置锁超时时间时出现异常或宕机导致死锁:
方案:可以将设置锁与设置超时间执行原子操作:
上述代码在高并发场景下的问题:
1.单条任务执行时间大于redis锁超时时间。第二个请求进来,就破坏了锁,导致redis锁永久失效。如下图:
解决redis锁方案:
1.解决释放别的请求redis锁:在使用setNX设置锁时,将value设置为线程ID(请求私有属性)。这样就解决了不同的请求释放别的请求的reis锁的问题。
2.解决业务处理时长超过redis锁超时时间:在请求A的redis锁主线程下开一个分线程,内设置定时器监听,redis锁强行续命。(定时时间为超时时间的1/3,再次设置超时时长为10s)
更优方案:redisson。
redisson续命:
redisson分布式锁实现原理:
redis主从集群问题:
主Redis设置锁成功,在同步给从Redis前宕机:所有从redis都没有redis锁的lockkey。(可使用zookeeper保持数据一致性,可实现稳定性更高的分布式锁,性能不如redis),不推荐使用redLock
redis锁性能偏低,无法应用数千万计的并发场景。
增加并发性能:将产品库存分段存储。分段锁。