面试题答案
一键面试队列设计
- 合理划分队列数量:
- 根据业务场景和预计的并发量来确定队列数量。如果队列数量过少,可能会成为性能瓶颈,过多则会增加管理成本和资源消耗。例如,对于订单处理场景,若预估每秒有1000个订单消息,每个队列能处理200条消息/秒,那么可设置5 - 10个队列(考虑一定冗余)。
- 对于顺序性要求严格且高并发的场景,可适当增加队列数量,通过将不同类型的顺序消息分配到不同队列,避免单个队列压力过大。
- 分区策略:
- 采用一致性哈希算法对消息进行分区,使得消息均匀分布到各个队列中。这样可以避免某些队列负载过高,同时保证同一业务逻辑相关的消息能进入同一队列,从而保障顺序性。例如,以订单ID作为哈希键,确保同一订单的所有消息进入同一个队列。
生产者发送策略
- 同步发送与异步发送结合:
- 对于对顺序性和可靠性要求极高的关键消息,采用同步发送方式,确保消息发送成功且顺序性得到保障。例如订单创建、支付成功等核心消息。
- 对于一些非关键且允许一定延迟的消息,如订单状态变更通知等,采用异步发送方式,提高发送效率,提升系统整体性能。可以使用
SendCallback
接口来处理异步发送的回调,在消息发送成功或失败时进行相应处理。
- 批量发送:
- 将多条消息合并为一个批量消息进行发送,减少网络交互次数,提高发送性能。但要注意批量消息大小不能超过RocketMQ规定的限制(默认4MB)。例如,对于一些日志消息或同一类别的状态变更消息,可以批量收集一定数量后发送。
消费者消费策略
- 单线程消费:
- 为保障消息顺序性,消费者采用单线程消费模式。在消费者端,为每个队列分配一个独立的消费线程,确保每个队列中的消息按顺序依次被消费。这样虽然牺牲了部分并发处理能力,但能有效保障消息顺序。
- 消费线程池优化:
- 如果业务场景允许一定程度的并行处理,可适当增加消费线程池大小,但要注意不能破坏消息顺序性。例如,对于同一订单的消息,可在订单级别内并行处理不同子任务的消息,但整体订单消息仍需按顺序消费。
- 合理设置线程池的核心线程数、最大线程数、队列容量等参数。比如,根据服务器的CPU核数和内存情况,将核心线程数设置为CPU核数的1 - 2倍,最大线程数根据系统负载动态调整。
- 消费重试机制:
- 当消费消息失败时,合理设置重试策略。对于一些可恢复的错误(如网络短暂波动、数据库短暂连接异常等),自动进行重试。但要注意设置重试次数和重试间隔,避免无限重试导致系统资源耗尽。例如,设置重试3 - 5次,每次重试间隔从1秒开始,每次翻倍。
存储优化
- 选择合适的存储介质:
- 对于高性能要求,可选用SSD磁盘作为存储介质,相比传统机械硬盘,SSD具有更高的读写速度,能有效提升消息存储和读取的性能。
- 存储结构优化:
- RocketMQ采用CommitLog和ConsumeQueue的存储结构。合理调整CommitLog和ConsumeQueue的刷盘策略,对于性能要求高的场景,可采用异步刷盘方式,提高写入性能,但会牺牲一定的数据可靠性;对于数据可靠性要求极高的场景,采用同步刷盘方式。
- 定期清理过期的消息和日志文件,释放磁盘空间,避免因磁盘空间不足导致性能下降。
- 主从架构与负载均衡:
- 搭建RocketMQ主从架构,主节点负责消息的写入和读取,从节点作为备份和分担读压力。通过负载均衡机制,将读请求合理分配到主从节点上,提高系统整体的读性能。同时,主从之间的数据同步采用异步复制或同步复制策略,根据业务对数据一致性和性能的要求进行选择。