手写MQ框架(一)-准备启程
一、背景
很久以前写了DAO框架和MVC框架,前段时间又重写了DAO框架-GDAO(手写DAO框架(一)-从“1”开始,源码:https://github.com/shuimutong/gdao.git)和MVC框架-GMVC(手写MVC框架(一)-再出发,源码:https://gitee.com/simpleha/gmvc.git)。
之前也尝试过写RPC框架(源码:https://github.com/shuimutong/grpc_beta.git),客户端、服务端的方法调用写完了,但是网络传输没有写。
其实写框架也好,写博客也好,主要是为了学习。所以现在再开始的时候,我就在思考写什么好?
我的想法很简单:把目前用到的框架,能自己实现的尽量都实现一遍。站在这个时间点,写哪个框架有两个选择:继续写RPC;写MQ。这两个框架个人认为有很多相似的地方:MQ虽然是异步的,其实也是有“长连接”在连着的。比如订阅方,会有长连接连着MQ的服务端。RPC框架不分订阅、发送,而是客户端、服务端,当客户端找到服务端之后,客户端会尽量和服务端保持连接。
相比MQ,RPC框架不需要持久化的动作,而MQ不仅需要考虑持久化,还需要考虑如何进行高效的持久化。
通过一番对比,我最终选择实现MQ框架,以学习序列化、网络传输、高效持久化方面的知识。选择的参照框架是kafka。
二、如何下手
既然选择了实现MQ,那从何下手呢?
先了解一下kafka吧。
1、mq框架大致流程
生产方和服务端建立连接,将消息发送到服务端。
订阅方和服务端建立连接,服务端将订阅方订阅的消息推送给订阅方,或者订阅方自己拉取指定的消息。
2、了解一下kafka
1)为什么kafka有如此高的qps
kafka服务可以部署在机械硬盘上,接收到的每条消息都会存盘,但是qps可以轻松过万,甚至达到百万级别(数据来源于网上,本人暂未亲测)。怎么做到的?
通过官网可以了解到,我记录的有3点。
首先,采用磁盘顺序读写。其次,基于java,使用堆外内存,避免gc的干扰。再次,所有数据写两份,防止丢失。此外,还有零拷贝技术等。
以上各个方面结合起来,最终成就了kafka的英名!
2)是推消息还是拉消息
推消息的话,如果消息骤增,可能导致订阅方崩掉,所以kafka采用的是拉的方式。以什么频率拉,由订阅方自己决定。
其实采用拉消息的方式也有缺点,比如订阅方为了拉消息,就会一直在哪里循环请求。如果没有新消息,订阅方就会频繁的请求,白白浪费资源。
针对这个循环空请求的问题,kafka增加了一个特性。当拉消息的时候,可以设置:如果没有消息,就先夯住请求,等到消息来了,再返回结果。这样,就能够避免这类问题了。
3、写框架计划
在稍微看了kafka之后,感觉这个技术含量还是很高的。虽然上面只列了几点,其实还有很多很重要的点没有提及。但是,我就是要学写。如果等我先把kafka看透之后再写,那可能得等很长时间。(其实我已经磨蹭了很长时间)
所以我决定,先把架子搭起来。万丈高楼也得平地起!
1)大致方案
写服务端,网络传输使用http,序列化使用json(传输字符串,其实无所谓json),数据持久化使用DB。
虽然使用http传输,但是需要封装成具体的工具,避免客户端自己写请求工具,方便后期升级。
2)生产方发消息
消息包括:主题、消息内容
3)订阅方拉消息
主题、消息内容、offset(拉多少条)
4)服务端处理
消息来了之后,将消息存在DB,编offset。
拉消息动作,根据offset,返回取的多少条。
offset的提交应在客户端里进行封装,可先实现为自动提交。
5)框架组成
a、服务端
b、生产消息客户端(服务配置)
c、消费消息客户端(服务配置)
6)配置项
a、服务地址
b、主题号
大致计划已定,那就开始实现吧
三、服务端功能梳理
1、注册主题号
校验主题号是否存在,不存在则新增
2、接收消息
参数:主题号、消息体
先校验主题号是否存在,存在则保存消息到DB,然后返回结果
3、拉消息
参数:主题号、offset、希望取的消息数量
校验主题号是否存在,校验offset是否正常,正常则返回希望的消息数量(如果有消息)。
4、更改offset
参数:主题号、offset
校验主题号是否存在,校验offset。
重复消费功能后期做。
四、结语
关于手写MQ,暂时想的就这么多,后面想到其他的再加上。
先实现一个简易的服务端,接下来就是代码实现了。
写代码中……
第一个版本在上周写完了,欢迎指教->手写MQ框架(二)-服务端实现