1.消息存储
RocketMQ的消息存储通过consume queue和commit log实现;
consume queue是逻辑队列,相当于目录,指定消息在物理文件commit log中的存储地址;
可以通过配置指定consume queue存储的目录(commit log也可以指定),其默认目录为${rocketmq.home}/store/consumequeue/${topicName}/${queueId}/${fileName},每个topic下的每个queue都有一个consumequeue文件;
按照消费端的GroupName分组重试队列,如果消费端消费失败,消息会被发往重试队列中;
按照消费端的GroupName分组死信队列,如果消费端消费失败,并重试指定次数后仍然失败,消息会被发往死信队列中(死信队列中存储着消费失败及过期的消息);
consume queue中的存储单元是一个20字节的二进制数据,分为8byte的commitlog offset(消息在commit log文件中的实际偏移量)、4byte的size(消息的大小)、8byte message tag hashcode(消息tag的哈希值,主要用于消息订阅时的过滤);
每台broker上的commit log被本机所有的queue共享,不做任何区分;
commitlog的文件位置可配置,默认为${user.home} \store\${commitlog}\${fileName};
commitlog的消息存储单元长度不固定,消息顺序写,随机读;
2.消息订阅
RocketMQ消息订阅有两种模式,一种是push模式,即MQServer主动向消费端推送;另一种是pull,即消费端在需要时,主动到MQServer拉取,不过在具体实现时,两种模式都采用消费端主动拉取的方式;
push模式采用长轮询实现:Consumer每隔一段时间就主动向broker发送拉消息请求,broker在收到请求后,如果有消息则立即返回,consumer收到返回的消息后,再回调消费者设置的Listener方法;如果消息队列中没有数据,broker端会阻塞请求直到有数据或超时;
consumer端通过一个线程将阻塞队列LinkedBlockingQueue<PullRequest>中的PullRequest发送到broker;
broker端在接收到PullRequest时,如果发现没有消息,就会把PullRequest扔到ConcurrentHashMap中,而broker在启动时会启动一个线程不断对ConcurrentHashMap进行检查,有数据,就返回;
核心:Broker端Hold住Client过来的请求一小段时间,在这段时间内有消息到达,就利用现有连接立刻返回消息给Consumer。长轮询的主动权依然掌握在Consumer手中。
局限性:在Hold住Consumer请求时需要占用资源,比较适合消息队列这种客户端连接数可控的场景中。
优点:既掌握了主动权,又保证了实时性。
Push优点:实时性高;Push缺点:1.加大Server端工作量,进而影响Server端性能;2.各个Client性能不同,处理发送过来的任务时可能出现各种潜在问题;Pull优点:有主动权;Pull缺点:间隔不好确定;间隔小,容易“忙等”,浪费资源;间隔大,不能及时处理。
转载于:https://www.cnblogs.com/yuanfei1110111/p/10135557.html