设计MQ的路程
基本要求:
为了解耦削峰,需要设计一个Message Queue(MQ)作为消息中间件,尝试实现以下功能:
- 确保消息被消费的ack机制
- 尝试使用Broker模型来实现
- 提供RESTful api给使用者
- 对消息有可靠的通知机制
- 有发布订阅模型
- 高性能
- 有优先级队列
- 消息持久化
- 支持集群化部署(水平扩展)
经过了解之后,预计MQ具有以下功能:
publish端
publish——server端:
主线程{
主动与server建立连接
客户端通过调用函数发送msg
}
子线程{重发功能
监听server端返回的ack消息
超时未收到之后,重发msg
}
server端
server——publish端:
主线程{
接收publish端msg,判断是否重复消费,一定返回ack
将消息放进队列
}
server——consumer端:
主线程{
if consumer状态允许{
主动将接收的msg推送给consumer
consumer状态+1
}
}
子线程{
监听consumer端返回的ack消息
超时未收到之后,重发msg
}
consumer端
consumer——server端:
主线程{
主动与server建立连接
消费msg
返回ack
}
子线程{
接收server端msg,判断重复消费
}
功能总结:
- publish端:发送消息、超时重发
- server端: 建立MQ模型
- publish:接收消息、避免重复消费、返回ack
- consumer:发送消息、超时重发
- consumer端:接收消息、避免重复消费、返回ack
过程中遇到的问题及解决方案
问题:
server创建的子线程无法发送消息
解决:
是libevent多线程的问题,需要开启多线程的一些选项
问题:
粘包问题
解决:
第一次是使用短连接:不能从根本解决问题、而且效率很慢
改用长连接,加入消息头设定。
问题:
如何判断重复消费
解决:
consumer可以通过server控制唯一的guid来判断
publish端不唯一,第一次是server将消息存起来,然后使用暴力比对判断(内存肯定爆)
因此删除publish——server端ack、超时重发机制
问题:
如何模拟多个客户端
解决:
通过多线程模拟,但是每个客户端都有子线程,这就相当于用子线程去创建子线程,同一个主线程的所有子线程之间是并列的关系,因此不能达到要求
改用bat批处理,给main函数传参,达到控制的效果
问题:
server端只使用一个缓冲区去存所有客户端的消息,导致各种消息错乱(不是消息头的问题)
解决:
针对每个客户端创建一个独立的缓冲区,这样就可以正常工作
已完成功能:
- 模式:
一对一
多对一
发布订阅 - ack机制、超时重发机制
- 客户端接口;
设置consumer消费上限
设置重发检测间隔
设置重发上限 - 优先级队列:只考虑优先级,先发优先级高的msg
拿到课题之后解析问题的过程
- 将问题抽象出来,高度概括成一个核心问题:考察抽象能力
- 根据核心问题进行具体的模型设计:考察设计能力
- 根据模型设计进行编码实现:考察编码能力
汇报
中期:
- 之前做了什么,做到什么程度了,要展示你针对这个问题进行的思考,针对这些思考做了哪些行动,要具体,这是重点
- 过程中遇到了什么问题,挑一两个重点的讲,主要讲遇到了什么问题,我是怎么思考的,最后怎么解决的
- 之后计划:简单介绍
终期:
- 成果展示,简单介绍并演示
- 数据展示,数据表可以有很多,但是讲的时候不能全都很全面的讲,挑一两组最基本最经典的数据,讲清楚,其他的高度概括一下就可以
- 整体设计,说清楚我这个设计是什么样子的,他是怎么运作的,为什么是这么设计的,另外一种方法行不行,行:为什么不用那个;不行:为什么不行(重点)
- 过程中遇到了什么问题,挑一两个重点的讲,主要讲遇到了什么问题,我是怎么思考的,最后怎么解决的
- 如果有足够的时间,我还会加什么功能,我的设计还有那个部分需要去完善
最后:针对设计中的每个环节都需要发散性的考虑问题
举几个例子:
- 我这次的设计是基于RabbitMQ的模型实现的,那有没有了解过他的工作原理,为什么要选这个MQ,而不是RocketMQ
- 过程中使用了guid,你的guid是怎么生成的,有么有了解过一些现有的guid生成器,为什么不用那些比较经典的guid生成器
- 数据展示的挺好,那有没有了解过其他经典MQ的压测数据,你和他差距在哪个部分,为什么会出现这样的差距,你之后准备怎么去缩小这样的差距
以上所有过程都添加了一些答辩的元素