高并发环境下编程注意事项-分布式锁

高并发始终要注意的问题:原子性
分布式锁常见的可以使用redis、zookeeper、seata。目前用的比较多的redis,使用分布式锁组件redisson。

  1. 单机版程序接口调用容易出现超卖现象,需要加锁。
    最基本的是synchronize(obj),ReentranLock.lock() (不拿到锁就不走,可能导致请求堆积)
    或者ReentranLock.tryLock(time)(过时不候,到点就返回),根据业务要求调整。

  2. 改用微服务架构,加单机版的锁只能控制一台节点,也避免不了超卖,需要分布式锁统一管理调用

如果是直接操作redisTemplate,需要注意finally中释放锁,避免程序问题导致锁无法释放。

  1. 宕机导致分布式锁无法释放
    key需要加一个过期时间,确保会释放。

  2. 删除锁要确保是自己线程创建的那把,不要删除别的线程创建的锁
    某些情况下A线程处理缓慢导致分布式锁自动释放,线程B开始创建锁,之后A线程执行完毕并且删除了B创建的锁

  1. 分布式事务原子性支持
    比如线程A上锁之前或者业务操作提交之前发现已经被改了,就要取消当前操作。redis可以考虑使用jedis+官网上提供的lua脚本去判断key是否被修改过。或者是手动通过watch命令+事务支持相关命令去操作和判断处理。相比之下还是seata要舒服一点。

  2. 针对redis锁自动过期的问题:不知道当前业务到底会执行多久,还可以设计一种锁缓存续期的机制。同时redis集群同步的AP机制导致有可能主节点还没同步就挂了,引发锁丢失问题。(相比之下zookeeper采用的是CP机制,先同步完再响应,一致性加强了,但是牺牲了高可用性)生产上通常会使用Redisson这个redis锁插件,相对成熟一些。也不用手写什么lua脚本了。

使用redisson.unlock的时候注意加个逻辑判断(redLock.isLocked() &&redLock.isHeldByCurrentThread())防止某些极端并发情况下出现错误EleagleMonitorStateException:attempt to lock,not locked by current thread。

关于redissson原理

你可能感兴趣的:(高并发环境下编程注意事项-分布式锁)