我正在编写一个任务计划组件,以便仅应执行计时器任务 一次在重复的调度程序(即应用服务器)集群中,并且 当前使用分布式锁来提高可靠性。
分布式锁由Redis记录实现。当任务提交给调度程序A时,
调度程序B将使用SETNX
(原子)并在Redis服务器中写入任务记录。
如果另一个调度程序正在提交完全相同的任务(例如,向用户发送电子邮件),
SETNX
将失败,然后在调度程序B中取消调度。
我的问题发生在一种特殊情况下,描述如下:
scheduler A Redis scheduler B scheduler C
| lock | |
|--------------->| lock |
| success |<--------------|
|<---------------| fail |
task alpha o |-------------->|
submit | | x schedule
success | | canceled 0 a new scheduler
| | | is scaled in cluster
| | fetch existing tasks |
| |<----------------------------------|
| | report submitted tasks |
| |---------------------------------->| now scheduler C
| | | knows task alpha.
| | |
task alpha o lock | lock o task alpha
starts |--------------->|<----------------------------------| starts
execute | fail | success | execute
|<---------------|---------------------------------->|
schedule x | | keep executing
canceled | |
| |
| |
x Redis fail |
|
unlock v execution success
<----------------------------------| delete task record
|
Redis 0 |
recovered | |
| 0 scheduler B
the record | fetch | recovered
of task alpha |<-------------|
still exists | report |
|------------->| task alpha needs
| lock o execution because
|<-------------| time has arrived!
| success |
|------------->|
| |
| unlock v execution success (inconsistent execution)
|<-------------|
|
|
在此图中,task alpha
由调度程序C执行。但是,由于解锁失败,
任务记录未从Redis删除。之后,当调度程序B恢复时,
该任务将再次执行,从而导致不一致。
通常,不假定基本服务Redis发生故障,这会导致此问题 是一个罕见的问题。始终可以将Redis视为同步记录的重复集群 彼此之间,Redis的失败意味着所有重复的Redis节点均已死亡。
详细描述,但简短的问题: