分布式锁初探--redis锁

前言

最近开发任务需要在多个时间点执行,时间点一部分由定时任务设定,一部分由mq监听来执行,但必须保证同一时间点只能有一个任务来执行。我们知道jdk自身提供的锁只能适用用单机应用,但如今分布式架构应用越来越多,多个应用部署集群时,我们可能需要某个时刻只有一个应用执行,这时就需要用到分布式锁。

分布锁基本应用场景及设计

案例

有2个计算基金涨跌幅数据服务,一个是定时计算,一个是在每天基金净值更新后发送到mq,然后由多个监听服务去计算,净值更新时间是不固定的,因此计算时间也不固定。所以2个计算涨跌幅服务的服务会发生冲突,如何保证在同一时间只有一个任务执行,那就需要用到分布式锁。在这个场景中我用的是redis作为分布式锁来实现的。
这里写图片描述
上图基本为实现这个案例的流程,设计服务时我们需要保证以下几点:
1、分布锁必须保证多个服务请求同一个锁时绝对互斥。
2、需要设计超时间,防止任务停止或服务阻塞时锁无法释放,从而引发下一次任务一直无法获取锁。

Redis具体实现分布式锁

redis实现分布锁是通过SETNX 命令来实现的,具体格式

SETNX key value

命令的作用是如果key存在,则什么都不做,并且返回0,如果key不存在则将key的值设置成value,并且返回1,该命令是原子性的。我们可以利用该命令来实现分布式锁。
主要代码:

//这里设置锁过期时间,防止在获得锁的服务阻塞或者崩溃引起的锁无法释放
boolean getlock = lockManager.aquireLock("redisKey");
//判断获取锁成功
if(getlock){
    try{
       //do some thing                             
    }finally {
       //释放锁
       lockManager.releaseLock("redisKey");
    }
}
//lockManager
@Service
public class LockServiceImpl implements LockManager {
    @Resource(name = "redisServiceImpl")
    private RedisManager redisManager;
    //设置锁时间为10分钟,避免停服务 时计算涨跌幅,锁没释放,可根据其它具体业务需求修改过期时间
    private static final Long LOCK_EXPIRE = 10*60L;
    @Override
    public boolean aquireLock(String key) {
        boolean isSet = redisManager.put(key, "1", LOCK_EXPIRE, true);
        return isSet;
    }
    @Override
    public void releaseLock(String key){
        redisManager.delete(key);
    }
}

后续

以上为我所用到的reids作为分布式锁的一个应用场景,或许你已经看出上面应用案列中有可能的问题。因为本业务对互斥要求不高,所以即使重复计算也不会有多大问题,但对于互斥要求高的服务或许需要考虑的更多。
比如redis宕机了,该如何保证redis的可用性。即使是用redis的主从集群复制,主挂了,从可以接替上,但是依然会出现问题,因为redis主从复制是异步的,没办法保证主挂了,从节点上一定有锁数据。

猜你喜欢

转载自blog.csdn.net/lh87270202/article/details/79791356