现在的设计是一台 Redis 作为缓存,多个服务器进行负载均衡,某些操作需要加锁。
看了几篇分布式锁的文章后尝试自己实现一个,遇到了两个问题,想问问有经验的各位。
看到的文章中基本都是使用线程 id 来作为锁拥有人的判断。不熟悉 Java,是 Java 的不同请求不会在同一个线程中吗? 但在 asyncio 中,整个事件循环都是在同一个进程的同一个线程中。如果用线程 ID 的话可能会有同一个服务器的两个不同请求认为自己都是锁的拥有者而出现问题,不知道有什么其他的比较好的判断依据吗,比如一个请求在申请锁的时候先生成一个 UUID,用这个 UUID 来代替线程 ID。还想过一个办法是在每个线程中再加一个锁,要请求一个资源的时候要先获取到线程中这个资源对应的锁才能去请求 Redis 中的锁,解锁的时候则要解锁两个锁,理论上也能避免线程 id 相同造成的问题。不太确定哪种做法更好一些。
如果是阻塞获取锁,有两种做法,一是订阅 Redis 的事件,等待对应的 key 被删除或者过期。另一种是在应用里 sleep+循环,不断的尝试获取 key 直到超时,想问一下这两种做法哪一种比较好一些?
1
aijam 2019-04-20 04:02:47 +08:00 1
岔开说一句,最好解决方案就是不自己实现分布式锁,FLP impossibility, Paxos, tlaplus 什么的多了解一下,就知道对 99.9%的程序员来说,想实现一个高可用的正确的锁是不可能的。即便是 redis 官方的 redlock 正确性都存在争议。
|
2
676529483 2019-04-20 10:07:53 +08:00
为啥我感觉不用锁才是比较好的,如果只是要数据一致性 C,负载均衡可以分业务来分配机器,如果是因为更新 redis 缓存雪崩的问题,可以后台主动更新 redis 而不是每个线程都去更新
|
3
pktangyue 2019-04-20 11:03:48 +08:00
只有一台 redis 服务器应该不算分布式锁吧,只用普通的 redis 锁就可以了。
第一个问题,可以考虑用 connection 做区分。 第二个问题,asyncio 本身就是 loop 的,你 await 等着获取锁就可以了,已获得锁的地方用完了 wakeup 就行了。 |