postgresql+rabbitmq+clickhouse集群搭建方案
postgresql+rabbitmq+clickhouse集群搭建方案
文章目录
方案介绍
本文档仅为示例,采用内网三台集群组成集群:192.168.1.6、192.168.1.89、192.168.1.83
其中1.6作为主服务器,1.89作为备选服务器,1.83作为兜底服务器
需要安装插件介绍
keepalived
作用说明
Keepalived 的核心作用是解决 HAProxy 自身的单点故障问题,为负载均衡层提供高可用保障。
提供虚拟 IP(VIP):Keepalived 会在多台 HAProxy 节点之间维护一个漂移的虚拟 IP。客户端只需连接这个 VIP,而非具体某个 HAProxy 的物理 IP
主备自动切换:正常情况下,VIP 只在主 HAProxy 节点上生效。如果主节点宕机或服务异常,Keepalived 会自动将 VIP 漂移到备节点,整个过程对客户端无感知。
健康检查联动:Keepalived 会持续检测 HAProxy 进程的状态(比如通过检查端口、进程或自定义脚本)。一旦发现 HAProxy 服务失效,会主动触发 VIP 切换,避免客户端被路由到已失效的负载均衡器。
通常会是这样的 2 + N 模式:
两台服务器部署 HAProxy + Keepalived 组合,形成主备关系,对外暴露一个虚拟 IP。
Patroni
它是一个Python编写的模板,用于配置和管理PostgreSQL高可用集群,利用分布式共识存储(etcd)进行领导者选举和配置管理,可以理解为它就是一个死循环,一直去分布式配置管理信息存储系统里去取数据,你可以理解为它是一个管家,管理PostgreSQL进程,自动化处理故障转移,每个安装了pgsql的机器都需要安装一个Patroni。
etcd
它的稳定性直接决定了整个高可用体系是否可靠。etcd 是通过 Raft 共识算法,为 Patroni 集群提供了一个永远不会出现“两个主库”的、绝对一致的控制中心
作用:
-
领导者选举:所有 Patroni 节点都盯着 etcd 中的同一把“领导者锁”,保证有且仅有一个主库。
-
集群状态共识:集群拓扑、各节点健康状态和复制位点等关键信息,都储存在 etcd 中,所有节点看到的视图完全一致。
-
动态配置下发:修改 max_connections 等参数,Patroni 会写入 etcd,其他节点 Watch 到变化后自动响应。
HAProxy
HAProxy 在这个集群方案中的核心作用是一个 四层(TCP)负载均衡器,它为客户端提供一个统一的、高可用的入口,并将请求流量分发到后端的多台服务器上
需要注意的是:
HAProxy 本身不是高可用的,如果 HAProxy 挂了,整个入口就没了。所以生产环境通常会部署多个 HAProxy 实例,并在其上层用 Keepalived (VIP) 或云负载均衡器来保证 HAProxy 自身的冗余- 它不做连接池:HAProxy 是逐连接的转发,如果应用频繁短连接,后端 PostgreSQL 压力会很大。这通常通过追加PgBouncer解决,而非在 HAProxy 层面。
- 只做路由,不参与决策:HAProxy 完全信任 Patroni 的健康检查反馈,自身不具备任何数据库角色判断逻辑,这保证了责任清晰。
PgBouncer
PgBouncer 是 PostgreSQL 生态中最轻量、最成熟的开源连接池。在 Patroni + HAProxy 的高可用架构里,它专门解决一个关键问题:PostgreSQL 的进程模型无法承受海量短连接。
PostgreSQL 采用“一个连接一个进程”的模型,每次连接都需 fork 一个新进程,占用约 2-10MB 内存,且频繁建立/销毁连接会导致 CPU 争抢和上下文切换开销巨大。PgBouncer 通过连接复用解决了这个问题
pgsql的定时任务工具(cron)
pgsql定时执行作业的一个插件
端口使用详情
| 组件 | 节点/实例 | IP地址 | 端口 | 用途 |
|---|---|---|---|---|
| etcd (DCS) | etcd1 | 192.168.1.6 | 2379, 2380 | 集群状态存储与选主 |
| etcd2 | 192.168.1.89 | 2379, 2380 | ||
| etcd3 | 192.168.1.83 | 2379, 2380 | ||
| PostgreSQL + Patroni | pg-node1 | 192.168.1.6 | 5432, 8008 | 主库 |
| pg-node2 | 192.168.1.89 | 5432, 8008 | 备库 | |
| pg-node3 | 192.168.1.83 | 5432, 8008 | 备库 | |
| PgBouncer (连接池) | pgbouncer-1 | 192.168.1.6 | 6432 | 连接池,减少数据库连接开销 |
| pgbouncer-2 | 192.168.1.89 | 6432 | ||
| pgbouncer-3 | 192.168.1.83 | 6432 | ||
| HAProxy (读写分离) | haproxy-1 | 192.168.1.6 | 5431(写), 5430(读) | 将写请求路由到主库,读请求负载均衡到从库 |
| haproxy-2 | 192.168.1.89 | 5431(写), 5430(读) | ||
| Keepalived (VIP) | VIP | 192.168.1.100 | - | 对外提供高可用入口,故障时自动漂移 |
| keeplived-1 | 192.168.1.6 | - | MASTER(优先级100) | |
| keeplived-2 | 192.168.1.89 | - | BACKUP(优先级90) | |
| rabbitmq | rabbit-node-1 | 192.168.1.6 | 5672(AMQP),1883(MQTT) | 消息队列服务 |
| rabbit-node-2 | 192.168.1.89 | 5672(AMQP),1883(MQTT) | ||
| rabbit-node-3 | 192.168.1.83 | 5672(AMQP),1883(MQTT) |
基础配置
增加host
执行以下语句配置host
echo "192.168.1.6 master" >> /etc/hosts
echo "192.168.1.89 backup" >> /etc/hosts
echo "192.168.1.83 follower" >> /etc/hosts
安装postgresql
执行以下命令进行安装
sudo apt update
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo apt install postgresql-18
配置运行外网访问
编辑 /etc/postgresql/18/main/pg_hba.conf文件,增加 0.0.0.0/0 运行外部访问

编辑 /etc/postgresql/18/main/postgresql.conf文件,修改监听地址为 *,把timezone 设置为’Asia/Shanghai’


pgsql创建集群所需用户
先执行以下命令进入数据库
sudo -u postgres psql
配置管理员账户设置
ALTER USER postgres WITH PASSWORD '你的新密码';
创建复制用户
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '用于集群复制账户的密码';
创建执行比对和回滚操作的用户
CREATE USER rewind_user WITH ENCRYPTED PASSWORD '密码';
GRANT EXECUTE ON FUNCTION pg_catalog.pg_ls_dir(text, boolean, boolean) TO rewind_user;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stat_file(text, boolean) TO rewind_user;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_read_binary_file(text) TO rewind_user;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_read_binary_file(text, bigint, bigint, boolean) TO rewind_user;
-- 确认授权
\du rewind_user
安装rabbitmq
注意以下脚本我指定了rabbitmq版本为4.1.3
#!/bin/sh
sudo apt-get install curl gnupg apt-transport-https -y
## Team RabbitMQ's main signing key
curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null
## Community mirror of Cloudsmith: modern Erlang repository
curl -1sLf https://github.com/rabbitmq/signing-keys/releases/download/3.0/cloudsmith.rabbitmq-erlang.E495BB49CC4BBE5B.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg > /dev/null
## Community mirror of Cloudsmith: RabbitMQ repository
curl -1sLf https://github.com/rabbitmq/signing-keys/releases/download/3.0/cloudsmith.rabbitmq-server.9F4587F226208342.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.9F4587F226208342.gpg > /dev/null
## Add apt repositories maintained by Team RabbitMQ
sudo tee /etc/apt/sources.list.d/rabbitmq.list <<EOF
## Provides modern Erlang/OTP releases
##
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
# another mirror for redundancy
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
## Provides RabbitMQ
##
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
# another mirror for redundancy
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
EOF
## RabbitMQ Start
sudo apt-get install apt-transport-https
sudo apt-get install curl gnupg apt-transport-https -y
## Team RabbitMQ's signing key
curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null
sudo tee /etc/apt/sources.list.d/rabbitmq.list <<EOF
## Modern Erlang/OTP releases
##
deb [arch=amd64 signed-by=/usr/share/keyrings/com.rabbitmq.team.gpg] https://deb1.rabbitmq.com/rabbitmq-erlang/ubuntu/noble noble main
deb [arch=amd64 signed-by=/usr/share/keyrings/com.rabbitmq.team.gpg] https://deb2.rabbitmq.com/rabbitmq-erlang/ubuntu/noble noble main
## Provides modern RabbitMQ releases
##
deb [arch=amd64 signed-by=/usr/share/keyrings/com.rabbitmq.team.gpg] https://deb1.rabbitmq.com/rabbitmq-server/ubuntu/noble noble main
deb [arch=amd64 signed-by=/usr/share/keyrings/com.rabbitmq.team.gpg] https://deb2.rabbitmq.com/rabbitmq-server/ubuntu/noble noble main
EOF
## Update package indices
sudo apt-get update -y
## Install Erlang packages
sudo apt-get install -y erlang-base \
erlang-asn1 erlang-crypto erlang-eldap erlang-ftp erlang-inets \
erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key \
erlang-runtime-tools erlang-snmp erlang-ssl \
erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl
## Install rabbitmq-server and its dependencies
sudo apt-get install rabbitmq-server=4.1.3-1 -y --fix-missing
## RabbitMQ End
rabbitmq集群相关配置
代码方面
默认情况下创建队列的时候rabbitmq x-queue-type值为classic,但是classic不支持Raft协议。需要在创建队列的时候把类型设置为quorum。这里需要注意如果是从classic改为quorum类型的时候如果之前业务里使用到了队列的优先级参数需要调整,classic支持10级,但是quorunm只有两级一种是普通一种是高优先级(1-4为普通;5-9高)这里说的是给 BasicProperties中Priority赋的值
MQ配置方面
修改erlang的cookie文件
- 查看主服务器上cookie的值
cat /var/lib/rabbitmq/.erlang.cookie
- 把备服务器和从服务器的cookie的值修改为主服务器上的值
vi /var/lib/rabbitmq/.erlang.cookie
- 加入集群
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@master
rabbitmqctl start_app
- 开启mqtt服务
systemctl rabbitmq-plugins enable rabbitmq_mqtt
ststemctl rabbitmq-plugins enable rabbitmq_management
- 设置磁盘限制避免因磁盘占满导致rabbitmq崩溃
设置配置文件
vi /etc/rabbitmq/rabbitmq.conf
然后把以下内容复制到文件中
disk_free_limit.absolute = 5GB
集群运维常用命令
查看队列的Leader所在位置
rabbitmq-queues quorum_status 队列名称
集群重新平衡
rabbitmq-queues rebalance quorum
查看你集群状态
sudo rabbitmqctl cluster_status
清除指定vhsot中队列里的数据
rabbitmqctl purge_queue queue_Name -p V_hostName
查看队列所属节点信息
sudo rabbitmqctl list_queues name type pid | grep quorum
集群问题解决
- 只有三台机器组成集群时,当某台机器上的rabbitmq挂掉之后,如果它是某个队列的leader,那它挂掉这个队列就无法正常使用了
1.1 执行以下命令查看是那台机器挂掉了
rabbitmq-diagnostics cluster_status
1.2 查看队列的leader处于那个节点上
rabbitmq-queues quorum_status 队列名
1.3 执行手动转移 Leader
sudo rabbitmq-queues rebalance quorum --vhost-pattern ".*" --queue-pattern ".*"
执行这个命令耗时会比较长,执行完成后结果如下图:
- 集群中某台机器崩溃了再进行手动启动的时候,启动失败,执行以下命令查看报错信息
journalctl -xeu rabbitmq-server -n 50
报错信息中提示:Error during startup: {error, {aborted_feature_flags_compat_check, {error, {erpc, noconnection}}}}字样,这说明是RabbitMQ 在崩掉的时候有残留的 epmd 进程,残留的epmd会阻断Erlang节点之间的RPC通讯
执行以下命令就可以解决此问题
sudo systemctl stop rabbitmq-server
sudo pkill -9 beam.smp
sudo pkill -9 epmd
sudo rm -f /tmp/epmd.socket # 清理 epmd socket 文件ver
- rabbitmq因为磁盘空间满了导致rabbitmq崩溃,后续启动无法正常启动。
为什么会让rabbitmq无法启动?因为磁盘写满导致的数据损坏是不完整、非原子性的,这会让RabbitMQ在重启时无法加载和验证原有的数据文件。 根本的解决方案是预防。核心在于提前修改RabbitMQ的默认磁盘阈值 disk_free_limit(默认为50MB)。生产环境必须将其设置得更高,例如设为内存的1.0~2.0倍或一个绝对值为数GB。
执行以下命令创建配置文件
vi /etc/rabbitmq/rabbitmq.conf
执行以下命令动态设置限制
disk_free_limit.relative = 1.5
这个命令的效果是: 运行内存 × 1.5 = 磁盘阈值
注意:如果运行内存是100个G,磁盘也是100个G,会导致 RabbitMQ 服务无法正常启动或瞬间触发磁盘告警,云服务器和docker这类容器不能用这个命令设置。
这种情况下就直接设置绝对值
disk_free_limit.absolute = 5GB
怎么查看是否生效执行以下命令
rabbitmqctl status
查看输出的内容中是否有以下内容,如果有就说明成功了
Low free disk space watermark: 5.0 gb
Free disk space: 96.7431 gb
如果部署的时候忘记了设置磁盘预警的化,因磁盘空间满了导致崩溃就需要清除rabbitmq的数据然后再启动,命令如下:
systemctl stop rabbitmq-server
mv /var/lib/rabbitmq/mnesia /var/lib/rabbitmq/mnesia.bak
systemctl start rabbitmq-server
注意:这个操作会让RabbitMQ“恢复出厂设置”,启动后需要重建所有配置(用户、vhost、权限等)
etcd安装
注意这个插件三台机器上都需要安装,最好不要放到数据库服务器上
下载
在github上下载:Releases · etcd-io/etcd
如果你的Linux是x64版本的就可以直接选择amd64

安装
解压压缩包
tar -xvf etcd-v3.6.10-linux-amd64.tar.gz
安装到系统
cd etcd-v3.6.10-linux-amd64
sudo cp etcd etcdctl /usr/local/bin/
验证是否安装成功
etcd --version
etcdctl version
配置
创建配置文件
vi /etc/etcd/etcd.conf
1.6机器上配置如下
name: 'etcd1'
data-dir: /var/lib/etcd
initial-cluster-token: 'patroni-cluster'
initial-cluster: 'etcd1=http://192.168.1.6:2380,etcd2=http://192.168.1.89:2380,etcd3=http://192.168.1.83:2380'
initial-cluster-state: 'new'
listen-peer-urls: http://192.168.1.6:2380
listen-client-urls: http://192.168.1.6:2379,http://localhost:2379
advertise-client-urls: http://192.168.1.6:2379
initial-advertise-peer-urls: http://192.168.1.6:2380
1.89机器上配置如下
name: 'etcd2'
data-dir: /var/lib/etcd
initial-cluster-token: 'patroni-cluster'
initial-cluster: 'etcd1=http://192.168.1.6:2380,etcd2=http://192.168.1.89:2380,etcd3=http://192.168.1.83:2380'
initial-cluster-state: 'new'
listen-peer-urls: http://192.168.1.89:2380
listen-client-urls: http://192.168.1.89:2379,http://localhost:2379
advertise-client-urls: http://192.168.1.89:2379
initial-advertise-peer-urls: http://192.168.1.89:2380
1.83机器上配置如下
name: 'etcd3'
data-dir: /var/lib/etcd
initial-cluster-token: 'patroni-cluster'
initial-cluster: 'etcd1=http://192.168.1.6:2380,etcd2=http://192.168.1.89:2380,etcd3=http://192.168.1.83:2380'
initial-cluster-state: 'new'
listen-peer-urls: http://192.168.1.83:2380
listen-client-urls: http://192.168.1.83:2379,http://localhost:2379
advertise-client-urls: http://192.168.1.83:2379
initial-advertise-peer-urls: http://192.168.1.83:2380
其他命令
重载 systemd 配置
sudo systemctl daemon-reload
设置为开机自启
sudo systemctl enable --now etcd
查看服务状态
sudo systemctl status etcd
节点子检查
etcdctl endpoint health
查看集群详情
etcdctl member list
所有节点健康检查
etcdctl endpoint health --cluster -w table
PgBouncer安装
在安装了Postgresql的机器上都要安装
安装
执行以下命令进行安装
sudo apt update && sudo apt install -y pgbouncer
配置
修改配置文件
vi /etc/pgbouncer/pgbouncer.ini
主要需要注意的配置有以下几个,有些默认是被注释掉的需要恢复。
需要注意连接databases配置端口和dbname不要配置错了
[databases]
# 将所有数据库请求路由到本地的 PostgreSQL 服务
* = host=localhost port=5433 dbname=fsmgw user=postgres
[pgbouncer]
# 监听设置
listen_addr = 0.0.0.0
listen_port = 6432
# Unix socket 设置(可选)
unix_socket_dir = /var/run/postgresql
# 认证设置
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
# 连接池设置
pool_mode = transaction # 推荐使用事务级池化
default_pool_size = 50 # 每个数据库的默认连接池大小
max_client_conn = 500 # PgBouncer 能接受的最大客户端连接数
# 日志设置
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
# 管理设置
admin_users = postgres
stats_users = stats, postgres
配置用户认证
vi /etc/pgbouncer/userlist.txt
加入以下内容
"postgres" "数据库连接密码"
服务相关命令
启动服务并查看服务是否正常
sudo systemctl restart pgbouncer && systemctl status pgbouncer
cron安装
安装插件,注意以下命令的18是指pgsql的版本
sudo apt-get install postgresql-18-cron
这里单机版本下一步是直接去配置pgsql的配置文件,但是我们这里是集群安装,后续在安装Patroni的配置中进行设置
patroni安装
执行以下命令进行安装,注意以下命令的18是指pgsql的版本
sudo apt install postgresql-18 patroni
主服务器配置(1.6)
- 创建配置文件
vi /etc/patroni/config.yml
- 把以下内容复制到文件中
scope: "18-clusteredData"
namespace: "/postgresql-common/"
name: fsmgw-clustered-1-6
etcd3:
hosts:
- 192.168.1.6:2379
- 192.168.1.89:2379
- 192.168.1.83:2379 # 修正为 83 的 2379,删掉 2382
tags:
failover_priority: 100
restapi:
listen: 192.168.1.6:8008
connect_address: 192.168.1.6:8008
bootstrap:
method: pg_createcluster
pg_createcluster:
command: /usr/share/patroni/pg_createcluster_patroni
dcs: # 注意缩进:dcs 是 bootstrap 的子项
ttl: 30
loop_wait: 10
retry_timeout: 5
maximum_lag_on_failover: 1048576
check_timeline: true
postgresql:
use_pg_rewind: true
remove_data_directory_on_rewind_failure: true
remove_data_directory_on_diverged_timelines: true
use_slots: true
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 scram-sha-256
- host all all ::1/128 scram-sha-256
- host replication replicator 192.168.1.0/24 scram-sha-256
- host replication replicator 127.0.0.1/32 scram-sha-256
- host all all 192.168.1.0/24 scram-sha-256
parameters:
wal_log_hints: 'on'
hot_standby_feedback: 'on'
max_replication_slots: 10
max_wal_senders: 10
wal_keep_size: 1GB
password_encryption: scram-sha-256
shared_preload_libraries: pg_cron
cron.database_name: fsmgw
cron.use_background_workers: 'on'
recovery_conf: # 正确位置:dcs 的子项
standby_mode: 'on'
slots: # 正确位置:dcs 的子项,与 postgresql、recovery_conf 同级
fsmgw-clustered-1-6:
type: physical
fsmgw-clustered-1-89:
type: physical
fsmgw-clustered-1-83:
type: physical
postgresql:
create_replica_method:
- pg_clonecluster
pg_clonecluster:
command: /usr/share/patroni/pg_clonecluster_patroni
listen: 0.0.0.0:5433
connect_address: 192.168.1.6:5433
use_unix_socket: true
data_dir: /data2/postgresql/18/clusteredData
bin_dir: /usr/lib/postgresql/18/bin
config_dir: /etc/postgresql/18/clusteredData
pgpass: /var/lib/postgresql/18-clusteredData.pgpass
authentication:
replication:
username: "replicator"
password: "copyP@ssw0rd"
superuser:
username: "postgres"
password: "maiyuan!2#"
rewind:
username: "rewind_user"
password: "maiyuan!2#"
parameters:
unix_socket_directories: '/var/run/postgresql/'
logging_collector: 'on'
log_directory: '/var/log/postgresql'
log_filename: 'postgresql-18-clusteredData.log'
shared_buffers: '8GB' # 这里根据机器实际情况设置
effective_cache_size: '24GB' # 这里根据机器实际情况设置
- 设置文件权限
sudo chown postgres:postgres /etc/patroni/config.yml
从服务器配置(1.89)
从服务器的配置只有config.yml文件内容的差异,其他步骤按照上面主库的操作步骤执行即可
scope: "18-clusteredData"
namespace: "/postgresql-common/"
name: fsmgw-clustered-1-89
etcd3:
hosts:
- 192.168.1.6:2379
- 192.168.1.89:2379
- 192.168.1.83:2379
tags:
failover_priority: 90
restapi:
listen: 192.168.1.89:8008
connect_address: 192.168.1.89:8008
bootstrap:
method: pg_createcluster
pg_createcluster:
command: /usr/share/patroni/pg_createcluster_patroni
dcs: # 注意缩进:dcs 是 bootstrap 的子项
ttl: 30
loop_wait: 10
retry_timeout: 5
maximum_lag_on_failover: 1048576
check_timeline: true
postgresql:
use_pg_rewind: true
remove_data_directory_on_rewind_failure: true
remove_data_directory_on_diverged_timelines: true
use_slots: true
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 scram-sha-256
- host all all ::1/128 scram-sha-256
- host replication replicator 192.168.1.0/24 scram-sha-256
- host replication replicator 127.0.0.1/32 scram-sha-256
- host all all 192.168.1.0/24 scram-sha-256
parameters:
wal_log_hints: 'on'
hot_standby_feedback: 'on'
max_replication_slots: 10
max_wal_senders: 10
wal_keep_size: 1GB
password_encryption: scram-sha-256
shared_preload_libraries: pg_cron
cron.database_name: fsmgw
cron.use_background_workers: 'on'
recovery_conf: # 正确位置:dcs 的子项
standby_mode: 'on'
slots: # 正确位置:dcs 的子项,与 postgresql、recovery_conf 同级
fsmgw-clustered-1-6:
type: physical
fsmgw-clustered-1-89:
type: physical
fsmgw-clustered-1-83:
type: physical
postgresql:
create_replica_method:
- pg_clonecluster
pg_clonecluster:
command: /usr/share/patroni/pg_clonecluster_patroni
listen: 0.0.0.0:5433
connect_address: 192.168.1.89:5433
use_unix_socket: true
data_dir: /data2/postgresql/18/clusteredData
bin_dir: /usr/lib/postgresql/18/bin
config_dir: /etc/postgresql/18/clusteredData
pgpass: /var/lib/postgresql/18-clusteredData.pgpass
authentication:
replication:
username: "replicator"
password: "copyP@ssw0rd"
superuser:
username: "postgres"
password: "maiyuan!2#"
rewind:
username: "rewind_user"
password: "maiyuan!2#"
parameters:
unix_socket_directories: '/var/run/postgresql/'
logging_collector: 'on'
log_directory: '/var/log/postgresql'
log_filename: 'postgresql-18-clusteredData.log'
shared_buffers: '2GB' # 这里根据机器实际情况设置
effective_cache_size: '10GB' # 这里根据机器实际情况设置
备服务器配置(1.83)
备服务器的配置只有config.yml文件内容的差异,其他步骤按照上面主库的操作步骤执行即可
scope: "18-clusteredData"
namespace: "/postgresql-common/"
name: fsmgw-clustered-1-83
tags:
failover_priority: 2 # 设置一个正数但不高于主库的值
etcd3:
hosts:
- 192.168.1.6:2379
- 192.168.1.89:2379
- 192.168.1.83:2379
restapi:
listen: 192.168.1.83:8008
connect_address: 192.168.1.83:8008
bootstrap:
method: initdb
initdb:
- encoding: UTF8
- data-checksums
#pg_createcluster:
# command: /usr/share/patroni/pg_createcluster_patroni
dcs:
# 与主库保持一致(内容相同,是全局配置)
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
check_timeline: true
postgresql:
use_pg_rewind: true
remove_data_directory_on_rewind_failure: true
remove_data_directory_on_diverged_timelines: true
use_slots: true
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 scram-sha-256
- host all all ::1/128 scram-sha-256
- host replication replicator 192.168.1.0/24 scram-sha-256
- host replication replicator 127.0.0.1/32 scram-sha-256
- host all all 192.168.1.0/24 scram-sha-256
parameters:
max_replication_slots: 10
max_wal_senders: 10
wal_keep_size: 1GB
password_encryption: scram-sha-256
postgresql:
create_replica_method:
- pg_clonecluster
pg_clonecluster:
command: /usr/share/patroni/pg_clonecluster_patroni
listen: 0.0.0.0:5433
connect_address: 192.168.1.83:5433
use_unix_socket: true
data_dir: /data/postgresql/18/clusteredData # 备库也应使用独立路径,但建议与主库路径相同(如果磁盘布局一致)
bin_dir: /usr/lib/postgresql/18/bin
config_dir: /etc/postgresql/18/clusteredData
pgpass: /var/lib/postgresql/18-clusteredData.pgpass
authentication:
replication:
username: "replicator"
password: "copyP@ssw0rd"
superuser:
username: "postgres"
password: "maiyuan!2#"
rewind:
username: "rewind_user"
password: "maiyuan!2#"
parameters:
unix_socket_directories: '/var/run/postgresql/'
logging_collector: 'on'
log_directory: '/var/log/postgresql'
log_filename: 'postgresql-18-clusteredData.log'
shared_buffers: '2GB' # 这里根据机器实际情况设置
effective_cache_size: '10GB' # 这里根据机器实际情况设置
配置cron
这里我们执行以下命令进行配置
export EDITOR=vim
patronictl -c /etc/patroni/config.yml edit-config 18-clusteredData
修改配置文件内容如下
check_timeline: true
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters:
cron.database_name: fsmgw #cron作用的表
cron.use_background_workers: 'on' #开启后台线程执行
max_replication_slots: 10
max_wal_senders: 10
password_encryption: scram-sha-256
shared_preload_libraries: pg_cron
wal_keep_size: 1GB
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 scram-sha-256
- host all all ::1/128 scram-sha-256
- host replication replicator 192.168.1.0/24 scram-sha-256
- host all all 192.168.1.0/24 scram-sha-256
recovery_conf:
standby_mode: 'on'
remove_data_directory_on_diverged_timelines: true
remove_data_directory_on_rewind_failure: true
use_pg_rewind: true
use_slots: true
retry_timeout: 10
ttl: 30
在主库机器上执行以下语句创建插件
sudo -u postgres psql -h 127.0.0.1 -p 5433 -d fsmgw -c "CREATE EXTENSION pg_cron;"
验证是否配置成功,在集群中的任意一个机器上执行以下sql
SELECT datname FROM pg_database
WHERE datname = (
SELECT setting FROM pg_settings
WHERE name = 'cron.database_name'
);
服务相关命令
启动服务
systemctl start patroni
检查服务状态
journalctl -u patroni -f
查看集群状态
patronictl -c /etc/patroni/config.yml list
强制指定leader
sudo patronictl -c /etc/patroni/config.yml failover --candidate fsmgw-clustered-1-6 --force
补充知识:
集群里的每个集群上patroni都有自己的配置文件在:/etc/patroni/config.yml路径下。
vi /etc/patroni/config.yml 和patronictl -c /etc/patroni/config.yml edit-config看到的内容是不同的,因为前者查看的是 Patroni 进程本身启动时读取的本地静态配置文件 ;后者查看或修改的是存储在 DCS (Distributed Configuration Store,分布式配置存储) 中的集群动态配置。本地静态配置文件的优先级要比分布式集群中存储的配置文件优先级高 (本地配置>集群配置)
postgresql 集群相关问题解决
- 数据同步风暴,现象是,Replice状态机器一直重启,状态从starting变为Crashed,然后一直重启,此时查看postgresql状态也为正常状态。出现这个问题的原因是:
备库因 WAL 延迟过大进入长时间 recovery → Patroni 探活在 recovery 期间连续失败 → 触发自动重启 → DCS 将节点标记为失败 → 节点被踢出集群 → 集群进入 uninitialized 状态 → reinit 无法找到合法 REPLICA → 只能重建节点
故障并非 PostgreSQL 数据异常,而是备库复制延迟引发的 Patroni 探活误判,叠加 DCS 状态失效,最终导致节点脱离集群。属于典型的“recovery 时间过长 + 自动化管理工具过激”问题。
如下图
解决方案:
直接把从库重新初始化就可以了,执行以下语句
patronictl -c /etc/patroni/config.yml reinit 18-clusteredData
之后输入要重新初始化的从库的名称例如:fsmgw-clustered-1-89
查看集群状态是否正常
patronictl -c /etc/patroni/config.yml list

HAproxy安装
为了稳定可以配置多个HAProxy实现高可用,防止一台机器上的HAProxy服务挂了数据库直接访问不了的尴尬场景,这里我们在主库(1.6)和备库(1.89)上都安装一个HAproxy
在主库和备库上都按照以下步骤执行,配置文件不需要改动。
安装
执行以下命令进行安装
sudo apt install -y haproxy
配置
sudo vi /etc/haproxy/haproxy.cfg
按照以下格式进行配置
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode tcp # 使用 TCP 模式,这是 PostgreSQL 协议所必需的
option tcplog
retries 3
timeout connect 10s
timeout client 1m
timeout server 1m
# 确保长连接不会因空闲而被断开
timeout client 1h
timeout server 1h
#errorfile 400 /etc/haproxy/errors/400.http
#errorfile 403 /etc/haproxy/errors/403.http
#errorfile 408 /etc/haproxy/errors/408.http
#errorfile 500 /etc/haproxy/errors/500.http
#errorfile 502 /etc/haproxy/errors/502.http
#errorfile 503 /etc/haproxy/errors/503.http
#errorfile 504 /etc/haproxy/errors/504.http
# 用于管理界面的后端配置
frontend stats
mode http
bind *:7000
stats enable
stats uri /stats
stats refresh 10s
stats admin if LOCALHOST
# ---------------------------------------------------------------------
# 1.pgsql 读写端口:只路由到主库
# ---------------------------------------------------------------------
listen postgres_primary
bind *:5431
mode tcp
option httpchk
http-check send meth GET uri /primary ver HTTP/1.0
http-check expect status 200
default-server inter 5s fall 2 rise 3 on-marked-down shutdown-sessions
server pg-node1 192.168.1.6:6432 check port 8008
server pg-node2 192.168.1.89:6432 check port 8008
# ---------------------------------------------------------------------
# 2.pgsql 只读端口:路由到所有健康副本 (Replicas)
# ---------------------------------------------------------------------
listen postgres_replica
bind *:5430
mode tcp
balance roundrobin
option httpchk
http-check send meth GET uri /replica ver HTTP/1.0
http-check expect status 200
default-server inter 5s fall 2 rise 3 on-marked-down shutdown-sessions
server pg-node1 192.168.1.6:6432 check port 8008
server pg-node2 192.168.1.89:6432 check port 8008
# ---------------------------------------------------------------------
# RabbitMQ 负载均衡核心配置
# ---------------------------------------------------------------------
# RabbitMQ MQTT 代理配置
listen rabbitmq_mqtt
bind *:1880 # 1. 监听 MQTT 默认端口
mode tcp # 2. 使用四层代理模式
balance roundrobin # 3. 采用轮询负载均衡算法
# 4. 后端服务器列表,配置你的RabbitMQ节点
server rabbit-node-1 192.168.1.6:1883 check inter 5000 rise 2 fall 3
server rabbit-node-2 192.168.1.89:1883 check inter 5000 rise 2 fall 3
server rabbit-node-3 192.168.1.83:1883 check inter 5000 rise 2 fall 3
# ---------------------------------------------------------------------
# Clickhouse 负载均衡核心配置
# ---------------------------------------------------------------------
# tcp监听
listen clickhouse_tcp
bind *:9001
mode tcp
balance roundrobin
option tcp-check
tcp-check send "SELECT 1\n"
tcp-check expect string "1"
default-server inter 5s fall 3 rise 2
server ch-node1 192.168.1.6:9000 check inter 5s fall 3 rise 2
server ch-node2 192.168.1.89:9000 check inter 5s fall 3 rise 2
#http端口监听
listen clickhouse_http
bind *:9123
mode http
balance roundrobin
option httpchk GET /ping HTTP/1.0
http-check expect status 200
server ch-node1 192.168.1.6:8123 check inter 5s fall 3 rise 2
server ch-node2 192.168.1.89:8123 check inter 5s fall 3 rise 2
# ---------------------------------------------------------------------
# Redis 单机代理核心配置
# ---------------------------------------------------------------------
listen redis_proxy
bind *:6380
mode tcp
balance first
option tcpka # 已覆盖客户端+服务端 TCP keepalive
timeout connect 5s
timeout client 300s # 长连接池空闲超时 5 分钟
timeout server 300s
timeout check 3s
retries 3
# 健康检查:发送 PING 命令(二进制格式),期待 +PONG
option tcp-check
# 先发 AUTH 命令(‘密码’替换成你的真实密码)
# "用 printf 'AUTH 密码\r\n' | xxd -p" 命令生成的十六进制
tcp-check send-binary 415554482072656469732132230d0a
tcp-check expect string +OK
# 再发 PING
tcp-check send-binary 50494e470d0a
tcp-check expect string +PONG
default-server inter 5s fall 3 rise 2 maxconn 2000
server redis-node1 127.0.0.1:6379 check
服务相关命令
启动服务
systemctl start haproxy
验证是否监听相关端口
sudo netstat -tulpn | grep 5431
刷新配置文件
sudo systemctl reload haproxy
验证是否正常运行,可前往以下页面查看集群状态
http://192.168.1.100:7000/stats
keepalived安装
它是为了保障Haproxy高可用的,所以在安装了haproxy的机器上都要安装一个keepalived.
这里我们在主库(1.6)和备库(1.89)上都安装一个。
安装
执行以下命令进行安装
sudo apt install keepalived
配置
创建健康检查脚本
vi /etc/keepalived/check_haproxy.sh
将以下内容复制到检查脚本中
#!/bin/bash
if pgrep haproxy > /dev/null; then
exit 0
fi
# 尝试重启
systemctl start haproxy
sleep 2
if pgrep haproxy > /dev/null; then
exit 0
else
# 重启失败,停止 keepalived 释放 VIP
systemctl stop keepalived
exit 1
fi
授予脚本执行权限
chmod +x /etc/keepalived/check_haproxy.sh
主服务器配置(1.6)
创建配置文件
vim /etc/keepalived/keepalived.conf
将以下内容复制到配置文件中
注意以下配置文件中‘eno1’为网卡名称,需要改为自己机器上的网卡名称
global_defs {
router_id RABBIT1
script_user root
enable_script_security
}
vrrp_script chk_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight 2
fall 2
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eno1
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
chk_haproxy
}
}
从服务器配置(1.89)
都需要创建配置文件和健康检查脚本,以及给健康检查脚本进行授权。这里不多赘述,不同的地方只有keepalived.conf文件的内容,因此下面只展示keepalived.conf文件内容
global_defs {
router_id RABBIT2
script_user root
enable_script_security
}
vrrp_script chk_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 2
fall 2
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass maiyuan!2#
}
virtual_ipaddress {
192.168.1.100/24 dev ens160
}
track_script {
chk_haproxy
}
}
服务相关命令
启动服务
systemctl start keepalived
设置开机自启
systemctl enable keepalived
查看服务状态
systemctl status keepalived
验证 VIP 是否已绑定
ip addr show eno1 | grep 192.168.1.100
当配置完成之后就可以通过我们指定的ip(192.168.1.100)去访问mq和pgsql的服务了
clickhouse 安装&配置
clickhouse安装
docker安装
准备clickhouse所需要的配置文件
创建一个临时的文件夹放配置文件/temp/ch-config
mkdir -p /temp/ch-config
cp /etc/clickhouse-server/config.xml /temp/ch-config
cp /etc/clickhouse-server/users.xml /temp/ch-config
sudo chmod 644 /temp/ch-config/config.xml
sudo chmod 644 /temp/ch-config/users.xml
创建虚拟ip
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=ens160 \
docker_macvlan
网卡配置修改,开启检查混杂模式
sudo ip link set ens160 promisc on

创建容器
注意下面的路径/temp/ch-config/config.xml 这里对应的是你创建的那个文件夹路径
docker run -d \
--name ch-node-3 \
--network docker_macvlan \
--ip 192.168.1.200 \
-v /temp/ch-config/config.xml:/etc/clickhouse-server/config.xml \
-v /temp/ch-config/users.xml:/etc/clickhouse-server/users.xml \
clickhouse/clickhouse-server:25.11.2.24
这里通过在clickhous要用到的端口前面加1,避免与物理机上的clickhouse端口冲突
物理机安装
# Install prerequisite packages
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
# Download the ClickHouse GPG key and store it in the keyring
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
# Get the system architecture
ARCH=$(dpkg --print-architecture)
# Add the ClickHouse repository to apt sources
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
# Update apt package lists
sudo apt-get update
# 查看可安装的版本列表
# apt-cache madison clickhouse-server
sudo apt-get install -y \
clickhouse-server=26.2.2.9 \
clickhouse-client=26.2.2.9 \
clickhouse-common-static=26.2.2.9
配置
设置允许外部访问
sudo vim /etc/clickhouse-server/config.xml
# 搜索 <listen_host>0.0.0.0</listen_host> 取消注释
配置文件修改存储位置
sudo vim /etc/clickhouse-server/config.xml
# 搜索 <path>修改,然后修改权限
sudo chown -R clickhouse:clickhouse /data/clickhouse
sudo chmod 750 /data/clickhouse
集群配置
设置时区
搭建集群的机器时区必须相同
在ubuntu上执行以下命令查看时区
timedatectl
设置为中国时区
sudo timedatectl set-timezone Asia/Shanghai
配置 Keeper
创建所需的配置文件
在 /etc/clickhouse-server/config.d 下创建以下文件
- 创建cluster.xml文件
这个文件是配置集群拓扑信息
```powershell
vi /etc/clickhouse-server/cluster.xml
```
`这个文件需要注意,配置不好会导致数据无法正确同步`
- 如果是希望一台机器挂掉您一个机器上有完整的数据可以直接顶替它,可以配置为”1个分片,2个副本“
<clickhouse>
<remote_servers>
<opslogsch>
<!-- 只有 1 个 shard -->
<shard>
<internal_replication>true</internal_replication>
<!-- 第 1 个副本 -->
<replica>
<host>192.168.1.6</host>
<port>9000</port>
<user>default</user>
<password>maiyuan!2#</password>
</replica>
<!-- 第 2 个副本 -->
<replica>
<host>192.168.1.89</host>
<port>9000</port>
<user>default</user>
<password>maiyuan!2#</password>
</replica>
</shard>
</opslogsch>
</remote_servers>
</clickhouse>
- 如果数据量极大,一台机器存不下,希望 6 节点存一半,89 节点存一半那么可以如下配置
<clickhouse>
<remote_servers>
<!--这是集群的名称-->
<opslogsch>
<shard>
<internal_replication>true</internal_replication>
<replica>
<!--这是host配置的主机名-->
<host>192.168.1.6</host>
<port>9000</port>
<user>default</user>
<password>maiyuan!2#</password>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>192.168.1.89</host>
<port>9000</port>
<user>default</user>
<password>maiyuan!2#</password>
</replica>
</shard>
<!--这是集群的名称-->
</opslogsch>
</remote_servers>
</clickhouse>
如果是使用这种方式
就不能直接 INSERT 本地表,需要创建一个 分布式表(Distributed) 作为“路由代理”。
操作步骤(无需重启,无需删旧表):
- 保持现有的本地表不动(ReplicatedMergeTree)。
- 在两台机器上分别执行以下 SQL,创建分布式表:
例如:
CREATE TABLE default.black_api_log_dist ON CLUSTER opslogsch
(
-- 这里的字段结构必须和底层的本地表结构完全一模一样
id UInt64,
create_time DateTime,
api_name String
)
ENGINE = Distributed(
'opslogsch', -- 集群名称 (cluster.xml 里的名字)
'default', -- 数据库名
'black_api_log', -- 底层的本地表名
rand() -- 分片键(这里用 rand() 表示随机均匀分发到两个分片)
);
- 创建zookeeper.xml文件
这个配置是存储的集群信息
```powershell
vi /etc/clickhouse-server/zookeeper.xml
```
把以下内容复制到文件中
```powershell
<clickhouse>
<zookeeper>
<node>
<host>192.168.1.6</host>
<port>9181</port>
</node>
<node>
<host>192.168.1.89</host>
<port>9181</port>
</node>
<node>
<host>192.168.1.86</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
```
- 创建 macros.xml文件
每个节点需要配置不同的宏,用于 ReplicatedMergeTree 表自动替换
如果是使用的1个分片,2个副本那么所有集群种的机器上的<shard>01</shard>都相同,然后<replica>node1</replica>不能设置为相同的,按序号可以分别设为node1、node2等等
vi /etc/clickhouse-server/macros.xml
把以下内容复制到文件中
<clickhouse>
<macros>
<shard>01</shard>
<replica>node1</replica>
</macros>
</clickhouse>
- 创建distributed_ddl.xml文件
启用分布式 DDL在每个节点的都要配置
```powershell
vi /etc/clickhouse-server/distributed_ddl.xml
```
把以下内容复制到文件中
```powershell
<clickhouse>
<distributed_ddl>
<path>/clickhouse/task_queue/ddl</path>
</distributed_ddl>
</clickhouse>
```
keeper_config.xml
配置文件路径:/etc/clickhouse-keeper/keeper_config.xml
这里配置需要注意几点:
-
日志相关配置
-
:设置日志级别,在生产环境应该改为:常用
information或error -
/: 普通日志和错误日志的存储路径
mkdir -p 路径 sudo chown -R clickhouse:clickhouse 路径-
:每个日志文件最大大小
-
:保留最近 多少个文件
-
-
keeper_server核心配置
-
<tcp_port>:客户端(如 ClickHouse 服务器)连接 Keeper 的端口
-
<server_id>:当前节点的唯一 ID,集群中每个 Keeper 实例必须不同
-
<log_storage_path>:Raft 日志存储位置;如果需要修改需要先创建好文件夹并授权
mkdir -p 路径 sudo chown -R clickhouse:clickhouse 路径- <snapshot_storage_path>:快照的存储路径;如果需要修改需要先创建好文件夹并授权
mkdir -p 路径 sudo chown -R clickhouse:clickhouse 路径- 协调参数
-
operation_timeout_ms: 单次操作超时时间(10秒)
-
session_timeout_ms: 客户端会话超时时间(100秒)
-
raft_logs_level: Raft 内部日志级别
-
compress_logs: 是否压缩 Raft 日志(
false表示不压缩)
- <raft_configuration>Raft 集群配置定义 Raft 集群成员,默认为单节点部署
-
id: 对应
server_id,必须一致 -
hostname/port: 节点内部通信地址(用于 Raft 节点间选主、日志同步)
-
集群的配置需要在这里增加相关机器配置
-
注意事项:
当clickhouse-keeper启动之后,会在/etc/clickhouse-keeper/路径下产生一个名为keeper_config-preprocessed.xml的配置文件,它是clickhouse合并了所有配置文件之后产生的一个配置文件。如果修改了keeper_config.xml配置文件需要把这个它自动产生的文件先删除了,让它重新产生才会生效
配置示例
情景介绍:有三台台机器,1.6和1.89和1.86。分别都安装了clickhouse。然后在89上安装docker模拟第三台机器组成集群。
在每个机器的配置文件中增加一下内容
<listen_host>::</listen_host>
这里主要注意的是<raft_configuration>标签内的配置
配置文件详情
<raft_configuration>
<server>
<id>1</id>
<!-- Internal port and hostname -->
<hostname>192.168.1.6</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<!-- Internal port and hostname -->
<hostname>192.168.1.89</hostname>
<port>9234</port>
</server>
<!-- Add more servers here -->
</raft_configuration>
注意每个机器上的<server_id>要对应上<id>里给它设置的序号
例如1.6上的server_id配置如下
<clickhouse>
<logger>
<!-- Possible levels [1]:
- none (turns off logging)
- fatal
- critical
- error
- warning
- notice
- information
- debug
- trace
[1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
-->
<level>error</level>
<log>/data2/clickhouse-keeper/clickhouse-keeper.log</log>
<errorlog>/data2/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
<!-- Rotation policy
See https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/FileChannel.h#L54-L85
-->
<size>1000M</size>
<count>10</count>
<!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
</logger>
<listen_host>::</listen_host>
<max_connections>4096</max_connections>
<keeper_server>
<tcp_port>9181</tcp_port>
<!-- Must be unique among all keeper serves -->
<server_id>1</server_id>
<log_storage_path>/data2/clickhouse/coordination/logs</log_storage_path>
<snapshot_storage_path>/data2/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<min_session_timeout_ms>10000</min_session_timeout_ms>
<session_timeout_ms>100000</session_timeout_ms>
<raft_logs_level>information</raft_logs_level>
<compress_logs>false</compress_logs>
<!-- All settings listed in https://github.com/ClickHouse/ClickHouse/blob/master/src/Coordination/CoordinationSettings.h -->
</coordination_settings>
<!-- enable sanity hostname checks for cluster configuration (e.g. if localhost is used with remote endpoints) -->
<hostname_checks_enabled>true</hostname_checks_enabled>
<raft_configuration>
<server>
<id>1</id>
<!-- Internal port and hostname -->
<hostname>192.168.1.6</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<!-- Internal port and hostname -->
<hostname>192.168.1.89</hostname>
<port>9234</port>
</server>
<!-- Add more servers here -->
</raft_configuration>
</keeper_server>
<openSSL>
<server>
<!-- Used for secure tcp port -->
<!-- openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt -->
<!-- <certificateFile>/etc/clickhouse-keeper/server.crt</certificateFile> -->
<!-- <privateKeyFile>/etc/clickhouse-keeper/server.key</privateKeyFile> -->
<!-- dhparams are optional. You can delete the <dhParamsFile> element.
To generate dhparams, use the following command:
openssl dhparam -out /etc/clickhouse-keeper/dhparam.pem 4096
Only file format with BEGIN DH PARAMETERS is supported.
-->
<!-- <dhParamsFile>/etc/clickhouse-keeper/dhparam.pem</dhParamsFile> -->
<verificationMode>none</verificationMode>
<loadDefaultCAFile>true</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
</openSSL>
</clickhouse>
集群所需命令
在集群中删除某个表
注意:ON CLUSTER ‘opslogsch’ SYNC 这句sql的作用是让集群中做同步删除
DROP TABLE IF EXISTS default.black_api_log ON CLUSTER 'opslogsch' SYNC;
集群中创建表
注意:ON CLUSTER opslogsch 这是集群名称
CREATE TABLE default.black_api_log ON CLUSTER opslogsch
(
`id` UInt64,
`target_type` Int16,
`target_code` Int32,
`black_id` UUID,
`mobile` String,
`execution_time` DateTime DEFAULT now(),
`execution_duration` UInt64,
`is_black_mobile` Bool
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/default.black_api_log', '{replica}')
PARTITION BY toYYYYMM(execution_time)
ORDER BY (mobile, toStartOfHour(execution_time), execution_time)
PRIMARY KEY (mobile, toStartOfHour(execution_time))
TTL execution_time + INTERVAL 90 DAY
SETTINGS index_granularity = 8192;
查看集群中那个机器为leader
echo stat | nc 127.0.0.1 9181 | grep Mode

查看集群是否运行正常
执行以下命令连接clickhouse
clickhouse-client
执行以下sql
SELECT * FROM system.zookeeper WHERE path = '/';
出现以下内容说明成功了
刷新配置
连接clickhouse
clickhouse-client
修改了集群配置后执行以下语句进行配置刷新
SYSTEM RELOAD CONFIG;
查看集群信息
注意opslogsch是集群名称也就是cluster.xml里<opslogsch>标签
SELECT cluster, shard_num, replica_num, host_name, host_address, port
FROM system.clusters
WHERE cluster = 'opslogsch';
输出结果如下:
删除集群中的某个表
DROP TABLE default.black_api_log SYNC;
集群相关问题解决
路径错误,问题现象:执行
sudo journalctl -u clickhouse-keeper -f
出现以下字样
Jun 02 17:08:42 rabbit-node-1 systemd[1]: clickhouse-keeper.service: Failed with result 'exit-code'.
Jun 02 17:09:01 rabbit-node-1 systemd[1]: Stopped clickhouse-keeper.service - ClickHouse Keeper - zookeeper compatible distributed coordination server.
执行:cat 日志路径
这里的日志路径为:在keeper_config.xml内<errorlog>里设置的路径
可看到如下内容:
这里异常说明对应路径没有创建,此时我们只需要创建对应路径就可以了例如:
# 创建日志和快照目录
sudo mkdir -p /data2/clickhouse/coordination/log
sudo mkdir -p /data2/clickhouse/coordination/snapshots
# 设置权限
sudo chown -R clickhouse:clickhouse /data2/clickhouse
sudo chmod -R 755 /data2/clickhouse
集群连接异常
执行以下命令
cat /data2/clickhouse-keeper/clickhouse-keeper.err.log

这种情况说明集群里某台机器没有启动clickhouse-keeper,把那台机器上对应的服务启动起来就可以了
ClickHouse Keeper 集群陷入了“无限选举循环”
执行以下命令:
tail -f /data2/clickhouse-keeper/clickhouse-keeper.err.log
出现以下内容
这种情况是因为只有两台机器,他们选不出leader,此时需要把三台几器都启动起来才能正常选举leader。
表引擎的切换,表引擎需要切换
从MergeTree切换为:ReplicatedMergeTree
ReplacingMergeTree要切换为ReplicatedReplacingMergeTree
查看集群任务队列信息
执行以下sql语句
SELECT * FROM system.zookeeper WHERE path = '/clickhouse/task_queue/ddl/';
如果发现任务队列卡住了的话可以进行任务清理
在ubuntu命令行上执行
clickhouse-keeper-client --host 192.168.1.6 --port 9181
查看任务信息
ls '/clickhouse/task_queue/ddl/'
删除卡住的任务
rmr '/clickhouse/task_queue/ddl/query-0000000000'
查看卡住的 DDL 任务
在leader机器上执行以下sql语句就能看到任务卡住的原因
SELECT
entry,
host,
status,
query,
exception_code,
exception_text,
query_create_time
FROM system.distributed_ddl_queue
WHERE query LIKE '%black_api_log%'
ORDER BY entry DESC
LIMIT 20;

clickhouse运维相关知识
磁盘急救
clickhouse当某些日志没有设置日志最长保存时间的话就会一直累加,这样就会造成磁盘被clickhouse占满。下面我给大家分享一下急救教程
限制Core Dump
Core Dump是ClickHouse 频繁崩溃生成的文件
vi /usr/lib/systemd/system/clickhouse-server.service
在 [Service]标记下增加:LimitCORE=1G
查看日志文件占用详情
执行以下sql查询各类日志占用情况
SELECT
database,
table,
formatReadableSize(sum(data_compressed_bytes)) AS compressed_size
FROM system.parts
WHERE database = 'system' AND table LIKE '%_log'
GROUP BY database, table
ORDER BY sum(data_compressed_bytes) DESC;
SELECT
database,
`table`,
formatReadableSize(sum(data_compressed_bytes)) AS compressed_size
FROM system.parts
WHERE (database = 'system') AND (`table` LIKE '%_log')
GROUP BY
database,
`table`
ORDER BY sum(data_compressed_bytes) DESC
可得到如下结果
这里我们一眼就能看到"query_log"它占用了1.67TB。这种显然是配置clickhouse的时候忘记设置它的日志保存时间限制了。
拯救磁盘
此时如果执行清楚数据的语句可能会出现报错如下:
Elapsed: 0.003 sec.
Received exception from server (version 24.5.1):
Code: 243. DB::Exception:
Received from localhost:9000.
DB::Exception: Cannot reserve 1.00 MiB,
not enough space. (NOT_ENOUGH_SPACE)
这说明我们磁盘连1MB都没有了,这种情况我们可以直接去clickhouse存储文件的文件夹中直接删除一些文件腾出位置来供我们执行清除语句
ls -la /data/clickhouse/data/system/trace_log/

删除古老文件
cd /data/clickhouse/data/system/trace_log/ &&
sudo rm -rf 202507_*
清理数据
执行以下语句查看“query_log”表分区情况
SELECT partition, count() as parts, sum(rows) as rows, formatReadableSize(sum(bytes)) as size
FROM system.parts
WHERE database = 'system' AND table = 'query_log' AND active
GROUP BY partition
ORDER BY partition;
SELECT
partition,
count() AS parts,
sum(rows) AS rows,
formatReadableSize(sum(bytes)) AS size
FROM system.parts
WHERE (database = 'system') AND (`table` = 'query_log') AND active
GROUP BY partition
ORDER BY partition ASC
可以看到这个表的分区情况如下
接着就是删除数据操作了
这里是临时提升删除表最大限制
ALTER TABLE system.query_log DROP PARTITION '202506'
SETTINGS max_partition_size_to_drop = 200000000000; -- 200GB
防止重蹈覆辙
设置日志过期时间
ALTER TABLE system.query_log
MODIFY TTL event_date + INTERVAL 30 DAY;
查看是否设置成功
SHOW CREATE TABLE system.query_log;
注意观察输出内容的最后几行,出现以下内容说明设置成功
更多推荐
所有评论(0)