skywalking源码分析第八篇一ClusterModule集群模块启动

ClusterModule能力

  • coreModule主要定义了服务注册与服务发现能力
public class ClusterModule extends ModuleDefine {

    public static final String NAME = "cluster";

    public ClusterModule() {
        super(NAME);
    }
    服务注册与服务发现
    @Override public Class[] services() {
        return new Class[] {ClusterRegister.class, ClusterNodesQuery.class};
    }
}

集群注册发现实现

  • 支持单机
  • 支持zk,nacos,consul
  • 支持云原生场景下k8s管理

单机模式

  • prepare阶段构建StandaloneManager单机管理器
  • core模块启动时注册自身到StandaloneManager
public class ClusterModuleStandaloneProvider extends ModuleProvider {
    @Override public void prepare() throws ServiceNotProvidedException {
        单机管理器
        StandaloneManager standaloneManager = new StandaloneManager();
        this.registerServiceImplementation(ClusterRegister.class, standaloneManager);
        this.registerServiceImplementation(ClusterNodesQuery.class, standaloneManager);
    }
}
  • core模块启动时注册自己,因为是Standalone模式,信息维护在内存
  • 单机模式包装自己成list返回
public class StandaloneManager implements ClusterNodesQuery, ClusterRegister {
    private volatile RemoteInstance remoteInstance;

    @Override public void registerRemote(RemoteInstance remoteInstance) {
        core模块启动时注册自己,因为是Standalone模式,信息维护在内存
        this.remoteInstance = remoteInstance;
        this.remoteInstance.getAddress().setSelf(true);
        TelemetryRelatedContext.INSTANCE.setId("standalone");
    }

    @Override
    public List<RemoteInstance> queryRemoteNodes() {
        if (remoteInstance == null) {
            return new ArrayList(0);
        }
        ArrayList remoteList = new ArrayList(1);
        remoteList.add(remoteInstance);
        单机模式包装自己成list返回
        return remoteList;
    }
}

集群模式一zookeeper

原理图

  • curator-framework.jar提供zkclient通信封装
  • curator-x-discovery.jar提供zk的服务注册发现封装
  • ServiceCache监听并缓存zk数据
  • ServiceDiscovery向zk写数据并触发ServiceCache监听变更
  • ZookeeperCoordinator是集群模块对zk的封装,提供服务注册发现能力
    在这里插入图片描述

源码分析一ClusterModuleZookeeperProvider.prepare

  • 构建zk客户端
  • 构建CuratorFrameworkFactory.Builder
  • 构建zk的服务发现类serviceDiscovery
  • 启动服务发现
  • 对外暴露ZookeeperCoordinator,封装zk服务发现工具[serviceDiscovery]
  • ZookeeperCoordinator实现服务注册ClusterRegister和服务发现ClusterNodesQuery接口
public class ClusterModuleZookeeperProvider extends ModuleProvider {

    private final ClusterModuleZookeeperConfig config;
    private CuratorFramework client;
    private ServiceDiscovery<RemoteInstance> serviceDiscovery;

    @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(config.getBaseSleepTimeMs(), config.getMaxRetries());
        构建zk CuratorFrameworkFactory
        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
            .retryPolicy(retryPolicy)
            .connectString(config.getHostPort());
        访问控制安全相关
        if (config.isEnableACL()) {
            String authInfo = config.getExpression();
            if ("digest".equals(config.getSchema())) {
                try {
                    authInfo = DigestAuthenticationProvider.generateDigest(authInfo);
                } catch (NoSuchAlgorithmException e) {
                    throw new ModuleStartException(e.getMessage(), e);
                }
            } else {
                throw new ModuleStartException("Support digest schema only.");
            }
            final List<ACL> acls = Lists.newArrayList();
            acls.add(new ACL(ZooDefs.Perms.ALL, new Id(config.getSchema(), authInfo)));
            acls.add(new ACL(ZooDefs.Perms.READ, ZooDefs.Ids.ANYONE_ID_UNSAFE));

            ACLProvider provider = new ACLProvider() {
                @Override
                public List<ACL> getDefaultAcl() {
                    return acls;
                }

                @Override
                public List<ACL> getAclForPath(String s) {
                    return acls;
                }
            };
            builder.aclProvider(provider);
            builder.authorization(config.getSchema(), config.getExpression().getBytes());
        }
        zkClient 构建
        client = builder.build();

        String path = BASE_PATH + (StringUtil.isEmpty(config.getNameSpace()) ? "" : "/" + config.getNameSpace());


        zk curator-x-discovery模块,该模块支持封装了zk的服务注册发现能力
        serviceDiscovery = ServiceDiscoveryBuilder.builder(RemoteInstance.class).client(client)
            .basePath(path)
            .watchInstances(true)
            SWInstanceSerializer 将数据序列化成json
            .serializer(new SWInstanceSerializer()).build();

        提供zk节点注册和集群信息读取
        ZookeeperCoordinator coordinator;
        try {
            client.start();
            阻塞下 等待连接成功
            client.blockUntilConnected();
            serviceDiscovery.start();
            构建服务注册发现对象封装zk 提供服务注册和服务发现能力
            coordinator = new ZookeeperCoordinator(config, serviceDiscovery);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ModuleStartException(e.getMessage(), e);
        }
        通过coordinator对集群的信息进行注册,注册数据维护在zk
        this.registerServiceImplementation(ClusterRegister.class, coordinator);
        通过coordinator对集群的信息进行查询
        this.registerServiceImplementation(ClusterNodesQuery.class, coordinator);
    }

    @Override public void start() {
        无实现
    }

    @Override public void notifyAfterCompleted() {
        无实现
    }
}

源码分析一ZookeeperCoordinator

  • 提供服务注册接口
  • 提供服务发现接口
  • 基于zk工具包curator-x-discovery提供serviceDiscovery进行服务注册
  • 基于zk工具包curator-x-discovery提供serviceCache进行服务发现
  • serviceCache负责监听zk服务端数据并缓存在JVM进程
public class ZookeeperCoordinator implements ClusterRegister, ClusterNodesQuery {
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperCoordinator.class);

    private static final String REMOTE_NAME_PATH = "remote";

    private final ClusterModuleZookeeperConfig config;
    zk工具包curator-x-discovery模块 服务发现工具
    private final ServiceDiscovery<RemoteInstance> serviceDiscovery;
    zk工具包curator-x-discovery模块 服务发现结果缓存
    private final ServiceCache<RemoteInstance> serviceCache;
    private volatile Address selfAddress;

    ZookeeperCoordinator(ClusterModuleZookeeperConfig config, ServiceDiscovery<RemoteInstance> serviceDiscovery) throws Exception {
        this.config = config;
        this.serviceDiscovery = serviceDiscovery;
        this.serviceCache = serviceDiscovery.serviceCacheBuilder().name(REMOTE_NAME_PATH).build();
        首次拉取zk上监听的数据 并开启listen机制监听zk数据
        this.serviceCache.start();
    }
    服务注册
    @Override public synchronized void registerRemote(RemoteInstance remoteInstance) throws ServiceRegisterException {
        try {
            if (needUsingInternalAddr()) {
                remoteInstance = new RemoteInstance(new Address(config.getInternalComHost(), config.getInternalComPort(), true));
            }

            ServiceInstance<RemoteInstance> thisInstance = ServiceInstance.<RemoteInstance>builder()
                .name(REMOTE_NAME_PATH)
                .id(UUID.randomUUID().toString())
                .address(remoteInstance.getAddress().getHost())
                .port(remoteInstance.getAddress().getPort())
                .payload(remoteInstance)
                .build();
            向zk注册数据
            serviceDiscovery.registerService(thisInstance);

            this.selfAddress = remoteInstance.getAddress();
            TelemetryRelatedContext.INSTANCE.setId(selfAddress.toString());
        } catch (Exception e) {
            throw new ServiceRegisterException(e.getMessage());
        }
    }
    服务发现
    @Override public List<RemoteInstance> queryRemoteNodes() {
        List<RemoteInstance> remoteInstanceDetails = new ArrayList<>(20);
        从缓存中获取zk上注册的集群机器集合
        List<ServiceInstance<RemoteInstance>> serviceInstances = serviceCache.getInstances();
        serviceInstances.forEach(serviceInstance -> {
            RemoteInstance instance = serviceInstance.getPayload();
            if (instance.getAddress().equals(selfAddress)) {
                instance.getAddress().setSelf(true);
            } else {
                instance.getAddress().setSelf(false);
            }
            remoteInstanceDetails.add(instance);
        });
        return remoteInstanceDetails;
    }

    private boolean needUsingInternalAddr() {
        return !Strings.isNullOrEmpty(config.getInternalComHost()) && config.getInternalComPort() > 0;
    }
}

总结

  • skywalking提供了多种服务注册发现机制,包括k8s,nacos等等
  • 集群主要用于RemoteClientManager,agent上报的一条数据在处理的过程中,可能会经过多个集群节点,此时就需要服务注册发现机制进行节点数据传输
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值