CSCluster for PLProxy用户手册

1. 功能与原理简介

1.1 功能

乘数Cluster for PLProxy软件在PostgreSQL数据库集群中实现了一种读写分离及高可用的解决方案。

本软件工作在以下场景:

  1. 集群中有一主多备的PostgreSQL数据库,主备数据库之间通过流复制同步数据。一台机器上只能有一个数据库实例,不能有多个。
  2. 主数据库上有一个主vip,应用连接此主vip。
  3. 应用调用主数据库上的plproxy中的服务,而在plproxy服务中配置了两个cluster:一个为写cluster,即为“write_cluster”,建在”write_cluster”的函数,将发送到主库;另一个为读cluster,即为“read_cluster”,建在此cluster上的函数,会负载均衡到所有Standby数据库中。因为主备库之间有一定的延迟,所以对于一致性要求的处理也需要放到“write_cluster”上。
  4. 当主数据库出现问题之后,本软件会从多个备库中挑选出一个备库,把此备库激活成主库,同时把主vip会切换到此新的主库上。同时会此挑选出的备库从plproxy的“read_cluster”中剔除掉。
  5. 当一台备库出现问题时,会把此备库从plproxy的“read_cluster”中剔除掉。

应用的使用方法:

  1. 应用连接主vip,通过这个IP地址来访问plproxy上的函数。而plproxy函数有两类,一类是在plproxy的“write_cluster”中,这类函数通常是做插入、删除、更新等DML操作以及一些对一致性要求高的读,这些操作会被plproxy路由到主库上。另一类是在plproxy的“read_cluster”中,这些函数会被plproxy负载均衡到各个只读的备库中。
  2. 每台机器上还有一个vip,这个vip也可以提供给应用使用,这一台机器出故障后,这个vip也会切换到另一台机器上。

1.2 plproxy的示例说明

一台主库: 192.168.0.41 三台备库: 192.168.0.42/43/44 主VIP为:192.168.0.40

这四台机器的主机名分别为:pg01,pg02,pg03,pg04

用于业务的数据库用户为u01,相应建用户的语句为:

CREATE USER u01 password 'u01pwd';

存业务数据的数据库叫businessdb:

CREATE DATABASE businessdb owner u01;

连接businessdb,把businessdb中的public这个schema的属主改为u01:

alter schema public owner to u01;

建一个plproxy的代理库,名叫proxydb:

CREATE DATABASE proxydb owner u01;

应用就连接这个proxydb。

用超级用户连接proxydb,装载plproxy的扩展:

CREATE EXTENSION plproxy;

然后在proxydb中执行:

GRANT ALL ON FOREIGN DATA WRAPPER plproxy to u01;
GRANT USAGE ON LANGUAGE plproxy TO u01;

然后用u01用户连接数据库proxydb,然后在其中建读和写的plproxy的cluster:

CREATE SERVER read_cluster FOREIGN DATA WRAPPER plproxy
        OPTIONS (
                connection_lifetime '1800',
                disable_binary '1',
                p0 'dbname=businessdb host=192.168.0.42',
                p1 'dbname=businessdb host=192.168.0.43',
                p2 'dbname=businessdb host=192.168.0.44',
                p3 'dbname=businessdb host=192.168.0.42'
                );

CREATE SERVER write_cluster FOREIGN DATA WRAPPER plproxy
        OPTIONS (
                connection_lifetime '1800',
                disable_binary '1',
                p0 'dbname=businessdb host=192.168.0.40'
                );

上面内容中的“192.168.0.40”是主库的vip,但如果clux没有启动,机器192.168.0.41上还没有这个vip,可以通过下面的命令把vip加上:

ip addr add 192.168.0.40/32 dev eth0

建用户映射,以便plproxy能访问底层的数据节点:

CREATE USER MAPPING FOR public SERVER read_cluster OPTIONS (user 'u01', password 'u01pwd');
CREATE USER MAPPING FOR public SERVER write_cluster OPTIONS (user 'u01', password 'u01pwd');

下面假设有一张业务表users,此表记录了用户名,和用户的email

CREATE TABLE users(username text primary key, email text);

业务的需求是:

  1. 插入数据到users表中。
  2. 根据用户名(username)查询出用户的email。

则我们应该在businessdb中把表users建立起来,在其中建一个函数insert_user来完成第一个需求:插入数据的功能:

CREATE OR REPLACE FUNCTION insert_user(i_username text, i_emailaddress text)
RETURNS integer AS $$
       INSERT INTO users (username, email) VALUES ($1,$2);
       SELECT 1;
$$ LANGUAGE SQL;

在proxydb中建以下两个函数:

--插数据的函数:
CREATE OR REPLACE FUNCTION insert_user(i_username text, i_emailaddress text)
RETURNS integer AS $$
    CLUSTER 'write_cluster';
    RUN ON ANY;
$$ LANGUAGE plproxy;

--查询数据的函数
CREATE OR REPLACE FUNCTION get_user_email(i_username text)
RETURNS SETOF text AS $$
    CLUSTER 'read_cluster';
    RUN ON ANY;
    SELECT email FROM users WHERE username = i_username;
$$ LANGUAGE plproxy;

其中函数insert_user使用的是plproxy的“write_cluster”, 因为“write_cluster”中只有一台主库,所以插入数据的请求只会发到主库上。而“write_cluster”中用的是主库vip,所以不管哪台机器变成主库,请求都会发到这台机器上。

而函数get_user_email使用的是plproxy的‘read_cluster’,则请求会负载均衡的分发到“read_cluster”集群中的某一台机器上。

使用情况如下:

proxydb=> select insert_user('osdba', 'osdba@163.com');
 insert_user
-------------
           1
(1 row)

proxydb=> select insert_user('chengfen', 'cf@163.com');
 insert_user
-------------
           1
(1 row)

proxydb=> select get_user_email('chengfen');
 get_user_email
----------------
 cf@163.com
(1 row)

proxydb=> select get_user_email('osdba');
 get_user_email
----------------
 osdba@163.com
(1 row)

2. 安装配置

2.1 安装要求

每台机器上需要安装arping包,因为此软件需要用到arping命令。

PostgreSQL的版本要求在9.5以上。

2.2 软件安装

本软件安装在root用户下,也运行root用户下。

安装包主要有两个:

  • cluxX.Y.Z.tar.gz: 其中X.Y.Z是版本号,如1.1.0
  • python3.6.tar.gz

把安装包cluxX.Y.Z.tar.gz和python3.6.tar.gz解压到/opt目录下即可。

会形成以下目录:

/opt/clux1.X.X目录。

然后建软链接:

cd /opt
ln -sf clux1.1.0 clux

cluxserver正常启动,需要license文件,这时需要把机器第一块网卡的mac地址上报给乘数科技,乘数科技会根据mac地址生成license文件,把生成的license文件cstech.lic拷贝到/opt/clux/conf目录下即可。

注意:上面的操作需要在每台机器上都执行。

为了方便运行命令,可以把/opt/clux/bin目录加入PATH环境变量中:

如在.bash_profile文件中添加:

PATH=$PATH:/opt/clux/bin
export PATH

2.2 配置

2.2.1 主机配置

每台机器上在/etc/hosts中添加主机名与ip地址的对应关系:

192.168.0.41 pg01
192.168.0.42 pg02
192.168.0.43 pg03
192.168.0.44 pg04

这样/etc/hosts的内容类似如下:

[root@pg01 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.0.41 pg01
192.168.0.42 pg02
192.168.0.43 pg03
192.168.0.44 pg04

需要打通各台机器之间root用户的ssh通道,以便能用ssh连接各台机器而不需要密码,ssh自己也不需要密码。其中一个简单的方法为:

在第一台机器上生成ssh的key:

ssh-keygen

运行的实际情况如下:

[root@pg01 ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
02:74:f1:34:f9:cb:47:da:ff:95:c3:78:ba:e6:37:1a root@pg04
The key's randomart image is:
+--[ RSA 2048]----+
|    . o.o.       |
|   . . o..       |
|    .   ..       |
|     .    . .    |
|      . S. =     |
|       .  + o o .|
|           . E =.|
|             .=oo|
|            o=+.o|
+-----------------+

然后进入.ssh目录下,把id_rsa.pub的内容添加到

cd .ssh
cat id_rsa.pub >> authorized_keys
chmod 600 authorized_keys

这时应该ssh自己应该不需要密码了:

[root@pg01 ~]# ssh 127.0.0.1
Last login: Sat Oct 28 15:06:03 2017 from 127.0.0.1
[root@pg01 ~]# exit
logout
Connection to 127.0.0.1 closed.

然后把这台机器的.ssh目录拷贝到所有的机器上:

[root@pg01 ~]# scp -r .ssh root@192.168.0.42:/root/.
root@192.168.0.42's password:
id_rsa                                                                                                                                       100% 1679     1.6KB/s   00:00
id_rsa.pub                                                                                                                                   100%  391     0.4KB/s   00:00
authorized_keys                                                                                                                              100% 1011     1.0KB/s   00:00
known_hosts

为了方便,用相同的方法把数据库用户postgres的ssh通道也打通。

还有其它的一些打通各台机器互相ssh不需要密码的方法可以参见网上的一些文章,这里就不在赘述了。

2.2.2 配置数据库

首先需要把主备数据库搭建起来:

备库的recovery.conf文件的内容类似如下:

standby_mode = 'on'
recovery_target_timeline = 'latest'
primary_conninfo = 'application_name=stb234 user=postgres host=192.168.0.41 port=5432 password=postgres sslmode=disable sslcompression=1'

其中“primary_conninfo”中的:

  • application_name=stb42,每台备库上这个都不能相同,可以用“stb”加上ip地址的最后一部分,如ip地址为192.168.0.42,就用stb42,这个名称需要与后面的init.json中“db_list”中的“repl_app_name”的值相同。
  • “user=postgres password=postgres”需要与配置文件ha_adm.conf中的配置项db_repl_user和db_repl_pass保持相同。
  • host=192.168.0.41 port=5432这是主库的IP地址和端口

主备库搭建好了,需要在主库上查询select * from pg_stat_replication;来确定备库都正常工作:

postgres@pg01:~/pgdata$ psql postgres
psql (9.6.2)
Type "help" for help.

postgres=# select * from pg_stat_replication;
  pid  | usesysid | usename  | application_name |  client_addr   | client_hostname | client_port |         backend_start         | backend_xmin |   state   | sent_location | w
rite_location | flush_location | replay_location | sync_priority | sync_state
-------+----------+----------+------------------+----------------+-----------------+-------------+-------------------------------+--------------+-----------+---------------+--
--------------+----------------+-----------------+---------------+------------
 25541 |       10 | postgres | stb42            | 192.168.0.42  |                 |       56529 | 2017-10-26 04:05:31.10155+08  |              | streaming | 0/1B018140    | 0
/1B018140     | 0/1B018140     | 0/1B018140      |             0 | async
 25573 |       10 | postgres | stb43            | 192.168.0.43  |                 |       48956 | 2017-10-26 04:05:36.088541+08 |              | streaming | 0/1B018140    | 0
/1B018140     | 0/1B018140     | 0/1B018140      |             0 | async
 25605 |       10 | postgres | stb44            | 192.168.0.44  |                 |       40505 | 2017-10-26 04:05:40.938398+08 |              | streaming | 0/1B018140    | 0
/1B018140     | 0/1B018140     | 0/1B018140      |             0 | async
(3 rows)

然后按 “1.2 示例说明”中的例子把plproxy配置好。

在代理数据库(通常此库的名称为proxydb,需要与初使化文件init.json中的plproxy使用的代理库的名称保持一致,见后面init.json的介绍)中执行:

CREATE OR REPLACE FUNCTION csha_update_plp_server(in_serv_name text, in_db_list text, in_host_list text)
  RETURNS text AS
$BODY$
DECLARE
    v_ddl text;
    v_srv_opt text;
    v_db_array text[];
    v_host_array text[];
    i int;
    x text;
    rec RECORD;
BEGIN
    v_srv_opt := '';
    FOR rec IN (select split_part(opt, '=', 1) as part from (select unnest(srvoptions) as opt from pg_foreign_server where srvname=in_serv_name) t where t.opt like 'p%') LOOP
        IF length(v_srv_opt) =0 THEN
            v_srv_opt := 'drop '||rec.part;
        ELSE
            v_srv_opt := 'drop '||rec.part||','||v_srv_opt;
        END IF;
    END LOOP;

    v_db_array := string_to_array(in_db_list, ',');
    v_host_array := string_to_array(in_host_list, ',');
    i := 0;
    FOREACH x IN ARRAY v_db_array
    LOOP
        v_srv_opt = v_srv_opt || format(',add p%s ''dbname=%s host=%s''', i, x, v_host_array[i+1]);
        i := i + 1;
    END LOOP;
    v_ddl = 'ALTER SERVER '|| in_serv_name ||' OPTIONS('|| v_srv_opt ||');';
    EXECUTE v_ddl;
    return v_ddl;
END;
$BODY$
LANGUAGE 'plpgsql';

在主库中建探测库cs_sys_ha,注意此库的名称“cs_sys_ha”需要与clux.conf中的配置项probe_db_name的值保证一致(见后面clux.conf中的介绍 ):

CREATE DATABASE cs_sys_ha;

然后在探测库cs_sys_ha中建探测表:

CREATE TABLE cs_sys_heartbeat(
  hb_time TIMESTAMP
);
insert into cs_sys_heartbeat values(now());

2.2.3 乘数Cluster for PLProxy软件包的安装

把安装包cluxX.Y.Z.tar.gz和python3.6.tar.gz解压到/opt目录下即完成安装。

检查python3.6是否能正常工作,如果报如下错误:

[root@pg01 opt]# ./python3.6/bin/python3.6
./python3.6/bin/python3.6: /lib64/libcrypto.so.10: version `OPENSSL_1.0.2' not found (required by ./python3.6/bin/python3.6)

这是因为openssl的版本太旧,查看版本:

[root@pg01 opt]# rpm -qa |grep ssl
openssl-1.0.2k-8.el7.x86_64
openssl-libs-1.0.2k-8.el7.x86_64
openssl-devel-1.0.2k-8.el7.x86_64

openssl版本应该是1.0.2.

如果不是上面的版本,请运行:

yum update
yum install openssl-devel

2.2.4 乘数Cluster for PLProxy的配置

首先修改配置文件/opt/clux/conf/clux.conf

此配置文件的示例如下:

#格式为 key = value

# 一个局域网上这个名称要唯一
cluster_name = csha01
# 集群中的机器列表
host_list = 192.168.0.41,192.168.0.42,192.168.0.43,192.168.0.44

# 网络地址,本cluster软件的内部通信将运行在此网络中
network=192.168.0.0

#meta_server token
meta_server_token=9650ec2a-b405-11e7-955e-00163ea9adc2

#cluxadm管理工具与服务器之间通信的密码
ha_rpc_pass = csha_cluster_pass

probe_db_name = cs_sys_ha
probe_user = postgres
probe_password = postgres

ha_db_user = postgres
ha_db_pass = postgres

db_repl_user = postgres
db_repl_pass = postgres


# 检查数据库是否正常的周期,单位为秒
vip_probe_interval = 30
db_probe_interval = 10

配置文件说明:

  • cluster_name = csha01:给这个集群一个名称,配置之后不能更改。当同一个网络中有多个集群,这个名称需要不一样。
  • host_list = 192.168.0.41,192.168.0.42,192.168.0.43,192.168.0.44: 集群中的各台机器的ip地址列表,以逗号分隔。
  • network=192.168.0.0:网络,通常为内部元数据服务用的网络,与业务网段可相同。
  • meta_server_token=9650ec2a-b405-11e7-955e-00163ea9adc2:设置一个uuid的值,用于与meta server的验证,一般不需要修改。
  • ha_rpc_pass = csha_cluster_pass:管理工具与服务器之间通信的密码。
  • probe_db_name = cs_sys_ha:通过探测更新此数据库中的一张表来判定此节点是否正常工作。
  • probe_user = postgres :通过更新cs_sys_ha中表探测更新时使用的数据库用户名。
  • probe_password = postgres :通过探测更新时使用的数据库用户密码。
  • ha_db_user = postgres:此程序获得一些信息时使用的数据库用户名
  • ha_db_pass = postgres:此程序获得一些信息时使用的数据库用户密码
  • db_repl_user = postgres:主备数据库之间流复制使用的数据库用户名
  • db_repl_pass = postgres:主备数据库之间流复制使用的数据库用户密码
  • vip_probe_interval = 30:探测vip是否工作正常的周期
  • db_probe_interval = 10:探测数据库是否工作正常的周期

在每台机器上配置好上面的/opt/clux/conf/clux.conf文件。

2.2.5 初使化集群

先编辑init.json文件,其中的一个示例文件如下:

{
    "plproxy":
    {
        "clusters":
        [
            {
                "name": "read_cluster",
                "proxydb": "proxydb",
                "backend_db":"businessdb"
            }
        ]
    },
    "pri_vip": "192.168.0.40",
    "db_list":
    [
        {
            "id": 1,
            "state": 1,
            "os_user": "postgres",
            "pgdata": "/home/postgres/pgdata",
            "is_primary": 1,
            "vip": "192.168.0.45",
            "repl_app_name": "stb41",
            "host": "192.168.0.41",
            "switch_host": "192.168.0.41",
            "port": 5432
        },
        {
            "id": 2,
            "state": 1,
            "os_user": "postgres",
            "pgdata": "/home/postgres/pgdata",
            "is_primary": 0,
            "vip": "192.168.0.46",
            "repl_app_name": "stb42",
            "host": "192.168.0.42",
            "switch_host": "192.168.0.42",
            "port": 5432
        },
        {
            "id": 3,
            "state": 1,
            "os_user": "postgres",
            "pgdata": "/home/postgres/pgdata",
            "is_primary": 0,
            "vip": "192.168.0.47",
            "repl_app_name": "stb43",
            "host": "192.168.0.43",
            "switch_host": "192.168.0.43",
            "port": 5432
        },
        {
            "id": 4,
            "state": 1,
            "os_user": "postgres",
            "pgdata": "/home/postgres/pgdata",
            "is_primary": 0,
            "vip": "192.168.0.48",
            "repl_app_name": "stb44",
            "host": "192.168.0.44",
            "switch_host": "192.168.0.44",
            "port": 5432
        }
    ]
}

各个配置项说明:

    "plproxy":
    {
        "clusters":
        [
            {
                "name": "read_cluster",
                "proxydb": "proxydb",
                "backend_db":"businessdb"
            }
        ]
    },

上面这一段是对plproxy的配置中: * “name”:“read_cluster”中的“read_cluster”就是读负载均衡的plproxy的cluster,需要与plproxy中实际的读cluster的名称保持相同。 * “proxydb”:“proxydb”就是plproxy中的代理库的名称。 * “backend_db”:“db01”,就是plproxy中后端数据库的名称,即真正存数据的业务数据库。

    "db_list":
    [
        {
            "id": 1,
            "state": 1,
            "os_user": "postgres",
            "pgdata": "/home/postgres/pgdata",
            "is_primary": 1,
            "vip": "192.168.0.45",
            "repl_app_name": "stb41",
            "host": "192.168.0.41",
            "switch_host": "192.168.0.41",
            "port": 5432
        },

上面这一段,表明各台机器上的数据库配置:

  • “”id”: 1”: 这是每台机器的序列,从1开始顺序+1递增
  • “”state”: 1”: 其中1表示正常工作,初使化时,应该设置为1
  • “”os_user”:“postgres””:数据库实例是装在哪个操作系统用户下的,通常是在postgres用户下。
  • “”pgdata”: “/home/postgres/pgdata””:设置数据库的数据目录
  • “”is_primary”: 1,”: 1表示主库,0表示备库,只能有一台机器是1,即是主库。
  • “”vip”:“192.168.0.45””: 我们为每台机器都分配一个vip,当这台机器出现问题时,这个vip会切换到另一台机器上。
  • “”repl_app_name”: “stb232””: 这需要与recovery.conf文件中的application_name保持一致,对于主库也需要设置一个,因为有主库有可能会切换成备库,这时就需要这个名称。
  • “”host”: “192.168.0.41”,”:这台机器的ip地址。
  • “”switch_host”: “192.168.0.41””:配置时需要与“”host””保持相同。当这台机器故障时,“switch_host”指向替换这台机器的新机器的IP地址。
  • “”port”: 5432”:数据库的端口

配置好上面的文件之后,用以下命令初使化集群:

/opt/cscluster_plproxy/bin/cluxadm init

2.2.4 启动集群软件

只需要所有节点中的两个节点上运行:

/opt/clux/bin/cluxserver start

这个cluxserver就是探测故障的服务,当探测到故障时,就会执行高可用的切换工作。

可以在两台机器上各启动一个cluxserver来保持高可用,正常工作时,只会有一台机器上的cluxserver做故障探测工作,当这台机器上的cluxserver停止工作后,另一台机器上的cluxserver就会接管。

查看状态:

/opt/clux/bin/cluxadm show

实际运行的效果如下:

[root@pg01 ~]# cluxadm show
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
==================================================
cluster state: 1(Normal)
    primary vip: 192.168.0.40

                    Pl/Proxy
--------------------------------------------------
      name           proxydb         backend_db   
---------------- ---------------- ----------------
read_cluster     proxydb          businessdb      

                   db list
--------------------------------------------------
id   state    primary        host       port        vip            switch_to      os_user               pgdata            
-- ---------- ------- ----------------- ---- ----------------- ----------------- ---------- ------------------------------
 1 Normal           1 192.168.0.41      5432 192.168.0.45      192.168.0.41        postgres /home/postgres/pgdata         
 2 Normal           0 192.168.0.42      5432 192.168.0.46      192.168.0.42        postgres /home/postgres/pgdata         
 3 Normal           0 192.168.0.43      5432 192.168.0.47      192.168.0.43        postgres /home/postgres/pgdata         
 4 Normal           0 192.168.0.44      5432 192.168.0.48      192.168.0.44        postgres /home/postgres/pgdata  

3. 使用

3.1 命令的基本使用方法

3.1.1 集群服务命令

/opt/clux/bin/cluxserver是乘数CSCluster for PLProxy软件的主程序。

启动命令:

正常启动时,直接运行命令“/opt/clux/bin/cluxserver start”即可。

如果要以调试的模式运行,可以加上以下几个参数:

  • -f: 前台运行,不进入daemon模式
  • -l debug: 打印debug日志信息

用/opt/clux/bin/cluxserver status可以查看集群软件是否运行:

[root@pg01 ~]# cluxserver status
2017-11-11 12:28:24,923 INFO Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
2017-11-11 12:28:24,923 INFO Start loading configuration ...
2017-11-11 12:28:24,923 INFO Complete configuration loading.
Program(1971) is running.

运行/opt/clux/bin/cluxserver stop可以停止集群软件的运行:

[root@pg01 ~]# cluxserver stop
2017-11-11 12:29:31,384 INFO Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
2017-11-11 12:29:31,385 INFO Start loading configuration ...
2017-11-11 12:29:31,385 INFO Complete configuration loading.
Wait 20 second for program stopped...
Wait 20 second for program stopped...
Wait 20 second for program stopped...
Wait 20 second for program stopped...
Wait 20 second for program stopped...
Force stopped program

3.1.2 cluxadm程序的使用

cluxadm是主要的管理工具,主要功能可以见下:

root@pg01 ~]# cluxadm
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
usage: clux_adm.pyc <command> [options]
    command can be one of the following:
      init            :  initialize cluster
      start_meta_server: start meta server, if meta server alreading running, stop it and restart
      stop_meta_server: stop meta server
      show            : list all database.
      get_last_lsn    : get all database lsn.
      repl_delay      : show replication delay.
      log             : display log.
      meta_log        : display meta server log.
      froze           : froze the HA.
      repair          : repair fault node.
      unfroze         : unfroze the HA.
      switch          : switch primary database to another node
  • init: 主是要在第一次初使化集群里使用,见前面。
  • start_meta_server: 启动meta server。其中集群的状态信息是记录在meta serve中,在运行集群之前meta server需要先运行起来。这个命令会把所有节点上的meta server都启动起来。当然启动cluxserver时会检查meta server是否启动,如果没有启动,则会把meta server启动起来。
  • stop_meta_server: 停止meta server。
  • show: 展示集群中的节点信息。
  • get_last_lsn:显示每个结点的最后的LSN号。
  • repl_delay:显示各个备库的WAL日志的延迟情况。
  • log:显示本机中的主cluxserver节点的集群日志。
  • meta_log:显示本机中meta server的日志。
  • froze: “冻结”cluster,当cluster进入此状态后,不会再做相应的检查工作,就象cluster停止工作了一样。
  • unfroze: 解冻cluster
  • switch: 把主库切换到另一台机器上。
  • repair: 修复一台已离线的节点

cluxadm的命令的运行通常需要在集群中的meta server启动以及有一个cluxserver启动了。

如果没有启动meta server:

[root@pg01 ~]# cluxadm show
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
Can not connect meta server: connection failed

如果没有启动cluxserver,会出现如错误:

[root@pg01 ~]# cluxadm show
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
cluxserver not running.

下面展示一些命令的运行情况:

cluxadm get_last_lsn的运行情况:

[root@pg01 ~]# cluxadm get_last_lsn
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
                   db list
--------------------------------------------------
id        host       primary timeline       lsn       
-- ----------------- ------- -------- ----------------
 1 192.168.0.41            1       41       0/D66C0308
 2 192.168.0.42            0       41       0/D66C0308
 3 192.168.0.43            0       41       0/D66C0308
 4 192.168.0.44            0       41       0/D66C0308

在上面的结果中可以看到每个数据库的时间线(timeline)。

cluxadm show的运行情况:

Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
       host       primary current_lsn  sent_delay  write_delay  flush_delay  replay_delay   is_sync       state    
----------------- ------- ----------- ------------ ------------ ------------ ------------ ------------ ------------
192.168.0.41      1               N/A          N/A          N/A          N/A          N/A          N/A          N/A
192.168.0.42      0        0/D66DAAA0            0            0            0          128        async       normal
192.168.0.43      0        0/D66DAAA0            0            0            0          128        async       normal
192.168.0.44      0        0/D66DAAA0            0            0            0          128        async       normal

上面结果中,如果是主加,这一行显示的都是“N/A”。列is_sync表示这个备库的流复制是同步方式还是异步方式。

需要注意“state”列,如果不是“normal”,通常表示流复制没有正常传输,如当备库与主库延迟过大,它需要的WAL文件在主库中已经被被清除掉,这时就不会显示“normal”状态。

cluxadm log命令是显示主cluxserver节点上的日志,是通过“tail -f ”的方式显示,如果要退出,请按“Ctrl+C”:

(pyenv) [root@pg01 ~]# cluxadm log
2017-10-29 19:58:02,816 INFO CSCluster Complete configuration loading.
2017-10-29 19:59:34,193 INFO CSCluster Start loading configuration ...
2017-10-29 19:59:34,194 INFO CSCluster Complete configuration loading.
2017-10-29 19:59:34,430 INFO ========== CSCluster for plproxy starting ==========
2017-10-29 19:59:34,431 INFO Check if meta server is running...
2017-10-29 19:59:35,079 INFO Start ha checking thread...
2017-10-29 19:59:35,080 INFO Start vip health checking thread...
2017-10-29 19:59:35,084 INFO Complete the startup of vip health checking thread.
2017-10-29 19:59:35,084 INFO Start db health checking process...
2017-10-29 19:59:35,090 INFO Complete the startup of vip health checking thread.
^C(pyenv) [root@pg01 ~]# cluxadm meta_log
    2017/10/29 17:54:08 [INFO] snapshot: Creating new snapshot at /opt/cscluster_plproxy1.0.0/data/raft/snapshots/163-32781-1509270848449.tmp
    2017/10/29 17:54:08 [INFO] snapshot: reaping snapshot /opt/cscluster_plproxy1.0.0/data/raft/snapshots/163-16392-1509256884847
    2017/10/29 17:54:08 [INFO] raft: Compacting logs from 14346 to 22541
    2017/10/29 17:54:08 [INFO] raft: Snapshot to 32781 complete
    2017/10/29 19:49:59 [INFO] consul.fsm: snapshot created in 40.829µs
    2017/10/29 19:49:59 [INFO] raft: Starting snapshot up to 40975
    2017/10/29 19:49:59 [INFO] snapshot: Creating new snapshot at /opt/cscluster_plproxy1.0.0/data/raft/snapshots/163-40975-1509277799126.tmp
    2017/10/29 19:49:59 [INFO] snapshot: reaping snapshot /opt/cscluster_plproxy1.0.0/data/raft/snapshots/163-24584-1509263858341
    2017/10/29 19:49:59 [INFO] raft: Compacting logs from 22542 to 30735
    2017/10/29 19:49:59 [INFO] raft: Snapshot to 40975 complete
^C(pyenv) [root@pg01 ~]#

3.2 故障的模拟以及恢复方法

3.2.1 数据库宕掉,但主机还正常的情况

这时集群软件会检查到这个数据库出现了问题,但因为主机还是正常运行的,集群软件会自动把数据库拉起来,这种故障不需要人工参与。

当我们把一台数据库停掉:

[postgres@pg04 ~]$ pg_ctl stop
waiting for server to shut down.... done
server stopped

在log中可以看到类似“INFO Host(192.168.0.44) is ok, only database(192.168.0.44:5432) failed, restart database ….”的信息:

[root@pg01 ~]# cluxadm log
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
ssh -o BatchMode=yes -o ConnectTimeout=20 -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no root@192.168.0.41 tail -f /opt/clux1.1.0/logs/cluxserver.log
...
...
...
2017-11-11 13:25:40,836 INFO Find database(192.168.0.44:5432) failed, repair it ....
2017-11-11 13:25:40,897 INFO Host(192.168.0.44) is ok, only database(192.168.0.44:5432) failed, restart database ....

我们再看数据库时,发现数据库已经自动拉起来了:

[postgres@pg04 ~]$ ps -ef|grep postgres
root     22880 16391  0 20:10 pts/1    00:00:00 su - postgres
postgres 22881 22880  0 20:10 pts/1    00:00:00 -bash
postgres 22953     1  0 20:11 ?        00:00:00 /usr/pgsql-9.6/bin/postgres -D /home/postgres/pgdata
postgres 22954 22953  0 20:11 ?        00:00:00 postgres: logger process
postgres 22955 22953  0 20:11 ?        00:00:00 postgres: startup process   recovering 00000001000000000000000B
postgres 22956 22953  0 20:11 ?        00:00:00 postgres: checkpointer process
postgres 22957 22953  0 20:11 ?        00:00:00 postgres: writer process
postgres 22958 22953  0 20:11 ?        00:00:00 postgres: stats collector process
postgres 22959 22953  0 20:11 ?        00:00:00 postgres: wal receiver process   streaming 0/B475A40
postgres 23071 22881  0 20:13 pts/1    00:00:00 ps -ef
postgres 23072 22881  0 20:13 pts/1    00:00:00 grep --color=auto postgres

3.2.2 备库主机宕掉

这时集群软件会检查到这个备数据库出现了问题,同时也会发现主机也出问题了。集群软件会自动把这个数据库从plproxy中的read_cluster中去掉,然后把结点标记为坏。

我们把一台备库重启来模拟这个故障:

在重启之前,我们先看一下plproxy的read_cluster的配置:

proxydb=# \des+ read_cluster
                                                                                                                                                  List of foreign servers
     Name     | Owner | Foreign-data wrapper | Access privileges | Type | Version |
           FDW Options                                                                                                        | Description
--------------+-------+----------------------+-------------------+------+---------+--------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------+-------------
 read_cluster | u01   | plproxy              |                   |      |         | (connection_lifetime '1800', disable_binary '1', p0 'dbname=businessdb host=192.168.0.42',
p1 'dbname=businessdb host=192.168.0.43', p2 'dbname=businessdb host=192.168.0.44', p3 'dbname=businessdb host=192.168.0.42') |
(1 row)

从上面可以看到,每台备库的IP地址都有。等后面我们重新pg04之后,会看到“192.168.0.44”这台机器从“read_cluser”中移除掉。

重新pg04

[root@pg04 ~]# reboot
Connection to 192.168.0.44 closed by remote host.
Connection to 192.168.0.44 closed.

这时我们在日志中可以看到如下信息:

2017-11-11 13:28:10,401 INFO Find database(192.168.0.44:5432) failed, repair it ....
2017-11-11 13:28:10,501 INFO Host(192.168.0.44) is not ok, switch database(192.168.0.44:5432)...
2017-11-11 13:28:10,506 INFO Switch database(192.168.0.44:5432): begin delete vip(192.168.0.48) ...
2017-11-11 13:28:30,553 INFO Switch database(192.168.0.44:5432): Delete vip(192.168.0.48) completed.
2017-11-11 13:28:30,554 INFO Switch database(192.168.0.44:5432): find a normal standby database .
2017-11-11 13:28:30,554 INFO Switch database(192.168.0.44:5432): switch to host(192.168.0.42).
2017-11-11 13:28:30,554 INFO Switch database(192.168.0.44:5432): if other bad standby database switch to this bad standby database, switch other bad standby database vip to new standby databse...
2017-11-11 13:28:30,554 INFO Switch database(192.168.0.44:5432): switch other bad standby database vip to new standby databse completed.
2017-11-11 13:28:30,554 INFO Switch database(192.168.0.44:5432): save node state to meta server...
2017-11-11 13:28:30,605 INFO Switch database(192.168.0.44:5432): save node state to meta server completed.
2017-11-11 13:28:30,605 INFO Switch database(192.168.0.44:5432): begin update plproxy configuration...
2017-11-11 13:28:31,117 INFO Switch database(192.168.0.44:5432): update plproxy configuration completed.
2017-11-11 13:28:31,210 INFO Switch database(192.168.0.44:5432): all commpleted.

同时我们用命令cluxadm show命令也可以看到这个结点的变成了“Fault”:

Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
==================================================
cluster state: 1(Normal)
    primary vip: 192.168.0.40

                    Pl/Proxy
--------------------------------------------------
      name           proxydb         backend_db   
---------------- ---------------- ----------------
read_cluster     proxydb          businessdb      

                   db list
--------------------------------------------------
id   state    primary        host       port        vip            switch_to      os_user               pgdata            
-- ---------- ------- ----------------- ---- ----------------- ----------------- ---------- ------------------------------
 1 Normal           1 192.168.0.41      5432 192.168.0.45      192.168.0.41        postgres /home/postgres/pgdata         
 2 Normal           0 192.168.0.42      5432 192.168.0.46      192.168.0.42        postgres /home/postgres/pgdata         
 3 Normal           0 192.168.0.43      5432 192.168.0.47      192.168.0.43        postgres /home/postgres/pgdata         
 4 Fault            0 192.168.0.44      5432 192.168.0.48      192.168.0.42        postgres /home/postgres/pgdata  

注意上面最后一行中“state”状态从“Normal”已变成了“Fault”。

这时我们看plproxy中“read_cluster”的配置,发现FDW Options中的“192.168.0.44”这台机器的配置不见了:

proxydb=# \x
Expanded display is on.
proxydb=# \des+ read_cluster
List of foreign servers
-[ RECORD 1 ]--------+-------------------------------------------------------------------------------------------------------------------------------------
Name                 | read_cluster
Owner                | u01
Foreign-data wrapper | plproxy
Access privileges    | 
Type                 | 
Version              | 
FDW Options          | (connection_lifetime '1800', disable_binary '1', p0 'dbname=businessdb host=192.168.0.42', p1 'dbname=businessdb host=192.168.0.43')
Description          | 

当这台机器恢复后,clux不会自动把这台数据库加进来,我们需要手工把备库启动起来:

在启动数据库之前,我们需要检查一下这台机器上的meta server是否已自动被集群启动:

[root@pg04 ~]# ps -ef|grep cscluster_meta_server
root      1992     1  1 20:24 ?        00:00:03 /opt/cscluster_plproxy1.0.0/bin/cscluster_meta_server agent -data-dir /opt/cscluster_plproxy1.0.0/data -node node04 -datacenter csha01 -bind=192.168.0.44 -client 0.0.0.0 -ui -server -join 192.168.0.41 -config-file /opt/cscluster_plproxy1.0.0/conf/meta_server.json
root      2131  2031  0 20:28 pts/0    00:00:00 grep --color=auto cscluster_meta_server

如果没有启动运行cluxadm start_meta_server就可以这台机器上的meta server启动。

[root@pg04 ~]# su - postgres
Last login: Sun Oct 29 20:11:11 CST 2017
[postgres@pg04 ~]$ pg_ctl start
server starting
[postgres@pg04 ~]$ < 2017-10-29 20:26:07.703 CST > LOG:  redirecting log output to logging collector process
< 2017-10-29 20:26:07.703 CST > HINT:  Future log output will appear in directory "pg_log".

完成上面操作之后,我们就可以用cluxadm repair命令把这个节点重新加入集群中:

[root@pg01 ~]# cluxadm repair -i 4
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
Repair(192.168.0.44) OK
[root@pg01 ~]# cluxadm show
Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
==================================================
cluster state: 1(Normal)
    primary vip: 192.168.0.40

                    Pl/Proxy
--------------------------------------------------
      name           proxydb         backend_db   
---------------- ---------------- ----------------
read_cluster     proxydb          businessdb      

                   db list
--------------------------------------------------
id   state    primary        host       port        vip            switch_to      os_user               pgdata            
-- ---------- ------- ----------------- ---- ----------------- ----------------- ---------- ------------------------------
 1 Normal           1 192.168.0.41      5432 192.168.0.45      192.168.0.41        postgres /home/postgres/pgdata         
 2 Normal           0 192.168.0.42      5432 192.168.0.46      192.168.0.42        postgres /home/postgres/pgdata         
 3 Normal           0 192.168.0.43      5432 192.168.0.47      192.168.0.43        postgres /home/postgres/pgdata         
 4 Normal           0 192.168.0.44      5432 192.168.0.48      192.168.0.44        postgres /home/postgres/pgdata  

上面的最后的命令cluxadm show中可以看到此节点的状态又从“Fault”变回了“Normal”。

在pg04节点上用ip addr命令可以看到vip也加回来了:

[root@pg04 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:ef:ed:8a brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.44/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.0.48/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:feef:ed8a/64 scope link
       valid_lft forever preferred_lft forever

上面的“192.168.0.48”就是vip

到数据库中,可以看到此节点重新加到了plprox中的“read_cluster”中:

proxydb=# \des+ read_cluster
List of foreign servers
-[ RECORD 1 ]--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name                 | read_cluster
Owner                | u01
Foreign-data wrapper | plproxy
Access privileges    | 
Type                 | 
Version              | 
FDW Options          | (connection_lifetime '1800', disable_binary '1', p0 'dbname=businessdb host=192.168.0.42', p1 'dbname=businessdb host=192.168.0.43', p2 'dbname=businessdb host=192.168.0.44', p3 'dbname=businessdb host=192.168.0.42')
Description          | 

3.2.3 主库主机宕掉

这时集群软件会检查到这个主数据库出现了问题,同时也会发现主机也出问题了。集群软件会从备库中挑选一台机器做为新主库。原主库标记为坏:

目前是192.168.0.41是主库,我们把这台机器重启掉:

[root@pg02 ~]# cluxadm show
Error: ConsulException('500 No cluster leader',)
[root@pg02 ~]# cluxadm show
==================================================
cluster state: 2(Reparing)
    primary vip: 192.168.0.40

                    Pl/Proxy
--------------------------------------------------
      name           proxydb         backend_db
---------------- ---------------- ----------------
read_cluster     proxydb          businessdb

                   db list
--------------------------------------------------
id   state    primary        host       port        vip            switch_to      os_user               pgdata
-- ---------- ------- ----------------- ---- ----------------- ----------------- ---------- ------------------------------
 1 Normal           1 192.168.0.41      5432 192.168.0.45      192.168.0.41        postgres /home/postgres/pgdata
 2 Normal           0 192.168.0.42      5432 192.168.0.46      192.168.0.42        postgres /home/postgres/pgdata
 3 Normal           0 192.168.0.43      5432 192.168.0.47      192.168.0.43        postgres /home/postgres/pgdata
 4 Normal           0 192.168.0.44      5432 192.168.0.48      192.168.0.44        postgres /home/postgres/pgdata
[root@pg02 ~]# cluxadm show
==================================================
cluster state: 1(Normal)
    primary vip: 192.168.0.40

                    Pl/Proxy
--------------------------------------------------
      name           proxydb         backend_db
---------------- ---------------- ----------------
read_cluster     proxydb          businessdb

                   db list
--------------------------------------------------
id   state    primary        host       port        vip            switch_to      os_user               pgdata
-- ---------- ------- ----------------- ---- ----------------- ----------------- ---------- ------------------------------
 1 Fault            0 192.168.0.41      5432 192.168.0.45      192.168.0.41        postgres /home/postgres/pgdata
 2 Normal           1 192.168.0.42      5432 192.168.0.46      192.168.0.42        postgres /home/postgres/pgdata
 3 Normal           0 192.168.0.43      5432 192.168.0.47      192.168.0.43        postgres /home/postgres/pgdata
 4 Normal           0 192.168.0.44      5432 192.168.0.48      192.168.0.44        postgres /home/postgres/pgdata

上面每一次运行“cluxadm show”时有可能报“Error: ConsulException(‘500 No cluster leader’,)”,不管它,再次运行就可以了,这我们可以看到,192.168.0.42变成了主库。而192.168.0.41标记成了“Fault”。

同时在日志中也可以看到如下信息:

2017-11-11 13:41:48,769 INFO Find database(192.168.0.41:5432) failed, repair it ....
2017-11-11 13:41:48,849 INFO Host(192.168.0.41) is not ok, switch database(192.168.0.41:5432)...
2017-11-11 13:41:48,855 INFO Switch primary database(192.168.0.41:5432): begin delete vip(192.168.0.40,192.168.0.45) ...
2017-11-11 13:42:28,974 INFO Switch primary database(192.168.0.41:5432): delete vip(192.168.0.40,192.168.0.45) completed.
2017-11-11 13:42:29,082 INFO Switch primary database(192.168.0.41:5432): switch to new host(192.168.0.42)...
2017-11-11 13:42:29,082 INFO Switch primary database(192.168.0.41:5432): switch other bad database vip to new databse...
2017-11-11 13:42:29,082 INFO Switch primary database(192.168.0.41:5432): switch other bad database vip to new databse completed.
2017-11-11 13:42:29,131 INFO Switch primary database(192.168.0.41:5432): save node state to meta server completed.
2017-11-11 13:42:29,216 INFO Switch primary database(192.168.0.41:5432): change all standby database upper level primary database to host(192.168.0.42)...
2017-11-11 13:42:40,861 INFO Switch primary database(192.168.0.41:5432): change all standby database upper level primary database to host(192.168.0.42) completed.
2017-11-11 13:42:40,999 INFO Switch primary database(192.168.0.41:5432): Promote standby database(192.168.0.42) to primary...
2017-11-11 13:42:42,316 INFO Switch primary database(192.168.0.41:5432): Promote standby database(192.168.0.42) to primary completed.
2017-11-11 13:42:43,881 INFO Switch primary database(192.168.0.41:5432): update plproxy configuration completed.
2017-11-11 13:42:44,227 INFO Switch primary database(192.168.0.41:5432): switch to new host(192.168.0.42) completed.

这时在192.168.0.42上可以看到,主库的vip(192.168.0.40)也切换到这台机器上了:

[root@pg02 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:e7:00:fc brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.42/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.0.46/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.0.40/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fee7:fc/64 scope link 
       valid_lft forever preferred_lft forever

等192.168.0.41机器恢复之后,同样我们用命令“cluxadm start_meta_server”把这台机器上的“meta server”启动起来。 这台机器想加入集群,只能做为备库加入了,这时我们需要在这台机器上重新搭建备库,如果没有搭建好备库,我们运行repair命令会有如下结果:

[root@pg02 ~]# cluxadm repair -i 1
请在坏的节点上搭建好备库后,再重试:

搭建备库的命令如下:
pg_basebackup -D /home/postgres/pgdata -Upostgres -h 192.168.0.42 -p 5432 -x

recovery.conf的内容如下:
standby_mode = 'on'
recovery_target_timeline = 'latest'
primary_conninfo = 'application_name=stb41 user=postgres host=192.168.0.42 port=5432 password=****** sslmode=disable sslcompression=1'

通常我们不能把这个数据库直接转成备库,因为旧的主库是异常宕机,有可能超前原先的备库,这时如果我们添加recovery.conf,启动这个原主库时,发现无法与新主库建立流复制,同时会在数据库日志上看到如下日志:

[postgres@pg01 pg_log]$ tail -f postgresql-Sun.log
< 2017-10-29 20:58:57.088 CST > DETAIL:  End of WAL reached on timeline 1 at 0/B49CF78.
< 2017-10-29 20:58:57.089 CST > LOG:  new timeline 2 forked off current database system timeline 1 before current recovery point 0/B49CFE8
< 2017-10-29 20:59:02.067 CST > LOG:  restarted WAL streaming at 0/B000000 on timeline 1
< 2017-10-29 20:59:02.094 CST > LOG:  replication terminated by primary server
< 2017-10-29 20:59:02.094 CST > DETAIL:  End of WAL reached on timeline 1 at 0/B49CF78.
< 2017-10-29 20:59:02.095 CST > LOG:  new timeline 2 forked off current database system timeline 1 before current recovery point 0/B49CFE8
< 2017-10-29 20:59:07.072 CST > LOG:  restarted WAL streaming at 0/B000000 on timeline 1
< 2017-10-29 20:59:07.098 CST > LOG:  replication terminated by primary server
< 2017-10-29 20:59:07.098 CST > DETAIL:  End of WAL reached on timeline 1 at 0/B49CF78.
< 2017-10-29 20:59:07.099 CST > LOG:  new timeline 2 forked off current database system timeline 1 before current recovery point 0/B49CFE8
< 2017-10-29 20:59:12.075 CST > LOG:  restarted WAL streaming at 0/B000000 on timeline 1
< 2017-10-29 20:59:12.099 CST > LOG:  replication terminated by primary server
< 2017-10-29 20:59:12.099 CST > DETAIL:  End of WAL reached on timeline 1 at 0/B49CF78.
< 2017-10-29 20:59:12.100 CST > LOG:  new timeline 2 forked off current database system timeline 1 before current recovery point 0/B49CFE8

上面的信息中“new timeline X forked off current database system timeline Y before current recovery point 0/XXXXXXX”这样的信息,就表明这个新主库与旧主库走到了不同的分支上,旧主库不能再做为新主库的备库使用了。

同时用cluxadm repl_delay命令看到这个节点的流复制的状态始终是“startup”,不能变成正常状态“normal”:

Clux v1.1.0  Copyright (c) 2017 HangZhou CSTech.Ltd. All rights reserved.
       host       primary current_lsn  sent_delay  write_delay  flush_delay  replay_delay   is_sync       state    
----------------- ------- ----------- ------------ ------------ ------------ ------------ ------------ ------------
192.168.0.41      0        0/D6707ED0        87192        87192        87080        87080        async      startup
192.168.0.42      1               N/A          N/A          N/A          N/A          N/A          N/A          N/A
192.168.0.43      0        0/D6707ED0            0            0            0          128        async       normal
192.168.0.44      0        0/D6707ED0            0            0            0          128        async       normal

这时可以尝试用pg_rewind把此旧主库转成standby,如果pg_rewind不行,只能在此机器上重新搭建备库了。

运行pg_rewind,这台旧数据库上的数据库不能启动,使用pg_rewind的命令如下:

[postgres@pg01 pg_log]$ pg_rewind --target-pgdata $PGDATA --source-server='host=192.168.0.42 port=5432 user=postgres dbname=template1 password=postgres' -P
connected to server
servers diverged at WAL position 0/B49CF78 on timeline 1
rewinding from last common checkpoint at 0/B49A850 on timeline 1
reading source file list
reading target file list
reading WAL in target
need to copy 151 MB (total source directory size is 187 MB)
155617/155617 kB (100%) copied
creating backup label and updating control file
syncing target data directory
initdb: could not stat file "/home/postgres/pgdata/postmaster.pid": No such file or directory
Done!

当在192.168.0.41上面搭建后备库后,我们就可以用repair命令重新把节点加入集群中:

[root@pg02 ~]# cluxadm repair -i 1
Repair(192.168.0.41) OK
[root@pg02 ~]# cluxadm show
==================================================
cluster state: 1(Normal)
    primary vip: 192.168.0.40

                    Pl/Proxy
--------------------------------------------------
      name           proxydb         backend_db
---------------- ---------------- ----------------
read_cluster     proxydb          businessdb

                   db list
--------------------------------------------------
id   state    primary        host       port        vip            switch_to      os_user               pgdata
-- ---------- ------- ----------------- ---- ----------------- ----------------- ---------- ------------------------------
 1 Normal           0 192.168.0.41      5432 192.168.0.45      192.168.0.41        postgres /home/postgres/pgdata
 2 Normal           1 192.168.0.42      5432 192.168.0.46      192.168.0.42        postgres /home/postgres/pgdata
 3 Normal           0 192.168.0.43      5432 192.168.0.47      192.168.0.43        postgres /home/postgres/pgdata
 4 Normal           0 192.168.0.44      5432 192.168.0.48      192.168.0.44        postgres /home/postgres/pgdata

这样集群就恢复成正常状态。只是现在主库变成了192.168.0.42。

3.2.4 人工切换主库

有时我们需求把主库切换到另一台机器上,这时可以用switch命令,如下所示:

 cluxadm switch -i 1

上面的把主库切换到结点1。

3.3 注意事项

3.2.1 recovery.conf的注意事项

当发生切换时,原主库会转换成备库,会自动生成一个recovery.conf文件覆盖原先的recovery.conf文件。所以不能在recovery.conf中添加一些自定义的内容,因为在每次切换后这些内容会被覆盖掉。

3.2.2 主备库之间WAL落后太多,导致备库失效的问题

通常主库发生一次checkpoint点这后,这个checkpoint点之前的WAL日志会被删除掉,但这些日志如果还没有来得及传到备库,会导致备库失效掉。这导致发生故障时无法让备库成为主库。

解决办法是在数据库的配置文件postgresql.conf中设置:

max_wal_size = 8GB
min_wal_size = 6GB

保证min_wal_size有一定的大小。