技术架构
主要分为四个部分:
- NameServer:整个消息系统的状态服务器,没有使用 ZK 是因为用不到 ZK 那么多的功能,例如选举、同步等。NameServer 本身是无状态的,可以部署多个,相互之间没有数据交互。它主要用于管理 Broker 集群信息(提供心跳检查,检查是否有 Broker 下线) 和 Topic 路由信息(用于客户端查询)。
- BrokerServer:存储消息,提供消息的存储、推送、查询,集群部署可保证高性能、高可用。Broker 一主可以对应多从,主从之间会同步数据,同步方式分同步和异步,保存数据到磁盘文件也分为同步刷盘和异步刷盘。Broker 维护了 Topic 订阅信息,方便客户端做负载。
- Producer:消息生产者,通过负载选择合适的 Broker 发送消息,支持失败重试和故障规避。
- Consumer:消息消费者,订阅某一 Topic 的消息,支持 Push 和 Pull 两种模式。
工作流程:
- 首先启动 NameServer,等待 Broker、Producer、Consumer 来连接,并提供各种查询服务。
- 接着启动 BrokerServer,每隔 30s 定时向所有的 NameServer 发送心跳包,信息包括自己的状态和存储的 Topic 信息。
- NameServer 收到 Broker 心跳包后,更新相关信息,且会每隔 10s 检查上次 Broker 发送心跳的时间,若超过 120s 就判定 Broker 下线,并移除此 Broker 所有信息。
- 启动 Producer,先随机和 NameServer 建立长连接,发送消息前先需要创建 Topic,可以通过控制台也可以选择发送时自动创建,从 NameServer 获取这个主题可以发往的所有 Broker 的地址,轮询队列并和 Broker 建立长连接,然后发送数据。
- Broker 收到数据进行存储,并构建消费队列和索引文件。
- Consumer 跟 Producer 类似,启动后先随机和 NameServer 建立长连接,获取订阅信息,然后根据这心信息从 Broker 获取消息进行消费。
NameServer 启动流程
使用 commons-cli 解析启动参数,启动后默认监听 9876 端口,启动远程通信服务 RemotingServer。
this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
this.remotingExecutor =
Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_"));
注册默认处理器 DefaultRequestProcessor,用于接收客户端查询 Topic、查询 Broker,接收 Broker 注册、Broker 删除等的请求。
接着启动一个定时任务,定期检查 Broker 的心跳。
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
NamesrvController.this.routeInfoManager.scanNotActiveBroker();
}
}, 5, 10, TimeUnit.SECONDS);
NameServer 接收 Broker 的注册,并保存路由信息到 RouteInfoManager 类中。
private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable;
private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;
public class QueueData implements Comparable<QueueData> {
private String brokerName;
private int readQueueNums;
private int writeQueueNums;
private int perm;
private int topicSynFlag;
}
public class BrokerData implements Comparable<BrokerData> {
private String cluster;
private String brokerName;
private HashMap<Long/* brokerId */, String/* broker address */> brokerAddrs;
}
class BrokerLiveInfo {
private long lastUpdateTimestamp;
private DataVersion dataVersion;
private Channel channel;
private String haServerAddr;
}
- topicQueueTable:topic - Master Broker 队列信息
- brokerAddrTable:所有 Broker 的地址信息
- clusterAddrTable:集群和集群下 Broker 关系
- brokerLiveTable:Broker 的实时信息
- filterServerTable:过滤服务器
BrokerServer 主要提供的功能
- 消息存储(CommitLog 文件,ConsumeQueue 消息消费队列,IndexFile 索引文件,CheckPoint 文件)
- 消费者消费进度存储
- 消费者拉取消息过滤
- 消息推送到消费者
- 文件刷盘
- 主从同步
- 异常恢复
- 过期文件删除
- 定时消息
- 事务消息
- 消息追踪
- 流量控制
- 死信队列
Producer 消息发送流程
- 消息生产者启动
- 消息验证
- 查找主题路由信息
- 选择消息队列
- 发送消息
Consumer 消费消息流程
- 消息消费者启动
- 根据负载均衡策略选择 Broker
- 封装消息拉取请求,向 Broker 发出请求
- Broker 接收请求,通过验证、流控等后,查找并按照消息 tag 的 hash 过滤后返回消息(表达式过滤)
- Consumer 接收消息后再次验证 tag,消费后向 Broker 返回消费状态
- Broker 存储消费进度