最近准备写一个支持concurrent处理request的controller,说白了就是多线程reconcile, 但是一直有个疑问萦绕心头:如果同一个resource的request先后被触发,本应是在队列中先后被reconcile处理,但在concurrence的情况下会不会被同时处理?如果同时处理了,就出问题了。
在研究中,发现了一篇文章,多谢指导:https://openkruise.io/en-us/blog/blog2.html
其实client-go的队列机制避免了这个问题的发生:
首先, client-go设置了一个队列和两个set分别是:
- 队列: 无名queue(我也不知道叫啥,没去查)
- set: Dirty Set
- set:Processing Set
当有request过来时,有几条规则,注意:
1. 进入“Dirty Set”, 但如果Dirty Set已经存在同一个target的request,那直接丢弃, 也就是说不会允许多个指向同一resource的request存在于Dirty Set, 所以上面缺失了一种情况:
2. 经过Dirty Set筛选(去重)的request依次进入queue(并没有从Dirty Set中取出,而是copy一份,放入queue),但是如果request同时处于Processing Set,则不进去queue(但还在Dirty Set中), reconcile loop会从Front指针处开始处理。
3. Reconcile loop取出一个request(A)开始处理并将该request放入Processing Set并且从Dirty Set中移除。
4. 当某一request被reconcile loop处理结束后,会从Processing Set中移除,这时如果在Dirty Set中有同样resource的request,会进入queue的末尾。
OK,这就完全杜绝了在多线程reconcile下同意个resource的request会被同时处理的问题。
那这样会导致处理的顺序跟request到来的顺序不一致,想想那个倒霉的第二个A,如果在它在Dirty Set等待的时候呼啦啦来了一大群别的request,它就只能排在他们之后了!
但这没有问题,只是delay而已。
看看这篇过于玄妙的文章就有解释了:
https://speakerdeck.com/thockin/edge-vs-level-triggered-logic