关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

2026 SkyWalking链路追踪服务器租用部署攻略:采样率/存储/ES资源对比实测

发布时间:2026-09-24

2026 SkyWalking链路追踪服务器租用部署攻略:采样率/存储/ES资源对比实测

把 SkyWalking 从"能跑起来"推到"能长期稳定跑",中间隔着的是硬件选型这道坎。Apache SkyWalking 作为 Apache 软件基金会的顶级开源项目,在国内的落地密度非常高,但绝大多数故障并不是出在 SkyWalking 自身的功能上,而是出在服务器资源给错了地方:CPU 给了 OAP,磁盘却随便挂了一块;内存堆到了 32GB,Elasticsearch 却连 page cache 都分不到;采样率拍脑袋定的 100%,上线三天后 OAP 节点雪崩。这篇文章不谈探针怎么接、UI 怎么点,只谈一件事——自建一套 SkyWalking 可观测性平台,服务器到底该怎么选。

下面的分析全部基于公开的技术事实与工程经验推演,涉及量级的地方统一标注为(预估)、(行业经验值)或(按经验值估算),最终数值请以实际压测与线上实测为准。文中不引用任何虚构的基准测试数据与客户案例。

SkyWalking 的三段式架构与资源压力分布

SkyWalking 的部署形态可以清晰地切成三段。第一段是 Agent,也就是探针,它以 Java Agent 的形式通过字节码增强驻留在业务 JVM 内部,负责在方法调用边界创建 Span、在跨进程调用中传播上下文、并把数据上报给后端。第二段是 OAP,也就是 Observability Analysis Platform,负责接收数据、做流式聚合、构建服务拓扑、计算指标并驱动告警。第三段是 Storage,也就是持久化层,Storage 在 SkyWalking 中是可插拔设计,常见选择包括 Elasticsearch,也可以根据场景选择其他数据库实现。

这三段对硬件资源的诉求完全不同。Agent 是寄生在业务进程里的,它吃的是业务所在那台机器的 CPU 时间和少量堆内存,压力分散、单点量小,但实例数量成百上千时总量不可忽视。OAP 是纯计算节点,吃的是 CPU 与内存,而且是内存常驻型的吃法——窗口内的中间聚合态必须留在内存里,不能落盘。Storage 吃的是磁盘 IO、内存(JVM 堆与操作系统缓存)以及一部分 CPU(用于倒排索引构建与段合并)。

真正需要认真做硬件选型的,是后两段。把预算压在 Agent 所在的业务机上没有意义,把预算平均分给三台机器同样没有意义。一个合理的资源画像大致是:OAP 段是 CPU 密集加内存常驻,Storage 段是磁盘 IO 密集加内存缓存依赖,而 Agent 段只需要保证业务机本身有 10% 上下的余量即可(行业经验值,以实测为准)。

理解这一点之后,后面所有的选型讨论都会变得清晰:你要买的不是"一台跑 SkyWalking 的服务器",而是"一组计算节点"加"一组存储节点",这两组节点的硬件规格几乎不应该相同。

Agent 探针驻留在业务进程里,吃掉的是什么

SkyWalking 的 Java Agent 采用无侵入的字节码增强方式,业务代码不需要改一行,这一点是它相对很多同类方案的核心优势。但无侵入不等于零开销,探针的开销主要由三部分组成:类转换阶段的启动开销、运行期 Span 创建与上下文传播的对象分配开销、以及序列化与上报的 CPU 开销。

启动开销体现在 premain 阶段。探针需要在类加载时完成字节码改写,插件越多、被增强的类越多,应用启动时间增加得越明显。对于启动时间敏感、需要频繁弹性扩缩容的服务,这部分开销需要在灰度阶段就量出来,而不是等到大促扩容时才发现新实例拉起慢了一截(行业经验值,以实测为准)。

运行期开销与埋点密度直接相关。每创建一个 Span 就意味着一次对象分配、一次线程本地变量的读写,以及跨服务调用时请求头里上下文的注入与提取。HTTP 客户端、数据库驱动、消息队列客户端、RPC 框架这几类插件是埋点最密集的地方。如果应用本身是高并发短请求模型,Span 创建频率会非常高,CPU 占用率的抬升会更明显。

还有一个常被忽略的点:探针的上报队列是有界的。当 OAP 端处理能力不足或者网络抖动时,Agent 侧的队列会积压,队列满之后探针的策略是丢弃而不是阻塞业务线程。这个设计保护了业务,但也意味着你在 UI 上看到的链路数据可能是不完整的,而业务侧毫无感知。因此 Agent 的丢弃日志必须纳入监控,它是 OAP 端资源不足的第一信号。

OAP 的接收、聚合与拓扑构建:CPU 与内存的主战场

OAP 的工作可以拆成四条并行的流水线。第一条是接收,常见默认配置下 OAP 通过 gRPC 端口 11800 接收 Agent 上报,通过 HTTP 端口 12800 提供查询与部分上报能力。接收层要做 protobuf 反序列化、做基本的校验,这是一段纯 CPU 工作,且随 Span 量线性增长。第二条是 L1 聚合,也就是在接收节点本地先做一次窗口内的预聚合,把细碎的 Span 归并成可计算的数据结构。第三条是 L2 聚合,在集群模式下,L1 的结果会按照某种一致性策略分发到指定节点做全局聚合,这一层要处理跨节点的数据交换。第四条是拓扑构建与指标持久化,把服务之间的依赖关系、实例级别的指标按不同时间粒度写入 Storage。

这四条流水线里,CPU 压力主要集中在反序列化、聚合计算与拓扑推导;内存压力则集中在窗口中间态。所谓窗口中间态,是指在一个分钟级窗口还没有关闭之前,这个窗口内所有服务的响应时间分布、错误计数、实例维度的中间累加量,都必须留在内存里等待最终结算。窗口没关,这些数据就不能释放。这意味着 OAP 的内存占用不是随流量瞬时波动的,而是有一个相当稳定的"底盘",流量越大、服务数越多、实例数越多,这个底盘越大。

拓扑构建同样吃内存。SkyWalking 要在内存里维护服务、实例、端点三级节点以及它们之间的调用边,一个中等规模微服务体系的服务实例轻松上千,端点(接口维度)数量往往是服务数的十倍以上。维度的膨胀比数据量的膨胀更容易压垮 OAP,这也是为什么很多团队的数据量看起来不大,OAP 却频繁触发 Full GC 的原因。

结论很直接:OAP 节点的选型应该偏向"多核 + 大内存",而对本地磁盘几乎没有要求。OAP 本身不持久化业务数据,本地磁盘只要能装下日志即可。给 OAP 节点配大容量高性能磁盘,是典型的资源错配。

采样率是整条链路的成本总闸

如果整篇文章只能留下一个结论,那就是:采样率决定了后面所有硬件的成本。采样率是一个乘数,它同时乘在 OAP 的 CPU 消耗、OAP 的内存底盘、Elasticsearch 的写入 IOPS 与磁盘容量上。采样率从 100% 降到 10%,并不是省了 90% 的某一个环节,而是整条链路的资源消耗同时降到接近十分之一。

SkyWalking 的探针侧通常提供基于时间窗口的采样配置,例如每 3 秒采样 N 条这类参数(常见配置项命名以 sample_n_per_3_secs 为代表,具体名称以对应版本的官方文档为准),同时也可以配置对错误链路或慢请求进行强制采样。全量采样在小规模、低 QPS 或者排查专项问题期间是可接受的,但对于日均请求量在千万级以上的系统,全量采样几乎必然带来资源灾难。

为什么采样率的杠杆这么大?因为一条链路不是一条记录,而是一棵树。一个用户请求在微服务体系里可能横跨七八个服务,产生十几到几十个 Span,每个 Span 都要被反序列化、被聚合、被写进 Elasticsearch 并参与后续的段合并。入口处减少 90% 的采样,末端减少的同样是 90%,中间没有任何环节能够打折。

所以采样率的决策必须前置到硬件采购之前。先定采样率,再算写入量,再定磁盘容量与节点规格,这个顺序不能颠倒。很多团队是先买了服务器、再把采样率开到 100%、最后发现撑不住才开始降采样率,这个顺序下多花的硬件钱是完全可以避免的。

从日均请求量到日写入量:一套可手算的估算方法

下面给出一套不依赖任何实测数据、只用业务侧已知量就能手算的估算方法,全部系数均为(按经验值估算),请务必以实测校准。

第一步,确定日均入口请求量 Q,这个数字一般能从网关或者 Nginx 访问日志里直接拿到。第二步,确定单请求平均产生的 Span 数 S。Span 数取决于调用链深度,一个请求串联 5 个服务、每个服务产生 2 到 3 个 Span(入口 Span、客户端调用 Span、数据库访问 Span)是相当常见的结构,因此 S 取 8 到 15 是一个可用的区间(行业经验值)。第三步,确定单个 Span 落到存储后的体积 U。一条 Span 记录包含 trace id、父 Span id、服务名、实例名、端点名、耗时、标签等字段,标签越多体积越大,常见量级在数百字节到 1 到 2KB 之间(按经验值估算)。第四步,乘上采样率 R。

于是日写入原始量的估算公式为:日写入量 ≈ Q × S × U × R。举例:日均入口请求 2000 万,S 取 10,U 取 1KB,采样率 100%,则日写入量约为 200GB;采样率降到 10%,约为 20GB;采样率降到 1%,约为 2GB。这三个数字对应的是三套完全不同的硬件预算,而它们之间只差一个配置参数。

需要强调的是,这只是写入 Elasticsearch 之前的原始量。Elasticsearch 会为每条记录建立倒排索引、保存原始文档、维护 Doc Values 等结构,落盘后的实际占用会明显大于原始量,这部分膨胀在下一节的容量公式里用膨胀系数统一处理。另外,上面的估算只覆盖了链路数据,没有覆盖 SkyWalking 自身产生的指标数据(服务级、实例级、端点级的分钟级指标)与拓扑数据,这部分量通常远小于链路数据,但在服务实例数量极大时不应当被忽略(预估)。

降低采样率的代价:样本稀疏与排查能力的折损

采样率不是可以无限下调的旋钮。它每降一档,省钱是确定的,但代价是排查能力的不确定性上升。

先说一个好消息:SkyWalking 的采样判定发生在链路入口,采样标记会随上下文一路传播到下游所有服务,因此同一条链路上的 Span 要么全采、要么全不采,不会出现一条 trace 在 UI 上断成半截的情况。这一点对排查体验至关重要,也是选型时值得写进评估表的特性。

问题出在低频事件上。假设某个接口日均失败 20 次,采样率 1% 意味着平均每天只能看到 0.2 条异常链路,也就是大约五天才能碰到一次。如果这个故障的触发条件还和特定参数、特定用户、特定地域相关,那么采样后的样本几乎不可能覆盖到它。长尾问题、低频定时任务、灰度流量、夜间低峰期的偶发抖动,这些都是低采样率下的盲区。

一个更合理的做法是分层采样而不是全局一刀切:核心交易链路维持较高采样率(例如 20% 到 50%),边缘查询链路与内部管理后台降到很低(例如 1% 到 5%),同时对错误响应与超过阈值耗时的请求做强制全采样(行业经验值,以实测为准)。这样既能把总体写入量压在可控区间,又能保证真正需要排查的样本不被抽走。SkyWalking 支持对慢请求与错误请求做侧重保留,这正是分层策略能落地的基础。

还有一层代价容易被忽视:采样率降低之后,基于链路数据算出来的统计指标(比如 P99 耗时)的置信度也会下降。样本越少,尾部分位数越不稳。如果你们的 SLO 报表直接从链路数据里出,那么采样率下调之前需要先确认报表口径能否容忍这个误差,必要时应改用指标通道而非链路采样数据。

OAP 堆内存、直接内存与 OOM 高发的原因

OAP 是一个 Java 服务,但它比大多数 Java 服务更容易 OOM,原因有三条。

第一条是常驻中间态。前面说过,窗口没关闭之前中间聚合结果必须留在内存里,这部分内存是刚性的,不随 GC 而释放。流量上涨时它涨,服务与实例维度膨胀时它也涨,而且涨上去之后不容易降回来,因为窗口是持续滚动的。

第二条是堆外内存。OAP 的接收层基于 gRPC 与 Netty,网络收发必然使用直接内存缓冲;同时 protobuf 反序列化过程中也会产生大量临时对象。很多团队在容器里只设置了 JVM 堆上限,认为堆不超就安全,结果进程被 cgroup 的 OOMKiller 直接杀掉——因为总内存 = 堆 + 元空间 + 线程栈 + 直接内存 + 各类本地库开销,其中堆只占一部分。给容器设置内存上限时,堆上限通常应明显小于容器上限,留出余量给堆外部分(行业经验值,以实测为准)。

第三条是突发流量下的队列积压。当 GC 停顿或者后端 Storage 写入变慢时,接收队列会迅速堆积,而队列里的对象都是活的、无法回收,堆占用会陡增。如果此时又触发了一次 Full GC,停顿时间拉长,队列继续积压,就可能进入"GC 停顿—队列积压—堆占用上升—再次 GC"的恶性循环,最终 OOM。这也是为什么 OAP 的 GC 配置必须保守:堆的初始值与最大值应设为相同,避免运行期扩容带来的抖动;使用 G1 收集器时也要关注停顿目标与区域大小的合理性。

量级建议(预估,以实测为准):小规模部署(日均采样后 Span 量在千万级)OAP 堆配置 4 到 8GB、2 到 4 核即可起步;中等规模(亿级)建议 8 到 16GB 堆、4 到 8 核,并至少部署 2 个节点做冗余;大规模(十亿级以上或实例数过千)建议单节点 16GB 以上堆、8 核以上,并横向扩展到多节点分担 L1 与 L2。无论哪一档,都建议把堆的初始值与最大值设为一致,并给堆外内存预留充足空间。

Elasticsearch 作为默认存储时的索引与分片设计

当 Storage 选择 Elasticsearch 时,绝大部分运维复杂度就从 SkyWalking 转移到了 Elasticsearch 身上。SkyWalking 会在 ES 中按数据类型建立不同的索引,链路记录、指标、拓扑各有归属,并按时间维度滚动创建。

索引滚动粒度是最先要定的参数。常见默认配置按天滚动,也就是每天生成一批新索引;写入量极大的场景可以改成按小时滚动。判断依据很简单:单个索引里的单个分片保持在 20GB 到 50GB 量级是比较舒服的状态(行业经验值)。如果按天滚动导致每天单分片超过 50GB,就该考虑按小时滚动或者增加主分片数;如果每天的数据量只有几个 GB,按天滚动并只用 1 个主分片反而更健康。

分片数开太大是新手最常犯的错误。分片不是免费的,每个分片都是一个完整的 Lucene 索引,有自己的 segment 文件、有自己的内存开销、有自己在集群状态里的元数据。分片数开到几十上百,而每天数据量只有几个 GB,就会出现典型的"小分片爆炸":集群分片总数迅速破万,集群状态更新变慢、节点恢复时间拉长、堆内存被分片元数据吃掉一大块,最终查询反而更慢。正确做法是让分片数跟着数据量走,用索引模板固化主分片数,并随数据增长按天生效新的分片数配置。

副本数决定冗余与写入放大的平衡。副本数为 1 意味着每份数据存两份,写入量直接翻倍(bulk 请求要在主分片与副本上都完成),但换来的是单节点故障时不丢数据、且读请求可以分摊。对于链路追踪这种"丢了不致命、但重建很麻烦"的数据,副本 1 是常见默认配置下的合理选择;副本设为 0 在磁盘紧张时很诱人,但节点磁盘故障时会直接丢掉对应时间段的数据。反过来,副本设 2 以上对于追踪数据通常没有必要,写入放大与磁盘成本都会明显上升(行业经验值)。

写入侧还有几个直接影响 IO 的调优点:适当调大 refresh 间隔可以降低 segment 生成频率,从而减少段合并压力;批量写入的 bulk 大小与并发数需要匹配磁盘能力,过大反而会造成请求堆积;translog 的刷盘策略决定了宕机时可能丢失的数据窗口,需要在可靠性与 IO 之间取平衡。这些都属于通用 Elasticsearch 调优范畴,不因 SkyWalking 而改变,但正因为 SkyWalking 是持续高写入场景,这些参数的影响会被放大。

最后一条,也是本文最想强调的:Lucene 的索引文件是通过操作系统的 page cache 来加速随机读写的,Elasticsearch 的 JVM 堆并不能替代它。如果一台 64GB 内存的机器把 48GB 都分给了 ES 堆,那么留给 page cache 的只剩十几 GB,索引文件的随机访问会大量穿透到磁盘,性能会出现数量级级别的下降(按经验值估算,以实测为准)。业界长期以来的经验是把堆控制在 30GB 上下、并把剩余内存的相当大一部分留给操作系统缓存,而不是把内存尽量堆给 JVM。

磁盘 IO:整套系统里唯一真正的硬件瓶颈

在 OAP 与 Storage 分离部署之后,整套 SkyWalking 平台里几乎只有 Elasticsearch 节点存在真正的磁盘压力。OAP 只写日志,UI 只做查询转发,业务机上的 Agent 只写自己的应用日志。所有的追踪数据写入、索引构建、段合并、历史查询,全部压在 ES 的数据盘上。

为什么必须是 SSD 甚至 NVMe?关键在于段合并。Elasticsearch 的写入并不是"写进去就完了",后台会持续把多个小 segment 合并成大 segment,这个过程要读取多个文件、排序、写出新文件、再删除旧文件,是典型的随机读写混合负载。合并跟不上写入速度时,Elasticsearch 会主动限流写入,极端情况下会拒绝写入请求,此时 SkyWalking 的表现就是 UI 上数据断档、链路查不到。

机械硬盘在这种负载下会彻底卡死。一块企业级机械盘的随机 IOPS 量级在百级,而 SATA SSD 在数万级,NVMe 更高(行业经验值)。注意这里比的是随机 IOPS 而不是顺序带宽——很多服务器销售话术强调"读写多少 GB/s",那是顺序带宽,对 Elasticsearch 的数据盘几乎没有参考价值。采购时应当关注 4K 随机写的 IOPS 与写延迟,以及设备在长时间高负载下是否会出现掉速(部分消费级固态在持续写入后会触发限速,服务器场景务必选择企业级或数据中心级介质,并确认稳态写入表现)。

还有一个部署层面的禁忌:不要把 ES 数据盘放在网络存储或共享文件系统上。这类存储的延迟与一致性特征与本地盘差异很大,而 Lucene 对文件操作的延迟极其敏感,且分布式文件系统在节点故障恢复时的行为与本地盘不一致,容易引发索引损坏风险。ES 自身的副本机制已经提供了冗余能力,不需要在存储层再叠一层共享存储。

监控上建议盯住三个指标:磁盘的 IOPS 与 await(IO 等待时间),ES 的段合并线程队列长度与合并节流次数,以及写入请求的拒绝计数。这三项任何一个持续恶化,都说明磁盘已经是瓶颈,而不是 CPU 或内存。

保留期与磁盘容量:一个线性公式与两档算例

链路数据的价值随时间快速衰减,因此保留期(TTL)是第二个成本闸口,而且它和磁盘容量是严格的线性关系。保留期从 7 天延长到 30 天,磁盘需求就是 4 倍多一点,没有任何优化空间可以规避这一点——除非减少写入量,也就是回到采样率。

容量估算公式(按经验值估算):实际容量 ≈ 日写入原始量 × 保留天数 × (1 + 副本数) × 膨胀系数。其中膨胀系数覆盖倒排索引、Doc Values、原始文档存储、未回收的 segment 与 translog 等额外占用,通常取 1.2 到 1.5(行业经验值,标签字段越多取值越大)。

算例一,7 天档:沿用前面的例子,采样后日写入原始量 20GB,副本数 1,膨胀系数取 1.3,则实际容量 ≈ 20 × 7 × 2 × 1.3 ≈ 364GB。考虑运行期余量,实际采购时建议按 500GB 到 600GB 可用容量规划(预估)。

算例二,30 天档:同样是 20GB 日写入、副本 1、系数 1.3,则实际容量 ≈ 20 × 30 × 2 × 1.3 ≈ 1560GB,也就是 1.5TB 出头。考虑 segment 合并过程中的临时空间与水位线余量,实际规划建议 2TB 以上可用容量(预估)。可以看到,仅仅是保留期从 7 天拉到 30 天,磁盘就从半 TB 级跳到 2TB 级,而且这还没有算上副本为 2 或者采样率上调的情况。

Elasticsearch 自身有磁盘水位线机制,常见默认配置下磁盘使用率到达高水位时会触发分片迁移,到达更高的 flood stage 水位后索引会被置为只读,写入直接失败。这意味着磁盘不能用到接近 100% 才扩容,通常应把长期水位控制在七成以下,给段合并的临时空间与节点故障时的分片重新分布留出缓冲(行业经验值)。

保留期的落地手段有两种:一种是在 SkyWalking 侧配置数据保留期,由它按时间清理;另一种是在 Elasticsearch 侧通过索引生命周期管理定期删除过期索引。两者选其一即可,但必须有其一,绝不能只靠"磁盘快满了人工删"这种不可控的方式。删除过期索引是最直接有效的方式,因为它是整索引删除,几乎不产生 IO 放大;而按条件删除文档会触发大量更新与后续合并,属于应该避免的做法。

网络链路:gRPC 长连接、集群内交换与跨公网的禁忌

Agent 到 OAP 是 gRPC 长连接。单个业务实例与 OAP 之间维持的连接数很少,但实例总量大,因此 OAP 侧要面对的是"连接数多、单连接流量小"的模型。这对带宽的要求并不高,但对连接的稳定性、延迟以及 OAP 侧的文件描述符与线程资源有要求。压测时需要关注的是并发连接数与每秒请求数,而不是字节带宽。

OAP 集群内部的数据交换则完全不同。L1 聚合结果要分发到负责 L2 的节点,节点之间还要做服务发现与状态同步,这部分流量是实打实的数据流,对内网带宽与延迟都有要求。集群协调组件在 SkyWalking 中有多种可选实现(常见包括 Kubernetes、Zookeeper、Nacos 等,具体以对应版本的官方文档为准),无论选哪一种,都必须保证 OAP 节点之间处于同一内网、延迟极低且稳定。

OAP 与 Elasticsearch 之间是批量写入,这是整套系统里流量最大的一段。按 20GB 日写入量计算,平均速率约 0.25MB/s 左右,看起来很小,但写入是高度突发的,峰值往往是均值的数倍(按经验值估算),而且段合并期间的数据重分布也会占用带宽。千兆内网对中小规模足够,万兆内网能提供更从容的余量(预估)。

最重要的一条原则:OAP 与 Elasticsearch 必须同机房内网互联,不要跨公网传输追踪数据。原因有四:公网延迟抖动会直接放大写入延迟,进而引发 OAP 队列积压;公网带宽的单位成本远高于内网,而追踪数据量不小;追踪数据里可能包含接口名、参数标签等敏感信息,走公网需要额外的加密与合规成本;公网链路的丢包与重传会让 gRPC 的表现极不稳定。

如果业务确实分布在多个地域,正确的做法是在每个地域各自部署一套 OAP 与 Storage,由 UI 层聚合查询,而不是让 Agent 跨地域上报到中心 OAP。跨境场景尤其如此,例如业务同时覆盖内地与中国香港节点时,应按地域分域部署,各自独立成栈。对于需要跨地域访问的控制台流量,可以选用优化回程线路或专属带宽来保障查询体验,但追踪数据的写路径绝不应依赖跨公网链路。

OAP 无状态、ES 有状态:两种截然不同的扩容路径

OAP 的设计是无状态的,这是它最友好的工程特性之一。OAP 节点本身不持久化业务数据,所有状态都在 Storage 里,因此扩容 OAP 就是"多起一个进程、接到同一个 Storage、加进集群"这么简单,前面挂负载均衡即可分摊 Agent 的上报连接。这让 OAP 层可以用非常廉价的方式水平扩展,甚至在流量高峰临时加节点、过后再摘掉。

但无状态是有前提的。前提一是 Storage 必须是共享的外部存储,如果把 OAP 配置成本地存储(部分实现支持单机模式下的本地库),那么 OAP 立刻变成有状态,扩容就无从谈起。前提二是不要把任何业务状态写进 OAP 节点的本地文件,包括自定义的插件输出、临时缓存、甚至一些团队习惯性放置的本地配置快照。前提三是 Agent 侧的负载均衡策略要合理,避免所有连接长期集中在某一个节点上。

Elasticsearch 的扩容则完全是另一回事。ES 是有状态服务,加节点意味着分片要重新分布,数据要在节点间搬迁,这个过程会消耗大量磁盘 IO 与网络带宽,期间集群性能会明显下降。节点下线同样麻烦,需要先排除分片再停机。这意味着 ES 集群的规模应该在规划阶段就尽量定准,而不是"先小规模试试,不够了再加"。

由此得出一个很实用的选型原则:OAP 层可以按当前需求起步,留出横向扩展的余量;Storage 层则应该在第一天就按半年到一年的数据增长规划容量,宁可磁盘多留一些。把预算的重点放在存储节点上,通常是更划算的分配方式(行业经验值)。

另外,ES 集群的节点角色划分也值得提前考虑。专用主节点、数据节点、协调节点的分离在中大规模集群上几乎是必须的,因为主节点负责集群状态管理,一旦被数据写入的高负载拖累,整个集群的稳定性都会受影响。小规模部署可以先用单一角色简化运维,但架构上应预留拆分的空间。

三档参考配置:从十人团队到千级实例

下面给出三档参考配置(预估)。请注意,这些数字是基于前文估算方法的量级推演,不是任何实测结果,实际选型必须以压测与线上观测为准。表中"日均采样后 Span 量"指的是经过采样率折算之后真正进入系统的 Span 数量,而非业务侧原始请求量。

档位 日均采样后 Span 量(预估) OAP 节点规格(参考配置·预估) Elasticsearch 集群(参考配置·预估) 磁盘类型与容量(7 天保留·预估) 内网要求(预估)
小团队 / 验证型 千万级以内 1 至 2 节点,4 核 8GB 至 16GB,堆 4 至 8GB,本地盘 100GB 单节点或 2 节点,8 核 32GB,堆不超 30GB,副本 0 至 1 SATA 或 NVMe SSD,可用容量 200 至 400GB 千兆内网即可满足
中型 / 百级服务 亿级 2 至 3 节点,8 核 32GB,堆 8 至 16GB,本地盘 200GB 3 节点,16 核 64GB,堆 30GB 上下,副本 1,主分片按天 1 至 2 企业级 NVMe SSD,可用容量 600GB 至 1TB 千兆内网,建议万兆余量
大型 / 千级实例 十亿级以上 4 节点以上,16 核 64GB,堆 16GB 以上,本地盘 200GB 5 节点以上,32 核 128GB,堆 30GB 上下,主节点与数据节点分离,副本 1 企业级 NVMe SSD 多盘,可用容量 2TB 以上 万兆内网,延迟稳定在毫秒级以内
中型档 + 30 天保留 同中型档数据量 OAP 规格不变,仅 Storage 侧扩容 节点数不变,磁盘容量按 4 倍余量规划 企业级 NVMe SSD,可用容量 2TB 以上 同中型档,段合并期需额外带宽余量

这张表最常见的误读是把 OAP 的规格和 ES 的规格当成"一台机器"的数字。它们是两个独立的资源池,只有在极小规模、资源确实紧张的情况下才考虑混部,而即便混部,也必须严格控制内存划分,这一点在后面的避坑清单里会展开。

另一个容易误读的点是磁盘容量那一列。它给的是"可用容量",也就是扣除副本、膨胀系数与水位线余量之后实际需要采购的容量,而日写入量那一栏的口径是原始写入量。两者之间是副本数与膨胀系数的关系,不要直接拿日写入量乘以天数和容量列做对比,会得出完全错误的结论。

SkyWalking 与 Zipkin、Jaeger 的取舍判断

同为分布式链路追踪方案,三者的定位差异比功能清单上的差异更重要。

SkyWalking 最突出的优势是无侵入的 Java Agent 探针。通过字节码增强,业务代码不需要引入依赖、不需要手工埋点,这在存量系统规模庞大、改造成本高的组织里是决定性的。除此之外,SkyWalking 不只是链路追踪,它自带了完整的应用性能监控能力:服务与实例的指标、自动构建的服务拓扑、端点级别的响应时延分布、以及可配置的告警。换句话说,它是一个一体化程度较高的 APM 平台,而不只是一个 trace 收集器。它同时支持通过 gRPC 与 HTTP 上报,也支持接入 OpenTelemetry 体系的数据,这让它在异构技术栈里的适应能力比外界印象中要强。

Zipkin 与 Jaeger 则更轻。它们的模型更聚焦在 trace 本身,部署与运维复杂度更低,资源占用也更小,与 OpenTelemetry 生态的结合更为紧密,对于已经全面采用 OpenTelemetry SDK 做统一采集的组织,接入路径会更短。如果你们的技术栈不是 Java 为主,或者已经有了成熟的指标与告警体系、只需要补上链路这一块,那么这两个方案的整体成本可能更低。

选型判断的依据可以收敛成三条。第一,看主力技术栈:以 Java 为主、且存量服务难以改造,SkyWalking 的探针优势会直接转化为落地速度。第二,看是否已有指标体系:如果 Prometheus 加 Grafana 已经覆盖了指标与告警,只需要 trace,那么更轻的方案更匹配;如果希望一套系统同时解决拓扑、指标、链路与告警,SkyWalking 的一体化更有价值。第三,看运维人力:SkyWalking 的后端(尤其是搭配 Elasticsearch 时)运维复杂度明显高于 Zipkin 或 Jaeger,如果团队没有专人维护 Elasticsearch,那么"轻方案搭配轻量存储"可能比"重方案搭配重存储"更现实。

还有一个现实的中间路线:用 OpenTelemetry 统一采集,后端仍选择 SkyWalking 承接。这样既保留了探针与二次开发的灵活度,又不会把采集侧锁死在单一厂商的协议上。这条路线对服务器的资源要求与本文分析的一致,因为资源压力取决于数据量与存储选型,而不取决于采集协议。

部署避坑清单:十六条来自现场的教训

第一条,分片数开太大导致小分片爆炸。每天只有几个 GB 数据却配了 10 个主分片,一年下来集群分片数轻松破万,集群状态更新变慢、节点重启恢复时间以小时计。分片数必须由数据量倒推,且用索引模板固化。

第二条,没有索引生命周期管理导致磁盘写满。链路数据是持续增长的,靠人工删索引一定会出事。要么在 SkyWalking 侧配置数据保留期,要么在 Elasticsearch 侧配置索引生命周期策略,二者必选其一,并且要在上线前验证策略真的生效。

第三条,把 OAP 和 Elasticsearch 混部在一台机器上。两者都是内存大户,且 ES 还强依赖操作系统缓存,混部的结果是双方互相挤压,ES 的分片元数据被堆挤掉、OAP 的窗口中间态被 GC 拖累。小规模验证可以临时混部,但只要数据上有量就应该拆开。

第四条,采样率 100% 直接上线。这是最高频的一次性事故。新接入时数据看着不多,一旦全量铺开到所有服务,写入量会成十倍地增长。正确做法是先按低采样率接入、观察资源曲线、再逐步上调。

第五条,忽略探针本身对业务进程的开销。没有评估启动时间增量、没有评估 CPU 占用抬升、没有配置探针的资源保护策略,就直接全量铺开。正确做法是选一两个代表性服务做灰度对比,量出启动时间与 CPU 的变化(以实测为准)。

第六条,Elasticsearch 堆内存设置超过 31GB,导致压缩指针失效。堆超过这个阈值后,对象引用的压缩优化不再生效,同样的对象会占用更多内存,实际可用堆反而下降。常见建议是堆不超过 30GB 上下,并且不超过物理内存的一半,剩下的留给操作系统缓存(行业经验值)。

第七条,把 OAP 做成了有状态。用了本地存储、在节点上写了本地文件、或者让 Agent 直连单一节点而没有负载均衡,这些都会让"OAP 可以水平扩展"这个特性失效。扩容困难往往不是架构问题,而是这些细节累积出来的。

第八条,时区与时钟配置不一致导致 UI 上数据断档。OAP、Elasticsearch、UI 以及业务机器之间的时区设置必须统一,机器之间必须有时间同步。时区不一致时,按天滚动的索引边界会错开,查询时间范围与数据实际落盘的时间范围对不上,表现为某个时间段"查不到数据",而数据其实一直都在。

第九条,只监控 OAP 进程是否存活。OAP 活着不代表它在正常处理数据。必须监控接收队列长度、Agent 侧丢弃计数、写入 Storage 的失败与重试次数,以及端到端的数据延迟。这几项才是真实健康度。

第十条,把 Elasticsearch 数据盘放在网络存储或共享文件系统上。延迟与一致性特征不满足 Lucene 的要求,恢复行为也与本地盘不同,存在索引损坏风险。冗余应该由 ES 副本提供,而不是由存储层提供。

第十一条,副本数设为 0 上线。磁盘压力小了很多,但任何一块盘故障都会直接丢掉对应时间段的数据,且不可恢复。至少保留 1 个副本,这是追踪数据能接受的最低冗余(行业经验值)。

第十二条,把机器内存全部分给 JVM 堆,没有给操作系统缓存留空间。结果是索引文件的随机访问大量穿透到磁盘,段合并与查询都变慢。这是本文反复强调的一条,也是性能调优里性价比最高的一条。

第十三条,Agent 与 OAP 版本不匹配。探针与后端之间有协议约定,版本跨度过大时可能出现数据格式不兼容,表现为部分数据能查到、部分数据丢失,排查起来非常费时。升级时应按官方兼容说明推进,并分批次灰度。

第十四条,防火墙只放行了 HTTP 端口而遗漏了 gRPC 端口。Agent 上报走的是 gRPC,端口不通时探针会持续重试并最终丢弃,UI 上什么都没有,日志里却是一堆连接失败。上线前应当从业务机直接验证到 OAP 的端口连通性。

第十五条,容器环境只设置了堆上限。总内存超过容器限制时进程会被直接杀掉,而 JVM 完全来不及记录任何堆转储信息,现场难以复盘。堆上限必须小于容器内存上限,并预留元空间、线程栈与直接内存的空间。

第十六条,告警规则直接照搬默认或者设得过于激进。微服务体系里一次底层抖动会同时触发上游几十个服务的告警,值班人员被通知风暴淹没之后,真正重要的告警反而被忽略。告警应当按服务等级分层配置,并设置合理的持续时间与收敛规则。

租用服务器时的硬件关注点与交付前检查项

如果选择租用物理机或裸金属来承载这套平台,采购的关注点应当和前面分析的瓶颈严格对齐。

存储节点优先看四件事:介质类型必须是数据中心级固态盘,需要确认长时间持续写入下的稳态表现而不是峰值标称;随机写 IOPS 与写延迟是核心指标,顺序带宽参考意义有限;内存容量要同时满足 JVM 堆与操作系统缓存,通常堆占一半以内、其余留给缓存;网络必须是同一机房内网互联,并确认内网带宽与延迟指标。

计算节点(也就是 OAP 与 UI)优先看 CPU 核数与内存容量,磁盘只要够装日志即可,不需要高性能介质。如果预算有限,宁可把钱从 OAP 的磁盘上挪到 ES 的内存上,这个取舍在绝大多数场景下都是正确的(行业经验值)。

交付前应完成一组基本检查:从业务机到 OAP 的 gRPC 端口连通性测试;从 OAP 到 Elasticsearch 的写入连通性与延迟测试;磁盘的随机写 IOPS 实测(建议用通用压测工具跑 4K 随机写,持续足够长的时间以观察稳态);内存与 swap 配置确认(Elasticsearch 节点通常建议禁用 swap 或将其降到极低);时间同步与时区一致性检查。这几项做完,后面踩坑的概率会明显下降。

在带宽形态的选择上,如果控制台需要跨地域访问,可以优先考虑优化回程线路或专属带宽的产品形态,以保障查询与页面加载体验;但如前文所述,追踪数据的写入链路应当始终留在同一内网,不应依赖跨地域链路。一万网络深耕 19 年(成立于 2007 年),在服务这类可观测性平台的服务器租用场景中,更建议把注意力放在介质型号、内网带宽与可扩容性这三项上,而不是单纯比较 CPU 型号与内存条数。

最后再强调一次口径:本文给出的所有量级数字均为(预估)或(按经验值估算),目的是提供一个可推导的选型起点,不能替代压测。真正的选型闭环应该是——按本文公式估算出一个起点配置,用真实流量压测一周,观察 OAP 的 GC 与队列、观察 Elasticsearch 的段合并与磁盘 await,然后再决定是调采样率、加 OAP 节点,还是扩存储。这个闭环跑过一轮之后,你手上的数字会比任何公开参考都更可靠。


上一篇:网页能打开但大文件传不动:隧道里的MTU和MSS到底出了什么问题

下一篇:做海湾本地合规接入,迪拜节点的"贵"到底贵在哪一环