(3)管理设计篇之"分布式锁"

1.Redis怎样用它来加锁和解锁,锁超时风险。数据库的乐观并发控制,通过版本号来解决。

2.数据库用 CAS,就没必要分布式锁

3.分布式锁服务能用来做同步,数据库锁不能

一、Redis 分布式锁

1、避免死锁

(1)对资源加锁:SET resource_name my_random_value NX PX 30000

    1)SET NX 命令:只会在 key 不存在的时候给 key 赋值,

    2)PX 命令:通知 Redis 保存这个 key30000ms(存活时间,称作锁过期时间,超过这个时间时,锁将自动释放)。没在时间内完成,其他客户端获得锁,引起争用问题

(3)my_random_value :全局唯一值。随机数释放锁时保证安全性

原理:某个 key 不存在,才能设置成功多个进程设置同一个 key,一个成功,其它失败。

2、解锁

(3)管理设计篇之

key 对应value 一致,删除 key。这样释放锁是避免释放其他 Client 申请锁。

(2)不区分Client问题:

    1.Client A 获得锁

    2.释放锁请求给 Redis 时被阻塞,没有及时到达 Redis。

    3.超时,Redis 认为锁到期,释放锁

    4.B申请到,A 解锁请求到达,将B锁定key 解锁

    5.C 获得,B C 同时持有锁。

(3)关于 value 的生成,

(1)官方:/dev/urandom 中取 20 个 byte 随机数。

(2)更简单: RC4 加密算法在 /dev/urandom 中得到一个种子(Seed),生成伪随机流;

(3)简单:使用时间戳 + 客户端编号生成随机数。 (安全性较差一些,大多数的场景足够安全 )

2、分布式锁服务的一个问题

避免Client占锁不放,Redis超时后把其释放掉。

(1)Client A 取锁,B等A完成。

(2)A 被外部阻塞调用,或CPU被进程吃满,或Full GC,A 超时,怕死锁,锁释放

(3)B 获得锁且更新

(4)A 缓过来去更新。B 更新被冲掉。数据出错。HBase 就曾经遇到

(3)管理设计篇之

解决:引入 fence(栅栏)。乐观锁机制,需要递增版本号排它。下图

(3)管理设计篇之

时带上自己版本号。数据库服务需要保存数据版本号,检查请求

如用 ZooKeeper 做锁服务,用 zxid znode 版本号来做 fence版本号。

二、从乐观锁到 CAS

如数据库保留版本号,用数据库锁不更方便了吗?

(3)管理设计篇之

数据版本(Version)记录机制,数据库表增加version字段。时将 version 字段读出,更新一次 version 加一

提交更新时,当前版本第一次version 比对。相等更新,否则过期

SQLUPDATE table_name SET xxx = #{xxx}, version=version+1 where version =#{version};乐观锁常用实现方式。版本号,或fence token不需要分布式锁。

fence token 玩法,数据库用 timestamp 时间截。更新提交时,和更新前时间戳对比,一致则 OK,否则冲突。

更新库存: 库存数量(stock)查出,更新时,查一下是否是上次读出。不是失败,重新再来。

SELECT stock FROM tb_product where product_id=#{product_id};

UPDATE tb_product SET stock=stock-#{num} WHERE product_id=#{product_id} AND stock=#{stock};

三、分布式锁服务能用来做同步,数据库锁不能

计算机汇编指令中原子操作 CAS(Compare And Swap),大量无锁数据结构都用到。(关于 CAS 可以CoolShell上写无锁队列实现 )。

分布式锁服务到乐观锁,再到 CAS,还需要分布式锁服务吗?

不需更新,只同步或是互斥不同机器上线程,Redis 分布式就有意义。

 CAS (无锁方式)更新数据,不需要使用分布式锁服务,

分布式锁设计的重点:

集群中,同一个方法同一时间只能被一台机器上的一个线程执行。分布式互斥:某个事时,去服务上请求标识。请求到操作,完成后把标识还回去,别进程可请求

死锁问题,ZooKeeper 靠自身sessionTimeout 删除节点

RedLock高可用:非阻塞方式锁服务。考虑锁可重入性。

Redis 也不错,ZooKeeper变通方式, Apache 有Curator封装了各种分布式锁玩法。

在哪些场景下会用到锁?有没有用到数据库锁?是OCC,还是悲观锁?如果是悲观锁的话,又是怎样避免死锁的?

你可能感兴趣的:((3)管理设计篇之"分布式锁")