消息路由设计总结
这学期做的一个作业,稍微总结一下自己的设计思路,顺便读了一篇美团技术部门写的《消息队列设计精要》,深感做一个消息队列的复杂程度。
简单介绍一下,我的消息路由开源中,但除了学习之中没有什么卵用(这篇文章也不会讲代码的实现,主要是设计思路),之所以这样是考虑到整个系统的开发难度进行了取舍,之后也会说到:https://github.com/csvwolf/Sky_Message_Routing_Middleware
我们要做的东西简单的来说英文是Message Router,也就是消息路由,实际上也就是没什么卵用的转发器,尤其是小规模的情况下——整体而言是一个问答系统,我们有3个前端,一个后端,在这种规模下,似乎确实没有什么意思,只能自己虚拟情况了。
因此假设我有100个前端,100个后端需要进行对接,首先我们想到的就是,使用消息路由,可以降低前后端的复杂度,否则的话,100个前端要和100个后端对接上是需要很多工作量的,为他们提供统一的接口,基本的解除业务流间的耦合,第二是为前后端提供方便扩展的接口和缓冲区域,之后是传输加密和安全。
基本上能想到的是这么几点,我的中间件主要做了正常的解耦,均衡负载,可扩展性,加密由于懒癌晚期跳票……。(还有一点是后端死活不肯配合一下)
最简单易行的当然是双向WebSocket通讯,双缓冲池(输入输出池)——设计参考SPOOLING。
但是考虑到我校的平均水平,基本上这样就完不成作业了,尤其是前端方面,因此前端换成了HTTP传输(很显然会存在问题),后端构造HTTP服务器可能会比较麻烦,所以选用了WebSocket通讯。
除此以外,我还考虑了一下这几种模式(双WS,HTTP+WS和双WS)会带来的问题:
双WS肯定是最好的,但开发难度可能会高,因为WebSocket并不方便调试。
前端改用HTTP,降低了前端的学习难度,但如果是Push模型,需要Hold住该连接,那么在中间件均衡负载上可能会存在困难,当然,也并不是完全无法解决,使用DNS轮询技术可破(换言之把轮询提前到域名转换为ip地址时),如果是pull模型,适合不太注重时效性的场合,此时的一个问题是,需要规定好查询时间间隔,否则会对服务器造成极大的负担。
后端改用HTTP,在扩展性方面可能会有所伤害(至少目前看来是这样),我们希望中间件能够无需重启即可支持大量业务,后端需要使用连接去解析路由表,最简单的方法自然是根据参数去判断到达的后端,扩展性可能会比较差,当然还有的方法是通过数据库之类的存储对应的Map Key-Value,这种方法应该是可行的,不过总的而言,个人认为WebSocket更加易于扩展(错误日志等),以及效率可能会更高。
HTTP的好处也并非完全没有,非常适合完整的信息加密(HTTPS就是现成的),相比之下,自己定制加密难度相对比较高。
然后在WebSocket上,存在客户端还是服务端的问题,为了方便解决动态接入的问题,我们让中间件成为服务端,保持长连接(实际上觉得可以由一个注册用服务器配合传输用客户端达成短连接)。
前端HTTP在构建服务器时需要解决常见的跨域问题,如果手写HTTP服务器的话,会发现OPTIONS需要进行单独处理(因为跨域是OPTIONS+对应请求,会发送两个请求),这里对跨域问题不再多做赘述。
总之觉得就这个设计而言,我设计的东西比较接近于一个RPC,而不太具有太多的实用价值。
接下来我们考虑缓冲消息(存储),缓冲存储使用Redis这类折中的解决方案,保证了一定量的可靠和速度要求。
之后根据规定的通信格式进行通信(可见GitHub),就能达到想要的效果了,当然,这其中其实忽略了很多细节问题:
首先是保证上文所说到的一些特性仍然存在,第一是要动态接入,这里我们定义一个new
命令来新增进存储单元,这样中间件就能做到只管消息转发,而无需在意客户端/服务端都是谁(只需要在意是否为指定类别)。
解析完通信指令并在内存中注册完成后,按照组别(我们假定同组是相同服务器、提供相同功能,也就是客户端与服务端请求需要幂等)进行均衡负载,这里我实现的比较简单,就是简单计算来轮询,实际上,可以通过服务器定期返回READY等字段来保证服务器的空闲可用,从可用中挑选,避免造成某一服务器的消息堆积。
之后还有一个问题是保证业务的原子性,也就是说多个事件要么同时成功,要么同时失败,比如说前端成功发送了请求,但是后端在处理过程中挂了,那么应该保证整个过程都是失败的,或者转接给其他可用的后端去做这个事情。
这个场景极为简单,简单的当然是统一的返回失败或者超时,当然,更好的用户体验是通过一些设计去尽可能的重发,比如说当返回超时时,过一段时间重新发送消息给后端,尝试获取,当成功处理后需要确认成功送达等(此处有点像TCP的超时重传和三次握手)。
当然,还有可能是依旧失败,依旧失败的情况下,我们就需要还原现场。(参考事务的概念)
保证消息处理的时序自然是不必说,必须保证一些模块的先后次序,否则必然会导致错误。
总的而言,这些想到了但没做的和美团的那篇文章中所写的差不多,当然,那篇文章中更有深度的讲了一些其他的东西以及进行了一系列比较。
说了半天,总结一下,就是……哎,又造了个没用的东西。
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。