“消息持久化”到底是几个开关?只设 delivery_mode=2 够不够?kill -9 之后会丢多少?transient 消息是不是只在内存里?durable 队列绑在非 durable 的 exchange 上重启会怎样?这篇用真的重启和真的 kill -9 来验证。
默认配置下 durable=False 的队列 → ConnectionClosedByBroker: (541, "(541, 'INTERNAL_ERROR - Feature `transient_nonexcl_queues` is deprecated."…) —— 注意是整条连接被关,不只是 channel exclusive=True 的非持久队列 → 成功(随连接消失) 服务器命名 + exclusive + auto_delete 的队列 → 成功
RabbitMQ 4.3.6 默认不允许声明“非持久、非排他”的队列(541 INTERNAL_ERROR,整条连接被关),只有 exclusive 的非持久队列可以。想做非持久队列的实验要在配置里打开 deprecated_features.permit.transient_nonexcl_queues。
重启前: {'tq.p': 100, 'tq.t': 100, 'dq.p': 100, 'dq.t': 100}
正常重启后: {'dq.p': 100, 'dq.t': 0}
规则:非持久队列重启后连队列本身都没了;持久队列里只有 persistent 消息还在,transient 消息没了(哪怕它所在的队列还在)队列要 durable、消息要 delivery_mode=2,重启后消息才保留。只满足一个不行:非持久队列重启后连队列都没了,持久队列里的 transient 消息被清空。RabbitMQ 4.x 还默认禁止建非持久、非排他的队列。
发完马上 kill -9(不等任何确认): 重启后 kq 里有 4080 条(发了 5000 条) 每条等 confirm、全部回来后 kill -9: 重启后 kq 里有 5000 条(发了 5000 条) 发完等 2 秒再 kill -9: 重启后 kq 里有 5000 条(发了 5000 条) 注意:kill -9 只杀进程,操作系统页缓存里的数据不会丢;真正的掉电丢数据这里测不到
没等 confirm 的发布在 broker 被杀时可能没处理完;收到 confirm 的不会丢。这里 kill -9 杀的是进程,操作系统缓存里的写入仍在,所以断电的情况需要另外的试验(没有测)。
基线 428 KiB;persistent 20000 条 × 1 KB 后增长 24844 KiB;transient 20000 条 × 1 KB 后增长 24852 KiB vhost 数据目录(msg_stores/vhosts/<id>/)下各子目录的大小(KiB): msg_store_persistent=0, msg_store_transient=0, queues=49704 每个队列一个子目录(队列索引文件 .qi):队列目录数 = 2;其中一个队列目录里的文件: ['.qi', '.qi', '.qi', '.qi', '.qi', '.qs', '.qs', '.qs', '.qs', '.qs', 'ame']
4.3.6 的经典队列把小消息直接写进自己目录里的 .qs 文件,索引放 .qi;transient 消息同样写盘,只是重启时不被恢复。所以 transient 并不意味着不占磁盘。
重启前 exchange: ['x.durable(durable=true)', 'x.transient(durable=false)'];绑定: ['x.durable → dq.bind', 'x.durable → tq.bind', 'x.transient → dq.bind', 'x.transient → tq.bind'] 正常重启后 exchange: ['x.durable(durable=true)', 'x.transient(durable=false)'];绑定: ['x.durable → dq.bind', 'x.transient → dq.bind'] 重启后的队列: ['disk.persistent', 'disk.transient', 'dq.bind'] 向 x.transient 发布并路由: dq.bind 里现在有 1 条 再 kill -9 重启后 exchange: ['x.durable(durable=true)', 'x.transient(durable=false)'];绑定: ['x.durable → dq.bind', 'x.transient → dq.bind']
非持久队列被清掉时,它的绑定也一起消失;而 durable=false 的 exchange 在 4.3.6 里重启后还在,绑定到持久队列的那条也保留。(这与较早版本的说法不同,以实测为准。)