FEATURED · 精选文章

TimescaleDB高可用实践:Docker Compose部署PostgreSQL流复制集群

发布时间 / 2026/9/7 18:38:56
来源 / 创域科博编辑部
栏目 / 资讯中心
TimescaleDB高可用实践:Docker Compose部署PostgreSQL流复制集群 之前帮一个监控平台搭时序存储单节点TimescaleDB跑得挺好查询响应都在毫秒级。可当业务提出要加一套只读副本做实时看板、同时防止宿主机宕机导致数据不可用时我就意识到不能再靠单库硬扛了。TimescaleDB虽然强在时序压缩和超表能力但它底子还是PostgreSQL要做副本、做容灾走的还是PostgreSQL流复制Streaming Replication这条路。但很多人对流复制的经验停留在裸机手工部署换到docker-compose之后配置文件、权限、初始化顺序到处是坑一个不小心从库就起不来。这篇文章把我实际跑通的TimescaleDB(PostgreSQL)流复制集群容器化部署方案完整拆一遍从WAL同步原理、主从配置、pg_basebackup初始化到故障切换和踩坑细节都会讲到。适合已经在用TimescaleDB但没有HA经验、或者想用docker-compose快速搭一套本地时序集群的团队参考。方案不追求复杂架构一主一从最常规跑通之后再加只读节点、做读写分离都很容易。1. 时序数据场景下为什么我不建议继续用单机TimescaleDB1.1 单机在监控数据面前的两个真实瓶颈很多团队最开始用TimescaleDB都是看中它的超表Hypertable能力。一张表按时间自动分chunk冷热数据自动管理时序聚合查询比原生PostgreSQL顺手很多。单节点在数据量几千万、上亿的时候依然能跑这也是TimescaleDB的卖点。但单节点的瓶颈不只在数据量而在“可用性”和“业务架构”两个层面。第一宿主机一挂整个监控大盘就没数据了对线上业务来说这是不可接受的第二业务想看板、要做报表、要做一些偏重的分析查询这些查询会和写入抢CPU、抢IO单库扛不住。流复制集群解决不了性能横向扩展的全部问题但能解决“只读流量分离”和“故障时快速切换”这两个最刚需的问题。所以我的建议很清楚TimescaleDB做主写节点一台从库专门扛读查询和看板日常还能拿从库做数据分析这是一套性价比很高的架构。1.2 流复制解决的是可用性问题不是性能扩展这里必须把预期放正。很多文章会把流复制描述成“集群”实际上它本质上是“主库持续把WAL日志送到备库并重放”的数据保护机制。从库不是负载均衡集群里的worker而是一份完整的数据副本。所以它解决的是主库宕机后数据不丢、业务能切到从库继续跑读请求可以从从库走减轻主库压力。如果你的目标是写性能水平扩展那需要的是读写中间件分片或TimescaleDB分布式版而不是流复制。这个边界搞清楚后面遇到问题才不会慌。1.3 为什么复制节点也必须加载TimescaleDB扩展这是大家最容易忽略的点。TimescaleDB不只是几张表它通过shared_preload_libraries在PostgreSQL启动时加载钩子函数在后台维护chunk、压缩、连续聚合等一系列逻辑。从库通过WAL重放拿到的是物理数据块不是逻辑SQL。也就是说从库如果没加载TimescaleDB扩展数据文件虽然都在但查询超表时数据库根本不知道这张表是超表也无法正确路由到对应chunk。我见过有人从库配好后SELECT * FROM sensor_data直接报错或者查不到数据最后发现就是扩展没加载。2. 流复制链路里WAL是怎么从主库“流”到从库的2.1 从walsender到walreceiver的完整链路理解流复制不需要把源码读完但几个关键角色必须知道。主库侧有一个walsender进程负责把WAL数据通过网络传给备库。备库侧有两个关键进程walreceiver负责接收WAL流startup进程负责把收到的WAL重放到数据文件里。整个链路是异步的备库时刻追着主库的WAL末尾跑。PostgreSQL 15之后流复制相关的函数和视图名字有些变化。比如pg_stat_wal_receiver是备库视角查的是接收状态pg_stat_replication是主库视角查的是每个walsender连接的复制状态。部署完成后我习惯在主库和备库各查一次这两个视图能快速判断链路是否正常。2.2 复制槽不是可有可无的复制槽Replication Slot是流复制里的一个关键设计。主库的WAL文件是循环使用的如果备库断了一会儿主库可能已经把备库还没拿走的WAL覆盖了那备库重新连上时就没法继续同步只能重新全量初始化。复制槽会让主库保留从库还没消费的WAL保护备库追上来。代价是如果备库挂了很久没消费主库的WAL会一直累积磁盘会被撑爆。所以复制槽设计是个双刃剑要么做好监控要么用wal_keep_size加物理保留策略配合使用。在pg_basebackup初始化从库时指定一个永久复制槽是最稳妥的这也是我下面脚本里的做法。2.3 同步提交与异步复制的选择流复制默认是异步的主库提交事务后不需要等备库确认性能损耗极小。异步复制的风险是主库宕机瞬间最后少量已提交事务可能还没到备库切换后会有数据丢失。PostgreSQL的同步复制通过synchronous_commit控制备库确认方式可以是remote_write、remote_apply等。同步复制能保证主备数据一致但每次写入都要等网络往返写入性能明显下降。时序场景写入频繁一审量级的数据同步流量非常大我日常部署默认用异步业务方如果明确要求RPO0再单独讨论同步方案。这里给一个经验值单机写入10000条/秒左右的监控数据内网环境下异步流复制的延迟通常在几十毫秒以内肉眼几乎看不出差异。3. 部署前必须定下的版本、目录和网络规划3.1 镜像版本如何锁TimescaleDB tag与PG主版本的绑定关系TimescaleDB镜像的tag很有讲究它是和PostgreSQL主版本绑定的。比如timescale/timescaledb:latest-pg16最后的pg16表示基础镜像的PostgreSQL大版本。你不能只看TimescaleDB版本而忽略PG版本因为两个节点如果PG主版本不一致pg_basebackup拉过来的数据目录根本没法启动。我的建议是开发环境可以用latest-pg16图省事生产环境一定要锁具体版本。比如timescale/timescaledb:2.17.2-pg16这样镜像拉取、重建、回滚都可控。镜像tag一变一旦TimescaleDB做了兼容性调整主从两个节点版本不一致重放WAL时很容易报FATAL: could not start WAL stream。为了统一管理版本我用一个.env文件放在项目根目录POSTGRES_MAJOR16 TIMESCALEDB_TAG2.17.2-pg16 POSTGRES_USERpostgres POSTGRES_PASSWORDpostgres123 REPLICATION_USERreplicator REPLICATION_PASSWORDreplicator123 REPLICATION_SLOTreplica_slot3.2 目录结构与配置挂载方案整个项目目录我习惯这样组织timescaledb-cluster/ ├── .env ├── docker-compose.yml ├── master/ │ ├── postgresql.conf │ ├── pg_hba.conf │ └── init/ │ └── 01-create-replication-user.sql ├── replica/ │ ├── postgresql.conf │ ├── pg_hba.conf │ └── init-replica.sh └── data/ ├── master/ └── replica/主库和从库的配置文件一定要分开不要共用一份。原因有两个第一从库的primary_conninfo、primary_slot_name这些连接主库的参数主库配置里不该有第二主库和从库虽然大部分参数一致但将来你很可能需要给从库调不同的work_mem、max_connections共用一份文件会让两个节点互相污染。数据目录用bind mount挂到宿主机data/下方便排查问题。但要注意权限容器内postgres用户默认uid是999挂载目录后宿主机目录归属如果不是999容器启动时会遇到权限拒绝。一个简单的办法是创建目录后执行mkdir -p data/master data/replica chown -R 999:999 data3.3 自定义网络与固定IPdocker-compose默认会创建一个网络但容器重启后IP可能变化。流复制场景下primary_conninfo里写的主库host建议用服务名timescaledb-masterdocker内部DNS会自动解析IP变不变其实问题不大。但我还是习惯给集群指定一个独立网段和固定IP理由有两点一是pg_hba.conf里如果要按IP限制访问固定IP可以精确控制二是后续如果有其他中间件容器要接入这个集群固定IP比容器名更好排查网络链路。网络规划如下networks: cluster: driver: bridge ipam: config: - subnet: 172.28.0.0/24主库分配172.28.0.10从库分配172.28.0.11端口映射上主库映射宿主机5432从库映射5433这样宿主机上两个库都能访问只读流量走5433写流量走5432。4. 主库配置和初始化复制用户、hba与复制槽4.1 主库postgresql.conf的关键参数主库的postgresql.conf不需要面面俱到但和流复制相关的参数必须正确。下面是完整配置listen_addresses * hba_file /etc/postgresql/pg_hba.conf wal_level replica max_wal_senders 4 max_replication_slots 4 wal_keep_size 512MB shared_preload_libraries timescaledb synchronous_commit off wal_log_hints on逐个说明一下。wal_level replica是流复制的最低要求它保证WAL里包含足够的信息供备库重放。max_wal_senders和max_replication_slots决定了最多能连接几个备库一主一从设4足够如果你以后想加到3个从库也能扛住。wal_keep_size 512MB是PG15之后的参数相当于给主库额外保留512MB的WAL防止备库短暂断开后因为复制槽没建好导致追不上。wal_log_hints on是为将来可能用pg_rewind做时间线回退准备的现在不开启以后想开还需要重启。最后一行shared_preload_libraries timescaledb是整个方案的核心。主库靠它加载TimescaleDB从库的配置文件里也必须有一模一样的配置。4.2 pg_hba.conf里replication条目为什么单独写pg_hba.conf是很多人的盲区。流复制连接走的是replication伪数据库它在pg_hba.conf里不是普通数据库条目必须单独写。我的配置如下local all all trust host all all 0.0.0.0/0 md5 local replication all trust host replication replicator 0.0.0.0/0 md5注意最后一行我限定只有replicator用户允许从任意IP发起复制连接而且只能用md5密码认证。不要用trust去放行replication否则任何能连通5432端口的人都能拖走你全库数据。这里如果配置漏了从库pg_basebackup时会直接报FATAL: no pg_hba.conf entry for replication connection from host。4.3 复制用户与物理复制槽的创建主库第一次启动时官方镜像会执行/docker-entrypoint-initdb.d/目录下的所有.sql和.sh脚本。我利用这个机制创建复制用户-- master/init/01-create-replication-user.sql CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD replicator123;这里给replicator角色加了REPLICATION权限这是它执行pg_basebackup和建立复制流的必要条件。物理复制槽我选择放在从库初始化脚本里动态创建而不是写死在主库的init目录。原因很直接如果从库数据卷被我清掉重新初始化脚本可以在不手动登录主库的情况下自动补建slot省去一次人工操作。主库的init目录只需要保证复制用户存在slot由从库脚本用SQL检查后再创建。5. 从库初始化脚本pg_basebackup拉取与自动拉起5.1 官方entrypoint没法直接干这件事docker官方postgres镜像有一个特点如果容器启动命令不是postgres它不会自动执行initdb。这个特性正好可以被我们用来做自定义从库初始化但也意味着我们需要自己处理数据目录的创建、权限、初始化这三件事。很多人一开始的思路是给从库也挂docker-entrypoint-initdb.d指望镜像帮你把pg_basebackup跑了。这个思路有一个致命问题官方entrypoint在跑initdb.d脚本之前已经执行了initdb数据目录里已经生成了一套完整数据这时候你再pg_basebackup去覆盖它容易留下脏文件而且脚本执行环境也别扭。我的做法更干净从库启动命令直接指向一个自定义脚本数据目录为空时跑pg_basebackup非空时直接正常启动。5.2 init-replica.sh完整脚本拆解先看完整脚本再逐步解释#!/bin/bash set -e MASTER_HOSTtimescaledb-master MASTER_PORT5432 REPLICATION_USER${REPLICATION_USER:-replicator} REPLICATION_PASSWORD${REPLICATION_PASSWORD:-replicator123} REPLICATION_SLOT${REPLICATION_SLOT:-replica_slot} export PGPASSWORD${POSTGRES_PASSWORD} # 1. 等待主库复制用户创建完成 echo [replica] waiting for master replication user... until psql -h $MASTER_HOST -p $MASTER_PORT -U $POSTGRES_USER -d postgres -tAc \ SELECT 1 FROM pg_roles WHERE rolname${REPLICATION_USER} 2/dev/null | grep -q 1; do sleep 2 done echo [replica] creating replication slot if not exists psql -h $MASTER_HOST -p $MASTER_PORT -U $POSTGRES_USER -d postgres -tAc \ SELECT 1 FROM pg_replication_slots WHERE slot_name${REPLICATION_SLOT} | grep -q 1 || \ psql -h $MASTER_HOST -p $MASTER_PORT -U $POSTGRES_USER -d postgres -c \ SELECT pg_create_physical_replication_slot(${REPLICATION_SLOT}); # 2. 准备数据目录 mkdir -p $PGDATA chown postgres:postgres $PGDATA chmod 700 $PGDATA # 3. 写.pgpass供后续流复制连接认证使用 cat /var/lib/postgresql/.pgpass EOF ${MASTER_HOST}:${MASTER_PORT}:replication:${REPLICATION_USER}:${REPLICATION_PASSWORD} EOF chown postgres:postgres /var/lib/postgresql/.pgpass chmod 600 /var/lib/postgresql/.pgpass # 4. 如果数据目录还没有PG_VERSION就全量拉取主库数据 if [ ! -s $PGDATA/PG_VERSION ]; then echo [replica] running pg_basebackup from master... export PGPASSWORD${REPLICATION_PASSWORD} gosu postgres pg_basebackup -h $MASTER_HOST -p $MASTER_PORT -U $REPLICATION_USER \ -D $PGDATA -R -X stream -S $REPLICATION_SLOT -P -v rm -f $PGDATA/postmaster.pid echo [replica] basebackup done else echo [replica] data directory already exists, skip basebackup fi # 5. 进入正常启动流程 exec docker-entrypoint.sh postgres -c config_file/etc/postgresql/postgresql.conf几个关键点展开说。等待循环为什么不用pg_isready而用psql查角色表因为pg_isready只能判断端口通没通而主库容器首次启动时会先跑一个临时postgres执行initdb.d脚本这时候端口已经通了但复制用户还没创建完。如果从库在这个时候发起pg_basebackup会因角色不存在失败。所以必须等到pg_roles里能查到replicator。.pgpass是libpq的密码文件。pg_basebackup用-R参数生成postgresql.auto.conf时不会把密码明文写进去而是记录passfile/var/lib/postgresql/.pgpass。如果不提前创建这个文件从库容器重启后流复制连接会因为拿不到密码而反复失败主库pg_stat_replication里能看到state一直是startup。很多从库“莫名其妙连不上”的问题根子都在这里。-X stream表示WAL通过复制流直接传输-S指定复制槽-R会生成从库所需的postgresql.auto.conf里面自动写好primary_conninfo和primary_slot_name。整个脚本是幂等的。数据目录已经有PG_VERSION时它跳过basebackup直接启动postgres所以从库容器重启不会重复初始化。5.3 postgresql.auto.conf里的连接信息与同步参数pg_basebackup执行完后从库数据目录下会生成一个postgresql.auto.conf内容类似primary_conninfo userreplicator passfile/var/lib/postgresql/.pgpass channel_bindingprefer hosttimescaledb-master port5432 sslmodeprefer sslcompression0 sslcertmodeallow sslsni1 ssl_min_protocol_versionTLSv1.2 gssencmodeprefer krbsrvnamepostgres target_session_attrsany primary_slot_name replica_slot这里要提醒一句primary_conninfo不要手工写进从库的postgresql.conf因为postgresql.auto.conf的优先级更高你写半天最后会被auto.conf覆盖容易产生“我明明改了为什么没生效”的困惑。连接信息全权交给-R生成的auto.conf即可。如果你要启用同步复制需要确保primary_conninfo里有application_name并且和主库配置的synchronous_standby_names对应。auto.conf默认不带application_name你可以在pg_basebackup完成后追加一行覆盖或者在从库启动前改掉auto.conf里的内容。6. docker-compose.yml完整编排与健康检查设计6.1 两个service的配置要点docker-compose.yml是全流程的枢纽完整内容如下version: 3.9 services: master: image: timescale/timescaledb:${TIMESCALEDB_TAG} container_name: timescaledb-master environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} PGDATA: /var/lib/postgresql/data volumes: - ./data/master:/var/lib/postgresql/data - ./master/postgresql.conf:/etc/postgresql/postgresql.conf:ro - ./master/pg_hba.conf:/etc/postgresql/pg_hba.conf:ro - ./master/init:/docker-entrypoint-initdb.d:ro command: [postgres, -c, config_file/etc/postgresql/postgresql.conf] healthcheck: test: [CMD-SHELL, pg_isready -U ${POSTGRES_USER} -d postgres] interval: 5s timeout: 3s retries: 20 start_period: 10s networks: cluster: ipv4_address: 172.28.0.10 ports: - 5432:5432 replica: image: timescale/timescaledb:${TIMESCALEDB_TAG} container_name: timescaledb-replica environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} REPLICATION_USER: ${REPLICATION_USER} REPLICATION_PASSWORD: ${REPLICATION_PASSWORD} REPLICATION_SLOT: ${REPLICATION_SLOT} PGDATA: /var/lib/postgresql/data volumes: - ./data/replica:/var/lib/postgresql/data - ./replica/postgresql.conf:/etc/postgresql/postgresql.conf:ro - ./replica/pg_hba.conf:/etc/postgresql/pg_hba.conf:ro - ./replica/init-replica.sh:/init-replica.sh:ro command: [bash, /init-replica.sh] depends_on: master: condition: service_healthy networks: cluster: ipv4_address: 172.28.0.11 ports: - 5433:5432 healthcheck: test: [CMD-SHELL, pg_isready -U ${POSTGRES_USER} -d postgres] interval: 5s timeout: 3s retries: 20 start_period: 20s networks: cluster: driver: bridge ipam: config: - subnet: 172.28.0.0/24主库的command用-c config_file/etc/postgresql/postgresql.conf指定我们挂载的配置文件避免用到数据目录里的默认配置。从库因为要跑自定义初始化脚本command直接指向bash /init-replica.sh。脚本最后会调用docker-entrypoint.sh postgres -c config_file...进入正常启动流程。6.2 depends_on为什么不够healthcheck才是关键docker-compose里depends_on默认只控制容器启动顺序不等应用就绪。也就是说从库容器启动时主库可能还在跑initdb复制用户都还没创建。depends_on加condition: service_healthy之后compose会等主库healthcheck通过才启动从库。主库的healthcheck用了pg_isready这是在dokcer层面做的一次“端口可用性”检查。但如前面说的主库临时postgres阶段端口也是通的所以从库脚本内部还做了一层角色等待。这两层配合才能保证从库初始化时主库真正可服务。6.3 启动顺序与幂等性设计整个编排有一个隐藏优点从库脚本天然幂等。docker compose down之后再up从库数据目录已经有了PG_VERSION脚本会跳过pg_basebackup直接启动从库复制链路自动恢复。真正需要警惕的是如果你手动清掉了从库数据目录脚本会重新全量拉数据。拉数据期间主库的WAL必须保留足够多否则pg_basebackup会报requested WAL segment has already been removed。复制槽就是用来解决这个问题的所以脚本里先确保slot存在再执行basebackup是有讲究的。7. 部署后的验证复制状态、超表查询与延迟观测7.1 复制状态SQL判读部署完成后第一步不是急着造数据而是确认复制链路状态。在主库执行SELECT pid, application_name, state, sync_state, replay_lag FROM pg_stat_replication;能看到一行记录state为streamingsync_state为async因为我们没开同步复制说明从库已经追着主库走了。如果state一直是startup或catchup说明从库还在初始化或追赶中。从库上执行SELECT pg_is_in_recovery();返回t说明当前是备库处于只读热备状态。再查SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();两个值应该非常接近甚至完全相等。receive_lsn是从库已经接收到的WAL位置replay_lsn是已经重放的位置如果差距持续增大说明从库重放速度跟不上写入速度。7.2 在主库建超表并写入从库同步查询验证复制链路只是第一步还要验证TimescaleDB扩展在主从两个节点都正常工作。在主库执行CREATE TABLE sensor_data ( time TIMESTAMPTZ NOT NULL, device_id INTEGER, temperature DOUBLE PRECISION ); SELECT create_hypertable(sensor_data, time);然后写入一批测试数据INSERT INTO sensor_data SELECT now() - (i || minutes)::interval, i % 10, random() * 30 15 FROM generate_series(1, 10000) i;到从库上执行SELECT time_bucket(1 minute, time) AS bucket, avg(temperature) FROM sensor_data GROUP BY bucket ORDER BY bucket LIMIT 10;能正常返回结果且数据量和主库一致说明从库已经成功加载TimescaleDB扩展WAL重放也正常。如果从库没加载扩展这一步大概率会报错或者只能查到部分数据这时回到配置文件检查shared_preload_libraries。7.3 replay_lag观测与从库只读约束从库毕竟是只读节点如果业务误把写请求发到5433端口会收到明确的报错ERROR: cannot execute INSERT in a read-only transaction这是预期行为不用慌。但如果你的应用需要从库提供强一致的读要注意从库默认存在复制延迟。时序场景一般几毫秒到几十毫秒可接受。如果延迟突然飙升优先看主库的WAL生成量和从库的磁盘IO大概率是从库重放瓶颈。8. 故障切换实验与把原主库拉回新从库8.1 手动提升从库的操作与验证流复制本身没有自动故障转移能力这一点必须提前跟团队讲清楚。但人工切换很简单模拟主库宕机docker stop timescaledb-master然后进入从库容器提升它docker exec -it timescaledb-replica psql -U postgres -c SELECT pg_promote();再验证SELECT pg_is_in_recovery();返回f从库已经变成新的主库可以正常接收写入了。此时应用连接需要切到5433端口也就是从库映射出来的端口。如果有负载均衡器把后端摘掉故障主库即可。8.2 原主库恢复为从库的完整步骤原主库因为之前是主库数据已经和新的主库分叉了直接启动继续跑流复制是行不通的。恢复思路只有一个把它当作一个全新的从库重新初始化。具体操作是清空原主库数据目录让init-replica.sh逻辑重新在新主库上做一次pg_basebackup。这里有个细节原主库容器还挂着master/init目录第一次启动时会重复执行01-create-replication-user.sql这会导致创建角色报错“already exists”。我在实际恢复时会把master目录临时改一个名字或者把它从docker-compose的正常启动流程里摘出来用一个一次性的初始化容器执行从库脚本再改回配置正常启动。如果你不想动目录结构也可以用另一个更简单的思路保留init-replica.sh脚本修改MASTER_HOST为新主库然后把原主库的volumes临时改成从库数据卷让它按从库方式初始化一次再改回来。总之核心是“全量重建”不要指望原主库能原地复活成从库。8.3 自动故障切换的边界如果业务要求“主库挂了自动切换应用无感知”那需要引入Patroni、repmgr或pg_auto_failover这类外部工具。TimescaleDB和PostgreSQL在这件事上一样流复制只负责数据同步不负责选主、不负责VIP漂移、不负责应用端连接切换。docker-compose方案最适合的场景是开发环境、预发环境、或者人力可以7x24响应的小规模生产环境。真要做自动HA建议在流复制基础上叠加Patroni那是另一个更复杂的架构话题本篇不再展开。9. 实际运维中容易翻车的四个细节9.1 复制槽残留导致主库WAL膨胀这是流复制集群最高频的故障。从库如果被删除或者长时间离线主库上的物理复制槽还挂着WAL就一直累积不清理最后磁盘写满主库直接宕机。对策是定期监控SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag_bytes FROM pg_replication_slots;如果发现某个slot已经不active了确认对应从库不会回来后第一时间手动删除SELECT pg_drop_replication_slot(replica_slot);这个操作要谨慎删早了从库会失去WAL保护。我的习惯是先看从库的pg_stat_wal_receiver状态确定它真的失联了再删。9.2 同步复制的APPLICATION_NAME必须匹配如果你启用了同步复制主库参数变成synchronous_standby_names replica1 synchronous_commit remote_apply那从库的primary_conninfo里必须带application_namereplica1。如果名字对不上主库没有可用的同步备库事务提交会一直等待你看到的现象就是“写入hang住”但日志里没有任何明显报错。排查这类问题看pg_stat_replication里的application_name和synchronous_standby_names是否匹配就行。9.3 脚本CRLF和权限问题从库初始化脚本是在宿主机上编辑再挂载进Linux容器的。如果你在Windows上编辑过脚本会带CRLF换行容器里执行会报/bin/bash^M: bad interpreter。解决方式很简单sed -i s/\r$// replica/init-replica.sh另外脚本挂载进容器后需要可执行权限在宿主机上执行chmod x replica/init-replica.sh即使compose里的command是bash /init-replica.sh没有执行权限也能跑但如果有人在容器里想直接执行脚本就会卡住。权限问题不是大坑但很烦人。9.4 流复制副本不等于备份最后说一个很多人容易混淆的概念从库是实时副本但它不是备份。如果主库上有人执行了误删除操作这个删除会瞬间同步到从库两份数据一起丢。流复制解决的是硬件故障不是逻辑错误。我现在的习惯是在流复制集群之外再定期用pg_dump做逻辑备份或者引入pgBackRest做物理备份。docker-compose方案里可以加一个定时任务容器每天凌晨从从库那边做全量备份既不影响主库业务又能在逻辑误删时派上用场。我自己在实际操作中还有一个小偏好所有配置文件尽量用LF换行、尽量用latest-pg16跑通后再锁版本。这套集群我已经在不同环境重复部署过多次每次踩坑基本都集中在复制槽残留、.pgpass文件和healthcheck等待这三个点上。如果按照上面的步骤从零走一遍大概率能一次跑通。后续如果你想在这个基础上加只读节点把replica服务复制一份改容器名、IP、端口和slot名就行原理完全一样。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻