消息队列存储消息数据的表结构
【设计思路】
一个队列对应一个表,一个队列只处理一个业务消息,因此消息数据格式统一降低生产者和消费者消息处理复杂度,且简单、高效、易维护、易扩展;
创建一个队列就在每台数据库上冗余相同的表结构,表名包含队列名称,SDK 轮询方式写入和读取消息;
需要考虑多种消息队列模式,对于该系统消息队列我们只考虑两种队列模式,即工作队列模式和发布订阅模式。
工作队列模式:消息消费者客户端允许有一个到多个,但每个消费者轮流从队列里面获取消息,每条消息只被读取和消费一次;
发布订阅模式:消息消费者客户端允许有一个到多个,每条消息需要被每个客户端消费一次;
需要考虑客户端消费消息的可靠性,分为客户端确认和不确认,分别对应消息传递可靠性要求不同的场景;
消息 ID 是消息队列的关键因素,需要自包含有意义的信息,如:创建时间,序列号、生产者、业务类型等,以保障粗略有序和提高索引效率的同时,便于消息传递失败情况下的故障诊断和后续数据修复和处理,比如:重发、重新读取或业务数据修正等等。
需要对消费者读取消息的位置和日志进行记录,以便于从最后一次读取的消息 ID 处继续读取未读取的消息,可配置消费者一次读一条或多条消息。
【整体架构示意图】
【表结构设计说明】
消息 ID 格式
说明:
可支持每台消息服务器对每个子业务单秒最高可产生 2 的 20 次方条消息,即支持每秒百万条消息 ID 生成,足以应对业务场景需求。
<queue_name>_msg_tbl:
说明:
1)msg_create_time + serial_number 作为组合索引,可以根据时间和序列号进行消息查询。
2)主键 ID 本身是有序自包含有意义的信息,因此主键 ID 本身也可进行范围查找和精确查找。
SELECT * FROM user_registration_msg_tbl WHERE id > 18446744073709551611 LIMIT 1;
该条语句查询性能可达到 range,因此性能有保障。
<queue_name>_consumption_position_tbl
说明:
1)consumer_id 在创建消息队列时就根据消息队列模式生成,其格式同消息 ID 一致,只是场景位取值不一样。同一个 consumer_id 可被一个或多个消费者持有。
2)多个客户端获取消息时在服务器端将用 lock 控制消息读取,每读取一个消息就将 last_read_msg_id 更新,下一个客户端消费者将继续下一个 msg_id 继续读取消息。
<queue_name>_consumption_log_tbl
说明:
1)每个客户端读取消息并返回前都会写入一条消息消费日志,并且将状态置位:0-客户端已读取但还未确认;
2)如果消息客户端启用了消息确认模式,将会在客户端处理消息和执行完对应的业务逻辑后,发送确认消息给到服务器,并更新日志状态为 1 或 2;
3) 对于超时为收到确认消息的可实现自动重新排队或人工处理未确认数据。
评论