消息越大吞吐越低是常识,但具体是怎么降的?拐点在哪里?大消息在线上被怎么拆帧?有没有大小上限?放在队列里占内存还是占磁盘?这篇用同一套带 confirm 的异步发布把这些都量一遍。
消息大小 条数 耗时 条/秒 MiB/秒 10 B 30000 502 ms 59713 0.6 100 B 30000 511 ms 58765 5.6 1 KiB 30000 549 ms 54651 53.4 10 KiB 30000 638 ms 47041 459.4 100 KiB 3072 221 ms 13876 1355.1 1 MiB 300 209 ms 1436 1435.7
小消息(≤ 1 KiB)吞吐约 5~6 万条/秒,每条的处理开销主导;从 10 KiB 起条数下降而带宽上升,100 KiB~1 MiB 时带宽约 1.4 GiB/秒。
消息大小 条数 耗时 条/秒 MiB/秒 10 B 30000 539 ms 55621 0.5 100 B 30000 515 ms 58295 5.6 1 KiB 30000 546 ms 54962 53.7 10 KiB 30000 642 ms 46703 456.1 100 KiB 3072 219 ms 14035 1370.6
单节点上 classic 和 quorum 的吞吐曲线几乎重合,消息大小才是主要因素。
协商的 frame_max = 131072 一条 300 KiB 的消息:Basic.Publish 1 个帧 + ContentHeader 1 个帧 + ContentBody 3 个帧(每个最大 131072 字节,最后一个 45080 字节)
消息体按协商的 frame_max(131072)拆成多个 ContentBody 帧;ContentHeader 记录总长度。
1 MiB: 成功
16 MiB: 成功
17 MiB: ChannelClosedByBroker: (406, 'PRECONDITION_FAILED - message size 17825792 is larger than configured max size 16777216')
130 MiB: ChannelClosedByBroker: (406, 'PRECONDITION_FAILED - message size 136314880 is larger than configured max size 16777216')
$ rabbitmqctl eval "application:get_env(rabbit, max_message_size)." → {ok,16777216}max_message_size 默认 16 MiB,超过得到 406 PRECONDITION_FAILED,channel 被关。
放入前:broker RSS 137 MiB,数据目录 0.1 MiB 1000 条 × 1 MiB 之后:broker RSS 152 MiB,数据目录 1000 MiB;队列 messages=1000 messages_ram=1 队列进程内存=0.0 MiB
大消息放进经典队列后主要在磁盘上(1000 条 1 MiB:磁盘 +1000 MiB,RSS +15 MiB)。