-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
另外一个cluster的消息顺序异常问题 #587
Comments
这里有几个框架没有承诺保证次序的地方:
我认为这种有序需求可以看成是一种多线程并行状态,不应该依赖隐式的次序来保证。比较简单的作为是使用 skynet.response ,把它放在一个自己维护的队列中。 如果要保持上面的结构,那么应该把 skynet.yield() 改为 skynet.wait 挂起,由前面的流程结束后再 wakeup 。即,第一步完成后再延续下一步。 另外还有一个方法,就是利用 https://github.com/cloudwu/skynet/wiki/CriticalSection 创建一个队列,这个队列可以按持续执行一系列步骤。那么,你可以在
上面的代码是随手写的,用的时候要理解一下,排查可能的潜在 bug 。 |
skynet.resume即是wakeup,我们理解上相同,实际上调用的确实是wakeup,只不过最终是协程resume,所以我就这么写了,一会我修改一下。 目前的情况就是在B服务中的调用有序,那么在A中按道理应该也是有序的,但目前的处理函数无序。 |
目前我B中复杂的wait跟wakeup应该也是可以用skynet.response替代的,不过这个不影响A中的协程wakeup乱序问题。 |
A
B xx_actor
可以看到我在b中刻意希望能保证u,r顺序,但是a中实际u,r唤醒的顺序是不固定的。 |
我大概明白了。是说 socketchannel 的 |
对,是这个意思,socket我打印了,read出来顺序是对的,但是唤醒的co是偶尔是顺序是反的,我觉得这个应该会影响到所有使用socketchannel的。 修改了上述代码,大致就是偶尔 1 2 ,但是偶尔打印又是 2 1 |
ok 那我把 skynet.wakeup 改成保证次序的。你看一下。 |
我测试过,保证有序是可以的,但是我不太敢修改项目源码,毕竟影响比较大,所以在这里发issue跟你商量看看有没有应用层可以解决的方案。 |
确保次序比无序的保证更强,应该没有兼容性问题。如果不改 skynet.wakeup ,也需要修改 socket channel 来保证这点。 |
也是,都忘记了还有by order的场景 |
原来你已经提交了commit的,我没有发现,我修改下项目源码测试一下,另外我看了下源码,是用默认的lua table remove,会有后续元素的移动,是否有考虑用 |
没有必要,O(n) 取决于 n 有多大。这里 n 和 同时 wakeup 的数量相关。 |
ok |
hi,目前测试下来新代码没有问题,解决了我们这里socket消息与wakeup协程乱序的问题。 |
目前我的issue比较特别,与上一位仁兄的情况不太一致,我所以我重开了一个issue,主要的问题点我们排查下来在socketchannel与wakeup_session结构中。
我描述下问题,假设A通过cluster.call调用B的某个lua api,为了简介起见,我假设api是这样的
在A服务中写了这样的代码
cluster.call(B, "xx_actor", "xx_function", arg)
此时B服务中的xx_function在某个参数为特定值的情况下,会skynet.wait当前协程暂缓发送(假设这个逻辑为u),然后在参数为另外一个特地值的时候,与之前暂缓发送的协程重新wakeup并处理当前逻辑(假设这个逻辑为r)。
比如是这样的
这里特地增加了一个yield是希望最终执行的顺序是先真正wakeup,再执行本次返回逻辑(也就是说会有两条B->A的socket消息发送到A中,而且时间上很接近),目前从socket层抓到A中消息的顺序确实是u->r,不过最终函数处理顺序却变成了r->u。
目前我们通过日志进行分析,发现是这样的情况,在socket_channel的dispatch_by_session(self)函数中,会进行sock读取,这里的日志打印是顺序的,但是当wakeup后,情况就不一定是如此了,目前查看wakeup代码,发现是wakeup是个table结构,由next函数返回下一个键值,顺序是无法保证的,那么当接收包比较相近或者网络层阻塞的情况下,是有可能导致接收函数处理乱序的。
目前暂时我想的一个方案是否需要修改wakeup结构为先入先出的队列,或者在socketchannel中yield一次,保证每次read的wakeup队列只有一个,测试结构才是有序的。但是这些方法都不太好,修改了源码,而且socketchannel在很多第三方api中都有使用,按道理不应该出现这个问题。
希望我描述的细节云风能理解,不吝赐教。
The text was updated successfully, but these errors were encountered: