源码安装patroni+postgresql+citus+zookeeper
1. 安装环境
软件版本:
- python 3.9.16
- postgresql 16.4
- citus 12.1
- patroni 4.0.3
- zookeeper 3.7.1
1.1 设置SELinux、防火墙
systemctl status firewalld
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
1.2 主机信息
- Citus CN
- node1:192.168.198.167
- node4:192.168.198.177
- Citus Worker1
- node2:192.168.198.168
- node5:192.168.198.178
- Citus Worker2
- node3:192.168.198.169
- node6:192.168.198.179
- zookeeper
- node1:192.168.198.167
- node2:192.168.198.168
- node3:192.168.198.169
节点名称 | 主机名 | 网卡 | IP地址 | OS | 安装软件 | 角色作用 |
---|---|---|---|---|---|---|
PGSQL1 | pgsql1 | ens33 | 192.168.198.167 | CentOS7 | PostgreSQL、zookeeper、Patroni | CN-主 |
PGSQL2 | pgsql2 | ens33 | 192.168.198.168 | CentOS7 | PostgreSQL、zookeeper、Patroni | DN1-主 |
PGSQL3 | pgsql3 | ens33 | 192.168.198.169 | CentOS7 | PostgreSQL、zookeeper、Patroni | DN2-主 |
PGSQL4 | pgsql4 | ens33 | 192.168.198.177 | CentOS7 | PostgreSQL、Patroni | CN-从 |
PGSQL5 | pgsql5 | ens33 | 192.168.198.178 | CentOS7 | PostgreSQL、Patroni | DN1-从 |
PGSQL6 | pgsql6 | ens33 | 192.168.198.179 | CentOS7 | PostgreSQL、Patroni | DN2-从 |
2. 安装步骤
2.1 python安装
2.1.1 安装依赖
yum install -y gcc openssl-devel bzip2-devel libffi-devel
2.1.2 安装Python
mkdir /opt/soft
cd /opt/soft
wget https://www.python.org/ftp/python/3.9.16/Python-3.9.16.tgz
mkdir -m 755 -p /usr/local/python/3.9
cd /opt/soft
tar zxvf Python-3.9.16.tgz
cd /opt/soft/Python-3.9.16
./configure --prefix=/usr/local/python/3.9 --enable-optimizations --enable-shared
make altinstall
cp /usr/local/python/3.9/lib/libpython3.so /usr/lib64/
cp /usr/local/python/3.9/lib/libpython3.9.so.1.0 /usr/lib64/
cd /usr/lib64
ln -s libpython3.9.so.1.0 libpython3.9.so
ln -s /usr/local/python/3.9/bin/python3.9 /usr/bin/python3
ln -s /usr/local/python/3.9/bin/pip3.9 /usr/bin/pip3
2.2 postgresql安装
2.2.1 编译安装
下载压缩包postgresql-16.4.tar.gz
,上传到服务器,解压。
cd /soft/pg
tar -zxvf postgresql-16.4.tar.gz
cd postgresql-16.4
# 安装编译依赖
yum install -y libicu-devel readline-devel zlib-devel
# 编译
./configure
# 编译安装
make
make install
2.2.2 创建用户和数据库目录
# 创建用户
adduser postgres
# 设置密码
passwd postgres
# 若要赋予该用户sudo权限(可选,取决于你希望osdba用户是否具有管理员权限)
sudo usermod -aG wheel postgres # 对于使用wheel组的系统
sudo usermod -aG sudo postgres # 对于使用sudo组的系统
# 确认用户和组信息已生效
id postgres
# 创建pg数据库数据存放目录
mkdir /usr/local/pgsql/data
# 给予权限
chown -R postgres:postgres /usr/local/pgsql/data/
chmod -R 700 /usr/local/pgsql/data/
2.2.3 新增环境变量
#此时需修改postgres用户环境变量
su - postgres
vi ~/.bash_profile
#添加以下几行,/usr/local/pgsql为编译时指定的安装目录
export PGHOME=/usr/local/pgsql
export PGDATA=/usr/local/pgsql/data
PATH=$PATH:$HOME/bin:$PGHOME/bin
# 让配置的环境变量生效
source ~/.bash_profile
2.2.4 安装contrib目录下的工具
# 进入解压后的源码目录下的、contrib
cd postgresql-16.4/contrib
make
make install
2.2.5 数据库初始化
# 如果配置好了环境变量
initdb
# 如果没有配置好
/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
2.2.6 数据库配置的修改
修改postgresql.conf
和pg_hba.conf
两个配置文件。
cd /usr/local/pgsql/data
vi postgresql.conf
# 修改
listen_addresses = '*'
vi pg_hba.conf
# 修改
host all all 0.0.0.0/0 trust
host replication all 0.0.0.0/0 trust
2.2.7 数据库启动
pg_ctl start -D $PGDATA
2.2.8 用户操作
su - postgres
psql
# 修改postgres用户的密码
ALTER USER postgres WITH PASSWORD '123456';
# 新增流复制用户repuser
CREATE ROLE repuser WITH REPLICATION LOGIN PASSWORD '123456';
2.3 citus插件安装
下载citus安装包citus-12.1.4.tar.gz
,上传到服务器,解压。
tar -zxvf citus-12.1.4.tar.gz
cd citus-12.1.4
# 安装curl依赖
yum install -y curl curl-devel
yum install -y lz4-devel zstd-devel
# 导入pg的环境变量
source /home/postgres/.bash_profile
# 安装
./configure --without-zstd
make
make install
验证是否安装:
修改postgresql.conf文件:
cd /usr/local/pgsql/data
vi postgresql.conf
# 修改
shared_preload_libraries = 'citus'
创建测试数据库:
su - postgres
psql
create database test;
创建citus扩展:
\c test
create extension citus;
postgres=# \c test
You are now connected to database "test" as user "postgres".
test=# create extension citus;
CREATE EXTENSION
test=# SELECT * FROM master_get_active_worker_nodes();
2024-11-04 13:32:02.150 CST [47322] LOG: starting maintenance daemon on database 16387 user 10
2024-11-04 13:32:02.150 CST [47322] CONTEXT: Citus maintenance daemon for database 16387 user 10
node_name | node_port
-----------+-----------
(0 rows)
2.4 zookeeper安装
2.4.1 上传解压jdk
下载jdk8的版本:jdk-8u431-linux-x64.tar.gz
。
tar -zxvf jdk-8u431-linux-x64.tar.gz
2.4.2 配置jdk环境
/etc/profile文件的改变会涉及到系统的环境,也就是有关Linux环境变量的东西
所以,我们要将jdk配置到/etc/profile,才可以在任何一个目录访问jdk
vi /etc/profile
按i进入编辑,在profile文件尾部添加如下内容:
# jdk安装目录
export JAVA_HOME=/usr/local/jdk/jdk1.8.0_431
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH
export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin
export PATH=$PATH:${JAVA_PATH}
保存并退出编辑
通过命令source /etc/profile让profile文件立即生效:
source /etc/profile
测试是否安装成功:
javac
java -version
[root@pg1 jdk1.8.0_431]# javac
用法: javac <options> <source files>
其中, 可能的选项包括:
-g 生成所有调试信息
-g:none 不生成任何调试信息
-g:{lines,vars,source} 只生成某些调试信息
-nowarn 不生成任何警告
-verbose 输出有关编译器正在执行的操作的消息
-deprecation 输出使用已过时的 API 的源位置
-classpath <路径> 指定查找用户类文件和注释处理程序的位置
-cp <路径> 指定查找用户类文件和注释处理程序的位置
-sourcepath <路径> 指定查找输入源文件的位置
-bootclasspath <路径> 覆盖引导类文件的位置
-extdirs <目录> 覆盖所安装扩展的位置
-endorseddirs <目录> 覆盖签名的标准路径的位置
-proc:{none,only,full} 控制是否执行注释处理和/或编译。
-processor <class1>[,<class2>,<class3>...] 要运行的注释处理程序的名称; 绕过默认的搜索进程
-processorpath <路径> 指定查找注释处理程序的位置
-parameters 生成元数据以用于方法参数的反射
-d <目录> 指定放置生成的类文件的位置
-s <目录> 指定放置生成的源文件的位置
-h <目录> 指定放置生成的本机标头文件的位置
-implicit:{none,class} 指定是否为隐式引用文件生成类文件
-encoding <编码> 指定源文件使用的字符编码
-source <发行版> 提供与指定发行版的源兼容性
-target <发行版> 生成特定 VM 版本的类文件
-profile <配置文件> 请确保使用的 API 在指定的配置文件中可用
-version 版本信息
-help 输出标准选项的提要
-A关键字[=值] 传递给注释处理程序的选项
-X 输出非标准选项的提要
-J<标记> 直接将 <标记> 传递给运行时系统
-Werror 出现警告时终止编译
@<文件名> 从文件读取选项和文件名
[root@pg1 jdk1.8.0_431]# java -version
java version "1.8.0_431"
Java(TM) SE Runtime Environment (build 1.8.0_431-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.431-b10, mixed mode)
2.4.3 安装zookeeper
2.4.3.1 上传解压
将zookeeper的压缩包apache-zookeeper-3.7.1-bin.tar.gz
上传到服务器解压,并查看README.md
文件,查看需要的java版本。
tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz
mv apache-zookeeper-3.7.1-bin zookeeper-3.7.1
cd zookeeper-3.7.1/
cat README.md
## Java 8
If you are going to compile with Java 1.8, you should use a
recent release at u211 or above.
2.4.3.2 创建文件夹
mkdir -p /usr/local/zookeeper/data
mkdir -p /usr/local/zookeeper/datalog
2.4.3.3 修改配置文件
cd conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
-- 修改内容
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/datalog
2.4.3.4 设置环境变量
vim /etc/profile
# 添加
export PATH=$PATH:${JAVA_PATH}:/soft/zk/zookeeper-3.7.1/bin
# 重新加载
source /etc/profile
2.4.3.5 启动 Zookeeper
# 启动
zkServer.sh start
# 查看状态
zkServer.sh status
# 停止
zkServer.sh stop
2.5 patroni安装
2.5.1 下载源码
下载patroni源码patroni-4.0.3.tar.gz
,上传到服务器,解压。
tar -zxvf patroni-4.0.3.tar.gz
cd patroni-4.0.3
# 也可以自行拉取代码
git clone https://github.com/zalando/patroni.git
cd patroni
对于没有安装python环境的,建议执行下面的安装依赖的命令。
yum install -y python3 python3-pip python3-dev gcc libffi-devel
yum install -y libpq-devel
2.5.2 安装python依赖
在克隆了源代码后,使用 pip
安装 Patroni 需要的所有 Python 依赖:
# pip更换国内源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install -r requirements.txt
2.5.3 安装 Patroni
通过 setup.py
安装 Patroni,这会将 Patroni 安装到系统中,允许你通过命令行运行 patroni
。
python3 setup.py install
2.5.4 修改配置
安装完 Patroni 后,你需要创建一个配置文件来定义你的 PostgreSQL 集群的高可用性设置。
mkdir -p /usr/patroni/conf
cd /usr/patroni/conf
touch patroni_postgresql.yml
cat > /usr/patroni/conf/patroni_postgresql.yml << EOF
scope: cn
namespace: /pgsql/
name: pgsql1
restapi:
listen: 192.168.198.167:8008
connect_address: 192.168.198.167:8008
zookeeper:
hosts:
- 192.168.198.167:2181
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
master_start_timeout: 300
synchronous_mode: false
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
listen_addresses: "0.0.0.0"
port: 5432
wal_level: logical
hot_standby: "on"
wal_keep_segments: 1000
max_wal_senders: 10
max_replication_slots: 10
wal_log_hints: "on"
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.198.167:5432
data_dir: /usr/local/pgsql/data
bin_dir: /usr/local/pgsql/bin
authentication:
replication:
username: repuser
password: 123456
superuser:
username: postgres
password: 123456
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
log:
level: INFO
dir: /tmp
EOF
2.5.5 使用虚拟环境
安装 virtualenv
(如果没有安装)
pip3 install virtualenv
创建一个新的虚拟环境: 进入你的项目目录,并创建一个虚拟环境
virtualenv venv
激活虚拟环境:对于 Linux/macOS:
source venv/bin/activate
安装依赖包:
pip install psycopg2-binary
pip install -r requirements.txt
python setup.py install
退出虚拟环境: 完成工作后,可以通过以下命令退出虚拟环境
deactivate
2.5.6 启动patroni
pip show patroni
patroni --version
# 默认前台运行
patroni /usr/patroni/conf/patroni_postgresql.yml
# 后台运行
patroni /usr/patroni/conf/patroni_postgresql.yml &
# 停止
curl -X POST http://localhost:8008/manage/stop
patroni /usr/patroni/conf/patroni_postgresql.yml stop
# 查看集群状态
patronictl -c /usr/patroni/conf/patroni_postgresql.yml list
使用 systemd
或其他服务管理工具
通常,生产环境中都会将 Patroni 配置为系统服务,这样它会以后台方式运行,并在系统重启时自动启动。可以通过创建一个 systemd
服务单元来管理 Patroni。
首先,确保 /etc/systemd/system/patroni.service
存在并包含类似以下内容:
touch /usr/lib/systemd/system/patroni.service
vim /usr/lib/systemd/system/patroni.service
cat > /usr/lib/systemd/system/patroni.service << EOF
[Unit]
Description=patroni - a high-availability PostgreSQL
Documentation=https://patroni.readthedocs.io/en/latest/index.html
After=syslog.target network.target etcd.target
Wants=network-online.target
[Service]
Type=simple
User=postgres
Group=postgres
PermissionsStartOnly=true
ExecStart=patroni /usr/patroni/conf/patroni_postgresql.yml
ExecReload=/bin/kill -HUP $MAINPID
LimitNOFILE=65536
KillMode=process
KillSignal=SIGINT
Restart=on-abnormal
RestartSec=30s
TimeoutSec=0
[Install]
WantedBy=multi-user.target
EOF
使用systemctl来管理的命令:
systemctl daemon-reload
systemctl start patroni
systemctl stop patroni
systemctl status patroni
3. 集群搭建
因为我是已经将上面的软件源码安装到了一台虚拟机上,然后再复制两台虚拟机出来,因此有些配置和路径是一样的。
3.1 基本环境搭建
3.1.1 安装基本软件
yum install -y vim lrzsz bash-completion
lrzsz
是一组用于文件传输的工具,主要用于通过串口或其他基于终端的通信协议(例如 ZModem)在计算机之间传输文件。
- 通过命令行(比如
rz
或sz
)发送和接收文件,尤其是在没有图形界面或网络连接不稳定时,ZModem 可以保证高效和可靠的文件传输。- 一些远程终端(如
telnet
或SSH
)支持通过lrzsz
进行文件传输。
bash-completion
是一个用于增强bash
命令行的补全功能的工具,它通过提供自动完成的功能来提高用户体验,特别是在使用复杂命令或长路径时。
- 命令补全:
bash-completion
允许用户在命令行中自动完成常见命令。比如,当你输入一个命令的部分内容时,按下 Tab 键可以补全命令。
- 例如,在输入
git
后按Tab
键,会自动补全为git
命令,或者显示所有可用的git
子命令(如git commit
,git push
等)。- 文件路径补全:自动补全文件和目录路径。比如,在输入文件路径时,可以按
Tab
补全路径。- 可扩展性:许多软件包和命令行工具可以通过安装额外的补全脚本来扩展其自动补全功能。
- 例如,
docker
、git
、kubectl
等命令行工具都可以通过bash-completion
提供更智能的命令补全。
3.1.2 设置名称解析
echo 192.168.198.167 pgsql1 >> /etc/hosts
echo 192.168.198.168 pgsql2 >> /etc/hosts
echo 192.168.198.169 pgsql3 >> /etc/hosts
3.1.3 设置NTP
yum -y install chrony
systemctl start chronyd
systemctl enable chronyd
systemctl status chronyd
chronyc sources
3.2 搭建原生citus集群
启动pg数据库,创建citus
扩展,将pgsql1
作为CN节点,pgsql2
和pgsql3
作为DN1和DN2节点,在CN节点添加两个DN节点。
su - postgres
# 如果数据库没有启动
pg_ctl start
# 进入命令行
psql
在CN和DN创建citus
扩展,再添加DN节点。
CREATE EXTENSION citus;
SELECT * from master_add_node('192.168.198.168', 5432);
SELECT * from master_add_node('192.168.198.169', 5432);
# 验证是否成功
SELECT * FROM master_get_active_worker_nodes();
postgres=# CREATE EXTENSION citus;
CREATE EXTENSION
postgres=# SELECT * from master_add_node('192.168.198.168', 5432);
2024-11-05 15:29:06.964 CST [3344] LOG: starting maintenance daemon on database 5 user 10
2024-11-05 15:29:06.964 CST [3344] CONTEXT: Citus maintenance daemon for database 5 user 10
master_add_node
-----------------
1
(1 row)
postgres=# SELECT * from master_add_node('192.168.198.169', 5432);
master_add_node
-----------------
2
(1 row)
postgres=# SELECT * FROM master_get_active_worker_nodes();
node_name | node_port
-----------------+-----------
192.168.198.169 | 5432
192.168.198.168 | 5432
(2 rows)
3.3 搭建zookeeper集群
3.3.1 修改zoo.cfg
dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/datalog
#服务器配置
server.1=192.168.198.167:2888:3888
server.2=192.168.198.168:2888:3888
server.3=192.168.198.169:2888:3888
3.3.2 创建myid文件
在三台服务器data
目录下面分别myid
文件,分别写入上面服务器配置中server
后面的数字。
cd /usr/local/zookeeper/data
#server.1
echo "1" > myid
#server.2
echo "2" > myid
#server.3
echo "3" > myid
3.3.3 启动zookeeper
#启动
zkServer.sh start
#停止
zkServer.sh stop
#重启
zkServer.sh restart
#查看状态
zkServer.sh status
如果正常启动的话,我们可以发现,因为选举机制,我们启动第一台和第二台时,都未能启动成功。
当我们启动第三台时,出现选票超过半数,则此时我们再去看,zookeeper3
成为了leader
而zookeeper1
和zookeeper2
成为了follower
。
3.4 搭建patroni集群
3.4.1 修改配置文件
修改/usr/patroni/conf/patroni_postgresql.yml
配置文件,将zookeeper
集群地址添加进去。
vi /usr/patroni/conf/patroni_postgresql.yml
# 修改成如下
zookeeper:
hosts:
- 192.168.198.167:2181
- 192.168.198.168:2181
- 192.168.198.169:2181
同时,因为是用pgsql1复制的虚拟机,对于pgsql2
和pgsql3
来说,需要修改配置文件中的一下内容:
pgsql2
:
scope: dn1
namespace: /pgsql/
name: pgsql2
restapi:
listen: 192.168.198.168:8008
connect_address: 192.168.198.168:8008
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.198.168:5432
pgsql3
:
scope: dn2
namespace: /pgsql/
name: pgsql3
restapi:
listen: 192.168.198.169:8008
connect_address: 192.168.198.169:8008
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.198.169:5432
3.4.2 启动patroni
su - postgres
cd /soft/partoni/patroni-4.0.3
# 激活虚拟环境
source venv/bin/activate
pip show patroni
patroni --version
# 默认前台运行
patroni /usr/patroni/conf/patroni_postgresql.yml
# 后台运行
patroni /usr/patroni/conf/patroni_postgresql.yml &
# 停止
curl -X POST http://localhost:8008/manage/stop
patroni /usr/patroni/conf/patroni_postgresql.yml stop
# 查看集群状态
patronictl -c /usr/patroni/conf/patroni_postgresql.yml list
# 退出虚拟环境
deactivate
启动日志如下:
集群信息如下:
3.4.3 修改配置文件兼容citus
停止patroni
的服务,在三个节点的配置文件中,都添加关于citus
的部分。
pgsql1
:
citus:
database: postgres
group: 0 # coordinator
pgsql2
:
citus:
database: postgres
group: 1 # worker
pgsql3
:
citus:
database: postgres
group: 2 # worker
3.4.4 再次启动patroni
su - postgres
cd /soft/partoni/patroni-4.0.3
# 激活虚拟环境
source venv/bin/activate
# 默认前台运行
patroni /usr/patroni/conf/patroni_postgresql.yml
# 查看集群状态
patronictl -c /usr/patroni/conf/patroni_postgresql.yml list
启动日志如下:
集群信息如下:
上面是单独设置的scope,在citus集群中尽量设置一样的scope:
修改三个节点的/usr/patroni/conf/patroni_postgresql.yml
文件:
vi /usr/patroni/conf/patroni_postgresql.yml
# 修改内容
scope: demo
对于同一个scope如果没有配置citus的话只能有一个主节点,如果配置了citus的话可以存在多个主节点,但是对应的每个group只能有一个主节点,如果有相同的group进来会变成从节点。
3.4.5 配置systemd管理Patroni
touch /usr/lib/systemd/system/patroni.service
vim /usr/lib/systemd/system/patroni.service
cat > /usr/lib/systemd/system/patroni.service << EOF
[Unit]
Description=patroni - a high-availability PostgreSQL
Documentation=https://patroni.readthedocs.io/en/latest/index.html
After=syslog.target network.target etcd.target
Wants=network-online.target
[Service]
Type=simple
User=postgres
Group=postgres
PermissionsStartOnly=true
ExecStart=/usr/local/python/3.9/bin/patroni /usr/patroni/conf/patroni_postgresql.yml
ExecReload=/bin/kill -HUP $MAINPID
LimitNOFILE=65536
KillMode=process
KillSignal=SIGINT
Restart=no
RestartSec=30s
TimeoutSec=0
[Install]
WantedBy=multi-user.target
EOF
想要异常退出时自动重启,使用 Restart=on-abnormal 。
3.4.6 使用systemctl启动patroni
systemctl daemon-reload
systemctl start patroni
systemctl stop patroni
systemctl status patroni
# 查看集群状态
patronictl -c /usr/patroni/conf/patroni_postgresql.yml list
4. 备库搭建
将之前搭建的CN节点和两个DN节点克隆一份作为各自的备数据库。
4.1 设置名称解析
echo 192.168.198.177 pgsql4 >> /etc/hosts
echo 192.168.198.178 pgsql5 >> /etc/hosts
echo 192.168.198.179 pgsql6 >> /etc/hosts
4.2 搭建cn节点备库
这里使用patroni自带的复制主库。原生主从搭建参考。
删除/usr/local/pgsql/data
下的数据。
rm -rf /usr/local/pgsql/data/*
4.3 修改patroni的配置
vi /usr/patroni/conf/patroni_postgresql.yml
修改内容如下:
pgsql4
:
scope: demo
namespace: /pgsql/
name: pgsql4
restapi:
listen: 192.168.198.177:8008
connect_address: 192.168.198.177:8008
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.198.177:5432
pgsql5
:
scope: demo
namespace: /pgsql/
name: pgsql5
restapi:
listen: 192.168.198.178:8008
connect_address: 192.168.198.178:8008
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.198.178:5432
pgsql6
:
scope: demo
namespace: /pgsql/
name: pgsql6
restapi:
listen: 192.168.198.179:8008
connect_address: 192.168.198.179:8008
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.198.179:5432
4.4 启动patroni
systemctl daemon-reload
systemctl start patroni
systemctl status patroni
# 查看集群状态
patronictl -c /usr/patroni/conf/patroni_postgresql.yml list
systemctl stop patroni
5. 故障测试
5.1 主备切换
5.1.1 CN节点主备切换
集群初始状态如下,group
为0的为cn主数据库和备数据库。
在任意节点输入以下命令:
patronictl -c /usr/patroni/conf/patroni_postgresql.yml switchover
patronictl -c /usr/patroni/conf/patroni_postgresql.yml switchover --group 0 --leader pgsql1 --candidate pgsql4
执行之后,CN节点的主备切换,结果如下:
5.1.2 DN节点主备切换
集群初始状态如下,group为1和2的分别对应两个DN主节点和备节点。
在任意节点输入以下命令:
patronictl -c /usr/patroni/conf/patroni_postgresql.yml switchover
patronictl -c /usr/patroni/conf/patroni_postgresql.yml switchover --group 1 --leader pgsql2 --candidate pgsql5
执行之后,group
为1的DN节点的主备切换,结果如下:
5.2 故障转移
5.2.1 CN节点故障转移
集群初始状态如下,group
为0的为cn主数据库和备数据库。
在CN的主节点输入以下命令:
su - postgres
pg_ctl stop
执行暂停数据库发现,虽然显示暂停了,但是很快就会被patroni
拉起来,因此应该要结束掉patroni
这个进程来测试故障转移。下面将尝试使用kill
命令和systemctl
两个命令来结束patroni
进程。
5.2.1.1 kill -9
ps aux | grep patroni
kill -9 2190
(venv) [root@pgsql4 patroni-4.0.3]# ps aux | grep patroni
postgres 2190 0.4 1.6 942132 33116 ? Ssl 19:14 1:04 /usr/bin/python3 /usr/local/python/3.9/bin/patroni /usr/patroni/conf/patroni_postgresql.yml
root 2544 0.0 0.0 112824 988 pts/0 S+ 23:28 0:00 grep --color=auto patroni
(venv) [root@pgsql4 patroni-4.0.3]# kill -9 2190
执行之后,触发CN节点的故障转移,在其他节点查看集群状态如下:
此时也发现kill之后patroni
会被再次启动,查看配置发现是因为在/usr/lib/systemd/system/patroni.service
配置文件中配置了Restart=on-abnormal
导致会在异常退出时重新启动,将这个配置改为Restart=no
,再次进行测试。
vi /usr/lib/systemd/system/patroni.service
systemctl daemon-reload
systemctl restart patroni
ps aux | grep patroni
kill -9 2649
这次正常进行了故障转移,此时再将停止服务的节点启动起来。
systemctl start patroni
查看集群状态如下:
5.2.1.2 kill -15
集群的初始状态如下:
在CN的主节点输入以下命令,执行之后,触发CN节点的故障转移,在其他节点查看集群状态如下:
ps aux | grep patroni
kill -15 4357
(venv) [root@pgsql1 /]# ps aux | grep patroni
postgres 4357 0.6 1.5 1089944 30956 ? Ssl 00:48 0:08 /usr/bin/python3 /usr/local/python/3.9/bin/patroni /usr/patroni/conf/patroni_postgresql.yml
root 4494 0.0 0.0 112828 984 pts/0 S+ 01:09 0:00 grep --color=auto patroni
(venv) [root@pgsql1 /]# kill -15 4357
此时再次启动服务:
systemctl start patroni
查看集群状态如下:
kill -9
服务是~状态,而kill -15
则是loaded
状态。
kill -9
结束patroni
进程时,使用patronictl list
命令查看会发现显示数据库还在运行状态,过一段时间会直接触发故障转移,而kill -15
结束进程时,查看集群状态会显示数据库已经进入stoped
状态,然后再出发故障转移。这一点上使用systemctl stop patroni
也是如此,并且也是显示服务为loaded
状态。
5.2.1.3 systemctl stop patroni
集群的初始状态如下:
在CN的主节点输入以下命令,执行之后,触发CN节点的故障转移,在其他节点查看集群状态如下:
systemctl stop patroni
systemctl status patroni
此时再次启动服务:
systemctl start patroni
查看集群状态如下:
感觉使用systemctl stop patroni进行故障转移比kill命令慢一点,数据库会在stoped状态停留更久。
5.2.2 DN节点故障转移
5.2.2.1 kill -9
集群的初始状态如下:
在group
为2的DN的主节点输入以下命令,执行之后,触发DN节点的故障转移,在其他节点查看集群状态如下:
ps aux | grep patroni
kill -9 3523
(venv) [root@pgsql3 patroni-4.0.3]# ps aux | grep patroni
postgres 3523 0.3 1.5 1089612 30888 ? Ssl 00:42 0:08 /usr/bin/python3 /usr/local/python/3.9/bin/patroni /usr/patroni/conf/patroni_postgresql.yml
root 3728 0.0 0.0 112828 988 pts/2 S+ 01:23 0:00 grep --color=auto patroni
(venv) [root@pgsql3 patroni-4.0.3]# kill -9 3523
此时再次启动服务:
systemctl start patroni
查看集群状态如下:
5.2.2.1 kill -15
集群的初始状态如下:
在group
为2的DN的主节点输入以下命令,执行之后,触发DN节点的故障转移,在其他节点查看集群状态如下:
ps aux | grep patroni
kill -15 2275
(venv) [root@pgsql6 tmp]# ps aux | grep patroni
postgres 2275 0.3 1.6 1089868 32976 ? Ssl 11月06 0:09 /usr/bin/python3 /usr/local/python/3.9/bin/patroni /usr/patroni/conf/patroni_postgresql.yml
root 2376 0.0 0.0 112824 984 pts/1 S+ 00:11 0:00 grep --color=auto patroni
(venv) [root@pgsql6 tmp]# kill -15 2275
此时再次启动服务:
systemctl start patroni
查看集群状态如下:
5.2.2.3 systemctl stop patroni
集群的初始状态如下:
在group
为2的DN的主节点输入以下命令,执行之后,触发DN节点的故障转移,在其他节点查看集群状态如下:
systemctl stop patroni
此时再次启动服务:
systemctl start patroni
查看集群状态如下:
6. 问题总结
6.1 bash_profile
文件登录时没有加载问题
问题描述:
为什么我把postgresql
的环境配置在postgres
用户的bash_profile
文件里,每次进入postgres
用户都要重新加载一遍才能使用pg_ctl
命令?
产生原因:
问题的根本原因在于你将 PostgreSQL 环境变量配置在了 postgres
用户的 ~/.bash_profile
中,但是该文件通常只有在登录时(例如通过 SSH 登录或直接进入 shell 时)才会被加载。如果你在切换到 postgres
用户时没有触发登录 shell,或者你只是切换到 postgres
用户而没有重新加载配置文件,就需要手动执行 source ~/.bash_profile
来加载这些环境变量。
解决方案:
-
确保是登录 shell:
如果你是通过
su postgres
或sudo -u postgres
切换用户的,这样切换并不会加载~/.bash_profile
,而是进入一个非登录 shell。如果你希望进入登录 shell,可以使用以下命令:
su - postgres 或者 sudo -i -u postgres
-
手动加载环境变量:
如果你不想每次都使用登录 shell,可以手动加载配置文件:
source ~/.bash_profile
-
将环境变量放在其他文件:
另一种解决方法是将 PostgreSQL 环境变量配置在
~/.bashrc
中。~/.bashrc
会在每次进入一个新的 shell 时加载。你可以将 PostgreSQL 环境变量(如PATH
或PGDATA
等)直接添加到~/.bashrc
中,而不是~/.bash_profile
。在
~/.bashrc
中加入类似如下的配置:export PATH=$PATH:/path/to/your/postgresql/bin export PGDATA=/path/to/your/data/directory
然后,确保每次切换用户时
~/.bashrc
会被加载。如果是通过su - postgres
进入的 shell,~/.bashrc
会被自动加载;如果是通过su postgres
或其他方式,则可以手动加载:source ~/.bashrc
-
全局配置:
如果 PostgreSQL 的环境变量是所有用户都需要的,可以将环境变量配置到系统范围内的配置文件,如
/etc/profile
或/etc/bash.bashrc
(具体文件视操作系统而定)。这样,无论哪个用户登录,都会加载相同的环境变量。
6.2 patroni配置citus启动cn节点报错
问题描述:
配置完patroni中的citus,启动三个节点是,pgsql2和pgsql3两个dn节点正常启动,cn节点启动报错。
报错日志如下:
2024-11-05 16:51:41,189 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,190 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,190 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,190 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,190 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,191 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,191 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,192 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,192 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,192 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,192 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,193 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,193 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,193 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,193 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,194 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,194 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,194 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,194 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,194 ERROR: Exception when executing query "SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node", (()): PostgresConnectionException('connection problems')
2024-11-05 16:51:41,194 INFO: establishing a new patroni citus connection to postgres
2024-11-05 16:51:41,774 INFO: Closing connection to 192.168.198.167:2181
2024-11-05 16:51:41,775 INFO: Zookeeper session closed, state: CLOSED
2024-11-05 16:51:41,779 INFO: Connecting to 192.168.198.168(192.168.198.168):2181, use_ssl: False
2024-11-05 16:51:41,809 INFO: Zookeeper connection established, state: CONNECTED
2024-11-05 16:51:41,810 WARNING: Recreating the member ZNode due to ownership mismatch
产生原因:
从日志来看,出现了多个问题。具体来说:
- 连接问题 (
PostgresConnectionException
):SELECT
查询到 Citus 元数据表pg_dist_node
时发生了连接问题。这意味着 Patroni 无法与 PostgreSQL 数据库建立连接。可能是数据库服务不可用、网络问题或数据库配置不正确。
- Zookeeper 相关信息:
- Zookeeper 是 Patroni 用来管理集群成员和协调的工具。日志中提到的“Recreating the member ZNode due to ownership mismatch”表明,Zookeeper 中的集群成员节点信息不一致,导致 Patroni 尝试重新创建该成员的 ZNode。
实际原因就是因为配置patroni中的citus配置是对database的配置错误,这个database需要使用已经存在数据库中的,比如使用postgres,如果使用不存在的话需要再每个节点都创建这个数据库。
解决方案:
- 创建数据库
postgres=# CREATE DATABASE citus;
NOTICE: Citus partially supports CREATE DATABASE for distributed databases
DETAIL: Citus does not propagate CREATE DATABASE command to workers
HINT: You can manually create a database and its extensions on workers.
CREATE DATABASE
- 更换数据库
citus:
database: postgres
group: 1 # worker
6.3 pg中切换数据库无法访问到citus中数据
问题描述:
在pg数据库中,在CN节点的postgres数据库添加了DN节点,然后切换到test数据库(其他数据库),在执行查看节点信息的sql无法查询到信息。
postgres=# \c citus
You are now connected to database "citus" as user "postgres".
citus=# SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node;
2024-11-05 19:45:30.391 CST [17614] ERROR: relation "pg_catalog.pg_dist_node" does not exist at character 59
2024-11-05 19:45:30.391 CST [17614] STATEMENT: SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node;
ERROR: relation "pg_catalog.pg_dist_node" does not exist
LINE 1: ...roupid, nodename, nodeport, noderole, nodeid FROM pg_catalog...
^
citus=# \c test
You are now connected to database "test" as user "postgres".
test=# SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node;
groupid | nodename | nodeport | noderole | nodeid
---------+----------+----------+----------+--------
(0 rows)
test=# \c postgres
You are now connected to database "postgres" as user "postgres".
postgres=# SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node;
groupid | nodename | nodeport | noderole | nodeid
---------+-----------------+----------+----------+--------
1 | 192.168.198.168 | 5432 | primary | 1
2 | 192.168.198.169 | 5432 | primary | 2
0 | 192.168.198.167 | 5432 | primary | 3
(3 rows)
SELECT * FROM pg_extension WHERE extname = 'citus';
CREATE EXTENSION IF NOT EXISTS citus;
SELECT * FROM master_get_active_worker_nodes();
SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node;
SELECT citus_set_coordinator_host('192.168.198.167', 5432);
SELECT * from citus_add_node('192.168.198.168', 5432);
SELECT * from citus_add_node('192.168.198.169', 5432);
SELECT * from master_add_node('192.168.198.168', 5432);
SELECT * from master_add_node('192.168.198.169', 5432);
SELECT * FROM master_get_active_worker_nodes();
SELECT groupid, nodename, nodeport, noderole, nodeid FROM pg_catalog.pg_dist_node;
SELECT * FROM pg_catalog.pg_dist_node;
产生原因:
patroni 运行有两种情况,一个是接管你机器上的数据库,一个是自动根据你的配置去初始化数据库.
因为data目录下已经有数据了,所以应该是接管数据库,因此会要求你数据库已经创建扩展这些,如果是空目录就会自动帮你创建。
解决方案:
修改为postgres数据库即可,如果是空目录则无事。
6.4 虚拟机的ip地址发生变化
问题描述:
虚拟机的ip地址发生变化,导致xshell无法连接。
产生原因:
虚拟机的ip地址可能轮换过期。
解决方案:
- 修改配置文件为现在的ip地址。
- 修改ip地址。
vi /etc/sysconfig/network-scripts/ifcfg-ens33
# 修改的内容
IPADDR=192.168.198.167//这是自己要改成的ip地址
GATEWAY=192.168.198.2//网关
DNS1=192.168.198.2//DNS
NETMASK=255.255.255.0//子网掩码
HWADDR=00:0c:29:4a:e8:e8//下面会教你查询mac地址
# 重启网卡
# (启动不了也没关系,直接查IP地址,你会发现已经改了)
ifdown ens33
ifup ens33
修改内容:
IPADDR=192.168.198.167
GATEWAY=192.168.198.2
DNS1=192.168.78.2
NETMASK=255.255.255.0
HWADDR=00:0c:29:4a:e8:e8
查询网关和子网掩码
DNS
在/home/etc
的目录下
cat /home/etc/resolv.conf
DNS若找不到,可以用网关IP试一试,有可能会一样。
MAC地址
6.5 failover和switchover的区别
patronictl failover
是一个与 switchover
不同的命令,通常用于强制故障转移。failover
命令适用于当主节点发生故障或不可用时,手动将备节点提升为新的主节点。
与 switchover
的区别:
switchover
:是有序的主备切换,通常用于维护或计划的主备切换,目标节点是指定的备节点。failover
:是一个强制的故障转移命令,通常用于处理主节点宕机或出现问题的情况。failover
不一定要按照预定的主备角色来切换,而是将备节点提升为主节点,强制进行切换。
使用 patronictl failover
进行主备切换
假设您在 Group 0 中要强制执行故障转移(即强制将 pgsql4
变成主节点,pgsql1
变为备节点),您可以按照以下步骤操作:
-
执行 failover 命令: 在集群中的任意节点上运行以下命令:
patronictl failover --scope group0 --master pgsql1 --candidate pgsql4
解释:
failover
:表示执行故障转移操作。--scope group0
:指定要进行故障转移的集群组(在您的案例中是group0
)。--master pgsql1
:当前主节点是pgsql1
,您想要将其切换掉。--candidate pgsql4
:指定备节点pgsql4
为候选主节点。
这个命令会强制执行主备切换,
pgsql4
会被提升为主节点,pgsql1
会变成备节点。 -
检查切换状态: 执行完
failover
命令后,可以使用patronictl status
来检查集群状态,确保切换已经完成。patronictl status
输出中应该可以看到
pgsql4
现在是主节点,pgsql1
成为备节点。 -
验证新主节点: 您可以使用
psql
来验证新的主节点状态。例如,登录到pgsql4
上,运行以下查询来确认它是否已成为新的主节点:psql -h pgsql4 -U postgres -c "SELECT pg_is_in_recovery();"
如果返回
false
,则表示pgsql4
是新的主节点。 -
验证旧主节点变为备节点: 同样,您可以在
pgsql1
上执行以下命令,确认它已变为备节点:psql -h pgsql1 -U postgres -c "SELECT pg_is_in_recovery();"
如果返回
true
,则表示pgsql1
成为备节点。
注意:
failover
是一个强制性的命令,通常用于当主节点出现故障时,系统需要尽快恢复服务。它会把指定的备节点提升为新的主节点,而不管该备节点的同步状态如何,因此请确保备节点在执行故障转移前已同步到足够的数据。- 如果
failover
是由于故障而执行的,您应该在操作之前确保集群的健康状况,避免数据丢失。
总结:
patronictl failover
是用来执行强制故障转移的命令,适用于主节点宕机或者出现问题时进行的切换。如果您只是想进行计划性的主备切换,可以使用 switchover
命令;而如果您想进行强制的主备切换(例如因为主节点失效),则使用 failover
命令。
1. 一主两从的环境,所有的从库都落后于主库,此时leader节点出现问题,这种情况下该怎办?
这种情况下,没有任何副本有资格成为新的主库,因为它们都落后于主库,此时我们只能触发手动故障转移,也就是failover。patronictl failover <your-cluster-name>
,这样会丢数据,它将一个从库变成新的主库。
2.maximum_lag_on_failover参数的含义
这个参数的具体含义。我们的Patroni每隔10秒,leader节点会将它的wal_position写入到etcd。在leader竞争的情况下,每个副本都会将其wal_position与etcd中领导者最后注册的wal_position进行比较。如果差值大于maximum_lag_on_failover,它将不会提升。
6.6 patronictl的所有命令报错
问题描述:
运行patronictl命令报错,找不到dcs配置。
(venv) [root@pgsql1 /]# patronictl show-config
Error: Can not find suitable configuration of distributed configuration store
Available implementations: consul, etcd, etcd3, exhibitor, kubernetes, raft, zookeeper
产生原因:
应该是没有找到patroni的配置文件。
解决方案:
使用命令的时候指定配置文件位置。
patronictl -c /usr/patroni/conf/patroni_postgresql.yml show-config
patronictl -c /usr/patroni/conf/patroni_postgresql.yml switchover
标签:postgresql,postgres,192.168,citus,patroni,源码,usr,节点,pg
From: https://www.cnblogs.com/zreo2home/p/18603985