Skip to content

最佳实践 ​

第一遍就该怎么做、为什么 —— 生产者侧、消费者侧、topic 设计、部署。

这里每一条都推导自冻结的设计决策,不是来自基准测试。凡是依赖实测才能定的选择,本页会直说,而不是猜。

1. 生产者 ​

1.1 让发布幂等 ​

每次发布都同时设 producer_id 和 producer_seq。broker 按 (topic_id, partition, producer_id) 窗口去重,所以超时后的客户端重试不会写重。

text
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 必须成立。

目前还没有代码

没有任何代码被实测过。上面没有一条声称数字 —— 这些实践来自冻结设计的取舍;凡是真正需要基准才能回答的问题,基准测试页会明说。