公司动态

【SkyWalking从入门到精通】第47篇:OAP集群协调器深度解析:ZooKeeper vs Nacos vs Kubernetes三大方案

📅 2026/7/14 12:48:48
【SkyWalking从入门到精通】第47篇:OAP集群协调器深度解析:ZooKeeper vs Nacos vs Kubernetes三大方案
上一篇【第46篇】OAP集群通信协议节点间对话的暗语下一篇【第48篇】OAP集群规划实战从理论到生产的容量设计一、开篇协调器——集群的居委会如果你住在一个小区里居委会负责记录谁住在哪栋楼、“谁搬走了”、“新搬来的住户”。如果没有居委会你就无法知道小区里到底住了多少人更不可能找到邻居借东西。OAP集群的协调器就是这样的居委会。它解决的核心问题只有两个服务发现集群里现在有哪些OAP节点是活跃的健康管理哪个节点宕机了节点加入/离开时如何通知其他节点---------------------------------------------------------------- | 集群协调器的职责 | | | | [OAP-1] ──┐ | | ├── 注册到协调器 | | [OAP-2] ──┤ 1. 节点发现 | | ├── 2. 健康检查 | | [OAP-3] ──┘ 3. 变更通知 | | | | 协调器提供 | | - 现在集群有哪些节点 → ClusterNodesQuery | | - 把我注册到集群 → ClusterRegister | | - 把工单发给某个节点 → ClusterModuleClient | | | ---------------------------------------------------------------- 图1协调器是集群节点的居委会二、方案一Standalone —— 孤胆英雄2.1 适用场景Standalone不是真正的集群它适合本地开发环境功能验证测试对高可用无要求的POC项目2.2 实现原理// Standalone实现——代码简洁到令人发指publicclassStandaloneClusterRegisterimplementsClusterRegister{OverridepublicvoidregisterRemote(RemoteInstanceinstance){// 单机模式唯一节点就是自己selfInstanceinstance;logger.info(Standalone模式启动本节点为唯一集群节点);}}publicclassStandaloneClusterNodesQueryimplementsClusterNodesQuery{OverridepublicListRemoteInstancequeryRemoteNodes(){// 永远只返回空列表只有一个节点returnCollections.emptyList();}}三、方案二ZooKeeper —— 分布式协调的老兵3.1 ZK方案的实现架构ZK集群3节点 ---------- ---------- ---------- | ZK Node1 |---| ZK Node2 |---| ZK Node3 | | (Leader) | |(Follower)| |(Follower)| ---------- ---------- ---------- ^ ^ | | ZNode: /skywalking/oap-cluster/ | | | ----------------- | | | | /instance-001 /instance-002 /instance-003 (EPHEMERAL) (EPHEMERAL) (EPHEMERAL) data: { data: { data: { host: 10.0.1.1, host: 10.0.1.2, host: 10.0.1.3, port: 11800 port: 11800 port: 11800 } } } ^ ^ ^ | | | -------- -------- -------- | OAP-1 | | OAP-2 | | OAP-3 | --------- --------- --------- 图2ZooKeeper协调方案的节点注册机制3.2 完整配置# application.yml - ZooKeeper模式cluster:selector:${SW_CLUSTER:zookeeper}zookeeper:# ZK集群地址逗号分隔hostPort:${SW_CLUSTER_ZK_HOST_PORT:zk1:2181,zk2:2181,zk3:2181}# 会话超时毫秒# OAP节点掉线后ZK最长等待这个时间才会删除临时节点sessionTimeout:${SW_CLUSTER_ZK_SESSION_TIMEOUT:40000}# ZK命名空间路径前缀# 用于在同一个ZK集群中隔离不同环境namespace:${SW_NAMESPACE:skywalking}# 重试策略基础睡眠时间baseSleepTimeMs:${SW_CLUSTER_ZK_SLEEP_TIME:1000}# 重试策略最大重试次数maxRetries:${SW_CLUSTER_ZK_MAX_RETRIES:3}# 是否启用ACL认证enableACL:${SW_CLUSTER_ZK_ENABLE_ACL:false}# ACL Schemaschema:${SW_CLUSTER_ZK_SCHEMA:digest}# ACL表达式expression:${SW_CLUSTER_ZK_EXPRESSION:skywalking:skywalking}# 用于内部通信的host和port可选自动探测internalComHost:${SW_CLUSTER_INTERNAL_COM_HOST:}internalComPort:${SW_CLUSTER_INTERNAL_COM_PORT:-1}3.3 ZK方案的优缺点维度评价说明成熟度★★★★★十余年生产验证Apache顶级项目一致性★★★★★CP系统ZAB协议数据绝对一致性能★★★☆☆写操作有性能瓶颈Leader瓶颈运维复杂度★★★☆☆需要单独部署和维护ZK集群管理界面★★☆☆☆无内置UI依赖第三方工具如zkCliJava依赖重需要Curator框架四、方案三Nacos —— 云原生的后起之秀4.1 Nacos方案的实现架构Nacos集群3节点 ----------- ----------- ----------- | Nacos-1 |---| Nacos-2 |---| Nacos-3 | ----------- ----------- ----------- | | Service: SkyWalking_OAP_Cluster -------------------------------------- | Instances: | | - 10.0.1.1:11800 (healthy) | | - 10.0.1.2:11800 (healthy) | | - 10.0.1.3:11800 (healthy) | -------------------------------------- ^ ^ ^ | | | --------- --------- --------- | OAP-1 | | OAP-2 | | OAP-3 | ---------- ---------- ---------- 图3Nacos基于服务模型的节点注册4.2 完整配置# application.yml - Nacos模式cluster:selector:${SW_CLUSTER:nacos}nacos:# 服务名在Nacos中注册的名称serviceName:${SW_SERVICE_NAME:SkyWalking_OAP_Cluster}# Nacos集群地址hostPort:${SW_CLUSTER_NACOS_HOST_PORT:nacos1:8848,nacos2:8848,nacos3:8848}# Nacos命名空间多环境隔离namespace:${SW_CLUSTER_NACOS_NAMESPACE:}# 认证信息username:${SW_CLUSTER_NACOS_USERNAME:}password:${SW_CLUSTER_NACOS_PASSWORD:}# AccessKey认证阿里云MSE NacosaccessKey:${SW_CLUSTER_NACOS_ACCESS_KEY:}# 分组名group:${SW_CLUSTER_NACOS_GROUP:DEFAULT_GROUP}# 集群名Nacos内的集群划分clusterName:${SW_CLUSTER_NACOS_CLUSTER_NAME:DEFAULT}4.3 Nacos方案的优缺点维度评价说明成熟度★★★★☆生产可用持续活跃开发一致性★★★★☆APCP可选Distro Raft性能★★★★☆性能优于ZK支持大规模运维复杂度★★★☆☆需要单独部署管理界面★★★★★内置Web控制台可视化操作额外功能★★★★★同时支持配置中心一举两得Java依赖中需要nacos-client五、方案四Kubernetes —— 生于云用于云5.1 K8s方案的精妙之处如果你已经把OAP部署在Kubernetes上K8s本身就提供了服务发现能力——根本不需要额外的协调器# k8s-deployment.yamlapiVersion:v1kind:Servicemetadata:name:skywalking-oap-clusterspec:clusterIP:None# Headless Serviceselector:app:skywalking-oapports:-port:11800name:grpc---apiVersion:apps/v1kind:StatefulSetmetadata:name:skywalking-oapspec:serviceName:skywalking-oap-clusterreplicas:3selector:matchLabels:app:skywalking-oaptemplate:metadata:labels:app:skywalking-oapspec:containers:-name:oapimage:apache/skywalking-oap-server:9.0.0env:-name:SW_CLUSTERvalue:kubernetes-name:SW_CLUSTER_K8S_NAMESPACEvalue:skywalking-name:SW_CLUSTER_K8S_LABELvalue:appskywalking-oap-name:SW_CLUSTER_K8S_UIDvalueFrom:fieldRef:fieldPath:metadata.uid5.2 K8s Provider实现publicclassClusterModuleKubernetesProviderextendsModuleProvider{privateKubernetesClientk8sClient;Overridepublicvoidprepare()throwsModuleStartException{ClusterModuleKubernetesConfigconfig(ClusterModuleKubernetesConfig)getModuleConfig();// 使用Kubernetes官方Java客户端this.k8sClientnewDefaultKubernetesClient(newConfigBuilder().withNamespace(config.getNamespace()).build());// 注册服务this.registerServiceImplementation(ClusterNodesQuery.class,newK8sClusterNodesQuery(k8sClient,config));}Overridepublicvoidstart()throwsModuleStartException{ClusterModuleKubernetesConfigconfig(ClusterModuleKubernetesConfig)getModuleConfig();// 将自己注册为集群节点// K8s中Pod本身就是注册的——通过Label Selector发现StringpodUIDSystem.getenv(config.getUidEnvName());logger.info(K8s模式启动Pod UID: {},podUID);// 监听Pod变化通过Watch APIk8sClient.pods().withLabelSelector(config.getLabelSelector()).watch(newWatcherPod(){OverridepublicvoideventReceived(Actionaction,Podpod){logger.info(K8s Pod事件: {} - {},action,pod.getMetadata().getName());}});}}5.3 K8s模式的配置# application.ymlcluster:selector:${SW_CLUSTER:kubernetes}kubernetes:# K8s命名空间namespace:${SW_CLUSTER_K8S_NAMESPACE:default}# Pod标签选择器用于发现同集群的OAP PodlabelSelector:${SW_CLUSTER_K8S_LABEL:appskywalking-oap}# Pod UID环境变量名uidEnvName:${SW_CLUSTER_K8S_UID:SKYWALKING_OAP_INSTANCE_UID}# 如何获取当前Pod的地址# 可选值: pod_ip (Pod IP), service_fqdn (Service DNS)howToGetSelfAddress:${SW_CLUSTER_K8S_SELF_ADDRESS:pod_ip}5.4 K8s方案的优缺点维度评价说明成熟度★★★★☆K8s生态成熟稳定可靠部署复杂度★☆☆☆☆不需要额外部署协调器运维负担★☆☆☆☆完全由K8s托管可移植性★☆☆☆☆强绑定K8s离开K8s不可用功能丰富度★★★☆☆基础服务发现高级功能有限适用场景纯K8s环境非K8s环境无法使用六、三(四)大方案对比矩阵 | 集群协调器方案对比 | | Standalone | ZooKeeper | Nacos | Kubernetes | |----------------------------------------------------------------------| | 高可用 | ✗ | ✓ | ✓ | ✓ | | 自动故障检测 | ✗ | ✓ | ✓ | ✓ | | 动态扩缩容 | ✗ | ✓ | ✓ | ✓ | | 额外部署依赖 | 无 | ZK集群 | Nacos集群 | 无需额外 | | 配置管理集成 | ✗ | ✗ | ✓ | ✗ | | 管理界面 | ✗ | 第三方工具 | 内置UI | kubectl | | 学习曲线 | 低 | 中 | 中 | 低(云原生) | | 社区活跃度 | N/A | 高 | 高 | 高 | |||||| | 推荐场景 | | | | | |----------------------------------------------------------------------| | 开发/测试 | ★★★★★ | ★★★☆☆ | ★★★★☆ | ★★★★☆ | | 中小规模生产 | ☆☆☆☆☆ | ★★★★☆ | ★★★★★ | ★★★★★ | | 大规模生产 | ☆☆☆☆☆ | ★★★★☆ | ★★★★★ | ★★★★★ | | 混合云/多云 | ☆☆☆☆☆ | ★★★★☆ | ★★☆☆☆ | ★★★★☆ | | 纯K8s环境 | ☆☆☆☆☆ | ★★☆☆☆ | ★★★☆☆ | ★★★★★ | 图4四大方案的全方位对比矩阵七、选型决策树你的部署环境是什么 | ------------------------------ | | 纯K8s环境 非K8s环境 | | v v 需要额外的配置中心吗? 已有哪些基础设施? | | -------------- -------------- | | | | 是 否 有ZK 有Nacos | | | | v v v v Nacos Kubernetes ZK Nacos (配置K8s) (零依赖方案) (复用现有) (复用现有) | | | | v v v v ------- ------- ------- ------- | 需要 | | 不需要 | | ZK版本| | Nacos | | 部署 | | 额外 | | 要3.4 | | 1.x | | Nacos | | 部署 | ------- ------- ------- ------- 图5集群协调器选型决策树八、总结选型建议一句话总结开发环境Standalone零配置已有ZooKeeper复用ZK减少基础设施云原生用户Nacos配置服务发现一体纯K8s部署Kubernetes模式零额外依赖新项目推荐Nacos ZK运维友好度更高下一篇我们将讨论OAP集群的容量规划——多少个节点合适内存和CPU怎么配上一篇【第46篇】OAP集群通信协议节点间对话的暗语下一篇【第48篇】OAP集群规划实战从理论到生产的容量设计