干运维这些年,我遇过最离谱的一次 Puppet 事故是这样的:一个八百来节点的环境,某天有人把 agent 的 runinterval 从 30 分钟改成 5 分钟,理由是"配置改完要等半小时才生效,太慢了"。改完当天下午,Puppet Server 的 catalog 编译队列堆到几百,agent 大面积超时,紧接着 PuppetDB 的磁盘在一周内涨了三十几个 GB。全程没加机器、没改模块,就动了一个数字。
这件事说明一个很基础但经常被人忽略的事实:Puppet 的容量不是一个"多少节点就配多大机器"的静态问题,而是一个"节点数 × 单次编译耗时 ÷ runinterval"的除法题。分母一动,需求立刻成倍变。下面这几条是全文最值得记住的判断,先摆出来:
一、JRuby 实例数就是 catalog 编译的并发上限。max-active-instances 决定同一时刻能有几个节点在编译,默认值通常等于 CPU 核数减一(旧版本默认 1,得手动调)。一个 JRuby 一次只编译一个节点,纯粹串行。
二、缩短收敛间隔是容量翻车的头号原因。1000 节点、单次编译 3 秒、30 分钟间隔,平均并发只有 1.7;间隔压到 5 分钟,并发需求立刻变 10。同样的机器,撑不撑得住全看分母。
三、堆内存要按"JRuby 数 × 单实例内存"累加。每个 JRuby 几百 MB 量级,常见按 512MB–1GB 估,再加 JVM 自身与 code cache。16 个 JRuby 拍一个 2G 进去,只会不停 Full GC。
四、真正的磁盘压力在 PuppetDB,不在 Puppet Server。Server 本身几乎不落盘,PuppetDB 是唯一持续写入、持续增长的组件,增长速度等于"节点数 × 上报频率 × facts 体积"。
五、GC 与 TTL 是磁盘生死的闸门。gc-interval 默认 60 分钟,node-ttl / report-ttl 默认保留 14 天量级。关掉清理或者把 TTL 拉得太长,库涨到上百 GB 只是时间问题。
Puppet 是标准的 C/S 架构,但很多人对"一次 agent run"里到底谁在忙、忙在哪一步没概念,结果配机器全靠猜。先把链路拆开看,后面所有容量数字才立得住。
Agent 端跑着定时任务,默认 runinterval 是 30 分钟,到点就向 Puppet Server 发一次请求。这一趟大致分五步:一是插件同步(pluginsync),把 Server 上 modules 里的自定义 fact、自定义类型拉下来;二是上报 facts,Agent 把自己采集到的系统信息打包发给 Server;三是 Server 编译 catalog,这是整个链路里唯一吃 CPU 的重活;四是 Agent 下载 catalog 以及 catalog 里引用的文件(file 资源指向的源文件走 fileserver);五是本地 apply,Agent 在本机把资源收敛到目标状态。
第五步是纯本地行为,跑多久、占多少 CPU 都是节点自己的事,完全不消耗 Server 资源。这点很重要——有人看到 apply 慢就去扩容 Server,方向完全反了。Server 真正被消耗的只有"编译 catalog"和"分发文件"两件事,其中编译是 CPU 密集,分发是 IO 与带宽账。
编译完成后,Server 会把这次的 facts、catalog、report 三样东西转发给 PuppetDB(通过 puppetdb terminus)。也就是说,每个节点每跑一次 agent,PuppetDB 至少要吃三次写入:一份 facts、一份 catalog、一份 report。这三份里 facts 体积随自定义 fact 数量线性增长,catalog 体积随模块复杂度与资源数量增长,report 数量则严格等于"节点数 × 每天运行次数"。
算一下就有感觉了:1000 个节点、30 分钟间隔,一天就是 48 轮 × 1000 节点 = 48000 次上报。如果间隔改成 5 分钟,一天变成 288 轮,上报次数直接翻 6 倍,PuppetDB 的写入量和磁盘增长也跟着翻 6 倍。很多人只盯着 Server 的 CPU,等磁盘告警了才发现 PuppetDB 早就满了。
链路里还有一个经常被低估的环节:facts 的体积是会自己膨胀的。默认 fact 就那么几十项,可一旦业务往 facter 里塞自定义 fact——应用版本、容器列表、挂载点清单、甚至把某个配置文件的内容整个采上来——单节点 facts 从几十 KB 涨到几百 KB 是很自然的事。而 facts 每次上报都要完整写一份,这个膨胀会原封不动地传导到磁盘增速上。所以清理无用自定义 fact,是成本最低的一项容量优化。
Puppet Server 跑在 JVM 上,用 JRuby 实例去执行 Ruby 代码——你的 manifests、Hiera 数据、ERB 模板,全是在这些 JRuby 里跑出来的。核心参数就是 max-active-instances,它直接决定同一时刻能有几个节点在编译。
这个参数的默认值通常等于 CPU 核数减 1(留一核给 JVM 自身和操作系统),旧版本里默认是 1,必须手动调,否则你给一台 32 核机器,它一次也只编译一个节点,剩下 31 核闲着。我接手过的环境里,至少有三分之一还停留在默认值没动过,机器买得很豪横,性能却很差,原因就在这。
关键性质是:catalog 编译是纯 CPU 活,而且一个 JRuby 实例一次只编译一个节点的 catalog,串行执行。它没有线程内并发,也没有异步让出——一个节点占住一个 JRuby,编译完才释放。所以并发能力严格等于 JRuby 实例数,多一个节点排队就得多等一轮。
单次编译耗时则完全取决于你的代码复杂度。Hiera 层级多、模块多、ERB 模板嵌套深、到处调自定义函数,单节点编译几秒很常见;写得很克制的环境,一秒以内也能做到。这里给个经验区间:轻量环境 0.5–1 秒,中等复杂度 2–4 秒,重度 Hiera + 大量模板 5–10 秒。这个数字必须实测,方法是在Server 上看 catalog 编译的耗时统计,或者直接拿 puppet catalog compile 单节点计时,别拍脑袋。
有了这两个数,容量换算就很直白了:需要的 JRuby 数 ≈ 节点总数 × 单次编译耗时 ÷ runinterval。这个式子是全文的主干,后面几节都围着它转。
把公式里的分母换一下,感受一下什么叫线性放大。同样 1000 个节点,同样单次编译 3 秒:
间隔 30 分钟(1800 秒):1000 × 3 ÷ 1800 ≈ 1.67,平均并发不到 2,一台 4 核机器绰绰有余。间隔 10 分钟(600 秒):1000 × 3 ÷ 600 = 5,需要 5 个 JRuby,8 核机器够用。间隔 5 分钟(300 秒):1000 × 3 ÷ 300 = 10,需要 10 个 JRuby,得上 16 核左右。间隔 1 分钟(60 秒):1000 × 3 ÷ 60 = 50,需要 50 个 JRuby,堆内存按 1GB/实例算是 50GB,这已经不是加一台机器的问题了。
注意这只是平均值。真实场景里节点不会均匀分布,同一时刻涌进来几十个请求是常态——cron 撞车、批量上线、网络恢复后的补偿性重连,都会形成尖峰。按平均值配机器,尖峰时队列就会堆积,表现是 agent 报编译超时。经验做法是在平均值基础上留 1.5–2 倍的余量,1000 节点 3 秒编译 5 分钟间隔,我会直接按 16–20 个 JRuby 配,而不是刚好 10 个。
那到底该不该缩短间隔?我的判断很明确:大多数业务根本不需要 5 分钟。配置管理的价值在于"最终一致"和"漂移自愈",30 分钟足够覆盖绝大多数运维场景。真正需要分钟级收敛的只有少数情况——安全基线紧急下发、证书轮换这种。遇到这些场景,正确做法是走 MCollective 类的编排通道做一次性触发,或者用 Bolt 推,而不是把全量 runinterval 压下去,让整个集群为少数几次紧急变更买单。
还有个容易被忽略的点:runinterval 缩短不仅放大 CPU 需求,也同步放大 PuppetDB 的写入量与磁盘增长,因为上报次数同样按倍数增加。这是双份账单,改之前两边都要算。
说完 CPU 说内存,这里的错误更普遍。很多人装完 Puppet Server,看着配置文件里的 -Xms2g -Xmx2g 觉得"两G够了吧",然后 JRuby 实例加到 8 个、16 个,内存参数一动不动,就开始莫名其妙地卡。
正确的算法是累加:总堆需求 ≈ JRuby 实例数 × 单实例内存 + JVM 自身开销 + code cache。每个 JRuby 实例要占几百 MB 量级的堆,常见按 512MB–1GB 估,具体取决于你的模块加载量和 catalog 大小。JVM 自身(元空间、线程栈、GC 结构)再加 1–2GB,code cache 单独给 256–512MB。
举几个直观的数:8 个 JRuby × 512MB ≈ 4GB,加上开销配 6–8GB 堆;16 个 JRuby × 1GB = 16GB,加上开销要配 20–24GB 堆;32 个 JRuby × 1GB = 32GB,整机内存得往 64GB 走。你看,从 4 核小机到 64GB 大机,中间只差一个 JRuby 数的变化。
另外两个实操建议。一是 Xms 和 Xmx 设成一样,避免运行时扩容带来的停顿,Puppet Server 这种常驻服务尤其明显。二是别把整机内存吃满,要留出 PuppetDB(如果同机部署)、操作系统页缓存和 PostgreSQL 的空间。JRuby 数不是越多越好,超过 CPU 核数之后,多出来的实例只会抢 CPU 时间片、多占内存,编译吞吐不再提升,反而因 GC 压力下降。这条很反直觉但很实在:JRuby 数超过物理核数就是负优化。
再补一句判断依据:用 GC 日志而不是看内存占用率来决定要不要加堆。堆给小了的典型症状不是"内存满了",而是编译耗时出现长尾——大部分节点 2 秒编译完,偶尔一批要 20 秒,看 CPU 也不高,这基本就是 GC 在回收。把 GC 日志打开、看暂停时间的占比,比盯着监控图上的内存曲线有用得多。同理,如果发现加堆之后吞吐没变化,就该回头看是不是核数已经到顶了,而不是继续加内存。
Puppet Server 本身几乎不落盘——它编译完就把结果转发出去了,本地只有日志和代码目录。真正有持续写入、持续数据增长的是 PuppetDB,一个独立的 PostgreSQL 服务,存 facts、catalog、report 三类数据。
它的增长模型可以写成:磁盘增速 ≈ 节点数 × 每天运行次数 × 单次上报体积。三个因子都可以估:节点数是已知的;每天运行次数等于 1440 ÷ runinterval(分钟);单次上报体积里,facts 通常几十 KB 到几百 KB(自定义 fact 多的话更大),catalog 几十 KB 到几百 KB(资源数多的话更大),report 相对小但数量大。
拿 1000 节点、30 分钟间隔、单次三样合计按 100KB 估算,一天的量就是 1000 × 48 × 100KB ≈ 4.8GB/天。看着不大?乘上保留周期就吓人了:14 天保留就是 67GB,30 天保留是 144GB。要是把间隔压到 5 分钟,同样 14 天保留就是 400GB 往上。这就是为什么我反复说,改 runinterval 之前要同时算 CPU 和磁盘两笔账。
介质选择上没什么可商量的:PuppetDB 的 PostgreSQL 必须用 SSD。它的写入模式是大量小写入(每个节点每次上报都是若干条记录),同时每隔一小时还有一次大删除(GC 清掉过期数据)。删除之后 PostgreSQL 要做 vacuum 回收空间,机械盘上 vacuum 会严重拖垮正常写入,表现为节点上报排队、PuppetDB 响应变慢,最后 agent 卡在 facts 上传这一步。SATA SSD 是底线,规模上去了直接上 NVMe。
PuppetDB 自带垃圾清理(GC)机制,两个参数管着:gc-interval 默认 60 分钟,也就是每小时跑一次清理;node-ttl 与 report-ttl 决定数据保留多久,默认是 14 天量级,可以按自己的合规与查询需求调。
这套机制的意思是:PuppetDB 的磁盘占用在正常配置下会收敛在一个稳态——新数据进来,老数据被清走,用满一个 TTL 周期后磁盘就不再增长。稳态大小大约等于"单周期数据总量 × 1.5"(要留出 vacuum 回收前的空间)。这个"会收敛"的特性,是它能长期稳定运行的前提。
而最常见的磁盘事故,恰恰来自把这个前提破坏掉。一是关掉 GC——有人嫌 GC 期间 IO 高、影响上报,把 gc-interval 调成 0 或者设成几天一次,于是数据只进不出;二是把 TTL 拉得过长——为了"能查半年前的节点状态",把 report-ttl 设成 180 天甚至更长,等于把稳态大小乘了十几倍;三是两件事一起做,那基本就是在给磁盘写倒计时。
我处理过的真实案例里,一个 1200 节点的环境,因为 TTL 被改成永久保留,八个月后 PuppetDB 库涨到 400 多 GB,vacuum 一次要跑几个小时,白天根本跑不完,最后只能停机重建。重建的代价不只是时间:PuppetDB 里的历史 facts 与 report 是很多自动化流程(比如合规审计、变更回溯)的数据源,清库等于把这些能力一起清掉。
务实的做法是分层:PuppetDB 保留 7–14 天,够查问题就行;需要长期留存的 report 另外导出到日志系统或对象存储,那里便宜得多,也不影响 PuppetDB 的写入性能。同时盯住两个指标——库大小的变化曲线,以及 vacuum 的执行时长。vacuum 时长突然变长,通常就是 GC 配置出问题或者 SSD 性能到顶的信号。
把这前面的推演落成具体配置,按节点规模分四档。需要说明的是,下面的 JRuby 数与内存都按"单次编译 3 秒、runinterval 30 分钟、留 1.5–2 倍余量"这组前提算的,你的环境如果编译耗时是 8 秒,就按比例放大。
| 节点规模 | Puppet Server 配置与 JRuby 数 | PuppetDB 与 PostgreSQL | 磁盘与保留策略 | 适用业务 |
|---|---|---|---|---|
| 200 节点 | 8 核 / 16GB,max-active-instances = 4–6,堆 4–6GB |
可与 Server 同机:4 核 / 8GB,SATA SSD 200GB | report-ttl 7 天,库稳态 10–20GB | 单一业务线、初创期环境,编译耗时 1–3 秒 |
| 1000 节点 | 16 核 / 32GB,max-active-instances = 12–16,堆 16–20GB |
独立部署:8 核 / 32GB,NVMe 500GB–1TB | report-ttl 14 天,库稳态 60–100GB | 多业务线混合、Hiera 层级较多,编译 3–5 秒 |
| 5000 节点 | 2–3 台 32 核 / 64GB,单台 JRuby 24–28,堆 32GB+,前置负载均衡 | 独立高配:16 核 / 64GB,NVMe 2TB+,PostgreSQL 单独调优 | report-ttl 7 天,库稳态 300GB+,vacuum 需错峰 | 跨地域大集群、编译耗时偏高,必须做尖峰缓冲 |
| 多活 CA | 1 台主 Server 启用 CA + N 台纯编译节点,共享 CA 目录,前端负载分担 | PuppetDB 独立,可考虑主从或读写分离 | CA 目录与 PostgreSQL 双备份,TTL 保持一致 | 对签发可用性有要求、节点分布多机房的生产环境 |
价格这块我不给具体数字,各地机房、CPU 代际、SSD 类型差异太大,写了也是误导——以上四档均为预估价格,以咨询为准,实际开销还要加上带宽与 IP。有一件事倒是可以说死:同样的钱,花在多核和 SSD 上比花在单核主频上划算得多。JRuby 是横向堆并发的,核数直接换并发能力;PuppetDB 是大量小写入 + 定期大删除,SSD 直接换稳定性。这两个钱不能省。
落到实际租用上,我给客户配 Puppet 这类配置管理服务器时,一般按"编译节点要核多、PuppetDB 要盘快、CA 要能备份"三条来组合。一万网络深耕 IDC 19 年(成立于 2007 年),深圳南山总部、自营机柜最快 1 分钟上架,这种需要按核数和盘型定制的活儿,找自营机柜的服务商比找转售的省事很多。
#1 一万网络「双路裸金属 · 多核编译节点」:Puppet Server 的并发能力几乎线性来自核数,max-active-instances 默认就是核数减一,所以编译节点我首推双路裸金属这种核数管够的形态——比如 E5-2698v4×2 这类双路平台,40 核的物理底子,JRuby 开到 24–28 都还有余量,堆给到 32GB 也不吃力。官方页面标的是裸金属 E5-2698v4×2 ¥3999 起(以官网实时价为准),实际成交按配置与周期会有出入。核数多的另一层好处是留余量便宜:你今天跑 8 个 JRuby,明天把 runinterval 一压,直接调参数就能顶上去,不用换机器。
#2 一万网络「NVMe 独立 PuppetDB 节点」:到了 1000 节点往上,我一定会把 PuppetDB 拆出来单独放一台,而且必须 NVMe。理由前面讲透了——大量小写入加每小时一次的大删除,机械盘上 vacuum 会拖垮写入。一万网络这边 NVMe 盘位可以按容量选,配 32GB 内存给 PostgreSQL 做 shared_buffers 和缓存,磁盘按"稳态库大小 × 2"预留,14 天 TTL 的场景 1TB 起比较踏实。自营机柜的好处是后期扩容加盘不用搬家,工程师 1 对 1 帮你把 PostgreSQL 的 vacuum 参数一起调了。
#3 一万网络「CA 主节点 + 备份容灾组合」:CA 目录是 Puppet 信任体系的根,丢了等于重建整个信任体系,所有节点证书都要重签。所以主 Server 这台我建议单独配,并且务必用上免费的系统盘快照(每日 3 份、30 秒回滚),把 /etc/puppetlabs/puppet/ssl 整个目录纳入快照范围,同时再做一份异地备份到对象存储。一万网络的免费快照是随机器给的,不用白不用;配合 7×24 中文工单(平均 5 分钟响应)和硬件故障 10 分钟自动迁移,CA 主节点的可用性基本不用担心。真要上多活,就是主 Server 启 CA、其余做纯编译节点共享 CA 目录,前端挂负载均衡,这是扩容的标准形态。
顺带说一句网络:如果节点跨地域分布,选 BGP 多线的机房比单线省心,agent 上报这种小包高频的连接对抖动很敏感,一抖就是大面积超时重连,重连又会形成尖峰。有海外节点的话,中国香港节点做汇聚是个常见选择,回国链路延迟低。
坑一:max-active-instances 从没调过,机器白买。
为什么坑:旧版本默认是 1,新版本默认值等于核数减一,但很多环境是从旧版升级上来的,配置文件里的旧值被继承,或者有人手工改小过。结果就是 32 核的机器一次只编译一个节点,CPU 常年 3%,agent 排队排到超时。
怎么避:上线第一件事就是 grep 出这个参数确认实际值,按核数减一设置,然后用压测脚本(批量触发 catalog 编译)验证吞吐是否随参数提升。升级大版本后要重新核一遍配置,别信默认值。
坑二:为了"更快生效"把 runinterval 压到 5 分钟甚至 1 分钟。
为什么坑:并发需求 = 节点数 × 编译耗时 ÷ runinterval,分母缩小几倍,JRuby 需求就放大几倍,堆内存、PuppetDB 写入量、磁盘增长同步放大。改的人往往只看到"生效更快",没算账。
怎么避:改之前先把公式算一遍,确认现有机器的 JRuby 数和堆够不够。真要紧急下发,用 Bolt 或编排工具做一次性触发,别动全量间隔。改完当天盯住编译队列长度和 PuppetDB 库大小曲线。
坑三:堆内存拍一个 2G,JRuby 加到十几个。
为什么坑:每个 JRuby 占几百 MB 量级(按 512MB–1GB 估),16 个实例就是 8–16GB,再加 JVM 自身与 code cache,2G 的堆只会导致频繁 Full GC,表现为编译耗时突然飙长、节点大面积超时,看起来像 CPU 不够,其实是内存。
怎么避:按"JRuby 数 × 单实例内存 + 开销"累加计算,Xms 与 Xmx 设成相等。监控 GC 暂停时间,暂停占比超过 5% 就该加堆了。同时记住 JRuby 数别超过物理核数,超了是负优化。
坑四:PuppetDB 关掉 GC 或 TTL 设成永久。
为什么坑:PuppetDB 是唯一持续增长的组件,稳态靠 GC 与 TTL 维持。关掉清理或把 TTL 拉到半年以上,库会一路涨到几百 GB,vacuum 跑到几小时,白天根本跑不完,最后只能停机重建,历史 facts 和 report 一起丢。
怎么避:gc-interval 保持默认 60 分钟,report-ttl 设 7–14 天。需要长期留存的 report 导出到日志系统或对象存储,别留在 PuppetDB 里。库大小变化曲线和 vacuum 时长要纳入日常监控。
坑五:CA 目录没备份,autosign 配置图省事。
为什么坑:Puppet 自带 CA,所有节点证书签发都在 Server 上,CA 目录丢失等于重建整个信任体系,重签证书的工程量在千节点规模下是灾难级的。而 autosign 配置不当(比如放开整个网段、用通配符)等于给内网任何一台机器发合法证书,等于把配置下发权限拱手让人——配置管理服务器是能批量执行任意命令的高危资产。
怎么避:CA 目录纳入系统盘快照 + 异地备份双保险,并定期演练恢复。autosign 只在受控的装机阶段临时开启,或者用基于预共享密钥的策略脚本做一次性签发,绝不放开网段或通配符。
坑六:把几 GB 的大文件塞进 fileserver 走 Puppet 分发。
为什么坑:文件服务(fileserver / puppetserver 的文件分发)走的是 IO 与带宽账,跟 catalog 编译完全两码事。几 GB 的安装包被几百个节点同时拉,Server 网卡和磁盘先扛不住,连带把 catalog 请求的响应也拖慢,表现出来是"Puppet 变卡了",但查 CPU 又没什么异常。
怎么避:大文件走对象存储或内部镜像源,Puppet 只下发指向地址的配置文件。确实要用 fileserver 的,把文件服务和 catalog 服务在容量规划上分开算,必要时拆到独立节点,并给文件分发单独限流。
Q1:max-active-instances 到底设多少合适,是不是越多越好?
不是越多越好。这个值决定同时能编译几个节点的 catalog,一个 JRuby 一次只编译一个,串行执行。合理的起点是 CPU 核数减一(留一核给 JVM 和系统),再用公式"节点数 × 单次编译耗时 ÷ runinterval"算出平均并发,在这个基础上留 1.5–2 倍余量应对尖峰。超过物理核数之后,多出来的实例只能抢时间片、多占内存(每个几百 MB 量级),吞吐不再提升,GC 压力反而上升,属于负优化。所以正确顺序是先算需求,再看核数够不够,不够就换核更多的机器,而不是硬堆参数。
Q2:1000 个节点、30 分钟间隔,需要多大的机器?
按单次编译 3 秒算,平均并发是 1000 × 3 ÷ 1800 ≈ 1.67,理论上 4 核都够。但真实场景有尖峰——批量上线、网络恢复后的补偿重连、cron 撞车都会让请求集中到达,所以我会按 12–16 个 JRuby 配,也就是 16 核 / 32GB,堆给到 16–20GB(16 个实例 × 1GB 再加 JVM 与 code cache 开销)。PuppetDB 建议独立部署,8 核 / 32GB 配 NVMe 500GB 起,14 天 TTL 下库稳态在 60–100GB。如果你的编译耗时是 8 秒,上面所有数字乘以 2.7。
Q3:runinterval 设成多少最合适,能不能设成 1 分钟?
大多数业务 30 分钟完全够用。配置管理的价值在于最终一致和漂移自愈,不是实时性。设成 1 分钟的代价很直接:1000 节点 3 秒编译的并发需求从 1.67 变成 50,需要 50 个 JRuby、50GB 堆,PuppetDB 的写入量和磁盘增长也同步放大 30 倍,这个账单没有任何业务能 justification。真要分钟级生效,用 Bolt 或者编排工具做定向一次性触发,只推需要变更的节点,成本几乎为零。一句话:改间隔是全局成本,定向触发是局部成本。
Q4:PuppetDB 能不能和 Puppet Server 装在一台机器上?
200 节点以下可以,省一台机器的钱,代价是资源竞争和故障域合并。1000 节点往上我坚决反对同机部署:PuppetDB 的写入模式是大量小写入加每小时一次大删除,vacuum 起来会吃掉 IO,跟 catalog 编译抢资源,两边一起抖。而且两者的数据重要性不同——Server 挂了换个节点就能接管,PuppetDB 挂了要恢复数据。分开部署后,扩容也是各自独立:编译节点不够就加核,PuppetDB 磁盘不够就加盘,互不牵扯。
Q5:PuppetDB 的磁盘为什么会一直涨,怎么控制?
因为它存 facts、catalog、report 三类数据,每个节点每跑一次 agent 都要写三份,是全体系唯一持续增长的组件。增长速度约等于"节点数 × 每天运行次数 × 单次上报体积",1000 节点 30 分钟间隔、单次按 100KB 算就是 4.8GB/天。控制靠两件事:一是 gc-interval 保持默认 60 分钟,让清理按时跑;二是 node-ttl / report-ttl 设 7–14 天,让库收敛在稳态。需要长期留存的 report 导出到日志系统或对象存储,别留在库里。盯住库大小曲线和 vacuum 时长,这两个指标异常通常就是配置出问题的早期信号。
Q6:PuppetDB 的磁盘为什么一定要 SSD,机械盘不行吗?
机械盘能跑,但迟早出事。PuppetDB 的写入模式很特殊:一边是每个节点每次上报带来的大量小写入,一边是每小时一次的大批量删除(GC 清过期数据)。删除之后 PostgreSQL 要 vacuum 回收空间,机械盘上 vacuum 是随机 IO 密集操作,会严重拖垮正常写入,表现为上报排队、查询变慢,最后 agent 卡在 facts 上传。SATA SSD 是底线,规模上去直接 NVMe。磁盘容量按"稳态库大小 × 2"预留,因为 vacuum 回收之前空间不会立刻释放。
Q7:多台 Puppet Server 做负载分担时,CA 怎么处理?
CA 功能只能在单台主 Server 上启用,其余节点配成纯编译节点,共享同一份 CA 目录,前端挂负载均衡分发 catalog 请求——这是扩容的基本形态。千万别在两台机器上同时启用 CA,证书签发会出现分裂。主 CA 这个节点是整个信任体系的根,/etc/puppetlabs/puppet/ssl 目录必须做快照 + 异地备份双保险,并定期演练恢复:目录丢了等于重建整个信任体系,千节点规模下重签证书是灾难级工作量。另外 CA 相关的请求不能走负载轮询,要定向到主 Server。
Q8:Agent 侧的 apply 很慢,是不是该扩容 Puppet Server?
方向反了。Agent 的 apply 是纯本地行为,在本机收敛资源状态,完全不消耗 Server 资源,慢是节点自己的 CPU、磁盘 IO 或者包管理器的锅,跟 Server 配置无关。Server 只负责编译 catalog 和分发文件这两件事。不过要注意,apply 慢会让单次 agent run 变长,如果 runinterval 设得比 run 时长还短,就会出现上一轮没跑完下一轮又启动的情况,间接推高并发——这种情况应该把间隔拉开,或者优化 apply 本身(减少包资源、合并 exec),而不是扩容 Server。真正能帮 Server 降压的是关掉不需要的 report 上报。
把全文收成一句话就是:Puppet 的容量是一道除法题,不是一道配置题。需要的 JRuby 数 ≈ 节点总数 × 单次编译耗时 ÷ runinterval,分子由你的代码复杂度决定,分母由你的运维诉求决定,缩短收敛间隔会线性放大 JRuby 与堆需求——这是绝大多数翻车的起点。而真正的磁盘压力不在 Puppet Server 上,Server 几乎不落盘,持续写入、持续增长的是 PuppetDB 那个独立的 PostgreSQL,它的增速等于节点数 × 上报频率 × facts 体积,稳态靠 gc-interval 与 TTL 维持,关掉清理就是把库往百 GB 上推。
所以钱该花在哪,我的立场很明确:第一笔钱花在核数上,JRuby 并发几乎线性来自核数,40 核的双路平台比 8 核高频 U 有用得多;第二笔钱花在 NVMe 上,PuppetDB 的大量小写入加定期大删除,机械盘上 vacuum 迟早拖垮写入;第三笔钱花在备份上,CA 目录是信任体系的根,丢了就是全量重签。至于 runinterval,除非有明确的紧急下发诉求,30 分钟别动——这一个数字保守住,容量、内存、磁盘三笔账都能省下一大半。真要分钟级收敛,走定向触发,别让整个集群为少数几次变更买单。
本文涉及的 Puppet 架构参数(runinterval 默认 30 分钟、max-active-instances 默认核数减一、gc-interval 默认 60 分钟、node-ttl / report-ttl 默认 14 天量级)均来自 Puppet 官方配置文档;容量换算与配置档位为工程推演值,实际以你的环境实测为准。一万网络相关机型、价格与服务能力,参见一万网络官网 https://www.idc10000.net/ 的服务器租用与裸金属页面;文中提及的价格均为预估价格,以咨询为准,具体以签约时最新报价与合同为准。一万网络深耕 IDC 19 年(成立于 2007 年),深圳南山总部,自营机柜最快 1 分钟上架,提供 7×24 中文工单(平均 5 分钟响应)、硬件故障 10 分钟自动迁移、免费系统盘快照与网站备案协助、5–20G 免费 DDoS 防护。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品