这是本节的多页打印视图。
点击此处打印 .
返回本页常规视图 .
ETCD
分布式元数据存储
ETCD 是一个分布式、可靠的键值存储,用于分布式系统的最关键数据。
etcd 被用作 patroni 的 DCS (分布式配置存储),为 PostgreSQL 高可用代理提供配置管理和领导者选举功能。
简而言之,PGSQL 依赖于全局的 ETCD 模块,而 ETCD 依赖于 NODE 模块才能正常工作(使用节点 CA)。
剧本
可在 etcd 模块中使用的 Ansible 剧本
1 - 配置
描述您想要的集群
在部署之前,您必须在配置清单 中定义 etcd 集群。
通常您可以选择一个 etcd 集群:
单节点 ,无高可用性,仅具有 etcd 功能,适用于开发、测试和演示目的。
三节点 ,基本高可用性,容忍一个节点故障,适用于中等生产环境。
五节点 ,更好的高可用性,容忍两个节点故障,适用于大型生产环境。
使用偶数个 etcd 节点是没有意义的,超过五个节点也不常见。
单节点
在清单中定义组 etcd,它将创建一个单例 etcd 实例。
# etcd cluster for ha postgres
etcd : { hosts : { 10.10.10.10 : { etcd_seq : 1 } }, vars : { etcd_cluster : etcd } }
这一行几乎存在于所有单节点配置模板 中,其中占位符 IP 地址 10.10.10.10 将被替换为当前管理节点 IP。
唯一必要的参数是 etcd_seq 和 etcd_cluster ,它们唯一地标识集群和每个实例。
三节点
三节点 etcd 集群非常常见,容忍一个节点故障,适用于大多数情况。
trio 和 safe 配置模板使用三节点 etcd 集群,如下所示:
etcd : # dcs service for postgres/patroni ha consensus
hosts : # 1 node for testing, 3 or 5 for production
10.10.10.10 : { etcd_seq : 1 } # etcd_seq required
10.10.10.11 : { etcd_seq : 2 } # assign from 1 ~ n
10.10.10.12 : { etcd_seq : 3 } # use odd numbers
vars : # cluster level parameter override roles/etcd
etcd_cluster : etcd # mark etcd cluster name etcd
etcd_safeguard : false # safeguard against purging
五节点
五节点 etcd 集群可以容忍两个节点故障,适用于大型生产环境。
在 prod 模板中有一个五节点 etcd 集群示例:
etcd :
hosts :
10.10.10.21 : { etcd_seq : 1 }
10.10.10.22 : { etcd_seq : 2 }
10.10.10.23 : { etcd_seq : 3 }
10.10.10.24 : { etcd_seq : 4 }
10.10.10.25 : { etcd_seq : 5 }
vars : { etcd_cluster : etcd }
您可以使用更多节点,但建议使用 3 或 5 个节点。
Etcd 使用
这些是当前使用 Etcd 的服务:
patroni:使用 etcd 作为 PostgreSQL HA 的共识后端
vip-manager:从 Etcd 读取领导者信息,在 PostgreSQL 集群上绑定可选的 L2 VIP
在对 etcd 集群成员进行任何永久更改后,您必须重新加载 etcd 配置。
例如,更新 patroni 对 etcd 端点的引用:
./pgsql.yml -t pg_conf # re-gen patroni config
./pgsql.yml -t patroni_reload -e patroni_reload = true # reload patroni config
例如,更新 vip-manager 对 etcd 端点的引用(如果您使用 PGSQL L2 VIP):
./pgsql.yml -t pg_vip # reload vip-manager config
2 - 参数
使用 12 个参数自定义 etcd
ETCD 模块共有 12 个参数。
ETCD: 9 个参数:
ETCD_REMOVE: 3 个 参数:
默认值
默认参数在 roles/etcd/defaults/main.yml 中定义
额外的移除参数在 roles/etcd_remove/defaults/main.yml 中定义
#-----------------------------------------------------------------
# ETCD
#-----------------------------------------------------------------
#etcd_seq: 1 # etcd instance identifier, explicitly required
etcd_cluster : etcd # etcd cluster & group name, etcd by default
etcd_data : /data/etcd # etcd data directory, /data/etcd by default
etcd_learner : false # etcd instance run as learner? false by default
etcd_port : 2379 # etcd client port, 2379 by default
etcd_peer_port : 2380 # etcd peer port, 2380 by default
etcd_init : new # etcd initial cluster state, new or existing
etcd_election_timeout : 1000 # etcd election timeout, 1000ms by default
etcd_heartbeat_interval : 100 # etcd heartbeat interval, 100ms by default
ETCD_REMOVE 参数
#-----------------------------------------------------------------
# ETCD_REMOVE
#-----------------------------------------------------------------
etcd_safeguard : false # prevent accidental removal?
etcd_rm_data : true # remove etcd data during removal?
etcd_rm_pkg : false # uninstall etcd packages during removal?
etcd_seq
名称:etcd_seq,类型:int,级别:I
etcd 实例标识符,必需
没有默认值,您必须明确指定它。这里是一个 3 节点 etcd 集群示例:
etcd : # dcs service for postgres/patroni ha consensus
hosts : # 1 node for testing, 3 or 5 for production
10.10.10.10 : { etcd_seq : 1 } # etcd_seq required
10.10.10.11 : { etcd_seq : 2 } # assign from 1 ~ n
10.10.10.12 : { etcd_seq : 3 } # use odd numbers
vars : # cluster level parameter override roles/etcd
etcd_cluster : etcd # mark etcd cluster name etcd
etcd_safeguard : false # safeguard against purging
etcd_cluster
名称:etcd_cluster,类型:string,级别:C
etcd 集群和组名,默认为 etcd
默认值:etcd,这是一个固定的组名,当您想要部署一些额外的 etcd 集群时很有用
etcd_learner
名称:etcd_learner,类型:bool,级别:I
将 etcd 实例初始化为学习者?默认值为 false
当设置为 true 时,etcd 实例将被初始化为学习者,因此它无法在 etcd 集群中投票。
您可以稍后使用 etcdctl member promote 命令将其提升为完整成员。
etcd_data
名称:etcd_data,类型:path,级别:C
etcd 数据目录,默认为 /data/etcd
etcd_port
名称:etcd_port,类型:port,级别:C
etcd 客户端端口,默认为 2379
etcd_peer_port
名称:etcd_peer_port,类型:port,级别:C
etcd 对等端口,默认为 2380
etcd_init
名称:etcd_init,类型:enum,级别:C
etcd 初始集群状态,new 或 existing
默认值:new,将创建一个独立的新 etcd 集群。
值 existing 在尝试向现有 etcd 集群追加新成员 时使用。
etcd_election_timeout
名称:etcd_election_timeout,类型:int,级别:C
etcd 选举超时,默认为 1000(毫秒)
etcd_heartbeat_interval
名称:etcd_heartbeat_interval,类型:int,级别:C
etcd 心跳间隔,默认为 100(毫秒)
ETCD_REMOVE
这一节包含 etcd_remove 角色中定义的参数,
一些供 etcd-rm.yml 剧本使用的行为控制标记。
etcd_safeguard
名称:etcd_safeguard,类型:bool,级别:G/C/A
防止清除 etcd 实例?默认值为 false
如果启用,运行中的 etcd 实例将不会被 etcd-rm.yml playbook 清除。
etcd_rm_data
名称:etcd_rm_data,类型:bool,级别:G/C/A
移除期间删除 etcd 数据?默认值为 true
启用时,etcd-rm.yml playbook 将在集群或成员移除期间删除 etcd 数据目录和配置文件。
etcd_rm_pkg
名称:etcd_rm_pkg,类型:bool,级别:G/C/A
移除期间卸载 etcd 包?默认值为 false
启用时,etcd-rm.yml playbook 将在集群或成员移除期间卸载 etcd 包。
3 - 管理预案
etcd 集群管理 SOP:创建、销毁、扩缩容与更新配置。
以下是一些常见的 etcd 管理任务 SOP(预案):
创建集群 :如何初始化 etcd 集群?
销毁集群 :如何销毁 etcd 集群?
环境变量 :如何配置 etcd 客户端,以访问 etcd 服务器集群?
重载配置 :如何更新客户端使用的 etcd 服务器成员列表?
添加成员 :如何向现有 etcd 集群添加新成员?
移除成员 :如何从 etcd 集群移除老成员?
便捷脚本 :使用 bin/etcd-add 和 bin/etcd-rm 简化操作
更多问题请参考 FAQ:ETCD 。
创建集群
要创建一个集群,首先需要在 配置清单 中定义 etcd 集群:
etcd :
hosts :
10.10.10.10 : { etcd_seq : 1 }
10.10.10.11 : { etcd_seq : 2 }
10.10.10.12 : { etcd_seq : 3 }
vars : { etcd_cluster : etcd }
执行 etcd.yml 剧本即可。
架构变化:Pigsty v3.6+
自 Pigsty v3.6 起,etcd.yml 剧本专注于集群安装和成员添加,不再包含移除功能。所有移除操作请使用独立的 etcd-rm.yml 剧本。
对于已初始化的生产环境 etcd 集群,可以打开防误删保护 etcd_safeguard ,避免误删现有的 etcd 实例。
销毁集群
要销毁一个 etcd 集群,请使用独立的 etcd-rm.yml 剧本。执行此命令前请务必三思!
./etcd-rm.yml # 移除整个 etcd 集群
./etcd-rm.yml -e etcd_safeguard = false # 强制覆盖防误删保险
或使用便捷脚本:
bin/etcd-rm # 移除整个 etcd 集群
移除剧本会尊重 etcd_safeguard 防误删保险的配置。如果该参数设置为 true,剧本将中止执行以防止误删。
注意
在移除 etcd 集群之前,请确保没有 PostgreSQL 集群正在使用该 etcd 作为 DCS 服务。否则会导致 PostgreSQL 高可用功能失效。
环境变量
Pigsty 默认使用 etcd v3 API(v3.6+ 已移除 v2 API 支持)。Pigsty 会在 etcd 节点上自动配置环境变量脚本 /etc/profile.d/etcdctl.sh,登录后会自动加载。
以下是 etcd 客户端配置环境变量的示例:
alias e = "etcdctl"
alias em = "etcdctl member"
export ETCDCTL_ENDPOINTS = https://10.10.10.10:2379
export ETCDCTL_CACERT = /etc/etcd/ca.crt
export ETCDCTL_CERT = /etc/etcd/server.crt
export ETCDCTL_KEY = /etc/etcd/server.key
export ETCDCTL_USER = "root: $( cat /etc/etcd/etcd.pass) "
配置好客户端环境变量后,你可以使用以下命令进行 etcd CRUD 操作:
e put a 10 ; e get a; e del a # 基本 KV 操作
e member list # 列出集群成员
e endpoint health # 检查端点健康状态
e endpoint status # 查看端点状态
Pigsty v4.0 默认启用 etcd 的 RBAC(基于角色的访问控制)认证机制。在集群初始化时,etcd_auth 任务会自动创建 root 用户并启用认证。
root 用户密码 由 etcd_root_password 参数指定,默认值为 Etcd.Root。密码存储在 /etc/etcd/etcd.pass 文件中,权限为 0640(root 所有,etcd 组可读)。
在生产环境中,强烈建议修改默认密码 :
etcd :
hosts :
10.10.10.10 : { etcd_seq : 1 }
10.10.10.11 : { etcd_seq : 2 }
10.10.10.12 : { etcd_seq : 3 }
vars :
etcd_cluster : etcd
etcd_root_password : 'YourSecurePassword' # 修改默认密码
客户端认证方式 :
# 方式一:使用环境变量(推荐,已自动配置在 /etc/profile.d/etcdctl.sh)
export ETCDCTL_USER = "root: $( cat /etc/etcd/etcd.pass) "
# 方式二:在命令行中指定
etcdctl --user root:YourSecurePassword member list
Patroni 与 etcd 认证 :
PostgreSQL 高可用组件 Patroni 通过 pg_etcd_password 参数配置连接 etcd 的密码。如果该参数为空,Patroni 会使用集群名称作为密码(不推荐)。建议在生产环境中为每个 PG 集群配置独立的 etcd 密码。
重载配置
如果 etcd 集群的成员发生变化(添加或移除成员),我们需要刷新对 etcd 服务端点的引用。目前 Pigsty 中有以下几处 etcd 引用需要更新:
刷新 etcd 成员配置文件 :
./etcd.yml -t etcd_conf # 刷新 /etc/etcd/etcd.conf
ansible etcd -f 1 -b -a 'systemctl restart etcd' # 可选:逐一重启 etcd 实例
刷新 etcdctl 客户端环境变量 :
./etcd.yml -t etcd_config # 刷新 /etc/profile.d/etcdctl.sh
更新 Patroni DCS 端点配置 :
./pgsql.yml -t pg_conf # 重新生成 patroni 配置
ansible all -f 1 -b -a 'systemctl reload patroni' # 重新加载 patroni 配置
更新 VIP-Manager 端点配置 (仅当使用 PGSQL L2 VIP 时需要):
./pgsql.yml -t pg_vip_config # 重新生成 vip-manager 配置
ansible all -f 1 -b -a 'systemctl restart vip-manager' # 重启 vip-manager
提示
使用 bin/etcd-add 和 bin/etcd-rm 便捷脚本时,脚本会在操作完成后提示您需要执行的配置刷新命令。
添加成员
ETCD 参考: 添加成员
推荐方式:使用便捷脚本
使用 bin/etcd-add 脚本是向现有 etcd 集群添加新成员的推荐方式 :
# 首先在配置清单中添加新成员定义,然后执行:
bin/etcd-add <ip> # 添加单个新成员
bin/etcd-add <ip1> <ip2> ... # 添加多个新成员
脚本会自动完成以下操作:
验证 IP 地址有效性
执行 etcd.yml 剧本(自动设置 etcd_init=existing)
提供安全警告和倒计时
操作完成后提示配置刷新命令
手动方式:分步操作
向现有的 etcd 集群添加新成员需要以下步骤:
更新配置清单 :将新实例添加到 etcd 组
通知集群 :执行 etcdctl member add 命令(可选,剧本会自动执行)
初始化新成员 :使用 etcd_init=existing 参数运行剧本
提升成员 :将学习者提升为正式成员(可选,使用 etcd_learner=true 时需要)
重载配置 :更新所有客户端的 etcd 端点引用
# 配置清单更新后,初始化新成员
./etcd.yml -l <new_ins_ip> -e etcd_init = existing
# 如果使用 learner 模式,需要手动提升
etcdctl member promote <new_ins_server_id>
重要
添加新成员时必须使用 etcd_init=existing 参数,否则新实例会尝试创建新集群而非加入现有集群。
详细步骤:向etcd集群添加成员
下面是具体操作的详细细节,让我们从一个单实例 etcd 集群开始:
etcd :
hosts :
10.10.10.10 : { etcd_seq : 1 } # <--- 集群中原本存在的唯一实例
10.10.10.11 : { etcd_seq : 2 } # <--- 将此新成员定义添加到清单中
vars : { etcd_cluster : etcd }
使用便捷脚本添加新成员(推荐):
$ bin/etcd-add 10.10.10.11
或者手动操作。首先使用 etcdctl member add 向现有 etcd 集群宣告新的学习者实例 etcd-2 即将到来:
$ etcdctl member add etcd-2 --learner= true --peer-urls= https://10.10.10.11:2380
Member 33631ba6ced84cf8 added to cluster 6646fbcf5debc68f
ETCD_NAME = "etcd-2"
ETCD_INITIAL_CLUSTER = "etcd-2=https://10.10.10.11:2380,etcd-1=https://10.10.10.10:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS = "https://10.10.10.11:2380"
ETCD_INITIAL_CLUSTER_STATE = "existing"
使用 etcdctl member list(或 em list)检查成员列表,我们可以看到一个 unstarted 新成员:
33631ba6ced84cf8, unstarted, , https://10.10.10.11:2380, , true # 这里有一个未启动的新成员
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false
接下来使用 etcd.yml 剧本初始化新的 etcd 实例 etcd-2,完成后,我们可以看到新成员已经启动:
$ ./etcd.yml -l 10.10.10.11 -e etcd_init = existing # 一定要添加 existing 参数
...
33631ba6ced84cf8, started, etcd-2, https://10.10.10.11:2380, https://10.10.10.11:2379, true
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false
新成员初始化完成并稳定运行后,可以将新成员从学习者提升为追随者:
$ etcdctl member promote 33631ba6ced84cf8 # 将学习者提升为追随者
Member 33631ba6ced84cf8 promoted in cluster 6646fbcf5debc68f
$ em list # 再次检查,新成员已提升为正式成员
33631ba6ced84cf8, started, etcd-2, https://10.10.10.11:2380, https://10.10.10.11:2379, false
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false
新成员添加完成,请不要忘记 重载配置 ,让所有客户端也知道新成员的存在。
重复以上步骤,可以添加更多成员。记住,生产环境中至少要使用 3 个成员。
移除成员
推荐方式:使用便捷脚本
使用 bin/etcd-rm 脚本是从 etcd 集群移除成员的推荐方式 :
bin/etcd-rm <ip> # 移除指定成员
bin/etcd-rm <ip1> <ip2> ... # 移除多个成员
bin/etcd-rm # 移除整个 etcd 集群
脚本会自动完成以下操作:
从集群中优雅地移除成员
停止并禁用 etcd 服务
清理数据和配置文件
从监控系统中注销
手动方式:分步操作
要从 etcd 集群中删除一个成员实例,通常需要以下步骤:
从配置清单中移除 :注释或删除该实例,并 重载配置
从集群中踢除 :使用 etcdctl member remove 命令
清理实例 :使用 etcd-rm.yml 剧本清理实例
# 使用专用移除剧本(推荐)
./etcd-rm.yml -l <ip>
# 或者手动操作
etcdctl member remove <server_id> # 从集群中踢除
./etcd-rm.yml -l <ip> # 清理实例
详细步骤:从etcd集群移除成员
让我们以一个 3 节点的 etcd 集群为例,从中移除 3 号实例。
方法一:使用便捷脚本(推荐)
$ bin/etcd-rm 10.10.10.12
脚本会自动完成所有操作,包括从集群中移除成员、停止服务、清理数据。
方法二:手动操作
首先,为了刷新配置,您需要 注释 待删除的成员,然后 重载配置 ,让所有客户端都不要再使用此实例。
etcd :
hosts :
10.10.10.10 : { etcd_seq : 1 }
10.10.10.11 : { etcd_seq : 2 }
# 10.10.10.12: { etcd_seq: 3 } # <---- 注释掉这个成员
vars : { etcd_cluster : etcd }
然后,使用移除剧本:
$ ./etcd-rm.yml -l 10.10.10.12
剧本会自动执行以下操作:
获取成员列表并找到对应的成员 ID
执行 etcdctl member remove 从集群中踢除
停止 etcd 服务
清理数据和配置文件
如果需要手动操作,可以这样做:
$ etcdctl member list
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false
33631ba6ced84cf8, started, etcd-2, https://10.10.10.11:2380, https://10.10.10.11:2379, false
93fcf23b220473fb, started, etcd-3, https://10.10.10.12:2380, https://10.10.10.12:2379, false # <--- 移除这个
$ etcdctl member remove 93fcf23b220473fb # 从集群中踢除
Member 93fcf23b220473fb removed from cluster 6646fbcf5debc68f
执行完毕后,您可以将其从配置清单中永久删除,移除成员至此完成。
重复以上步骤,可以移除更多成员,与添加成员 配合使用,可以对 etcd 集群进行滚动升级搬迁。
便捷脚本
Pigsty v3.6+ 提供了便捷脚本简化 etcd 集群的扩容和缩容操作:
bin/etcd-add
向现有 etcd 集群添加新成员:
bin/etcd-add <ip> # 添加单个新成员
bin/etcd-add <ip1> <ip2> ... # 添加多个新成员
脚本功能:
验证 IP 地址是否在配置清单中定义
自动设置 etcd_init=existing 参数
执行 etcd.yml 剧本完成成员添加
操作完成后提示配置刷新命令
bin/etcd-rm
从 etcd 集群移除成员或整个集群:
bin/etcd-rm <ip> # 移除指定成员
bin/etcd-rm <ip1> <ip2> ... # 移除多个成员
bin/etcd-rm # 移除整个 etcd 集群
脚本功能:
提供安全警告和确认倒计时
自动执行 etcd-rm.yml 剧本
优雅地从集群中移除成员
清理数据和配置文件
4 - 剧本
使用剧本创建,销毁,扩容,缩容 Etcd 集群
有一个内置的 playbook:etcd.yml 用于 etcd 集群安装。
etcd.yml
要创建新的 etcd 集群 ,运行以下 playbook:
./etcd.yml # 在组 'etcd' 上安装 etcd 集群
bin/etcd-add # 创建整个 etcd 集群
以下是可用的子任务:
etcd_assert:生成 etcd 身份
etcd_install:安装 etcd rpm 包
etcd_dir:创建 etcd 数据和配置目录
etcd_config:生成 etcd 配置
etcd_conf:生成 etcd 主配置
etcd_cert:生成 etcd ssl 证书
etcd_launch:启动 etcd 服务
etcd_register:向 prometheus 注册 etcd
如果您想向现有 etcd 集群追加新成员 ,
您必须将其添加到配置清单 中,并使用 etcd_init = existing
对新成员运行 playbook:
./etcd.yml -l <new_instance> -e etcd_init = existing
bin/etcd-add <ip> # 向现有 etcd 集群追加新成员
通常重新运行 playbook 是可以的,它会更新 etcd 集群配置并重启 etcd 实例。
Pigsty v3.6+ 的变化
从 Pigsty v3.6+ 开始,etcd.yml playbook 不再具有集群移除功能。请使用专用的 etcd-rm.yml playbook 和 etcd_remove 角色进行 etcd 集群移除操作。
etcd-rm.yml
要移除 etcd 集群 ,运行以下 playbook:
./etcd-rm.yml # 移除 etcd 集群
以下是可用的子任务:
etcd_safeguard:检查安全防护并在启用时中止
prometheus:从 prometheus 移除 etcd 目标注册
etcd_leave:在清除前尝试优雅地离开 etcd 集群
etcd_stop:使用 systemd 停止并禁用 etcd 服务
etcd_data:移除 etcd 数据(使用 etcd_rm_data=false 禁用)
etcd_pkg:卸载 etcd 包(使用 etcd_rm_pkg=true 启用)
要从现有 etcd 集群中移除成员 ,您可以运行 playbook
bin/etcd-rm <ip1> <ip2> ... # 从 etcd 集群移除特定成员
bin/etcd-rm # 移除整个 etcd 集群
移除 playbook 使用新的 etcd_remove 角色,具有可配置参数:
5 - 监控
etcd 模块的仪表板和告警规则
仪表板
ETCD 模块提供一个监控仪表板:Etcd Overview。
ETCD Overview :ETCD 集群概览
该仪表板提供有关 ETCD 状态的关键信息,其中最值得注意的是 ETCD Aliveness,它显示 ETCD 集群的整体服务状态。
红色条带表示实例不可用的时期,而下方的蓝灰色条带显示整个集群不可用的时期。
告警规则
Pigsty 为 INFRA 模块提供以下两个告警规则:
您可以在 files/prometheus/rules/etcd.yml 中修改或添加新的 etcd 告警规则。
#==============================================================#
# Aliveness #
#==============================================================#
# etcd server instance down
- alert : EtcdServerDown
expr : etcd_up < 1
for : 1m
labels : { level : 0, severity : CRIT, category : etcd }
annotations :
summary : "CRIT EtcdServerDown {{ $labels.ins }}@{{ $labels.instance }}"
description : |
etcd_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
http://g.pigsty/d/etcd-overview
#==============================================================#
# Error #
#==============================================================#
# Etcd no Leader triggers a P0 alert immediately
# if dcs_failsafe mode is not enabled, this may lead to global outage
- alert : EtcdNoLeader
expr : min(etcd_server_has_leader) by (cls) < 1
for : 15s
labels : { level : 0, severity : CRIT, category : etcd }
annotations :
summary : "CRIT EtcdNoLeader: {{ $labels.cls }} {{ $value }}"
description : |
etcd_server_has_leader[cls={{ $labels.cls }}] = {{ $value }} < 1
http://g.pigsty/d/etcd-overview?from=now-5m&to=now&var-cls={{$labels.cls}}
#==============================================================#
# Saturation #
#==============================================================#
- alert : EtcdQuotaFull
expr : etcd:cls:quota_usage > 0.90
for : 1m
labels : { level : 1, severity : WARN, category : etcd }
annotations :
summary : "WARN EtcdQuotaFull: {{ $labels.cls }}"
description : |
etcd:cls:quota_usage[cls={{ $labels.cls }}] = {{ $value | printf "%.3f" }} > 90%
#==============================================================#
# Latency #
#==============================================================#
# etcd network peer rt p95 > 200ms for 1m
- alert : EtcdNetworkPeerRTSlow
expr : etcd:ins:network_peer_rt_p95_5m > 0.200
for : 1m
labels : { level : 2, severity : INFO, category : etcd }
annotations :
summary : "INFO EtcdNetworkPeerRTSlow: {{ $labels.cls }} {{ $labels.ins }}"
description : |
etcd:ins:network_peer_rt_p95_5m[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 200ms
http://g.pigsty/d/etcd-instance?from=now-10m&to=now&var-cls={{ $labels.cls }}
# Etcd wal fsync rt p95 > 50ms
- alert : EtcdWalFsyncSlow
expr : etcd:ins:wal_fsync_rt_p95_5m > 0.050
for : 1m
labels : { level : 2, severity : INFO, category : etcd }
annotations :
summary : "INFO EtcdWalFsyncSlow: {{ $labels.cls }} {{ $labels.ins }}"
description : |
etcd:ins:wal_fsync_rt_p95_5m[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 50ms
http://g.pigsty/d/etcd-instance?from=now-10m&to=now&var-cls={{ $labels.cls }}
6 - 常见问题
Pigsty etcd 模块常见问题答疑
etcd集群起什么作用?
etcd 是一个分布式的、可靠的键-值存储,用于存放系统中最为关键的数据,Pigsty 使用 etcd 作为 Patroni 的 DCS(分布式配置存储)服务,用于存储 PostgreSQL 集群的高可用状态信息。
Patroni 将通过 etcd,实现集群故障检测、自动故障转移、主从切换,集群配置管理等功能。
etcd 对于 PostgreSQL 集群的高可用至关重要,而 etcd 本身的可用性与容灾,是通过使用多个分布式的节点来保证的。
etcd集群使用多大规模合适?
如果超过集群成员数一半(包括正好一半)的 etcd 实例不可用,那么 etcd 集群将进入不可用状态,拒绝对外提供服务。
例如:使用 3 节点的 etcd 集群允许最多一个节点宕机,而其他两个节点仍然可以正常工作;而使用 5 节点的 etcd 集群则可以容忍 2 节点失效。
请注意,etcd 集群中的 学习者 (Learner)实例不计入成员数,因此在 3 节点 etcd 集群中,如果有一个学习者实例,那么实际上成员数量为 2,不能容忍任一节点失效。
在生产环境中,我们建议使用奇数个 etcd 实例,对于生产环境,建议使用 3 节点或 5 节点的 etcd 集群部署以确保足够的可靠性。
etcd集群不可用会有什么影响?
如果 etcd 集群不可用,那么会影响 PostgreSQL 的管控平面,但不会影响数据平面 —— 现有的 PostgreSQL 集群将继续运行,但通过 Patroni 进行的管理操作将无法执行。
etcd 故障期间,PostgreSQL 高可用将无法实现自动故障转移,您也无法使用 patronictl 对 PostgreSQL 集群发起管理操作,例如修改配置,执行手动故障转移等。
通过 Ansible 发起的管理命令不受 etcd 故障影响:例如创建数据库,创建用户,刷新 HBA 与 Service 配置等,etcd 故障期间,您依然可以直接操作 PostgreSQL 集群来实现这些功能。
请注意,以上描述的行为仅适用于较新版本的 Patroni (>=3.0,对应 Pigsty >= 2.0)。如果您使用的是较老版本的 Patroni (<3.0,对应 Pigsty 版本为 1.x),则 etcd / consul 故障会引发极为严重的全局性影响:
所有 PostgreSQL 集群将发生降级:主库将降级为从库,拒绝写请求,etcd 故障将放大为全局性 PostgreSQL 故障。在 Patroni 3.0 引入 DCS Failsafe 功能后,这种情况得到了显著改善。
etcd集群中存储着什么数据?
在 Pigsty 中,etcd 仅用于 PostgreSQL 高可用,并不会用于存储任何其他配置或状态数据。
而 PG 高可用组件 Patroni 会自动生成并管理 etcd 中的数据,当这些数据在 etcd 中丢失时,Patroni 会自动重建。
因此默认情况下,Pigsty 中的 etcd 可以视作 “无状态服务”,可以进行销毁与重建,这为维护工作带来了极大的便利。
如果您将 etcd 用于其他目的,例如作为 Kubernetes 的元数据存储,或自行存储其他数据,那么您需要自行备份 etcd 数据,并在 etcd 集群恢复后进行数据恢复。
如何从etcd故障中恢复?
因为 Pigsty 中的 etcd 只用于 PostgreSQL 高可用,本质上是可销毁、可重建的 “无状态服务”,因此在出现故障时,您可以通过 “重启” / “重置” 来进行快速止血。
要 重启 etcd 集群,您可以使用以下 Ansible 命令:
./etcd.yml -t etcd_launch
要 重置 etcd 集群,您可以直接执行以下剧本,实现覆盖抹除式重装:
如果您自行使用 etcd 存储了其他数据,那么通常需要备份 etcd 数据,并在 etcd 集群恢复后进行数据恢复。
维护etcd有什么注意事项?
简单的版本是:不要写爆 etcd 就好 。
Pigsty v2.6+ 默认启用了 etcd 自动压实(Auto Compact)和 16GB 的后端存储配额,通常无需担心写满 etcd 的问题。
etcd 的数据模型 使得每一次写入都会产生一个新的版本。
因此如果您的 etcd 集群频繁写入,即使只有极个别的 Key,etcd 数据库的大小也可能会不断增长。
当达到容量上限时,etcd 将会拒绝写入请求,这可能导致依赖 etcd 的 PostgreSQL 高可用机制无法正常工作。
Pigsty 默认的 etcd 配置已包含以下优化:
auto-compaction-mode : periodic # 周期性自动压缩
auto-compaction-retention : "24h" # 保留 24 小时历史
quota-backend-bytes : 17179869184 # 16 GiB 配额
更多维护细节请阅读 etcd 官方文档维护指南 。
提示
对于 Pigsty v2.6 之前的版本,请参照下面的说明手动启用 etcd 自动垃圾回收。
如何启动etcd自动垃圾回收?
如果您使用的早先版本的 Pigsty (v2.0 - v2.5),我们强烈建议您通过以下步骤,在生产环境中启用 etcd 的自动压实功能,从而避免 etcd 容量配额写满导致的 etcd 不可用故障。
在 Pigsty 源码目录中,编辑 etcd 配置文件模板:roles/etcd/templates/etcd.conf ,添加以下三条配置项:
auto-compaction-mode : periodic
auto-compaction-retention : "24h"
quota-backend-bytes : 17179869184
然后将所有相关 PostgreSQL 集群设置为 维护模式 后,重新使用 ./etcd.yml 覆盖部署 etcd 集群即可。
该配置会将 etcd 默认的容量配额从 2 GiB 提高到 16 GiB,并确保只保留最近一天的写入历史版本,从而避免了 etcd 数据库大小的无限增长。
etcd中的PostgreSQL高可用数据存储在哪里?
默认情况下,Patroni 使用 pg_namespace 指定的前缀(默认为 /pg)作为所有元数据键的前缀,随后是 PostgreSQL 集群名称。
例如,名为 pg-meta 的 PG 集群,其元数据键将存储在 /pg/pg-meta 下。
etcdctl get /pg/pg-meta --prefix
其中的数据样本如下所示:
/pg/pg-meta/config
{ "ttl" :30,"loop_wait" :10,"retry_timeout" :10,"primary_start_timeout" :10,"maximum_lag_on_failover" :1048576,"maximum_lag_on_syncnode" :-1,"primary_stop_timeout" :30,"synchronous_mode" :false,"synchronous_mode_strict" :false,"failsafe_mode" :true,"pg_version" :16,"pg_cluster" :"pg-meta" ,"pg_shard" :"pg-meta" ,"pg_group" :0,"postgresql" :{ "use_slots" :true,"use_pg_rewind" :true,"remove_data_directory_on_rewind_failure" :true,"parameters" :{ "max_connections" :100,"superuser_reserved_connections" :10,"max_locks_per_transaction" :200,"max_prepared_transactions" :0,"track_commit_timestamp" :"on" ,"wal_level" :"logical" ,"wal_log_hints" :"on" ,"max_worker_processes" :16,"max_wal_senders" :50,"max_replication_slots" :50,"password_encryption" :"scram-sha-256" ,"ssl" :"on" ,"ssl_cert_file" :"/pg/cert/server.crt" ,"ssl_key_file" :"/pg/cert/server.key" ,"ssl_ca_file" :"/pg/cert/ca.crt" ,"shared_buffers" :"7969MB" ,"maintenance_work_mem" :"1993MB" ,"work_mem" :"79MB" ,"max_parallel_workers" :8,"max_parallel_maintenance_workers" :2,"max_parallel_workers_per_gather" :0,"hash_mem_multiplier" :8.0,"huge_pages" :"try" ,"temp_file_limit" :"7GB" ,"vacuum_cost_delay" :"20ms" ,"vacuum_cost_limit" :2000,"bgwriter_delay" :"10ms" ,"bgwriter_lru_maxpages" :800,"bgwriter_lru_multiplier" :5.0,"min_wal_size" :"7GB" ,"max_wal_size" :"28GB" ,"max_slot_wal_keep_size" :"42GB" ,"wal_buffers" :"16MB" ,"wal_writer_delay" :"20ms" ,"wal_writer_flush_after" :"1MB" ,"commit_delay" :20,"commit_siblings" :10,"checkpoint_timeout" :"15min" ,"checkpoint_completion_target" :0.8,"archive_mode" :"on" ,"archive_timeout" :300,"archive_command" :"pgbackrest --stanza=pg-meta archive-push %p" ,"max_standby_archive_delay" :"10min" ,"max_standby_streaming_delay" :"3min" ,"wal_receiver_status_interval" :"1s" ,"hot_standby_feedback" :"on" ,"wal_receiver_timeout" :"60s" ,"max_logical_replication_workers" :8,"max_sync_workers_per_subscription" :6,"random_page_cost" :1.1,"effective_io_concurrency" :1000,"effective_cache_size" :"23907MB" ,"default_statistics_target" :200,"log_destination" :"csvlog" ,"logging_collector" :"on" ,"log_directory" :"/pg/log/postgres" ,"log_filename" :"postgresql-%Y-%m-%d.log" ,"log_checkpoints" :"on" ,"log_lock_waits" :"on" ,"log_replication_commands" :"on" ,"log_statement" :"ddl" ,"log_min_duration_statement" :100,"track_io_timing" :"on" ,"track_functions" :"all" ,"track_activity_query_size" :8192,"log_autovacuum_min_duration" :"1s" ,"autovacuum_max_workers" :2,"autovacuum_naptime" :"1min" ,"autovacuum_vacuum_cost_delay" :-1,"autovacuum_vacuum_cost_limit" :-1,"autovacuum_freeze_max_age" :1000000000,"deadlock_timeout" :"50ms" ,"idle_in_transaction_session_timeout" :"10min" ,"shared_preload_libraries" :"timescaledb, pg_stat_statements, auto_explain" ,"auto_explain.log_min_duration" :"1s" ,"auto_explain.log_analyze" :"on" ,"auto_explain.log_verbose" :"on" ,"auto_explain.log_timing" :"on" ,"auto_explain.log_nested_statements" :true,"pg_stat_statements.max" :5000,"pg_stat_statements.track" :"all" ,"pg_stat_statements.track_utility" :"off" ,"pg_stat_statements.track_planning" :"off" ,"timescaledb.telemetry_level" :"off" ,"timescaledb.max_background_workers" :8,"citus.node_conninfo" :"sslm
ode=prefer" }}}
/pg/pg-meta/failsafe
{ "pg-meta-2" :"http://10.10.10.11:8008/patroni" ,"pg-meta-1" :"http://10.10.10.10:8008/patroni" }
/pg/pg-meta/initialize
7418384210787662172
/pg/pg-meta/leader
pg-meta-1
/pg/pg-meta/members/pg-meta-1
{ "conn_url" :"postgres://10.10.10.10:5432/postgres" ,"api_url" :"http://10.10.10.10:8008/patroni" ,"state" :"running" ,"role" :"primary" ,"version" :"4.0.1" ,"tags" :{ "clonefrom" :true,"version" :"16" ,"spec" :"8C.32G.125G" ,"conf" :"tiny.yml" } ,"xlog_location" :184549376,"timeline" :1}
/pg/pg-meta/members/pg-meta-2
{ "conn_url" :"postgres://10.10.10.11:5432/postgres" ,"api_url" :"http://10.10.10.11:8008/patroni" ,"state" :"running" ,"role" :"replica" ,"version" :"4.0.1" ,"tags" :{ "clonefrom" :true,"version" :"16" ,"spec" :"8C.32G.125G" ,"conf" :"tiny.yml" } ,"xlog_location" :184549376,"replication_state" :"streaming" ,"timeline" :1}
/pg/pg-meta/status
{ "optime" :184549376,"slots" :{ "pg_meta_2" :184549376,"pg_meta_1" :184549376} ,"retain_slots" :[ "pg_meta_1" ,"pg_meta_2" ]}
如何使用一个外部的已经存在的 etcd 集群?
配置清单中硬编码了所使用 etcd 的分组名为 etcd,这个分组里的成员将被用作 PGSQL 的 DCS 服务器。您可以使用 etcd.yml 对它们进行初始化,或直接假设它是一个已存在的外部 etcd 集群。
要使用现有的外部 etcd 集群,只要像往常一样定义它们即可,您可以跳过 etcd.yml 剧本的执行,因为集群已经存在,不需要部署。
但用户必须确保 现有 etcd 集群证书是由 Pigsty 使用的相同 CA 签名颁发的 。否则客户端无法使用 Pigsty 自签名 CA 颁发的证书来访问外部的 etcd 集群。
如何向现有etcd集群添加新的成员?
详细过程,请参考向 etcd 集群添加成员
推荐方式:使用便捷脚本
# 首先在配置清单中添加新成员定义,然后执行:
bin/etcd-add <ip> # 添加单个新成员
bin/etcd-add <ip1> # 添加多个新成员
手动方式:
etcdctl member add <etcd-?> --learner= true --peer-urls= https://<new_ins_ip>:2380 # 宣告新成员加入
./etcd.yml -l <new_ins_ip> -e etcd_init = existing # 初始化新成员
etcdctl member promote <new_ins_server_id> # 提升为正式成员
请注意,我们建议一次只添加一个新成员。
如何从现有etcd集群中移除成员?
详细过程,请参考从 etcd 集群中移除成员
推荐方式:使用便捷脚本
bin/etcd-rm <ip> # 移除指定成员
bin/etcd-rm # 移除整个 etcd 集群
手动方式:
./etcd-rm.yml -l <ins_ip> # 使用专用移除剧本
etcdctl member remove <etcd_server_id> # 从集群中踢出成员
./etcd-rm.yml -l <ins_ip> # 清理实例