前面 14 篇我们已经把大模型链路的采集、拆解、关联、告警、存储选型全部打通。但所有这些能力都建立在一个前提上:SkyWalking 自身是稳定可用的。如果 OAP 是单节点,它一宕机,全公司的链路监控就黑屏,正在发生的大模型事故你将完全失明。

本篇是阶段收官,讲如何把 SkyWalking 从"单机演示"升级为"生产级高可用":OAP 横向扩成无状态集群,存储用多节点 ES 加副本,前置负载均衡,并通过故障演练验证真正的高可用。落地这套架构,你才算真正具备"线上大模型性能问题 7x24 可观测"的能力。

  1. 为什么单节点不够:高可用诉求
  2. 整体架构:OAP 集群 + 高可用 ES
  3. 部署实战:OAP 无状态集群
  4. 高可用存储:ES 多节点 + 副本
  5. 负载均衡与网关接入
  6. 灰度发布与故障演练
  7. 最佳实践与踩坑

1. 为什么单节点不够:高可用诉求

单机 OAP 有三道致命单点:

第一,进程单点。OAP 挂了,Agent 上报失败(数据丢失或堆积在 Agent 缓冲),UI 打不开,告警停发。而在大模型高峰,恰恰最容易因写入压力把单 OAP 压垮。

第二,存储单点。即使是 ES,单节点磁盘损坏 = 历史 Trace 全丢,事故复盘无据。

第三,升级单点。改 OAP 配置或升级版本,必须停服,期间监控空白。

高可用的目标不是"永远不挂"(那不现实),而是"挂一个不影响整体":OAP 任一实例故障,其余实例无缝接管;存储一节点故障,副本保证数据不丢、读写不中断。

2. 整体架构:OAP 集群 + 高可用 ES

生产推荐架构(自上而下):

  • 接入层:Agent 通过环境变量指向 `oap:11800`(gRPC),由 DNS / K8s Service 做客户端负载均衡;UI 前面挂 Nginx/SLB。
  • 计算层:2~N 个 OAP 实例,无状态,共享同一存储,通过集群协调器(Kubernetes / Nacos / Zookeeper / Consul / Etcd)互相发现。
  • 存储层:ES 至少 3 节点,索引副本数 >= 1,跨可用区部署。
  • 协调层:选一个你们已有的协调服务(K8s 集群内直接用 `cluster.selector=kubernetes` 最省事)。

关键认知:OAP 无状态,正是因为它把状态全交给了存储。所以"集群部署"的重点,一半在 OAP 多实例,一半在存储高可用。两层都冗余,才是真高可用。

3. 部署实战:OAP 无状态集群

OAP 集群配置在 `application.yml` 的 `cluster` 段。以 Kubernetes 为例,最简洁:

cluster:
  selector: ${SW_CLUSTER:kubernetes}
  kubernetes:
    namespace: ${SW_CLUSTER_K8S_NAMESPACE:skywalking}
    labelSelector: ${SW_CLUSTER_K8S_LABEL:app=oap}
    uidEnvName: ${SW_CLUSTER_K8S_UID:SKYWALKING_UID}

 

`core` 段固定 gRPC/HTTP 端口(多实例靠 K8s 多 Pod 实现,每个 Pod 内部端口相同):

core:
  selector: ${SW_CORE:default}
  default:
    gRPCHost: ${SW_CORE_GRPC_HOST:0.0.0.0}
    gRPCPort: ${SW_CORE_GRPC_PORT:11800}
    restHost: ${SW_CORE_REST_HOST:0.0.0.0}
    restPort: ${SW_CORE_REST_PORT:12800}

 

K8s Deployment 关键片段(3 副本):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: oap
  namespace: skywalking
  labels: { app: oap }
spec:
  replicas: 3
  selector:
    matchLabels: { app: oap }
  template:
    metadata:
      labels: { app: oap }
    spec:
      containers:
        - name: oap
          image: apache/skywalking-oap-server:9.7.0
          env:
            - name: SW_CLUSTER
              value: kubernetes
            - name: SW_STORAGE
              value: elasticsearch
            - name: SW_ES_CLUSTER_NODES
              value: "es:9200"
          ports:
            - { containerPort: 11800 }
            - { containerPort: 12800 }

 

Agent 侧通过 K8s Service 名访问,无需关心具体实例:

-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=oap.skywalking.svc:11800
 

扩缩容只需改 `replicas`,OAP 通过协调器自动感知新节点,无数据迁移成本。

4. 高可用存储:ES 多节点 + 副本

ES 高可用靠分片副本。部署 3 个数据节点,SkyWalking 索引副本设为 1(即每份数据存 2 份,分布在 2 个节点):

storage:
  elasticsearch:
    clusterNodes: ${SW_ES_CLUSTER_NODES:es1:9200,es2:9200,es3:9200}
    indexShardsNumber: 3
    indexReplicasNumber: 1

 

副本的作用:某节点宕机,另一节点上的副本立即升为主分片,读写不中断。但副本数也不是越大越好——副本=2 会把写入放大约 2 倍、存储翻倍。大模型高写入场景,`replicas=1` 是性价比最优。

跨可用区部署时,用 ES 的 `shard allocation awareness` 让主副分片落在不同 AZ,避免单 AZ 故障同时丢主副:

# 每个节点标注 zone
# elasticsearch.yml
node.attr.zone: az-a   # az-b / az-c
# 集群级
cluster.routing.allocation.awareness.attributes: zone

 

这样即使 az-a 整体断电,数据仍在 az-b/az-c 完整可用。

5. 负载均衡与网关接入

虽然 Agent 支持配置多个 `backend_service`(逗号分隔),但更稳妥是在前面放一层负载均衡,让 Agent 只认一个稳定地址。

Nginx 对 UI(rest 12800)做反向代理:

upstream oap_rest {
    server oap-0:12800;
    server oap-1:12800;
    server oap-2:12800;
}
server {
    listen 12800;
    location / {
        proxy_pass http://oap_rest;
        proxy_set_header Host $host;
    }
}

 

gRPC(11800)建议用支持 HTTP/2 的 LB(如 Nginx Plus、Envoy、或云 SLB 的 TCP 转发)。K8s 环境下直接用 Service 的 ClusterIP + kube-proxy 轮询即可,Agent 配 Service 名。

UI 单独部署(`skywalking-ui`),`SW_OAP_ADDRESS` 指向 LB 地址:

docker run -d --name ui -e SW_OAP_ADDRESS=http://oap-lb:12800 \
  -p 8080:8080 apache/skywalking-ui:9.7.0

 

注意:UI 与 OAP 版本必须一致,否则 GraphQL 接口不兼容会白屏。

6. 灰度发布与故障演练

高可用不是"配完就高可用",要靠演练验证。两类必做动作:

第一,滚动发布。OAP 升级用 K8s 滚动更新(maxUnavailable=1),保证始终有实例在跑。因为 OAP 无状态,升级期间 Agent 会自动重连到存活实例,监控不中断。演练命令:

kubectl -n skywalking set image deployment/oap oap=apache/skywalking-oap-server:9.7.1
kubectl -n skywalking rollout status deployment/oap

 

第二,故障演练(Chaos)。主动 kill 一个 OAP Pod,确认:① 其余实例自动接管;② Agent 侧 Trace 不丢(短暂缓冲后重连上报);③ UI 和告警正常。再 kill 一个 ES 节点,确认:① 副本升主、读写无中断;② 数据完整。

推荐用混沌工程工具(如 Chaos Mesh)定期自动演练,把"我以为高可用"变成"验证过高可用"。

下表给出高可用等级对照,帮你对标:

等级

OAP

存储

故障影响

适用

---

---

---

---

---

L0

单节点

H2

全盲

演示

L1

2 节点

单 ES

实例故障可扛

测试

L2

3 节点

ES 3 节点副本1

单点故障无感

生产

L3

3+ 节点

ES 跨 AZ 副本

AZ 故障无感

核心生产

7. 最佳实践与踩坑

第一,OAP 版本与存储、UI 必须一致。跨小版本连 ES 常因 mapping 不兼容报错;UI 与 OAP 版本差一级就可能 GraphQL 白屏。升级走"全栈同版本"策略。

第二,协调器别引入新单点。用 Zookeeper/Consul 做集群协调时,协调器本身也要集群化,否则"为去单点引入新单点"。K8s 内部直接用 `cluster.selector=kubernetes` 最省心。

第三,Agent 缓冲要留足。OAP 滚动升级瞬间,Agent 会短暂连不上,靠 Agent 内存缓冲暂存。缓冲有上限(默认几十 MB),升级要快、实例不要同时重启,否则高峰会丢数据。可用 `agent.config` 的 `buffer` 相关参数调大。

第四,ES 磁盘水位线要监控。ES 默认磁盘超 85% 停止分配分片、超 90% 只读。OAP 写不进去时静默失败,监控又恰好依赖 ES——典型的"监控自杀"。务必告警 ES 磁盘使用率。

第五,别把 OAP 和 ES 放同一台机器。它们都吃内存(OAP 堆 + ES 堆 + OS 缓存),混部会互相抢占,反而更易整体崩。计算与存储分离部署。

第六,配置统一走环境变量。所有 `SW_*` 环境变量不要写死在镜像里,用 ConfigMap / 部署变量注入,便于多环境(测试/生产)切换,也方便灰度。

至此,第 46 阶段"大模型调用链路追踪,SkyWalking 排查线上性能"15 篇全部完成:从链路模型、Token 耗时拆解、Trace-Log 联动、OAL 告警,到存储选型、集群高可用,构成了完整的大模型可观测性落地路径。把这套体系接进你的线上大模型服务,下一次性能工单,你将不再是"盲猜的那个人"。

更多推荐