分布式锁总结

1> redis处理过时key的方式:html

redis 当key过时的时候,可能会采起策略来清除掉key. 有如下三种方式: 当即清除(设置过时时间的时候,设置一下回调,当时间过时,直接删除掉key)   惰性清除(key过时的时候不会当即去清除掉key,等下次取数据的时候,判断是否过时,过时了就会删除掉key). 定时清除. redis使用的是 定时清除和惰性清除 两种策略.java

关于分布式锁:python

在平常开发中,若是是单应用实例,为了防止并发所致使的一系列的问题,咱们可使用java中提供的那些锁机制来保障( synchronized或者reentrantlock).  可是在分布式环境中,因为会存在多个jvm进程,致使锁对象不惟一,这样java中提供的那些锁机制就没有用了,这时候咱们就须要寻求分布式锁来保障 并发带来的问题.redis

 

                   分布式锁是用于解决分布式系统中操做共享资源时的数据一致性问题。数据库

分布式锁须要注意一些问题:缓存

互斥:   分布式系统中运行着多个节点,必须确保在同一时刻只能有一个节点的一个线程得到锁。

死锁: 分布式系统中若是一个节点获取到锁挂掉,锁一直不能释放,致使其余节点处于阻塞状态,因此有必要设置时效,不管什么状态,锁都能释放.

性能: 对于访问量大的共享资源,若是获取到锁会形成长时间的等待,致使大量节点阻塞,不能够.尽可能减小等待时间(业务执行时间以及及时通知)并发

重入: 锁是基于线程的分配.

阻塞性: 根据实际业务场景来判断,当没有获取到锁的时候,采起阻塞等待仍是直接返回.jvm

 

 

 

多个线程并发执行一个方法场景.分布式

1>>>>>若是该方法里面所有是操做数据库的一些东西, 能够直接使用数据库的事务并发机制来控制.不须要其余的分布式锁来保障.(单业务节点也可使用)性能

    通常存在repeatable read隔离级别下,对数据的读取,修改事务提交操做.(repeatable隔离级别下加锁机制,可能会死锁,用更新锁来解决)

2>>>>>若是是为了防止多个线程执行同一方法致使数据不一致性,可使用分布式锁.

 

分布式锁的实现方式:

1>基于数据库来实现. 新建一张表: id  method_name  创建method_name惟一索引,由数据库来保障. 执行方法前,先必须获取到锁,insert into tb (method_name) value(method_name) 返回成功就获取到锁,没有成功就没有获取到锁,执行完的时候 删除掉这条数据,让其余线程能够开始去处理.

缺点: 数据库单点故障,万一表挂了,则整个出错. 非重入性 没有过时时间,万一内部崩溃则锁一直没法释放  非阻塞

改进:使用select.....for update 有效避免非阻塞 可是可能会锁表.

 

3>基于zookeeper实现分布式锁

https://www.cnblogs.com/austinspark-jessylu/p/8043726.html

https://www.cnblogs.com/linjiqin/p/8003838.html

2>基于redis缓存来实现分布式锁

  注意点: 2.1> redis加锁的时候  setnx 和 设置有效期不能拆开,由于不是一个原子操做.正确使用

                  String result = jedis.set(lockKey, requestId, nx=Ture, px=5);

2.2> 删除锁的时候要注意:判断一下当前对象和持有锁的对象是否一致,避免释放掉其余线程的锁.(根据不一样业务来选择是否须要判断) 

实现的几种方式:直接上代码

1>  set方式:

while(jedis.exists(lock)){
Thread.sleep(500);
}

set(lock,1);
执行业务代码;
jedis.del(lock);

2> setnx 方式:

while(jedis.setnx(lock,1)==0){

Thread.sleep(300);

}

执行业务代码;
jedis.del(lock);






setnx不直接设置timeout:

while(jedis.setnx(lock,now+超时时间)==0){
    if(jedis.get(lock)<now){
       jedis.del(lock);
    jedis.setnx(lock,now+超时时间);
               break;
              }else{
                     Thread.sleep(300);
              }}

执行业务代码;
jedis.del(lock);

 

 

while(jedis.setnx(lock, now+超时时间)==0){
               if(now>jedis.get(lock) && now>jedis.getset(lock, now+超时时间)){
                     break;
             }else{ 
                    Thread.sleep(300);
              }
}
执行业务代码;
jedis.del(lock);



redis中存在一种   set 直接设置nx px(过时时间)  让判断过时时间的工做扔给redis更高效

目前python中改造采用:

while not cls.get_lock_rs().set(sender_rs_key, 1, nx=True, px=5):  #setnx+timeout 若是没有获取到锁    time.sleep(0.005)         #sleep 5ms执行业务代码;del(key)考虑一个问题:针对python部分的锁方式,若是保证锁的正确释放(A线程不能释放B线程的锁),能够采用value=thread_id del的时候进行判断对于java中的分布式锁服务 采用redisson来实现. redisson是对jedis的上层封装,提供分布式集合 和分布式锁.主要看一下分布式锁: 使用方式: 能够以redis单节点或者集群搭建不一样的redisson链接对象.使用集群能够避免redis单节点故障.  java中的锁具备重入性 unlock 能够判断是不是同一个线程.  python调用要注意: 超时时间  不一样的线程id问题.
相关文章
相关标签/搜索