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 集群提供了一个永远不会出现“两个主库”的、绝对一致的控制中心

作用:

  1. 领导者选举:所有 Patroni 节点都盯着 etcd 中的同一把“领导者锁”,保证有且仅有一个主库。

  2. 集群状态共识:集群拓扑、各节点健康状态和复制位点等关键信息,都储存在 etcd 中,所有节点看到的视图完全一致。

  3. 动态配置下发:修改 max_connections 等参数,Patroni 会写入 etcd,其他节点 Watch 到变化后自动响应。

HAProxy

HAProxy 在这个集群方案中的核心作用是一个 四层(TCP)负载均衡器,它为客户端提供一个统一的、高可用的入口,并将请求流量分发到后端的多台服务器上

需要注意的是:

  1. HAProxy 本身不是高可用的,如果 HAProxy 挂了,整个入口就没了。所以生产环境通常会部署多个 HAProxy 实例,并在其上层用 Keepalived (VIP) 或云负载均衡器来保证 HAProxy 自身的冗余
  2. 它不做连接池:HAProxy 是逐连接的转发,如果应用频繁短连接,后端 PostgreSQL 压力会很大。这通常通过追加PgBouncer解决,而非在 HAProxy 层面。
  3. 只做路由,不参与决策: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文件

  1. 查看主服务器上cookie的值
cat /var/lib/rabbitmq/.erlang.cookie
  1. 把备服务器和从服务器的cookie的值修改为主服务器上的值
vi /var/lib/rabbitmq/.erlang.cookie
  1. 加入集群
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@master
rabbitmqctl start_app
  1. 开启mqtt服务
systemctl rabbitmq-plugins enable rabbitmq_mqtt
ststemctl rabbitmq-plugins enable rabbitmq_management
  1. 设置磁盘限制避免因磁盘占满导致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
集群问题解决
  1. 只有三台机器组成集群时,当某台机器上的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 ".*"

执行这个命令耗时会比较长,执行完成后结果如下图:
在这里插入图片描述


  1. 集群中某台机器崩溃了再进行手动启动的时候,启动失败,执行以下命令查看报错信息
 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

  1. 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)

  1. 创建配置文件
vi  /etc/patroni/config.yml
  1. 把以下内容复制到文件中
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' # 这里根据机器实际情况设置
  1. 设置文件权限
 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.ymlpatronictl -c /etc/patroni/config.yml edit-config看到的内容是不同的,因为前者查看的是 Patroni 进程本身启动时读取的本地静态配置文件 ;后者查看或修改的是存储在 DCS (Distributed Configuration Store,分布式配置存储) 中的集群动态配置。本地静态配置文件的优先级要比分布式集群中存储的配置文件优先级高 (本地配置>集群配置)

postgresql 集群相关问题解决

  1. 数据同步风暴,现象是,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. 如果是希望一台机器挂掉您一个机器上有完整的数据可以直接顶替它,可以配置为”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>
  1. 如果数据量极大,一台机器存不下,希望 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) 作为“路由代理”。
操作步骤(无需重启,无需删旧表):

  1. 保持现有的本地表不动(ReplicatedMergeTree)。
  2. 在两台机器上分别执行以下 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

这里配置需要注意几点:

  • 日志相关配置

    1. :设置日志级别,在生产环境应该改为:常用 informationerror

    2. /: 普通日志和错误日志的存储路径

    mkdir -p 路径
    sudo chown -R clickhouse:clickhouse 路径
    
    1. :每个日志文件最大大小

    2. :保留最近 多少个文件

  • keeper_server核心配置

    1. <tcp_port>:客户端(如 ClickHouse 服务器)连接 Keeper 的端口

    2. <server_id>:当前节点的唯一 ID,集群中每个 Keeper 实例必须不同

    3. <log_storage_path>:Raft 日志存储位置;如果需要修改需要先创建好文件夹并授权

    mkdir -p 路径
    sudo chown -R clickhouse:clickhouse 路径
    
    1. <snapshot_storage_path>:快照的存储路径;如果需要修改需要先创建好文件夹并授权
    mkdir -p 路径
    sudo chown -R clickhouse:clickhouse 路径
    
    1. 协调参数
    • operation_timeout_ms: 单次操作超时时间(10秒)

    • session_timeout_ms: 客户端会话超时时间(100秒)

    • raft_logs_level: Raft 内部日志级别

    • compress_logs: 是否压缩 Raft 日志(false表示不压缩)

    1. <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;

注意观察输出内容的最后几行,出现以下内容说明设置成功
在这里插入图片描述

更多推荐