AWS DevOps Agent 接入 Wiz,告警排查自动带上安全上下文
值班工程师半夜收到 CPU 飙升、延迟异常或 API 报错时,第一反应往往是:这是运维问题还是安全事件?CPU 飙升可能是扩容问题,也可能是挖矿程序;延迟异常可能是部署失误,也可能是数据外泄。没有安全上下文,排查只能靠人工在多个工具间来回切换,拖慢恢复速度。
AWS DevOps Agent 是 AWS 推出的智能体,能自主调查事件并定位运维改进点,覆盖 AWS、多云和本地环境,把原本需要值班工程师数小时的手动排查压缩到分钟级。接入 Wiz 后,Agent 在调查过程中通过 MCP 协议查询 Wiz 的安全图谱,把漏洞数据、安全发现和暴露面分析叠加到运维遥测之上,直接回答"这是性能问题还是安全事件"。
对已用 Wiz 保护 AWS 环境的团队,这个集成把现有安全数据直接送进事件调查流程,让告警分流在人工介入前就完成。配置方式可参考 AWS 官方文档。
#DevOps #运维 #AWS #Wiz #MCP #安全 #云原生 #告警
@DevOpsTalkCN
值班工程师半夜收到 CPU 飙升、延迟异常或 API 报错时,第一反应往往是:这是运维问题还是安全事件?CPU 飙升可能是扩容问题,也可能是挖矿程序;延迟异常可能是部署失误,也可能是数据外泄。没有安全上下文,排查只能靠人工在多个工具间来回切换,拖慢恢复速度。
AWS DevOps Agent 是 AWS 推出的智能体,能自主调查事件并定位运维改进点,覆盖 AWS、多云和本地环境,把原本需要值班工程师数小时的手动排查压缩到分钟级。接入 Wiz 后,Agent 在调查过程中通过 MCP 协议查询 Wiz 的安全图谱,把漏洞数据、安全发现和暴露面分析叠加到运维遥测之上,直接回答"这是性能问题还是安全事件"。
三个场景说明这个集成如何改变处置路径。假设同一个 EC2 实例触发 CPU 飙升告警:
场景 A:Agent 查询 Wiz 确认实例被完整监控、无已知漏洞、无活跃威胁——纯运维问题,正常扩容、查部署、测试即可。
场景 B:同样的告警,Wiz 返回该实例存在已验证可利用的远程代码执行漏洞,且资源暴露在公网。症状与场景 A 完全一致,但正确响应完全相反:立即隔离、联系安全团队、按潜在入侵处理。
场景 C:资源根本没接入 Wiz。Agent 会在调查报告中标注"缺少安全上下文",团队据此补齐覆盖。
集成走 MCP 桥接:Agent 识别受影响资源后自动调用 Wiz 的远程 MCP 服务器,无需手动触发。查询只传资源标识符,不共享运维遥测或调查上下文。Wiz MCP 提供覆盖检查、漏洞详情(含 CVE 严重级别、修复版本、CISA KEV 可利用性)、风险问题(如公网暴露 + 无 EDR + 可利用 CVE 的毒性组合)、活跃威胁与恶意软件、AI 生成修复建议等工具。若 Wiz 服务器不可达或超时,Agent 继续用运维数据调查,并在结果中标记缺失的安全上下文。
对已用 Wiz 保护 AWS 环境的团队,这个集成把现有安全数据直接送进事件调查流程,让告警分流在人工介入前就完成。配置方式可参考 AWS 官方文档。
#DevOps #运维 #AWS #Wiz #MCP #安全 #云原生 #告警
@DevOpsTalkCN
hba_file 只是路径,改认证规则靠 reload
PostgreSQL 的 hba_file 参数只告诉服务器去哪找 pg_hba.conf,它本身不包含任何认证规则。这个参数是 postmaster 上下文,只在启动时读取,默认指向数据目录下的 pg_hba.conf,initdb 建集群时会自动生成。绝大多数场景不需要改它,除非你想把认证文件放到数据目录之外。
最容易踩坑的是文件内容和参数指向的更新规则完全不同:修改 pg_hba.conf 内容——加规则、收紧认证方式、放行新网段——只需要 reload,执行 pg_ctl reload、SELECT pg_reload_conf() 或发 SIGHUP 即可,新规则对后续连接立即生效,不中断任何会话。但改 hba_file 本身必须重启,因为它是启动时读取的参数。很多人把"改了认证配置"和"改了 hba_file"混为一谈,要么不需要重启却重启了,要么指望 reload 生效位置变更——后者不会生效。
日常操作记住这条链路:用 SHOW hba_file 找到真实文件,编辑它,用 pg_hba_file_rules 预检,最后 reload 生效。hba_file 本身几乎不用动,动了就要重启。
#DevOps #运维 #PostgreSQL #hba_file #pg_hba_conf #数据库运维 #认证配置 #pg_reload_conf
@DevOpsTalkCN
PostgreSQL 的 hba_file 参数只告诉服务器去哪找 pg_hba.conf,它本身不包含任何认证规则。这个参数是 postmaster 上下文,只在启动时读取,默认指向数据目录下的 pg_hba.conf,initdb 建集群时会自动生成。绝大多数场景不需要改它,除非你想把认证文件放到数据目录之外。
最容易踩坑的是文件内容和参数指向的更新规则完全不同:修改 pg_hba.conf 内容——加规则、收紧认证方式、放行新网段——只需要 reload,执行 pg_ctl reload、SELECT pg_reload_conf() 或发 SIGHUP 即可,新规则对后续连接立即生效,不中断任何会话。但改 hba_file 本身必须重启,因为它是启动时读取的参数。很多人把"改了认证配置"和"改了 hba_file"混为一谈,要么不需要重启却重启了,要么指望 reload 生效位置变更——后者不会生效。
Debian 系打包尤其容易坑人:它把 pg_hba.conf 放在 /etc/postgresql/ 下,和集群其他配置放一起,同时把 hba_file 指向那里。结果就是你编辑了一个 pg_hba.conf、reload 后毫无变化,因为你改的压根不是服务器正在读的那个文件。用 SHOW hba_file 或查 pg_settings 就能拿到运行中服务器实际加载的路径,那才是唯一值得编辑的文件。
认证配置还有个特殊风险:改错了可能把自己锁在服务器外面,而你还得靠它来修复。PostgreSQL 10 起提供的 pg_hba_file_rules 视图就是为此设计的预检工具——它按行展示 pg_hba.conf 的解析结果,解析失败的行会在 error 列给出错误信息。关键点:它读的是磁盘上的文件内容,不是服务器当前已加载的规则,所以可以在编辑后、reload 前查询,确认每行都能解析、规则符合预期,再发信号。该视图仅超级用户可读,出错行只显示行号和错误。
日常操作记住这条链路:用 SHOW hba_file 找到真实文件,编辑它,用 pg_hba_file_rules 预检,最后 reload 生效。hba_file 本身几乎不用动,动了就要重启。
#DevOps #运维 #PostgreSQL #hba_file #pg_hba_conf #数据库运维 #认证配置 #pg_reload_conf
@DevOpsTalkCN
EC2 Image Builder 原生自动版本管理上线,CDK L2 构造简化镜像流水线
影视后期公司 Company 3 的 New Technology 团队用 EC2 Image Builder 统一管理艺术家计算环境的 AMI 和容器镜像,配合 AWS CDK 规模化生成组件与配方。由于 Image Builder 资源不可变,每次改动都要手动递增版本号并同步更新 CDK 代码中的 ARN 引用,跨几十个组件手工传播版本号既易错又难扩展。
团队先用 MD5 哈希拼进组件名的临时方案绕过限制,但命名难维护且不符合语义化版本规范。随后与 AWS 合作改用 CDK Custom Resources 自动化版本传播,仍保留手动递增和自定义资源维护负担。2025 年 11 月 Image Builder 推出原生自动版本管理,同名同语义版本的组件自动递增构建版本,开发者用通配符(如 1.2.x)即可让流水线解析到最高可用版本,彻底消除手动传播环节。
对使用 Image Builder 管理镜像流水线的团队,自动版本管理可直接省去组件与配方的手动版本同步,CDK L2 构造则降低流水线代码维护成本。L2 构造仍在 alpha 阶段,生产环境采用前需评估稳定性。
#DevOps #运维 #AWS #EC2ImageBuilder #CDK #基础设施即代码 #镜像管理
@DevOpsTalkCN
影视后期公司 Company 3 的 New Technology 团队用 EC2 Image Builder 统一管理艺术家计算环境的 AMI 和容器镜像,配合 AWS CDK 规模化生成组件与配方。由于 Image Builder 资源不可变,每次改动都要手动递增版本号并同步更新 CDK 代码中的 ARN 引用,跨几十个组件手工传播版本号既易错又难扩展。
团队先用 MD5 哈希拼进组件名的临时方案绕过限制,但命名难维护且不符合语义化版本规范。随后与 AWS 合作改用 CDK Custom Resources 自动化版本传播,仍保留手动递增和自定义资源维护负担。2025 年 11 月 Image Builder 推出原生自动版本管理,同名同语义版本的组件自动递增构建版本,开发者用通配符(如 1.2.x)即可让流水线解析到最高可用版本,彻底消除手动传播环节。
配套的 CDK L2 构造(RFC 0789)目前处于 alpha 稳定阶段,提供默认最佳实践配置、自动最小权限 IAM 角色与策略创建。此前用 L1 构造编排一条 Image Builder 流水线需 50 多行代码,跨 6 个 CloudFormation 资源手动配置实例角色、配置文件与流水线;L2 构造将这一过程大幅简化,并消除了对 Custom Resources 的依赖。
对使用 Image Builder 管理镜像流水线的团队,自动版本管理可直接省去组件与配方的手动版本同步,CDK L2 构造则降低流水线代码维护成本。L2 构造仍在 alpha 阶段,生产环境采用前需评估稳定性。
#DevOps #运维 #AWS #EC2ImageBuilder #CDK #基础设施即代码 #镜像管理
@DevOpsTalkCN
Sysdig 推出 Runtime Remediation Skill:把告警变成可审计的处置流程
告警触发后,团队往往知道发生了什么,却不知道下一步该做什么:这个工作负载依赖什么?杀掉容器会不会弄坏 sidecar 网格?StatefulSet 会不会报错?PodDisruptionBudget 会不会直接拦住操作?销毁容器前证据收集了没有?平时这些判断要靠 SRE、安全工程师和云管理员在凌晨两点的 Slack 频道里临时拼凑,而攻击者不会等你。
Sysdig 新发布的 Runtime Remediation Skill 把这类判断编码成一套受控的响应流程,直接跑在分析师的终端里。它本质是一个 agent skill——一组指令,告诉 AI 编码代理如何按步骤执行安全处置,而不是让 AI 凭通用建议自由发挥。整个流程六步,每一步都完整播报,分析师始终能看到接下来要发生什么。
该技能通过 Sysdig MCP server 运行,让 AI 代理结构化访问 Sysdig 的运行时检测、工作负载上下文和响应动作,需通过 OAuth 注册。目前以 Public Beta 形式提供,支持 Claude Code 及任何兼容 Agent Skills 的环境。
#DevOps #运维 #Sysdig #云安全 #运行时安全 #MCP #Falco #云原生安全 #AI代理 #事件响应
@DevOpsTalkCN
告警触发后,团队往往知道发生了什么,却不知道下一步该做什么:这个工作负载依赖什么?杀掉容器会不会弄坏 sidecar 网格?StatefulSet 会不会报错?PodDisruptionBudget 会不会直接拦住操作?销毁容器前证据收集了没有?平时这些判断要靠 SRE、安全工程师和云管理员在凌晨两点的 Slack 频道里临时拼凑,而攻击者不会等你。
Sysdig 新发布的 Runtime Remediation Skill 把这类判断编码成一套受控的响应流程,直接跑在分析师的终端里。它本质是一个 agent skill——一组指令,告诉 AI 编码代理如何按步骤执行安全处置,而不是让 AI 凭通用建议自由发挥。整个流程六步,每一步都完整播报,分析师始终能看到接下来要发生什么。
流程先从构建实时爆炸半径地图开始:服务依赖、sidecar、ServiceAccount 权限、云身份绑定,以及 PodDisruptionBudget 这类运维约束。地图只读,动手前不猜任何东西。
随后代理按顺序提出处置动作,每个动作都标明它做什么、会破坏什么、能否撤销、可撤销时的精确回滚调用。每个破坏性动作都要单独确认,没有"全部批准"按钮——代理提议、人来决定、每个动作都留日志。
动作集覆盖完整响应面:先做取证(获取二进制、抓 syscall、快照卷),再做网络隔离和进程终止,最后是 IAM 会话撤销。顺序有讲究:凭据被盗时攻击者手里已经握着凭据,先撤销 IAM 会话才是对的。
处置后代理观察五分钟确认威胁没有复活,以 cleared、still_active 或 inconclusive 明确收尾。完整审计轨迹(UTC 时间戳、动作决策、观察结果)自动追加到事件工单。
该技能通过 Sysdig MCP server 运行,让 AI 代理结构化访问 Sysdig 的运行时检测、工作负载上下文和响应动作,需通过 OAuth 注册。目前以 Public Beta 形式提供,支持 Claude Code 及任何兼容 Agent Skills 的环境。
#DevOps #运维 #Sysdig #云安全 #运行时安全 #MCP #Falco #云原生安全 #AI代理 #事件响应
@DevOpsTalkCN
pgvector 混合检索:过滤 + 向量排序的四种模式
生产环境里的向量查询很少是纯最近邻搜索,通常是「在 legal 分类、最近 30 天发布的文档里找最相似的 10 条」。相似度排序叠加标量过滤就是混合检索,而 pgvector 的 HNSW 索引只返回近似排序的 top-k,不返回集合,一旦加上 WHERE 子句,召回率和性能就开始打架。
pgvector 0.8 起引入迭代索引扫描(iterative index scans),扫描 HNSW 或 IVFFlat 索引直到有足够行通过 WHERE 过滤,或达到安全上限为止。默认关闭时只做单次索引遍历后过滤:若条件匹配约 10% 的行、hnsw.ef_search 为 40,平均只能留下约 4 条幸存者,即使你要求 LIMIT 10。开启后可用 hnsw.max_scan_tuples 限制扫描范围,strict_order 保序、relaxed_order 换性能,内存不够时调 hnsw.scan_mem_multiplier(work_mem 的倍数)。
无论选哪种模式,都要用 EXPLAIN (ANALYZE, BUFFERS) 验证。看到 Bitmap Heap Scan 走标量列而不是向量索引,说明规划器判断标量过滤足够有选择性、那样更便宜。混合查询正是人们容易用规划器匹配不了的表达式意外禁用索引的地方。
决策速查:紧耦合的临时过滤用迭代扫描并调 max_scan_tuples;稳定低基数过滤用部分 HNSW;高基数或迭代扫描到顶用超采样再过滤;答案稳定的重复查询用缓存。混合检索不是一种查询形态,是召回与性能之间的一组权衡。
#DevOps #运维 #Postgres #pgvector #HNSW #向量检索 #混合检索 #数据库
@DevOpsTalkCN
生产环境里的向量查询很少是纯最近邻搜索,通常是「在 legal 分类、最近 30 天发布的文档里找最相似的 10 条」。相似度排序叠加标量过滤就是混合检索,而 pgvector 的 HNSW 索引只返回近似排序的 top-k,不返回集合,一旦加上 WHERE 子句,召回率和性能就开始打架。
pgvector 0.8 起引入迭代索引扫描(iterative index scans),扫描 HNSW 或 IVFFlat 索引直到有足够行通过 WHERE 过滤,或达到安全上限为止。默认关闭时只做单次索引遍历后过滤:若条件匹配约 10% 的行、hnsw.ef_search 为 40,平均只能留下约 4 条幸存者,即使你要求 LIMIT 10。开启后可用 hnsw.max_scan_tuples 限制扫描范围,strict_order 保序、relaxed_order 换性能,内存不够时调 hnsw.scan_mem_multiplier(work_mem 的倍数)。
迭代扫描之外还有三条路。向量优先:先取全表最近邻再过滤,性能可预测但召回差——若 legal 只占 5%,全表 top-10 里可能一条 legal 都没有。标量优先:先用 B-tree 收窄再算距离,召回没问题但查询时间不可控,百万行时要在巨大集合上逐个算距离。第三条是改需求:不承诺固定 top-10,过滤后剩多少返回多少。
更实用的做法是按场景选。过滤值低基数且稳定(category、status、region、少量租户),建部分 HNSW 索引,把过滤条件烘焙进索引,图里只含该子集,索引更小、构建更快、子集内召回接近 100%,代价是每个值一个索引,高基数过滤(user_id、自由标签、任意日期范围)不适用。
过滤条件高基数或迭代扫描撞上限时,用超采样再过滤:向全表索引多取候选再重排。池大小估算公式 pool_size = k / filter_selectivity × 2,5% 选择性取 10 条就是 10 / 0.05 × 2 = 400,×2 是给近似误差和分布不均留余量。选择性可从 pg_stats 读,MCV 列表里的值用存储频率,其余按规划器思路把剩余概率质量均摊到剩余 distinct 值。标签总落进 residual 桶时,用 ALTER TABLE ... SET STATISTICS 1000 加长 MCV 列表(默认 100)。超采样时记得调大 hnsw.ef_search,否则索引探索不到足够候选。
高频重复的混合查询可以缓存。写入时预计算存结果 ID,适合「相似文档」这类查询向量就是行自身 embedding 的场景;无法预判查询就按查询 embedding 哈希 + 过滤维度 + limit 做缓存键,命中即主键查找。缓存键必须包含过滤条件,否则「最近 10 条」缓存被 category = 'legal' 复用,等于把向量优先的召回 bug 又请回来。失效逻辑才是设计重点:源 embedding 变化或过滤成员变化(文档离开 legal)都要失效,短 TTL 是稳妥起点。
无论选哪种模式,都要用 EXPLAIN (ANALYZE, BUFFERS) 验证。看到 Bitmap Heap Scan 走标量列而不是向量索引,说明规划器判断标量过滤足够有选择性、那样更便宜。混合查询正是人们容易用规划器匹配不了的表达式意外禁用索引的地方。
决策速查:紧耦合的临时过滤用迭代扫描并调 max_scan_tuples;稳定低基数过滤用部分 HNSW;高基数或迭代扫描到顶用超采样再过滤;答案稳定的重复查询用缓存。混合检索不是一种查询形态,是召回与性能之间的一组权衡。
#DevOps #运维 #Postgres #pgvector #HNSW #向量检索 #混合检索 #数据库
@DevOpsTalkCN
hot_standby:只负责打开读副本,真正的调参在后面
PostgreSQL 的 hot_standby 参数决定备用服务器是只能故障切换的冷备,还是能同时提供读能力的副本。自 PG 10 起它默认开启,对大多数跑复制的用户来说,这个开关已经处于想要的位置,基本不用动。
结论
保持 hot_standby 开着。PG 10 起默认值就是几乎所有人都想要的,放着不管零成本。理解它在主库上无效、依赖主库 wal_level 为 replica 或更高,最重要的是:打开它只是可查询副本的 trivial 部分。真正的活儿在 max_standby_streaming_delay、max_standby_archive_delay 和 hot_standby_feedback 上——重放速度和查询自由之间的张力在这里解决,hot_standby 只是唤醒它们的开关。
#DevOps #运维 #PostgreSQL #hot_standby #WAL #流复制 #数据库运维 #PG复制
@DevOpsTalkCN
PostgreSQL 的 hot_standby 参数决定备用服务器是只能故障切换的冷备,还是能同时提供读能力的副本。自 PG 10 起它默认开启,对大多数跑复制的用户来说,这个开关已经处于想要的位置,基本不用动。
它是个布尔参数,默认 on,上下文是 postmaster,服务器启动时固定。开启后,处于恢复中的服务器(从归档或流复制主库重放 WAL)可以接受只读查询,且只读是强制而非信任——恢复期间任何会话的事务都被强制只读。Hot Standby 特性在 9.0 引入,正是它把现代读副本和只能干等提升的旧式 warm standby 区分开。
主库上它什么都不做
这是最容易踩坑的地方。hot_standby 只在恢复中的服务器上生效,主库正常运行时它的值毫无意义,文档也明确说了整组 standby 参数在主库上的值不重要。常见做法是主备共用一份 postgresql.conf,于是 hot_standby = on 就躺在主库配置里,改它、重启主库,结果都一样——没反应,因为主库不在恢复状态。
依赖 wal_level 的配合
备库要接受查询,重放的 WAL 必须携带足够信息来重建一致的、可查询的视图,这个决定在主库上做出。具体来说,主库 wal_level 低于 replica 时写的 WAL,无法启用 hot standby。PG 10 起默认值自动对齐:wal_level 默认 replica、hot_standby 默认 on。10 之前两者默认不配合,hot_standby 默认 off,得手动调。9.6 时 wal_level 里那个叫 hot_standby 的取值被并入 replica,现在只是映射关系。
开启的真正代价:冲突
把备库变成查询目标是一行配置的事,真正的活儿是处理冲突。备库同时干两件事:应用主库的变更,以及回答基于稍早时间点的查询。WAL 重放可能要删行、截断页面或加锁,而备库上正在跑的查询还依赖这些数据。PostgreSQL 不能既应用记录又保持查询视图完整,于是它等一段有界时间,超时就取消查询。
真正的调参参数在这里:
• max_standby_streaming_delay:流式 WAL 到达时,重放等待冲突查询多久,默认 30 秒
• max_standby_archive_delay:归档 WAL 同理,默认 30 秒
• 两者都接受 -1 表示永远等待
短延迟让备库保持最新,代价是干脆地取消查询——适合纯故障切换的备库。长或无限延迟让大分析查询跑完,代价是备库落后,落后期间所有会话看到的数据越来越旧。
有个尖锐的边角:这个延迟是单个 WAL 段的预算,不是单查询配额。一个查询耗掉大部分预算后,下一个冲突查询几乎没得等。
另一个杠杆是 hot_standby_feedback,默认 off。开启后备库告诉主库正在运行的查询还需要哪些行,主库暂缓 vacuum 掉它们。换来的是主库可能膨胀,但备库查询取消大幅减少。
什么时候该关掉
只有一个合理理由:备库只负责待命。如果副本纯粹为快速故障切换而存在、不打算跑查询,关掉 hot standby 意味着无查询冲突、无读者拖慢重放,lag 最小、追赶和提升最快。对专职热备是合理选择。对其他人来说,读能力才是跑副本的全部理由,关掉等于扔掉它。
结论
保持 hot_standby 开着。PG 10 起默认值就是几乎所有人都想要的,放着不管零成本。理解它在主库上无效、依赖主库 wal_level 为 replica 或更高,最重要的是:打开它只是可查询副本的 trivial 部分。真正的活儿在 max_standby_streaming_delay、max_standby_archive_delay 和 hot_standby_feedback 上——重放速度和查询自由之间的张力在这里解决,hot_standby 只是唤醒它们的开关。
#DevOps #运维 #PostgreSQL #hot_standby #WAL #流复制 #数据库运维 #PG复制
@DevOpsTalkCN
KubeElasti 用 ProbeResponse 让服务真正缩到零
Scale-to-zero 在纸面上很完美:空闲服务、零 Pod、零账单。但一上生产就露馅——负载均衡器不知道 Pod 是故意消失的,它持续发健康检查,每次检查打到 resolver,resolver 把流量当成扩容信号,Pod 被唤醒,你又开始为闲置 Pod 付费。
这不是 KubeElasti 的 bug,而是现代基础设施拼接方式的结构性矛盾:负载均衡器需要知道服务活着,Kubernetes 自动扩缩容需要知道服务死了。这两件事从有人尝试在云负载均衡器后面跑零副本部署那天起就一直在打架。
常规建议是把健康检查路由和应用路由分开,比如"把健康检查放到另一个 service"。这在多数情况下行不通:云负载均衡器检查的是服务注册的 IP 和端口,你没法让 ALB 对 /healthz 用不同后端;分离路由带来的运维复杂度团队根本维护不住,时间一长配置漂移,健康检查还是会打到应用端点;最关键的是,健康检查端点就是应用端点本身,重路由它没有意义。
ProbeResponse 在 resolver 上加了一层匹配逻辑。服务缩到零时,resolver 本来就拦截所有入站流量,ProbeResponse 让 resolver 在决定是否触发扩容前先评估规则——请求匹配探针规则就直接应答,返回你定义的状态码和 body,不通知 operator,工作负载保持为零,健康检查收到 200 OK。
配置长这样:
```
probeResponse:
- method: GET
path:
type: PathPrefix
value: /healthz
response:
status: 200
body: '{"ok":true}'
- method: HEAD
path:
type: Exact
value: /ready
response:
status: 204
body: '{}'
```
匹配规则支持 HTTP 方法、路径匹配(Exact / PathPrefix / RegularExpression)、Header 匹配(全部 AND)、查询参数匹配(全部 AND)。规则从上到下评估,首个匹配生效;无匹配则走正常逻辑——请求排队并触发扩容。ProbeResponse 是闸门,不是扩容的替代品,真实流量照样唤醒服务。
架构上,resolver 在代理模式下本来就是拦截层,加探针匹配不增加额外跳数、组件或常驻代理开销。服务有活跃 Pod 时 resolver 完全不在请求路径上,ProbeResponse 规则只在服务处于零副本时生效——运行中零延迟代价,零基础设施开销,不需要单独部署健康检查路由服务。
实际收益场景:内部开发服务(CI 预览环境、内部仪表盘)在真实使用间隙保持零副本,即使平台监控每 30 秒检查一次;GPU Pod 贵,健康检查触发的冷启动是团队不敢缩到零的主因,ProbeResponse 让 GPU 真正闲置成为可能;按运行实例计费的商业软件,健康检查流量不算"需要";服务网格的东西向流量健康检查也不会误触发扩容。
配置前先审计健康检查来源:云负载均衡器的路径、方法和频率,NGINX / Traefik / Istio 的 ingress 注解,Prometheus Blackbox Exporter / Datadog synthetic 等 uptime 工具探测的端点,服务网格 sidecar 的健康检查行为。每个来源建一条对应规则,PathPrefix 覆盖广(如 /health/ 下所有路径),Exact 针对具体端点。
#DevOps #运维 #Kubernetes #KubeElasti #ScaleToZero #健康检查 #负载均衡 #服务网格
@DevOpsTalkCN
Scale-to-zero 在纸面上很完美:空闲服务、零 Pod、零账单。但一上生产就露馅——负载均衡器不知道 Pod 是故意消失的,它持续发健康检查,每次检查打到 resolver,resolver 把流量当成扩容信号,Pod 被唤醒,你又开始为闲置 Pod 付费。
这不是 KubeElasti 的 bug,而是现代基础设施拼接方式的结构性矛盾:负载均衡器需要知道服务活着,Kubernetes 自动扩缩容需要知道服务死了。这两件事从有人尝试在云负载均衡器后面跑零副本部署那天起就一直在打架。
问题在三种场景下出现:
云负载均衡器:AWS ALB、GCP Load Balancer、Azure Application Gateway 都要求周期性健康检查来安全路由流量,它们不理解"故意闲置"这个概念。
Kubernetes 探针:Pod 上配置的 liveness/readiness 探针经常在入口层被复制,缩到零但注册了 uptime 监控的服务会持续触发请求。
平台监控:内部开发者平台、Istio 等服务网格、Prometheus Blackbox Exporter 都在持续探测端点,它们都不区分"服务降级"和"故意闲置"。
结果:配置了 scale-to-zero 的团队实际节省为 0%,因为监控栈根本不让你停在零。
常规建议是把健康检查路由和应用路由分开,比如"把健康检查放到另一个 service"。这在多数情况下行不通:云负载均衡器检查的是服务注册的 IP 和端口,你没法让 ALB 对 /healthz 用不同后端;分离路由带来的运维复杂度团队根本维护不住,时间一长配置漂移,健康检查还是会打到应用端点;最关键的是,健康检查端点就是应用端点本身,重路由它没有意义。
ProbeResponse 在 resolver 上加了一层匹配逻辑。服务缩到零时,resolver 本来就拦截所有入站流量,ProbeResponse 让 resolver 在决定是否触发扩容前先评估规则——请求匹配探针规则就直接应答,返回你定义的状态码和 body,不通知 operator,工作负载保持为零,健康检查收到 200 OK。
配置长这样:
```
probeResponse:
- method: GET
path:
type: PathPrefix
value: /healthz
response:
status: 200
body: '{"ok":true}'
- method: HEAD
path:
type: Exact
value: /ready
response:
status: 204
body: '{}'
```
匹配规则支持 HTTP 方法、路径匹配(Exact / PathPrefix / RegularExpression)、Header 匹配(全部 AND)、查询参数匹配(全部 AND)。规则从上到下评估,首个匹配生效;无匹配则走正常逻辑——请求排队并触发扩容。ProbeResponse 是闸门,不是扩容的替代品,真实流量照样唤醒服务。
架构上,resolver 在代理模式下本来就是拦截层,加探针匹配不增加额外跳数、组件或常驻代理开销。服务有活跃 Pod 时 resolver 完全不在请求路径上,ProbeResponse 规则只在服务处于零副本时生效——运行中零延迟代价,零基础设施开销,不需要单独部署健康检查路由服务。
实际收益场景:内部开发服务(CI 预览环境、内部仪表盘)在真实使用间隙保持零副本,即使平台监控每 30 秒检查一次;GPU Pod 贵,健康检查触发的冷启动是团队不敢缩到零的主因,ProbeResponse 让 GPU 真正闲置成为可能;按运行实例计费的商业软件,健康检查流量不算"需要";服务网格的东西向流量健康检查也不会误触发扩容。
配置前先审计健康检查来源:云负载均衡器的路径、方法和频率,NGINX / Traefik / Istio 的 ingress 注解,Prometheus Blackbox Exporter / Datadog synthetic 等 uptime 工具探测的端点,服务网格 sidecar 的健康检查行为。每个来源建一条对应规则,PathPrefix 覆盖广(如 /health/ 下所有路径),Exact 针对具体端点。
#DevOps #运维 #Kubernetes #KubeElasti #ScaleToZero #健康检查 #负载均衡 #服务网格
@DevOpsTalkCN
Postgres 19 新增随机日期与全局对象 DDL 查询函数
Postgres 19 将带来一批提升日常使用体验的内置函数改进。此前生成一个随机日期需要从年初加随机天数,表达式冗长且类型易被提升为 timestamp,还要处理闰年边界。新版本为 random() 增加了带上下界的重载,支持 date、timestamp、timestamptz、integer、bigint、numeric 等类型,输入什么类型就返回什么类型,不再需要额外 cast。
配合 setseed() 和 generate_series(),可以确定性生成批量测试数据,例如一次生成 500 个客户和全年分布的订单,用于构造负载测试夹具。
这些改动让生成随机日期和获取全局对象 DDL 不再依赖外部工具,全部变成一次函数调用。虽然目前只覆盖全局对象,但为后续扩展更多对象的 DDL 提取功能打下了基础。
#DevOps #运维 #Postgres #Postgres19 #数据库 #SQL #DDL
@DevOpsTalkCN
Postgres 19 将带来一批提升日常使用体验的内置函数改进。此前生成一个随机日期需要从年初加随机天数,表达式冗长且类型易被提升为 timestamp,还要处理闰年边界。新版本为 random() 增加了带上下界的重载,支持 date、timestamp、timestamptz、integer、bigint、numeric 等类型,输入什么类型就返回什么类型,不再需要额外 cast。
配合 setseed() 和 generate_series(),可以确定性生成批量测试数据,例如一次生成 500 个客户和全年分布的订单,用于构造负载测试夹具。
另一个重点是新增三个信息函数,用于直接获取全局对象的 DDL 定义。此前要查看 role、tablespace、database 的定义,只能借助 pg_dumpall 或 GUI 工具,无法用标准 SQL 查询和过滤。新函数 pg_get_role_ddl() 可直接返回重建指定 role 的完整语句,包含属性、per-role 设置和成员关系,但刻意不输出密码哈希以避免泄露敏感信息。函数支持 memberships 和 pretty 两个可选参数,分别控制是否输出成员授权和是否格式化输出。
对应的 pg_get_tablespace_ddl() 和 pg_get_database_ddl() 则解决了 tablespace 位置和存储参数、database 定义等信息的获取问题,返回结果可直接用于重建对象,owner 直接显示用户名而非需要 join 的 oid。这些函数同样支持参数选项,可以抑制特定子句或请求格式化输出,甚至可以用时间戳记录数据库定义的变更历史。
这些改动让生成随机日期和获取全局对象 DDL 不再依赖外部工具,全部变成一次函数调用。虽然目前只覆盖全局对象,但为后续扩展更多对象的 DDL 提取功能打下了基础。
#DevOps #运维 #Postgres #Postgres19 #数据库 #SQL #DDL
@DevOpsTalkCN
PostgreSQL 18 扩展容器化:按耦合度选方案
PostgreSQL 18 新增
这个模式是否值得用,取决于扩展与服务器的耦合深度。按耦合度分四类,结论差异很大。
纯按需加载扩展(最佳适配)
Hook 类扩展(适配良好,无热挂载)
后台 Worker 扩展(视情况而定)
系统集成类扩展(谨慎评估)
结论:
#DevOps #运维 #PostgreSQL #PostgreSQL18 #extension_control_path #Kubernetes #ImageVolume #CloudNativePG #pgvector #PostGIS #spock #容器化
@DevOpsTalkCN
PostgreSQL 18 新增
extension_control_path GUC,配合已有的 dynamic_library_path,扩展的 control 文件、SQL 脚本和共享库可以完全放在服务器安装目录之外。结合 Kubernetes ImageVolume 或 Docker --mount type=image,扩展可以打包成独立 OCI 镜像挂载进 Pod,无需重建服务器镜像。这个模式是否值得用,取决于扩展与服务器的耦合深度。按耦合度分四类,结论差异很大。
纯按需加载扩展(最佳适配)
pgvector、PostGIS、pg_partman(纯 SQL 模式)属于此类。它们在客户端执行CREATE EXTENSION前对服务器完全不可见,无shared_preload_libraries条目、无后台进程、无 GUC 改动。.so文件按需加载进后端进程,进程退出即卸载。
这意味着扩展容器可以热挂载/热卸载,无需重启。pgvector 镜像仅 613 KB,PostGIS 含依赖也只有几 MB,补丁升级只换镜像 tag,服务器镜像完全不动。
注意extension_control_path是冒号分隔的搜索路径,按序查找.control文件,不会自动枚举子目录。多个扩展各自挂载,路径条目一一对应,$system和$libdir必须放在最后保证内置扩展可解析。
Hook 类扩展(适配良好,无热挂载)
pgaudit、pg_stat_statements、auto_explain 等通过 hook 拦截执行管道,必须在任何查询运行前加载,因此需要shared_preload_libraries,增删必须重启(CloudNativePG 中为滚动重启)。
容器模式保留的价值是独立版本管理:pgaudit 补丁发布后换 tag 重启即可,服务器镜像不动。对多集群、部分集群需要审计合规的场景,这是实打实的运维改进。
后台 Worker 扩展(视情况而定)
pg_cron、pg_partman(带 worker)、pg_repack 注册常驻 OS 进程,随 postmaster 启停。挂载/卸载同样需要重启,且 worker 崩溃可能触发整个服务器重启,运维面比纯按需扩展大。
仅当有明确需求——大量集群中 pg_cron 可选、或合规要求每个二进制独立漏洞扫描——才值得为独立版本管理付出额外镜像管理成本。
系统集成类扩展(谨慎评估)
spock、pglogical、TimescaleDB、Citus 从根本上改变服务器运行方式。文件交付不是约束瓶颈。以 spock 为例:postmaster 启动时分配共享内存、要求wal_level=logical(全库 WAL 膨胀)、track_commit_timestamp=on(每次提交额外写时间戳)、多个带活连接的后台 worker、复制槽可能造成主库 WAL 无限堆积。
这些约束与文件位置无关,容器化无法实现热挂载。但仍有价值:spock 5.0.7 升 5.0.8 不用重建服务器镜像,服务器镜像保持精简可审计,spock 发布周期与 PostgreSQL 解耦。
结论:
extension_control_path 配合 ImageVolume(K8s 1.33 beta、1.36 GA)让 PG 18 集群的扩展容器化生产可用。收益最大的是 pgvector、PostGIS 这类按需加载扩展——热挂载、独立版本、服务器镜像永不因扩展补丁重建。Hook 类和后台 worker 类只保留独立版本管理收益。深度集成类扩展,耦合在配置、进程树和复制拓扑里,文件放哪都一样。先搞清楚扩展对服务器做了什么,答案自然清楚。#DevOps #运维 #PostgreSQL #PostgreSQL18 #extension_control_path #Kubernetes #ImageVolume #CloudNativePG #pgvector #PostGIS #spock #容器化
@DevOpsTalkCN
Sysdig 推出 SysQL Skill:用自然语言查询安全图谱
Sysdig 将安全图谱接入 Claude Code,推出 SysQL Skill。现在可以用自然语言直接提问,系统返回验证过的查询、真实的爆炸半径数据和修复优先级建议,无需学习查询语言或操作控制台。
演示中,提问“查找有已知漏洞利用的漏洞”,系统自动生成查询并按严重性排序,CVE-2024-41110(Docker 逃逸,CVSS 9.9)排在首位。追问“多少工作负载受影响”,结果显示为零——漏洞在 Go 依赖里,不在直接关联的工作负载中,系统自动推理图谱关系,最终定位到 quay.io 上的三个 sysdig/vuln-host-scanner 镜像。
对运维工程师来说,价值在于:CVE 披露后 10 小时内漏洞就可能被武器化,而手动评估暴露面往往更慢。SysQL 把“拉数据”变成“问问题”,直接给出修复决策和每个受影响镜像的 fixed-in 版本。适合在告警排查、漏洞响应场景下减少来回切控制台的时间。
#DevOps #运维 #Sysdig #SysQL #ClaudeCode #云安全 #CNAPP #漏洞管理 #MCP #安全图谱
@DevOpsTalkCN
Sysdig 将安全图谱接入 Claude Code,推出 SysQL Skill。现在可以用自然语言直接提问,系统返回验证过的查询、真实的爆炸半径数据和修复优先级建议,无需学习查询语言或操作控制台。
演示中,提问“查找有已知漏洞利用的漏洞”,系统自动生成查询并按严重性排序,CVE-2024-41110(Docker 逃逸,CVSS 9.9)排在首位。追问“多少工作负载受影响”,结果显示为零——漏洞在 Go 依赖里,不在直接关联的工作负载中,系统自动推理图谱关系,最终定位到 quay.io 上的三个 sysdig/vuln-host-scanner 镜像。
查询通过 Sysdig Secure MCP 服务器执行,对安全图谱只有读权限,每次提问都受治理和审计。Sysdig 称之为“无头云安全”:安全能力嵌入工程师已有的工作环境,而不是让人去某个平台操作。
对运维工程师来说,价值在于:CVE 披露后 10 小时内漏洞就可能被武器化,而手动评估暴露面往往更慢。SysQL 把“拉数据”变成“问问题”,直接给出修复决策和每个受影响镜像的 fixed-in 版本。适合在告警排查、漏洞响应场景下减少来回切控制台的时间。
#DevOps #运维 #Sysdig #SysQL #ClaudeCode #云安全 #CNAPP #漏洞管理 #MCP #安全图谱
@DevOpsTalkCN
KEDA 按 SQS 队列深度扩缩容 EKS 工作负载
事件驱动架构里,CPU 和内存利用率往往反映不了真实压力:worker Pod 可能 CPU 空闲,但 SQS 队列里积压着成千上万条消息;流量高峰过去后 Pod 也可能迟迟不缩。对异步队列型负载,积压量才是真正的扩缩容信号。
KEDA 通过轮询 SQS 队列属性计算积压,把目标指标写进 HPA,由 HPA 驱动 Deployment 扩缩。每个 Pod 目标处理 10 条消息(queueLength: "10"),队列为空时可缩到零(minReplicaCount: 0),上限 30 个副本。副本数按「积压消息数 / queueLength」向上取整:0 条→0 Pod,8 条→1 Pod,25 条→3 Pod,95 条→10 Pod。
队列驱动系统里,消息处理延迟直接影响用户和下游。按积压量扩缩能让扩容更快响应突发、队列空时省下闲置成本。这套模式不限于 SQS 和 EKS,其他事件驱动架构和消息平台同样适用——关键是选对能代表真实负载的扩缩容信号。
#DevOps #运维 #KEDA #Kubernetes #EKS #SQS #HPA #AWSPodIdentity #Helm #自动扩缩容
@DevOpsTalkCN
事件驱动架构里,CPU 和内存利用率往往反映不了真实压力:worker Pod 可能 CPU 空闲,但 SQS 队列里积压着成千上万条消息;流量高峰过去后 Pod 也可能迟迟不缩。对异步队列型负载,积压量才是真正的扩缩容信号。
KEDA 通过轮询 SQS 队列属性计算积压,把目标指标写进 HPA,由 HPA 驱动 Deployment 扩缩。每个 Pod 目标处理 10 条消息(queueLength: "10"),队列为空时可缩到零(minReplicaCount: 0),上限 30 个副本。副本数按「积压消息数 / queueLength」向上取整:0 条→0 Pod,8 条→1 Pod,25 条→3 Pod,95 条→10 Pod。
部署要点:
• KEDA 用 Helm 装进独立命名空间:helm install keda kedacore/keda --namespace keda --create-namespace
• worker 的 IAM 权限只给 GetQueueAttributes、GetQueueUrl、ReceiveMessage、DeleteMessage、ChangeMessageVisibility 五个动作,限定单个队列
• TriggerAuthentication 用 podIdentity 对接 AWS,ScaledObject 里 queueURLFromEnv 从环境变量读队列 URL,避免硬编码
• 调参注意:queueLength 按吞吐定,别拍脑袋;cooldownPeriod 和 HPA behavior 控制的是两条不同的缩容路径,要分开调;指标拉不到时建议开 fallback 副本兜底
• 常见坑:不扩容多半是队列 URL 或 IAM 权限问题,看 KEDA operator 日志;副本过多要查 in-flight 消息是否被重复计数(scaleOnInFlight、visibility timeout);缩不到零查延迟消息和未确认消息
队列驱动系统里,消息处理延迟直接影响用户和下游。按积压量扩缩能让扩容更快响应突发、队列空时省下闲置成本。这套模式不限于 SQS 和 EKS,其他事件驱动架构和消息平台同样适用——关键是选对能代表真实负载的扩缩容信号。
#DevOps #运维 #KEDA #Kubernetes #EKS #SQS #HPA #AWSPodIdentity #Helm #自动扩缩容
@DevOpsTalkCN
hot_standby_feedback:用主库膨胀换备库查询不中断
PostgreSQL 备库在回放主库 WAL 时,若主库已 vacuum 掉某行版本,备库上仍依赖该版本的查询会被强制取消,报
代价落在主库身上——vacuum 被拖住,死元组堆积成膨胀。默认关闭正是这个原因:备库查询不应反向限制主库维护。开启是主动选择,且要清楚三点:它只解决清理类冲突,
另一个杠杆是
开启后的运维要点:盯主库
结论:只有读副本的长查询既不能被取消、又必须与主库保持实时时才开。开之前确认你接受主库膨胀,且明白它只挡清理冲突、不挡锁和 drop 冲突。
#DevOps #运维 #PostgreSQL #hot_standby_feedback #数据库 #高可用 #复制
@DevOpsTalkCN
PostgreSQL 备库在回放主库 WAL 时,若主库已 vacuum 掉某行版本,备库上仍依赖该版本的查询会被强制取消,报
canceling statement due to conflict with recovery。hot_standby_feedback 就是用来缓解这个问题的:备库把自己正在运行的最老事务 ID 上报给主库,主库据此推迟清理,避免冲突。代价落在主库身上——vacuum 被拖住,死元组堆积成膨胀。默认关闭正是这个原因:备库查询不应反向限制主库维护。开启是主动选择,且要清楚三点:它只解决清理类冲突,
AccessExclusiveLock(如 DDL、TRUNCATE)和 drop 库/表空间导致的取消它管不了;备库断开期间保护失效,重连后积压的清理可能集中爆发;膨胀上限不会超过同样查询直接跑在主库上的效果,风险是"搬家"而非"新增"。该参数为布尔型,默认 off,context 是 sighup,在备库的 postgresql.conf 或命令行设置。9.1 引入,正是为了补 9.0 Hot Standby 自带的查询取消问题。
备库上报频率受wal_receiver_status_interval限制,默认 10 秒。级联复制中反馈逐级转发直到主库,中间备库只转发不处理。
最大风险是备库上一个被遗忘的 BEGIN 事务无限期拖住主库清理。文档给出的参照系很公允:膨胀不会比同样查询直接跑在主库上更糟。
备库断开期间主库恢复按正常节奏 vacuum,冲突会在重连回放时集中爆发。文档建议调大max_standby_archive_delay缓冲重连窗口,但网络抖动等窄竞态仍可能漏过,只能当强缓解手段而非保证。
另一个杠杆是
max_standby_streaming_delay:让备库等一段时间再取消查询,用备库延迟换主库不膨胀。备库必须实时就跟进用 feedback,允许落后就调大延迟、保持 feedback 关闭。曾被当作第三选项的 vacuum_defer_cleanup_age 已在 PG16 移除,旧配置里见到可视为化石。开启后的运维要点:盯主库
pg_stat_replication 的 backend_xmin 年龄,超阈值告警;查备库 pg_stat_activity 里以小时计的查询;给备库设 statement_timeout 兜底;用 pg_stat_database_conflicts 确认 feedback 是否真的覆盖了你实际遇到的冲突类型。结论:只有读副本的长查询既不能被取消、又必须与主库保持实时时才开。开之前确认你接受主库膨胀,且明白它只挡清理冲突、不挡锁和 drop 冲突。
#DevOps #运维 #PostgreSQL #hot_standby_feedback #数据库 #高可用 #复制
@DevOpsTalkCN
ident_file 配错时 PostgreSQL 会静默启动,认证直接失效
ident_file 这个 GUC 告诉服务器 pg_ident.conf 在哪里。配错时服务器不会拒绝启动,只在日志里留一行没人看的记录,然后继续运行——但所有依赖用户映射的认证方式全部失效。
关键差异:hba_file 和 ident_file 的容错完全不同
排查认证问题时,先 SHOW ident_file,再 SELECT * FROM pg_ident_file_mappings。很多时候答案就是:你精心编辑的文件,服务器从来没读过。
#DevOps #运维 #PostgreSQL #ident_file #pg_hba #认证 #数据库
@DevOpsTalkCN
ident_file 这个 GUC 告诉服务器 pg_ident.conf 在哪里。配错时服务器不会拒绝启动,只在日志里留一行没人看的记录,然后继续运行——但所有依赖用户映射的认证方式全部失效。
关键差异:hba_file 和 ident_file 的容错完全不同
hba_file 指向不存在的文件时,postmaster 直接 FATAL 拒绝启动。但 ident_file 指向不存在的文件时,服务器正常启动,只打一条 LOG,然后带着空的用户映射表运行。postmaster.c 里的注释明确说这是故意的:没有 ident 文件可以启动,只是不能用任何需要映射的认证方式——ident、peer、gssapi、sspi、cert,以及 PostgreSQL 18 新增的 oauth。
后果是:部署上线、健康检查全绿,然后每个依赖 map= 的应用连接都报 no match in usermap。服务没挂,认证没了。
更坑的是 reload 失败
pg_reload_conf() 遇到语法错误的 pg_ident.conf 只会记一条解析错误,之前加载的映射继续留在内存里。你删掉一个映射、改坏语法、reload,被删的映射依然能认证。你以为撤销的映射还活着,直到 postmaster 重启——而重启它的人通常不是你。
怎么查
pg_ident_file_mappings 视图(PG 15+,需超级用户或 pg_read_all_settings)能看到每行的 file_name、line_number、map_name、sys_name、pg_username 和 error,还会解析 include 指令。但注意:它每次查询都重新解析磁盘上的文件,报告的是磁盘状态,不是 postmaster 内存里的状态。失败 reload 的窗口期,视图显示坏文件,服务器却用着已不存在的映射在认证。
设置建议
大多数情况别动它。Debian/Ubuntu 已经配好,指向 /etc/postgresql/NN/main/pg_ident.conf。只有当你把配置外置到 PGDATA 之外做版本控制时,才需要和 hba_file 一起显式设置。ALTER SYSTEM SET ident_file 虽然被允许,但别用——postgresql.auto.conf 本身就在数据目录里,等于把外置配置的指针存在你试图外置的东西里面。
排查认证问题时,先 SHOW ident_file,再 SELECT * FROM pg_ident_file_mappings。很多时候答案就是:你精心编辑的文件,服务器从来没读过。
#DevOps #运维 #PostgreSQL #ident_file #pg_hba #认证 #数据库
@DevOpsTalkCN
idle_in_transaction_session_timeout:一条参数防住锁与膨胀
应用代码不可信,这是 PostgreSQL 提供
机制:每次后端完成一条命令、在事务打开状态下等待客户端时,就启动一个计时器。客户端在超时前无响应,后端就放弃:事务回滚、连接关闭,服务端记录
找出肇事者一条查询即可:
```
SELECT pid, usename, now() - state_change AS idle_for, query
FROM pg_stat_activity
WHERE state LIKE 'idle in transaction%'
ORDER BY idle_for DESC;
```
自动清理就是本参数,建议开启。全局设一个合法负载不会碰到的值:OLTP 系统 5 分钟是合理兜底。因为 context 是 user,可以按角色收紧——连接池应用用户设
#DevOps #运维 #PostgreSQL #数据库 #参数调优 #锁 #vacuum #pg_stat_activity
@DevOpsTalkCN
应用代码不可信,这是 PostgreSQL 提供
idle_in_transaction_session_timeout 的原因。ORM 开启事务后异常退出,连接归还连接池时事务仍开着,这个会话就会一直持有它碰过的所有东西,直到有人发现。该参数就是那个"有人"。默认值为 0(禁用),单位毫秒,最大为 INT_MAX 毫秒(略小于 25 天)。机制:每次后端完成一条命令、在事务打开状态下等待客户端时,就启动一个计时器。客户端在超时前无响应,后端就放弃:事务回滚、连接关闭,服务端记录
FATAL: terminating connection due to idle-in-transaction timeout,客户端下次触碰 socket 时收到该消息(SQLSTATE 25P03)。注意度量的是每次静默间隔,不是整个事务时长——每 4 分钟发一条语句的事务永远不会触发 5 分钟超时。限制总事务时长是 transaction_timeout 的职责(PostgreSQL 17 引入;17 及以上版本若 transaction_timeout 设置不高于本参数,空闲计时器根本不会启动)。空闲事务为什么值得专门处理:它是一捆其他会话都在等待的东西。碰过的每张表至少持有 ACCESS SHARE 锁直到提交或回滚;跑了一条 SELECT 就睡着的会话,几小时后仍握着锁。经典故障链:迁移的 ALTER TABLE 排在睡眠者的 ACCESS SHARE 后面,新查询又排在 ALTER TABLE 待定的 ACCESS EXCLUSIVE 后面,应用宕机而 pg_stat_activity 几乎看不到在跑什么。作者在生产环境诊断过多次这种堆积,根因从来不是 DDL。
还有 vacuum 问题。空闲事务若写过数据,或运行在 REPEATABLE READ / SERIALIZABLE 级别,会钉住 xid 水位线(pg_stat_activity 中可见为 backend_xid 或 backend_xmin),该数据库内任何 vacuum 都无法清理事务开始后死掉的元组。几小时就是到处膨胀,几天就是 wraparound 事故。一个部分豁免:只读的 read-committed 事务在语句之间不持有快照,只钉锁不钉水位线——但泄漏的事务通常都写过东西,所以这安慰有限。aborted 状态的事务已释放锁和快照,只浪费连接槽位,超时杀掉也无妨。纯 idle(无事务)会话什么都不持有,归idle_session_timeout管(PostgreSQL 14 起)。
找出肇事者一条查询即可:
```
SELECT pid, usename, now() - state_change AS idle_for, query
FROM pg_stat_activity
WHERE state LIKE 'idle in transaction%'
ORDER BY idle_for DESC;
```
自动清理就是本参数,建议开启。全局设一个合法负载不会碰到的值:OLTP 系统 5 分钟是合理兜底。因为 context 是 user,可以按角色收紧——连接池应用用户设
ALTER ROLE app SET idle_in_transaction_session_timeout = '1min',给真正需要思考的人类和批任务放宽。但任何会话也能 SET 回 0,所以这是给良性代码的安全带,不是防恶意代码的围栏。RDS 和 Aurora 默认 24 小时而非 0,等于承认问题存在却把响应排到一个工作日之后。触发 5 分钟超时的应用在计时器启动前就已经坏了,FATAL 只是让你知道的方式。#DevOps #运维 #PostgreSQL #数据库 #参数调优 #锁 #vacuum #pg_stat_activity
@DevOpsTalkCN
Cortex 完成 OSTIF 安全审计,7 项发现已全部修复
Cortex 是面向 Prometheus 和 OpenTelemetry 的长周期、多租户可扩展开源存储。OSTIF 联合 Quarkslab 与 CNCF 对其进行了白盒代码审计,重点检查租户边界与集群操作的安全健康度,即这两项功能的机密性、完整性和可用性。
审计于 2026 年初春启动,Quarkslab 两名审计员先进行发现期工作,研究既有威胁模型并与维护者对齐,随后进入静态分析与动态测试阶段。最终报告包含 7 项具有安全影响的发现:6 项中危、1 项低危,并附有修复建议及未来安全开发文档。
#DevOps #运维 #Cortex #Prometheus #OpenTelemetry #CNCF #OSTIF #安全审计 #多租户
@DevOpsTalkCN
Cortex 是面向 Prometheus 和 OpenTelemetry 的长周期、多租户可扩展开源存储。OSTIF 联合 Quarkslab 与 CNCF 对其进行了白盒代码审计,重点检查租户边界与集群操作的安全健康度,即这两项功能的机密性、完整性和可用性。
审计于 2026 年初春启动,Quarkslab 两名审计员先进行发现期工作,研究既有威胁模型并与维护者对齐,随后进入静态分析与动态测试阶段。最终报告包含 7 项具有安全影响的发现:6 项中危、1 项低危,并附有修复建议及未来安全开发文档。
所有 7 项发现均已完成验证修复。建议升级到 Cortex 最新版本,以应用维护者与审计方在本轮工作中的成果。完整审计报告、修复响应及双方博客均已公开,可前往 Cortex 项目官网查阅。
#DevOps #运维 #Cortex #Prometheus #OpenTelemetry #CNCF #OSTIF #安全审计 #多租户
@DevOpsTalkCN
Gateway API v1.6 发布:TCPRoute 与 UDPRoute 转正
Kubernetes SIG Network 于 6 月 30 日发布 Gateway API v1.6.0。本次更新中,TCPRoute 和 UDPRoute 从 Experimental 通道毕业至 Standard,并进入 v1 API 版本。此前 Gateway API 仅对 HTTP 和 TLS 流量提供稳定的路由模型,数据库、DNS、VoIP、游戏、IoT 遥测等基于 TCP/UDP 原始协议的工作负载,只能回退到普通 Service 或实现特定的 CRD,无法在不同 Gateway 控制器间移植。TCPRoute 和 UDPRoute 仅依据协议和端口路由流量到后端,无需 L7 感知即可填补这一空白。v1alpha2 版本自 v1.6 起弃用,将在未来版本移除。
发布当日通过 v1.6 一致性测试的实现包括 Agentgateway、Airlock Microgateway、GKE Gateway、kgateway、NGINX Gateway Fabric、Traefik Proxy。项目仓库在 kubernetes-sigs/gateway-api,可提交 issue、GEP 或 PR。
#DevOps #运维 #GatewayAPI #Kubernetes #TCPRoute #UDPRoute #XBackend #SIGNetwork #服务网格 #Ingress
@DevOpsTalkCN
Kubernetes SIG Network 于 6 月 30 日发布 Gateway API v1.6.0。本次更新中,TCPRoute 和 UDPRoute 从 Experimental 通道毕业至 Standard,并进入 v1 API 版本。此前 Gateway API 仅对 HTTP 和 TLS 流量提供稳定的路由模型,数据库、DNS、VoIP、游戏、IoT 遥测等基于 TCP/UDP 原始协议的工作负载,只能回退到普通 Service 或实现特定的 CRD,无法在不同 Gateway 控制器间移植。TCPRoute 和 UDPRoute 仅依据协议和端口路由流量到后端,无需 L7 感知即可填补这一空白。v1alpha2 版本自 v1.6 起弃用,将在未来版本移除。
使用方式上,Gateway 需配置允许 TCPRoute 挂载的 listener,TCPRoute 再通过 parentRefs 挂载到该 listener 并转发流量到后端。例如,Gateway 监听 12345 端口的 TCP 流量,TCPRoute 将其代理到 my-foo-service 的 6000 端口。省略 parentRefs 中的 sectionName 和 port 会将路由挂载到 Gateway 上所有 TCP listener。UDPRoute 遵循相同模式,只需替换 listener 协议和路由类型。
另一个重点是实验性 API 组分离。此前实验性资源与标准资源共享 gateway.networking.k8s.io 组,仅靠 v1alpha2 版本号区分。新方案将实验性资源定义在独立的 gateway.networking.x-k8s.io 组,API 类型名称加 X 前缀,如 XBackend 和 XMesh。毕业转正时再移入标准组并去掉 X 前缀。这一改动让实验与标准的边界在 API 组层面显式化,不再依赖版本字符串。
v1.6 还引入实验性 XBackend 资源,作为 Service 及其他后端类型的通用装饰器。首个版本支持 ExternalHostname 目的地,这在 Gateway API 中因 confused deputy 攻击风险而被 Service 排除。该能力为 Extended/Optional 特性,实现和用户可在理解安全权衡后选择启用,对集群托管 agentic 工作负载的 egress 场景很有用。注意 XBackend 仍为实验性 API,行为可能变化,不宜用于生产。
发布当日通过 v1.6 一致性测试的实现包括 Agentgateway、Airlock Microgateway、GKE Gateway、kgateway、NGINX Gateway Fabric、Traefik Proxy。项目仓库在 kubernetes-sigs/gateway-api,可提交 issue、GEP 或 PR。
#DevOps #运维 #GatewayAPI #Kubernetes #TCPRoute #UDPRoute #XBackend #SIGNetwork #服务网格 #Ingress
@DevOpsTalkCN
PostgreSQL 假死还是连接失效?五分钟分清
凌晨两点,应用连不上数据库,告警响了。同一周内同一个团队连续报了几次"数据库锁死",但排查下来只有一次是 Postgres 真的挂了,其余都是连接池里的连接悄悄死在了应用和数据库之间。两种故障表象完全一样,处理方式却天差地别——搞混了,最贵的是前十分钟的定位时间。
真正的锁死意味着服务器在操作系统层面已经停止响应,任何客户端、任何路径都开不了新会话,包括直接在机器上跑 psql。原因通常在 Postgres 之下:内核内存回收、存储卷 I/O 无响应、或某个进程占满 CPU 导致新连接无法被调度。已建立的会话可能还在苟延残喘,但新的进不来。
连接失效则常见得多,而且伪装得很好。负载均衡器判定空闲超时断开、NAT 网关老化连接表条目、K8s Pod 重启带走网络命名空间——TCP 会话在两端都没收到干净的 FIN/RST 时悄然结束。Postgres 以为后端还活着,应用以为池里的连接还能用,直到下次有人真正使用它,才报出 connection reset by peer 或驱动层"连接已关闭"的错误。整个过程新连接完全正常,只有池里那些早已建立的连接会失败。
确认是连接失效后,修复思路是让某处在应用发现之前先察觉。Postgres 侧,tcp_keepalives_idle、tcp_keepalives_interval、tcp_keepalives_count 在 postgresql.conf 里默认都是 0,即沿用系统默认——多数 Linux 上首次 keepalive 探测要等两小时。对负载均衡器空闲超时远短于此的生产库,两小时只是形式。显式设置,空闲时间 60 到 120 秒、间隔短的若干次探测,让连接从服务器侧真正保持活跃。Postgres 14 还新增了 client_connection_check_interval,默认 0 关闭,开启后服务器会在查询运行期间周期检查客户端 socket 是否仍连接,提前释放已死的 backend,对长查询尤其有用。
对任何有真实可用性承诺的 Postgres 团队,事故成本从来不在修复本身,而在判断"你到底在看什么"。真锁死和连接失效起点相同,但一个需要数据库介入,另一个只是换条连接、几毫秒重连的事。这套区分方法会了之后五分钟就能查完,跳过它代价远不止五分钟——通常表现为叫错人、重启错服务、或把一个根本不在数据库的问题升级。这个故障模式不罕见,诊断方法第一次遇到时也不直观,值得在告警响起之前就烂熟于心。
#DevOps #运维 #PostgreSQL #连接池 #HikariCP #PgBouncer #TCPkeepalive #故障排查
@DevOpsTalkCN
凌晨两点,应用连不上数据库,告警响了。同一周内同一个团队连续报了几次"数据库锁死",但排查下来只有一次是 Postgres 真的挂了,其余都是连接池里的连接悄悄死在了应用和数据库之间。两种故障表象完全一样,处理方式却天差地别——搞混了,最贵的是前十分钟的定位时间。
真正的锁死意味着服务器在操作系统层面已经停止响应,任何客户端、任何路径都开不了新会话,包括直接在机器上跑 psql。原因通常在 Postgres 之下:内核内存回收、存储卷 I/O 无响应、或某个进程占满 CPU 导致新连接无法被调度。已建立的会话可能还在苟延残喘,但新的进不来。
连接失效则常见得多,而且伪装得很好。负载均衡器判定空闲超时断开、NAT 网关老化连接表条目、K8s Pod 重启带走网络命名空间——TCP 会话在两端都没收到干净的 FIN/RST 时悄然结束。Postgres 以为后端还活着,应用以为池里的连接还能用,直到下次有人真正使用它,才报出 connection reset by peer 或驱动层"连接已关闭"的错误。整个过程新连接完全正常,只有池里那些早已建立的连接会失败。
为什么 Postgres 自己发现不了?TCP 本身没有机制让任一端在连接静默死亡时立刻收到通知。没有主动探测,双方都会无限期认为连接正常,直到某一方尝试发送数据。这正是 TCP keepalive 存在的意义,也是连接池必须在数据库能力之上再做一层健康检查的原因。检测静默死连接默认不是服务器的职责,需要刻意在多层构建。
五分钟排查清单:先在数据库主机上直接建新连接,如果也挂起或拒绝,就是真锁死,去看 OS 层资源(内存、磁盘 I/O、CPU);如果新连接立即成功,Postgres 没问题,进入下一步。检查故障是否只影响事件发生前已建立的连接——同一应用路径下新连接成功而旧池连接失败,就是连接失效的特征。查 Postgres 日志和应用驱动日志,在故障时刻找 reset by peer、broken pipe 或连接已关闭错误。真锁死产生的是静默或超时,连接失效则会在有人使用死 socket 时立刻报出干净的错误。最后查 pg_stat_activity 里受影响的 backend,如果仍显示 idle 且 state_change 时间戳正常,说明服务器从未感知到异常,问题完全发生在 Postgres 之外。
确认是连接失效后,修复思路是让某处在应用发现之前先察觉。Postgres 侧,tcp_keepalives_idle、tcp_keepalives_interval、tcp_keepalives_count 在 postgresql.conf 里默认都是 0,即沿用系统默认——多数 Linux 上首次 keepalive 探测要等两小时。对负载均衡器空闲超时远短于此的生产库,两小时只是形式。显式设置,空闲时间 60 到 120 秒、间隔短的若干次探测,让连接从服务器侧真正保持活跃。Postgres 14 还新增了 client_connection_check_interval,默认 0 关闭,开启后服务器会在查询运行期间周期检查客户端 socket 是否仍连接,提前释放已死的 backend,对长查询尤其有用。
连接池侧,HikariCP 的 maxLifetime 默认 30 分钟,4.0 加入的 keepaliveTime 默认关闭。把 keepaliveTime 设得明显短于 maxLifetime,且短于应用与数据库之间网络路径上最紧的空闲超时,让轻量验证查询频繁流动,中间设备就不会回收连接。PgBouncer 的 server_idle_timeout 默认 600 秒,管 PgBouncer 与 Postgres 之间空闲连接的存活;client_idle_timeout 默认 0 禁用,不会主动关闭面向客户端的空闲连接。很多团队以为 PgBouncer 默认端到端处理了这件事,其实要显式配置。
网络路径上,负载均衡器、NAT 网关、服务网格几乎都有各自的空闲超时,通常比预期短。AWS ALB 默认 60 秒,NLB 默认 350 秒。平台各有差异但模式一致:中间设备最终会丢弃静默连接。keepalive 间隔必须短于这个数字,而不是反过来。注意 idle_in_transaction_session_timeout 和 statement_timeout 解决的是完全不同的问题——它们管的是客户端连接着但行为恶劣(持事务不释放、跑慢查询),跟网络层已静默死亡的连接毫无关系,别拿它们来治连接失效。
对任何有真实可用性承诺的 Postgres 团队,事故成本从来不在修复本身,而在判断"你到底在看什么"。真锁死和连接失效起点相同,但一个需要数据库介入,另一个只是换条连接、几毫秒重连的事。这套区分方法会了之后五分钟就能查完,跳过它代价远不止五分钟——通常表现为叫错人、重启错服务、或把一个根本不在数据库的问题升级。这个故障模式不罕见,诊断方法第一次遇到时也不直观,值得在告警响起之前就烂熟于心。
#DevOps #运维 #PostgreSQL #连接池 #HikariCP #PgBouncer #TCPkeepalive #故障排查
@DevOpsTalkCN