一、问题描述
备机stop,主机执行gs_probackup,备份失败,报错信息为"unrecognized streaming header 'a'"。
二、分析思路
(1)查找报错信息,发现gs_probackup无法处理消息头'a'。
(2)查找代码中可能会发送消息头'a'的地方,在walsener和walreceiver循环处理消息的部分都有消息头'a',该消息为归档消息类型,且处理归档消息有一个条件,即g_instance.archive_obs_cxt.archive_slot_num不为0 的时候才会进行处理。
walreceiver线程:
XLogWalRcvProcessMsg -> ProcessArchiveXlogMessage -> find_archive_task_status
当有归档任务(archive_task != NULL)时,备机处理归档
walsender线程:
WalSndLoop
(3)查找archive_slot_num赋值的地方,尝试构造可能场景复现问题并找测试确认执行用例,复现问题,最终确认开启了备机归档,具体操作为:
- 开启enable_slot_log参数
- 主机执行SELECT pg_create_physical_replication_slot_extern('test_slot_1',false,'NAS;/usr1/zym_non/archive;0;0',false);
(4)复现问题,分析发送消息'a'的原因以及gs_probackup会接收到消息'a'的情况:
经尝试,问题必现场景为 -- 备机stop,集群中只有主机normal,执行gs_probackup;
查看主机walsender线程发送消息头'a'条件 ,涉及walsnd->archive_task_count,继续查找增加地方为add_archive_task_to_list <- pgarch_archiveRoachForPitrMaster,在函数pgarch_archiveRoachForPitrMaster中发现选择walsender的函数pgarch_chooseWalsnd,选择walsender的逻辑为:
如果是第一次发送或是上一次发送的备机已经断连,就选择第一个落盘位置不小于flushPtr(多数派落盘位置,具体是啥没有研究)的备机,否则就选择上一次发送的备机进行发送。当备机与gs_probackup与主机相连时,主机保存的walsnds内容为
当备机stop时按照该逻辑只能选择gs_probackup发送归档消息,而gs_probackup又不能处理'a',导致备份失败。
三、问题解决
(1)初版方案:每个与主机相连的备机对应一个walsender线程,备机开启归档后,标记对应的walsender线程;
具体代码:
存在的问题:归档功能不能正常使用;
问题原因:归档槽与主备之间的walsender不是绑定关系,不能修改其archive_config等内容;在主机调用pg_create_physical_replication_slot_extern创建归档槽前,每个备机会有一个归档槽(备机与主机连接时对应的walsender创建,在开启备机归档前),且与主备间的walsender进行绑定(slot_idx),后续创建或处理该归档槽的时候由于已经使用,没有对其archive_config进行处理,导致新增条件一直不满足,归档失败。
(2)终版方案:归档选择备机时,排除gs_probackup