最佳实践
第一遍就该怎么做、为什么 —— 生产者侧、消费者侧、topic 设计、部署。
这里每一条都推导自冻结的设计决策,不是来自基准测试。凡是依赖实测才能定的选择,本页会直说,而不是猜。
1. 生产者
1.1 让发布幂等
每次发布都同时设 producer_id 和 producer_seq。broker 按 (topic_id, partition, producer_id) 窗口去重,所以超时后的客户端重试不会写重。
producer_id=0 && producer_seq=0 → 允许,计入「非幂等发布」
producer_id=0 && producer_seq>0 → 拒绝,0x0013
其他 → 按窗口去重两个都留 0 也能跑 —— 但那等于把重试安全的全部负担搬到你自己的记账上,而且指标会悄悄把你算成非幂等。
1.2 认真挑 key
分区选择是 fnv1a32(key) % partition_count。所以 key 就是排序保证:同 key 的消息落同一分区、保持有序;key 只有分布均匀,流量才均匀。
- 需要按业务实体排序 → 用业务标识(
order_id)。 - 不在乎 → key 留空。均匀散开好过一个偏斜的 key 把 80% 流量灌进同一个分区。
1.3 分区数只定一次
分区数在 DECLARE 时定死,v0 不能改。 它决定并行度、消费者扩展余量、以及一次 rebalance 要多久。定少了只能换 topic 名重建(历史全丢);定多了则是每次 rebalance 都要为空分区买单。
默认是 4(partition_default_count)。改之前先想清楚峰值消费者数。
2. 消费者
2.1 及时 ACK
一条未 ACK 的消息同时占着 credit 和 租约(delivery_lease_ms,默认 30 s)。两者都有限:credit 耗尽只是暂停调度(不丢消息),但租约会超时重投 —— 超过 delivery_max_attempts(5 次)就进 DLQ。
处理器慢就把工作攒批、整批 ACK;别让一条消息跨着一次慢 IO 一直开着。
2.2 按消息大小调 credit 窗口
默认窗口是 256 条 / 2 MiB。这两个数不是独立的 —— credit_bytes 按同一比例从 credit_count 派生。大消息会先把字节数耗尽:拉 64 KiB 消息的消费者,实际在途是 32 条,不是 256 条。
2.3 把 0x4006 NO_CREDIT 当正常流控
它不是该告警的错误。窗口在 32 ACK / 1 MiB / 低水位 / 20 ms 任一触发时自动归还。要告警就告 mortarmq_group_lag 持续增长。
3. Topic 设计
- 命名规则是强制的,不是建议:不许通配符、不许空 token、不许
$前缀、不许.dlq后缀(保留给 DLQ 孪生 topic)、≤ 255 字节。违反返回0x000B INVALID_TOPIC。 - 一条业务流一个 topic,不要按消费者拆。消费者靠 group 区分,不是靠复制 topic。
$前缀是保留的,它标记系统 topic;用户 topic 不能占。
4. 部署
- 绝不暴露
listen_peer。 它跑复制流量:独立共享密钥、没有客户端认证。 listen_admin保持绑127.0.0.1。 v0 的指标面没有认证 —— 绑宽一点就等于把队列深度和拓扑不设防地读出去。ws_origins写明确。 空列表 = 拒绝所有来源(安全默认值);别把「空即全放」当成修复去改。- 每节点一个
data_dir。 否则互相破坏 segment。
5. 观测
盯守恒恒等式,不是盯单个 counter:
produced = delivered + dropped + dlq + Δdepth (静默窗口)任何漂移都意味着某个 counter 在说谎。dropped 涨只有在 dlq 跟着涨时才是正常的 —— dlq_total <= dropped_total 必须成立。
目前还没有代码
没有任何代码被实测过。上面没有一条声称数字 —— 这些实践来自冻结设计的取舍;凡是真正需要基准才能回答的问题,基准测试页会明说。