Open fankeke opened 6 years ago
这里不加不会影响到功能,但是从代码严谨的角度来说是要加。欢迎提交 PR。
@tokers 另外,感觉用lock来做唯一性的timer没有那么优雅,可以用worker id来做。 在初始化每个sync的时候,可以random(worker的数量)一个值赋值给sync,然后该sync就可以由这个random值出来的id所对应的worker来同步。这个也避免了LOCK_KEY和LOCK_TIME_KEY的使用。
(另外os.time的精度不够,连续起两个sync会导致同样的LOCK_TIME_KEY也是一个问题)
如果可行的话,我提个PR
@fankeke 你的方案,如果持有 sync timer 的 worker 进程 crash 了,怎么保证新起来的 worker 可以重新创建出 sync timer 来?
新的worker再走一遍init_worker阶段 ,也能够创建。
function _M.new(...) ..... local sync = { .... worker_id = random(ngx.worker.count()) } ..... }
function _M.start(self) ..... local worker_id = self.worker_id if worker_id ~= ngx.worker.id() then return end ....... end
基本思想和上面一样
那这个 worker_id 应该要放到共享内存里。
从你的伪代码来看,持有 sync timer 的 worker 如果挂了,新起来一个 worker,也是随机一个 worker_id
,进入到 start
函数,如果这个随机出来的 worker_id
不等于 ngx.worker.id()
的值的话,此时全局就没有 sync 定时器了。
额,好像是的 。。。 思路有点问题。
@fankeke 不过 os.time 的问题,可能是会有精度不够的问题,可以在这个基础上结合一个随机数,哈哈
嗯,我提个PR可以
@tokers 当前的做法还是有些问题: 场景如下:如果有两个worker,2个sync,sync1和sync2 nginx启动时,其中sync1和sync2都被worker1持有, 然后worker2突然挂掉,然后重启执行init_worker阶段,然后继续创建sync1和sync2. (因为此时的lock_key和lock_time_key都已经不同了,而且没有其他worker进行抢锁,必然会创建所有的sync)
这个时候就会发生问题, 是不是这样?
@fankeke 是的。
目前 resty-sync
的做法能够完全避免掉这些问题。
@tokers 目前的resty-sync如何避免我上面的场景的?
@fankeke 你可以仔细看下 _M.start
这个函数,我通过在共享内存里设置一个特殊的标记,即用 LOCK_TIMER_KEY
作为 key,存放成功启动 sync timer 的 worker 的 id,过期时间为这个 sync
实例所设置的 interval
+ 10,且每次定时器在处理回调的时候,都会更新下这个 key ,以避免过期。
如果某个 worker 进入到这个函数,先第一次抢锁,抢到锁的,首先会判断这个 LOCK_TIMER_KEY
对应的值是不是存在,如果不存在,则由这个 worker 抢占到 timer,同时共享内存里的 LOCK_TIMER_KEY
存放它的 id。
如果这个 LOCK_TIMER_KEY
对应的值已经是存在的,需要判断其值和当前 worker 自己的 id 是否一致,不一致则立刻返回,一致则接着往下走,抢占到 timer。
这样子,在有 worker 崩溃的时候,如果不是 timer owner 崩溃,则由于 LOCK_TIMER_KEY
对应的值和它本身的 ID 不同,是不会创建出 timer 来的,相反,如果是之前的 timer owner 奔溃,由于 worker id 只能是 [0, n - 1],新起来的 worker 必然和刚刚奔溃的 worker id 一致,此时它便可以重新创建出 timer 来,保证 resty.sync
工作正常。
@tokers crash后的worker创建的 LOCK_TIMER_KEY 在变化,并不是不变的,这个你考虑了吗?
这是我起了4个worker,创建一个sync时的shdict的数据,我kill了三次worker后的数据:
sync_timer_1513914468:1
sync_timer_1513914438:0
sync_timer_1513915510:2
_time_ex1:1513916022
_data_ex1:16
_version_ex1:version 10
此时3个worker都持有了这个sync的timer。
@fankeke 恩,这个 new
操作你要放到 init 阶段,可以放在 init 阶段再试试
https://github.com/upyun/lua-resty-sync/blob/master/lib/resty/sync.lua#L324
if var and var ~= id then release_lock(lock) return true end
没有看具体逻辑,但感觉这里应该要释放lock(抢到后)