Redis 分布式锁在 Python 中的客户端 Aioredlock

前言

最近遇到一个需求,每 60S 刷新数据库数据到 Redis 缓存中,但应用又不止一个进程。此需求中对原子性并无太大的要求,只是如果每次只有一个进程执行,那么数据库的压力就会小很多。

于是想到用分布式锁来解决这个问题,最终选择了通过 Redis 来实现。

关于 Redis 实现分布式锁可以查看下面的文章:
分布式锁的实现之 redis 篇

Aioredlock

在众多的官方推荐的分布式锁客户端中,我选择了 Aioredlock

Distributed locks with Redis

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
async def aioredlock():
# retry_count 重试次数,这里配置为1,杜绝进程重复去获取
lock_manager = Aioredlock([{'host': 'localhost', 'port': 6379, 'db': 1}],retry_count=1)

while True:

# 每秒钟去检测锁的状态,如果锁被其他进程占用就跳过
# lock_timeout 锁的时间为 65S,相当于进程拿到锁后最大65秒后释放
# 业务逻辑执行 小于 65秒,业务逻辑执行完后当即释放锁
# 每60秒执行一次 sleep 59s即可,因为检测已经sleep了1s

await asyncio.sleep(1)
if await lock_manager.is_locked("_ztsg_auto_generate_code"):
#logger.info('The resource is already acquired')
continue

try:
async with await lock_manager.lock("_ztsg_auto_generate_code", lock_timeout=65) as lock:

assert lock.valid is True
assert await lock_manager.is_locked("_ztsg_auto_generate_code") is True

# 每60s钟运行一次任务
await asyncio.sleep(59)

logger.info('Start Tick! The time is '+str(os.getpid())+': %s' % datetime.now())
# 业务代码
logger.info('Stop Tick! The time is '+str(os.getpid())+': %s' % datetime.now())
except LockAcquiringError:
print('Something happened during normal operation. We just log it.')
except LockError:
print('Something is really wrong and we prefer to raise the exception')
except Exception as e:
print(e)
print('Something else went wrong')

通过上面代码就能实现,需求所要求