openGauss备机追数Catchup过程中主库写入阻塞问题

时间:2022-07-25
本文章向大家介绍openGauss备机追数Catchup过程中主库写入阻塞问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

最近在测试openGauss主从复制时发现一个问题:当备机落后主机很多时(比如停了一段时间后再启动),启动后会自动的追数,追数的过程状态是catchup,而在catchup的过程中,主库上的写入会全部阻塞,当然经过进一步验证,如果存在其他正常的备库(状态是normal),那么其中一个备库catchup不会阻塞主库。

下面我们来复现一下这个问题,由于openGauss主从搭建会自动创建物理复制槽,所以备库需要的xlog主库不会自动清理,那么我们就可以先把两个备库都停掉(我这里的环境是一主两备),然后在主库插入大量数据,产生大量xlog的堆积,然后过一段时间再挨个开启备库,查看追数过程中tps的影响。

停止两个备库

[omm@db02 ~]$ gs_ctl stop
[2020-09-16 14:03:56.724][89873][][gs_ctl]: gs_ctl stopped ,datadir is (null)
waiting for server to shut down.... done
server stopped
[omm@db03 ~]$ gs_ctl stop
[2020-09-16 14:04:03.525][60271][][gs_ctl]: gs_ctl stopped ,datadir is (null)
waiting for server to shut down.... done
server stopped

使用压测工具对主库进行并发插入,并观察xlog个数

可以看到xlog在逐步堆积

199

199

199

203

210

217

224

231

238

245

253

260

267

274

tps比较稳定

14:04:58 22254

14:04:59 23582

14:05:00 23937

14:05:01 23316

14:05:02 22994

14:05:03 23452

14:05:04 23920

14:05:05 24097

14:05:06 23886

14:05:07 21578

14:05:08 22731

14:05:09 23315

14:05:10 24749

此时启动第一个备库,观察状态

[omm@db02 ~]$ gs_ctl start -M standby
[omm@db02 ~]$ gs_ctl query
[2020-09-16 14:07:48.392][108727][][gs_ctl]: gs_ctl query ,datadir is (null)
 HA state:           
        local_role                     : Standby
        static_connections             : 2
        db_state                       : Catchup
        detail_information             : Normal


 Senders info:       
No information
 Receiver info:      
        receiver_pid                   : 108470
        local_role                     : Standby
        peer_role                      : Primary
        peer_state                     : Normal
        state                          : Catchup
        sender_sent_location           : 2B/B6800000
        sender_write_location          : 2D/A2F5B7D8
        sender_flush_location          : 2D/A2F5B7D8
        sender_replay_location         : 2D/A2F5B7D8
        receiver_received_location     : 2B/B6800000
        receiver_write_location        : 2B/B6000000
        receiver_flush_location        : 2B/B6000000
        receiver_replay_location       : 2B/B4C1E548
        sync_percent                   : 95%
        channel                        : 192.168.1.2:38782<--192.168.1.1:5533

tps如下:

14:06:14 19037

14:06:15 18776

14:06:16 19302

14:06:17 11734

14:06:18 0

14:06:19 0

14:06:20 0

14:06:21 0

14:06:22 0

14:06:23 0

14:06:24 0

14:06:25 0

14:06:26 0

14:06:27 0

14:06:28 0

14:06:29 0

14:06:30 0

14:06:31 0

14:06:32 0

14:06:33 0

14:06:34 0

14:06:35 0

14:06:36 0

14:06:37 0

14:06:38 0

14:06:39 0

14:06:40 0

14:06:41 0

14:06:42 0

14:06:43 0

14:06:44 0

14:06:45 0

14:06:46 0

14:06:47 0

14:06:48 0

14:06:49 0

14:06:50 7753

14:06:51 12308

14:06:52 10988

14:06:53 12337

直到catchup状态变为normal时tps才恢复正常

启动第二个备库:

[omm@db03 ~]$ gs_ctl start -M standby

观察状态,虽然sync_percent没有完全同步完,状态是catchup,(有时候也有可能是normal,可能和主备启动时间间隔有关),因为此时已经有一个正常同步的备库,这时第二个备库在追数过程中不会影响主库。

[omm@db03 ~]$ gs_ctl query
[2020-09-16 14:09:19.995][74488][][gs_ctl]: gs_ctl query ,datadir is (null)
 HA state:           
        local_role                     : Standby
        static_connections             : 2
        db_state                       : Normal
        detail_information             : Normal


 Senders info:       
No information
 Receiver info:      
        receiver_pid                   : 73921
        local_role                     : Standby
        peer_role                      : Primary
        peer_state                     : Normal
        state                          : Catchup
        sender_sent_location           : 2C/3F800000
        sender_write_location          : 2D/D5F901D8
        sender_flush_location          : 2D/D5F901D8
        sender_replay_location         : 2D/D5F901D8
        receiver_received_location     : 2C/3F800000
        receiver_write_location        : 2C/3D000000
        receiver_flush_location        : 2C/3D000000
        receiver_replay_location       : 2C/2B070088
        sync_percent                   : 96%
        channel                        : 192.168.1.3:30200<--192.168.1.1:5533

tps一直比较稳定

14:07:14 12551

14:07:15 11853

14:07:16 12530

14:07:17 12432

14:07:18 12680

14:07:19 12036

14:07:20 11758

14:07:21 11242

14:07:22 11206

14:07:23 11607

14:07:24 11926

14:07:25 11494

14:07:26 11804

14:07:27 12842

14:07:28 12613

14:07:29 12188

14:07:30 13310

14:07:31 15119

14:07:32 15165

14:07:33 14045

为了找到catchup过程中阻塞主机的根本原因,看了相关代码。

在openGauss-server/src/bin/pg_ctl/pg_ctl.cpp中有如下代码:

 if (beforeStat.st_mtim.tv_sec != afterStat.st_mtim.tv_sec ||
                        beforeStat.st_mtim.tv_nsec != afterStat.st_mtim.tv_nsec) {
                        nRet = memset_s(&state, sizeof(state), 0, sizeof(state));
                        securec_check_c(nRet, "", "");
                        ReadDBStateFile(&state);
                        switch (state.state) {
                            case NORMAL_STATE:
                            case NEEDREPAIR_STATE:
                            case WAITING_STATE:
                            case DEMOTING_STATE:
                            case PROMOTING_STATE:
                            case BUILDING_STATE:
                            case CATCHUP_STATE:
                                return PQPING_OK;
                            case COREDUMP_STATE:
                                pg_log(PG_WARNING, _(" gaussDB state is %sn"), get_string_by_state(state.state));
                                return PQPING_NO_RESPONSE;
                            case STARTING_STATE:
                            case UNKNOWN_STATE:
                            default:
                                /* nothing to do */
                                break;
                        }

可以看到,如果数据库状态是catchup,那么代表PGPING_OK,也就是代表备机正常,那么主库收到该备机正常的信号后会去向备机同步,但是备机同步该条变更的前提是之前的xlog已经接收完成,但是当前还是catchup状态,依旧在发送日志,所以此时主库的变更都会陷入等待。PINGOK只能代表主备的连通性正常,不代表备机可以立刻提供服务,所以catchup这段时间不能认为该备机是一个正常的备机,除非当时有其他normal状态的备机。

那么如果第一个备机已经完成catchup,第二个备机再启动然后catchup追日志为什么不阻塞呢?因为synchronous_standby_names设置的是*,已经有一个备机能够同步了,不需要等待另一个备机同步了。

该问题需要提交华为解决。