ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

全国最完整的Repmgr高可用Postgresql

2021-06-28 22:04:08  阅读:626  来源: 互联网

标签:10 Repmgr Postgresql 可用 -- pgsql VIP conf repmgr


标题应该没有违反广告法

本教程为全国最完整的PGSQL高可用集群方案,以下的每一个步骤都事关重要。

安装环境

Centos7.8

Posgresql10

Repmgr10

两台服务器:

192.168.126.143

192.168.126.144

服务器名称:

hostnamectl set-hostname post1

hostnamectl set-hostname post2

数据库集群架构图

整体设计思路

1.先两台机器都安装Posgresql

2.两台机器都安装Repmgr

3.两台机器都设置postgres用户的相互信任

4.其中一台机器设置好postgresql的配置文件,并且初始化数据库

5.另一台机器克隆数据库

6.修改repmgr的配置

7.将两台机器加入集群节点

8.测试两台都关机

9.测试关机一台

10.安装keepalived配置VIP

11.配置高可用

安装步骤

1.分别安装Postgresql和Repmgr


两节点同时操作

yum install -y gcc bison gcc-c++ readline readline-devel zlib zlib-devel perl perl-devel telnet openssl openssl-devel

systemctl stop firewalld

安装PGSQL

sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm

sudo yum install -y postgresql10-server

sudo /usr/pgsql-10/bin/postgresql-10-setup initdb

sudo systemctl enable postgresql-10

sudo systemctl start postgresql-10

安装REPMGR

curl https://dl.2ndquadrant.com/default/release/get/10/rpm | sudo bash

sudo yum repolist

yum search repmgr

yum --showduplicates list repmgr10

yum install repmgr10-4.4-1.el7

su postgres

ln -s /usr/pgsql-11/bin/repmgr /usr/local/sbin/

exit

安装完成后的路径如下:

可执行目录/usr/pgsql-10/bin/

数据实例的目录/var/lib/pgsql/10/data/

修改主节点的postgesql.conf


别的地方不改,默认改这几个地方

listen_addresses = '*' # what IP address(es) to listen on;

# comma-separated list of addresses;

# defaults to 'localhost'; use '' for all

# (change requires restart)

port = 5432 # (change requires restart)

max_connections = 1000 # (change requires restart)

wal_log_hints=on

archive_mode=on

archive_command='test ! -f /pgarch/%f && cp %p /pgarch/%f'

shared_preload_libraries='repmgr'

修改主节点的pg_hba.conf


注意IP地址根据自己情况来配置

local all all peer

# IPv4 local connections:

host all all 127.0.0.1/32 trust

host all all 172.16.108.54/32 md5

host all all 192.168.126.144/32 trust

host all all 192.168.126.143/32 trust

host all all 0.0.0.0/0 md5

# IPv6 local connections:

host all all ::1/128 ident

# Allow replication connections from localhost, by a user with the

# replication privilege.

local replication repmgr trust

local repmgr repmgr trust

host replication repmgr 127.0.0.1/32 trust

host replication repmgr 192.168.126.143/32 trust

host replication repmgr 192.168.126.144/32 trust

host repmgr repmgr 127.0.0.1/32 trust

host repmgr repmgr 192.168.126.143/32 trust

host repmgr repmgr 192.168.126.144/32 trust

修改主节点的vim /etc/repmgr/10/repmgr.conf


node_id=143

#唯一值,用于标识本服务器

node_name=post1

#连接到本机的信息

conninfo='host=192.168.126.143 user=repmgr dbname=repmgr connect_timeout=2'

##postgresql的data路径

data_directory='/var/lib/pgsql/10/data'

connection_check_type=ping

failover='automatic'

promote_command='repmgr standby promote -f /etc/repmgr/10/repmgr.conf --log-to-file'

follow_command='repmgr standby follow -f /etc/repmgr/10/repmgr.conf --log-to-file --upstream-node-id=%n'

log_file='/var/lib/pgsql/10/repmgrd.log'

monitoring_history=true # (启用监控参数)

monitor_interval_secs=1 #(定义监视数据间隔写入时间参数)

reconnect_attempts=2 #(故障转移之前,尝试重新连接主库次数(默认为6)参数)

reconnect_interval=2 #(每间隔5s尝试重新连接一次参数)

修改备节点的vim /etc/repmgr/10/repmgr.conf


node_id=144

#唯一值,用于标识本服务器

node_name=post2

##连接到本机的信息

conninfo='host=192.168.126.144 user=repmgr dbname=repmgr connect_timeout=2'

##postgresql的data路径

data_directory='/var/lib/pgsql/10/data'

connection_check_type=ping

failover='automatic'

promote_command='repmgr standby promote -f /etc/repmgr/10/repmgr.conf --log-to-file'

follow_command='repmgr standby follow -f /etc/repmgr/10/repmgr.conf --log-to-file --upstream-node-id=%n'

log_file='/var/lib/pgsql/10/repmgrd.log'

monitoring_history=true # (启用监控参数)

monitor_interval_secs=1 #(定义监视数据间隔写入时间参数)

reconnect_attempts=2 #(故障转移之前,尝试重新连接主库次数(默认为6)参数)

reconnect_interval=2 #(每间隔5s尝试重新连接一次参数)

修改完成后重启PGSQL

重启数据库服务器有两个方法

方法1

service postgresql-10 restart

方法2

su postgres

cd /usr/pgsql-10/bin/

./pg_ctl -D /var/lib/pgsql/10/data restart

2.SSH互信以及PGSQL互信

两台服务器同时操作

su postgres

psql

ALTER USER postgres WITH PASSWORD '你的数据库密码';

\q

exit

ssh-keygen -t rsa

ssh-copy-id -i /var/lib/pgsql/.ssh/id_rsa.pub postgres@192.168.126.144

restorecon -r -vv /var/lib/pgsql/.ssh

ssh 'postgres@192.168.126.144'

如果不用输入密码就可以进入,则正常

另一台机器也相同的操作,IP不一样,要测试一下 不输入密码才是对的

ssh-keygen -t rsa

ssh-copy-id -i /var/lib/pgsql/.ssh/id_rsa.pub postgres@192.168.126.143

restorecon -r -vv /var/lib/pgsql/.ssh

ssh 'postgres@192.168.126.143'

主操作

su postgres

createuser -s repmgr

createdb repmgr -O repmgr

#进入psql

psql

#在psql中设置repmgr依次默认查找repmgr、同用户名、public三个schema

ALTER USER repmgr SET search_path TO repmgr, "$user", public;

#退出psql

\q

在备机测试是否能连接主机

su postgres

psql 'host=192.168.126.14 user=repmgr dbname=repmgr connect_timeout=2'

重启主服务器并且将主服务器注册为主节点

service postgresql-10 restart

su postgres

repmgr -f /etc/repmgr/10/repmgr.conf primary register

repmgr cluster show

这样就可以看到集群中有一台主节点

3.备机克隆数据库


停止备用数据库

su postgres

cd /usr/pgsql-10/bin/

./pg_ctl -D /var/lib/pgsql/10/data stop

删除备用数据库的数据目录

rm -rf /var/lib/pgsql/10/data/*

从机测试克隆

repmgr -h 192.168.126.143 -U repmgr -d repmgr -f /etc/repmgr/10/repmgr.conf standby clone --dry-run

如果没报错就继续

从机执行克隆

repmgr -h 192.168.126.143 -U repmgr -d repmgr -f /etc/repmgr/10/repmgr.conf standby clone

克隆完成后,检查/var/lib/pgsql/10/data/目录是否又有文件了

4.备机加入集群


从机启动PGSQL

su postgres

cd /usr/pgsql-10/bin/

./pg_ctl -D /var/lib/pgsql/10/data start

从机注册子节点

repmgr -f /etc/repmgr/10/repmgr.conf standby register

repmgr cluster show

查看是否两台都加入集群

5.主备切换


测试主备手动一键切换

su postgres

repmgr -f /etc/repmgr/10/repmgr.conf standby switchover -U repmgr --verbose --dry-run

没有报错就执行切换,仅仅在子节点执行切换命令

repmgr -f /etc/repmgr/10/repmgr.conf standby switchover -U repmgr --verbose

执行后,检查主备是否交换

repmgr cluster show

两台节点都启动repmgrd

repmgrd –f /etc/repmgr/10/repmgr.conf --pid-file /tmp/repmgrd.pid

查看进程是否存在

cat/tmp/repmgrd.pid

将repmgrd设置为开机启动

新建文件/rep.sh

内容如下:

sleep 8s

su postgres -c "/usr/pgsql-10/bin/repmgrd –f /etc/repmgr/10/repmgr.conf --pid-file /tmp/repmgrd.pid"

shift+z+z保存

给文件授权

chmod +x rep.sh

编辑文件

vim /etc/rc.local

#!/bin/bash

touch /var/lock/subsys/local

./rep.sh




到这里,集群的主备搭建就完成了,支持水平扩展多个子节点

6.keepalived安装

两台节点同时操作

yum install -y keepalived

cat /etc/keepalived/keepalived.conf

ifconfig查看网卡名称为ens33

vim /etc/keepalived/keepalived.conf

[root@post1 /]# cat /etc/keepalived/keepalived.conf

! Configuration File for keepalived

vrrp_instance VI_1 {

state BACKUP

#网卡名字

interface ens33

#局域网不能有冲突

virtual_router_id 55

#设置为不抢占

nopreempt

priority 99

#4秒检查一次

advert_int 4

authentication {

auth_type PASS

auth_pass 1111

}

virtual_ipaddress {

#集群VIP

192.168.126.150

}

}

设置开机启动与服务启动

systemctl start keepalived.service

systemctl enable keepalived.service

检查VIP被谁拿走了

ip a

安装完成后,测试集群VIP是否生效,然后关机测试VIP是否能继续访问,程序继续往数据库写入。

7.高可用的配置


两台节点执行

sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm

sudo yum install dotnet-sdk-5.0

cd /root

mkdir vip

cd vip

dotnet new console

dotnet add package Npgsql --version 5.0.7

vim Program.cs编辑如下代码

using Npgsql;
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
/****
 * 本代码的作用是确保keepalived的VIP是数据库的主节点。本代码仅仅只需要修改VIP和数据库链接密码
 * ***/
namespace vip
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                try
                {
                    //两个服务器的数据库链接字符串,VIP地址,主=False,True是备
                    bool zb =true;
				    zb = Exec("Host=127.0.0.1;Port=5432;Username=postgres;Password=数据库的密码;Database=postgres");//请修改数据库密码
                    string vip = "192.168.126.150";//请修改这里的IP
                    //Console.WriteLine("主备情况=>True是备,Flase是主----》"+zb);
                    //获取IP地址是否包含VIP
                    if (GetVIP(vip) && !zb)   
                    {
                        //正常情况 VIP在本机,并且本机是F主
                        //什么也不做
                    }
                    else if (!GetVIP(vip) && zb)
                    {
                        //VIP不在本机,本机不是主,正常
                        //什么也不做
                    }
                    else if (GetVIP(vip) && zb)
                    {
						Console.WriteLine("本机不是主,但是有VIP,所以重启KEEPALIVED丢弃VIP");
                        //VIP在本机,但是本机不是主,则重启keepalived
                        Bash("service keepalived stop");
                        Thread.Sleep(4000);//睡4秒的作用是确保VIP已经漂移
                        Bash("service keepalived start");
                    }
                    else if (!GetVIP(vip) && !zb )
                    {
                        //VIP不在本机,本机是主,又另外的从机来执行重启keepalived.
                        //什么也不做
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("异常:" + ex.Message);
                    continue;
                }
                Thread.Sleep(100);//防止占用太多资源100ms检查一次
            }
        }
        /// <summary>
        /// 检查本机是否包含VIP
        /// </summary>
        /// <param name="vip"></param>
        /// <returns></returns>
        static bool GetVIP(string vip)
        {
            string ipa=Bash("ip a");
            // Console.WriteLine(ipa);
            if (ipa.Contains(vip))
                return true;
            else return false;
        }
		
		/// <summary>
        /// 执行BASH命令
        /// </summary>
        /// <param name="vip"></param>
        /// <returns></returns>
        public static string Bash(string escapedArgs)
        {
            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/bash",
                    Arguments = $"-c \"{escapedArgs}\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                }
            };
            process.Start();
            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return result;
        }
        /// <summary>
        /// 数据库相关操作,读取PGSQL的pg_is_in_recovery表
        /// </summary>
        /// <param name="vip"></param>
        /// <returns></returns>
        public static bool Exec(string connStr)
        {
			bool ct = true;
            try
            {
                using (var conn = new NpgsqlConnection(connStr))
                {
                    conn.Open();
                    using (NpgsqlCommand cmd = new NpgsqlCommand("select pg_is_in_recovery from pg_is_in_recovery()", conn))
                    {

                        NpgsqlDataReader rd = cmd.ExecuteReader();
                        while (rd.Read())
                        {
                            ct = Convert.ToBoolean(rd["pg_is_in_recovery"]);
                            return ct;
                        }
                        conn.Close();
                        return ct;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("SQL异常:" + ex.Message);
                return ct;
            }
	}

    }
}

dotnet build

执行测试一下功能

dotnet run

将本程序设置为两个节点开机启动

vim rep.sh

sleep 8s

su postgres -c "/usr/pgsql-10/bin/repmgrd –f /etc/repmgr/10/repmgr.conf --pid-file /tmp/repmgrd.pid"

nohup dotnet /root/vip/bin/Debug/net5.0/vip.dll&

保存退出,确保程序开机执行!

8.测试用例

以下测试过程保持测试工具一直数据插入和读取状体,保持不丢失数据,保持数据一致性。

初始条件

执行

影响范围

预期状态

其他

测试结果

A主,B备

关闭B

不影响业务

一切正常

B再开机也正常

通过

A主,B备

关闭A

业务10秒内恢复

B为备,VIP在B机

稳妥起见,A机要人工介入检查,执行/rejoin.sh

通过

A主,B备

同时关闭AB

影响业务

链接失败

重新开机业务自动恢复正常

通过

A主,B备

主备人工切换

业务10秒内恢复

B主,A从

数据库主备在3秒左右切换

vip在7秒左右切换

通过

A主,B备

停止B的PGSQL

无影响

无影响

B在启动也无影响

通过

A主,B备

停止A的PGSQL

业务10秒内恢复

B会变成主

repmgrd会自动切换B为主

VIP守护进程链接不上本机数据库,丢弃VIP

A机要人工介入检查,执行/rejoin.sh

通过

A主,B备

手动关闭A的keepalived

业务异常,不可读写

B有VIP,但是B发现自己的数据库是备机,会重启丢弃VIP,导致大家都没有VIP

VIP守护发现本机有VIP,但是不是主节点

会循环重启keepalived,直到A机恢复正常。

通过

A主,B备

手动关闭B的keepalived

业务正常

一切正常

再启动keepalived也正常

通过

A主,B备

断开两个节点链接

业务异常

ip地址冲突

网内无法访问

通过

测试工具以及代码

https://github.com/cagy520/MYSQL-CLUSTER-TEST.git

9.总结

repmgr做主备搭建相对PGPOOL要容易一些,而且也不像PGPOOL那样有性能损耗。

用keepalived的目的是为了主备虚拟一个集群IP地址出来,避免单节点故障。

使用VIP进程守护的目的是为了避免VIP漂移到备用节点上。

不使用shell脚本处理VIP保持主节点的原因是不够灵活,逻辑不易理解,会给后续部署带来麻烦。

尽量避免使用编译安装的方式安装repmgr,会遇到很多问题。

为什么主节点挂了之后,主节点漂移,原来主节点需要手动添加到集群,当遇到这种情况的时候,建议人工介入检查一下,避免数据不一致。

本教程的每一个细节步骤都很重要。

10.其他命令

测试主备切换,仅仅在备机执行

repmgr -f /etc/repmgr/10/repmgr.conf standby switchover -U repmgr --verbose --dry-run

repmgr -f /etc/repmgr/10/repmgr.conf standby switchover -U repmgr --verbose

原来故障的主节点从新作为备节点加入集群,也就是/rejoin.sh

repmgr node rejoin -d 'host=192.168.126.143 dbname=repmgr user=repmgr' --force-rewind --config-files=postgresql.conf,postgresql.auto.conf --verbose --dry-run

repmgr node rejoin -d 'host=192.168.126.143 dbname=repmgr user=repmgr' --force-rewind --config-files=postgresql.conf,postgresql.auto.conf --verbose

从集群中剔除节点

repmgr primary unregister --force --node-id post1

标签:10,Repmgr,Postgresql,可用,--,pgsql,VIP,conf,repmgr
来源: https://blog.csdn.net/ccagy/article/details/118312986

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有