消息分发服务器,云风的 BLOG

本文提出了一种简化消息队列的设计方案,通过采用固定长度的循环队列来降低并发问题,减少服务过载时的雪崩效应,并探讨了任务调度的改进思路。

我们可以把每个服务的消息队列实现成固定长度,且固定长度并不需要太长,大约 256 个 slot 这种级别就足够了。一个固定长度的循环队列实现起来要简单的多,且很容易做成进出队列互不影响。因为出队列只发生在一个服务内,不可能并发,根本不需要考虑竞争;而仅仅只需要考虑进队列的竞争问题。

当队列满,或有人在入队列操作时,都认为队列忙,不需要做锁,直接失败即可。遇到忙的时候发送方可以自行缓存代发数据。而多方同时写入队列时,对 skynet 来说,其实不需要保证先后次序,有时序要求的仅仅是同一发送者对一个特定接受者。在队列不忙时,谁先写都是没问题的;且同一服务下,当有多个待发出队列时,先处理哪一个也不太所谓。

这样就可以把消息进出这块的所有竞争都去掉,实现起来也非常简单。而且可以大大缓解服务过载后的雪崩问题。因为退出一些有未发出消息的服务,那些没有发出的消息也自然被扔掉了。而目前的设计则会将所有消息都堆积在一条消息队列中,这些消息在玩家频繁上下线时会有大量无效信息。

这里提到的新设计比现在复杂的一点是,该什么时候唤醒一个服务。在现有的情况下,只有一个服务获得新消息,且不在热服务队列中,它才会把自己压入热服务队列,待工作线程去处理。而做出以上改变后,一个服务又未发出的消息时,也需要在接收方解除拥塞后唤醒。

我的想法是索性把服务的任务调度也一并改进。采用一个更简单更粗暴的方式来做。

目前其实把服务分成两类的,一类是热服务,就是有消息待处理的;另一类是冷服务,服务活着,但消息队列暂时为空。工作线程只要从热服务队列中依次取出服务调用回调函数即可。

这么设计是考虑到热服务的数量通常远小于总的服务数量,如此能减少工作线程轮询一个服务是否有消息可处理的开销。

是不是可以考虑另一种算法呢?

每个工作线程可以重复一个工作循环。

第一步就是遍历所有的服务,挑选出当前有事情要做(包括有消息要处理,有消息发出被拥塞)的服务,去掉正在被别的工作线程处理的那些(服务忙),把这些服务放在当前工作线程下的一个集合中。

第二步,依次处理自己集合中的服务消息。在处理工作中,如果碰到别的工作线程已经在处理,或消息队列空,或待发队列依然无法处理(接收方拥塞)则立刻将该服务从自己的集合中去掉。

由于移出集合的条件很宽松,而不会加入新的元素,所以只要不断循环第二步,自己所属的集合会越来越小。但为了防止某几个服务霸占工作线程,还可以加一个循环次数上限,相当于让过热的服务有个冷却的机会。

当第二步的集合为空,或是达到了循环上限。那么结束这个工作循环,回到第一步继续。

以上是一些初步的想法,晾到年后再动手实现。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值