手写一个分布式消息队列中间件(MQ)是一个复杂的系统工程,涉及网络通信、存储引擎、分布式协议、高可用性等多个核心模块。以下是实现一个基础版分布式消息队列的完整思路和代码框架,帮助你从0到1构建一个轻量级MQ。
一、核心设计目标
- 基础功能:消息的发布、存储、消费、ACK确认
- 扩展性:支持水平扩展(Broker集群)
- 高可用:消息持久化、副本机制
- 高性能:低延迟、高吞吐量
二、架构设计
1. 单机版MQ核心模块
text
复制
+---------------------+
| Producer | --> 发送消息
+---------------------+
|
| (TCP/HTTP)
v
+---------------------+
| Broker |
| +-----------------+ |
| | Storage Engine | | --> 消息存储(内存+磁盘)
| +-----------------+ |
| +-----------------+ |
| | Request Handler| | --> 处理生产/消费请求
| +-----------------+ |
+---------------------+
|
| (TCP/HTTP)
v
+---------------------+
| Consumer | --> 消费消息
+---------------------+
2. 分布式扩展
- Broker集群:多个Broker节点组成集群
- 服务发现:ZooKeeper/Etcd 管理节点注册与发现
- 分区机制:Topic分片存储在不同Broker
- 副本机制:主从复制保证高可用
三、核心实现步骤
1. 存储引擎设计
- 内存队列:快速读写(使用
ConcurrentHashMap+PriorityQueue) - 磁盘持久化:顺序写日志(类似Kafka的Segment设计)
- 索引文件:加速消息查找
java
复制
// 存储引擎核心逻辑(简化版)
public class StorageEngine {
// 内存中的消息队列(按Topic分区)
private Map<String, Queue<Message>> topicQueues = new ConcurrentHashMap<>();
// 持久化到磁盘(使用文件存储)
public void appendToDisk(Message message) {
try (FileChannel channel = new FileOutputStream("message.log", true).getChannel()) {
ByteBuffer buffer = ByteBuffer.wrap(message.serialize());
channel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
// 从磁盘加载消息(启动时恢复)
public void loadFromDisk() {
// 解析文件并重建内存队列
}
}
2. 网络通信层
- 协议设计:自定义二进制协议或使用HTTP/Protobuf
- 高性能IO:使用Netty实现异步非阻塞通信
java
复制
// Netty服务端核心代码(简化)
public class BrokerServer {
public void start(int port) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new MessageDecoder()); // 解码器
ch.pipeline().addLast(new MessageHandler()); // 业务处理
}
});
ChannelFuture future = bootstrap.bind(port).sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
3. Producer/Consumer客户端
- Producer:发送消息到指定Topic
- Consumer:订阅Topic并拉取消息,支持ACK机制
java
复制
// Producer发送消息示例
public class Producer {
public void send(String topic, String message) {
try (Socket socket = new Socket("localhost", 9090)) {
OutputStream out = socket.getOutputStream();
out.write(serializeMessage(topic, message));
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Consumer消费消息示例
public class Consumer {
public void poll(String topic) {
// 发送订阅请求到Broker
// 长轮询或事件驱动模式获取消息
}
}
4. 分布式集群实现
- 服务注册与发现:使用ZooKeeper管理Broker节点
- 分区路由:基于一致性哈希或Range策略分配Topic分区
- 副本同步:Leader-Follower副本同步(类似Kafka)
java
复制
// ZooKeeper服务注册示例
public class ServiceRegistry {
private CuratorFramework client;
public void register(String brokerId, String address) {
try {
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath("/brokers/" + brokerId, address.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}