聊聊nacos的ServiceReporter

本文主要研究一下nacos的ServiceReporter

ServiceManager.init

nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java

@Component
@DependsOn("nacosApplicationContext")
public class ServiceManager implements RecordListener<Service> {

    /**
     * Map<namespace, Map<group::serviceName, Service>>
     */
    private Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();

    private LinkedBlockingDeque<ServiceKey> toBeUpdatedServicesQueue = new LinkedBlockingDeque<>(1024 * 1024);

    private Synchronizer synchronizer = new ServiceStatusSynchronizer();

    private final Lock lock = new ReentrantLock();

    @Resource(name = "consistencyDelegate")
    private ConsistencyService consistencyService;

    @Autowired
    private SwitchDomain switchDomain;

    @Autowired
    private DistroMapper distroMapper;

    @Autowired
    private ServerListManager serverListManager;

    @Autowired
    private PushService pushService;

    private final Object putServiceLock = new Object();

    @PostConstruct
    public void init() {

        UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR.schedule(new ServiceReporter(), 60000, TimeUnit.MILLISECONDS);

        UtilsAndCommons.SERVICE_UPDATE_EXECUTOR.submit(new UpdatedServiceProcessor());

        try {
            Loggers.SRV_LOG.info("listen for service meta change");
            consistencyService.listen(KeyBuilder.SERVICE_META_KEY_PREFIX, this);
        } catch (NacosException e) {
            Loggers.SRV_LOG.error("listen for service meta change failed!");
        }
    }

    //......
}
  • ServiceManager的init方法往UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR注册了ServiceReporter

ServiceReporter

nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java

private class ServiceReporter implements Runnable {

@Override
public void run() {
    try {

        Map<String, Set<String>> allServiceNames = getAllServiceNames();

        if (allServiceNames.size() <= 0) {
            //ignore
            return;
        }

        for (String namespaceId : allServiceNames.keySet()) {

            ServiceChecksum checksum = new ServiceChecksum(namespaceId);

            for (String serviceName : allServiceNames.get(namespaceId)) {
                if (!distroMapper.responsible(serviceName)) {
                    continue;
                }

                Service service = getService(namespaceId, serviceName);

                if (service == null) {
                    continue;
                }

                service.recalculateChecksum();

                checksum.addItem(serviceName, service.getChecksum());
            }

            Message msg = new Message();

            msg.setData(JSON.toJSONString(checksum));

            List<Server> sameSiteServers = serverListManager.getServers();

            if (sameSiteServers == null || sameSiteServers.size() <= 0) {
                return;
            }

            for (Server server : sameSiteServers) {
                if (server.getKey().equals(NetUtils.localServer())) {
                    continue;
                }
                synchronizer.send(server.getKey(), msg);
            }
        }
    } catch (Exception e) {
        Loggers.SRV_LOG.error("[DOMAIN-STATUS] Exception while sending service status", e);
    } finally {
        UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR.schedule(this, switchDomain.getServiceStatusSynchronizationPeriodMillis(), TimeUnit.MILLISECONDS);
    }
}

}

  • ServiceReporter实现Runnable接口,其run方法会遍历allServiceNames,取出distroMapper.responsible的serviceName,重新计算recalculateChecksum,然后添加到ServiceChecksum中,构造Message,遍历sameSiteServers使用synchronizer.send发送该消息;最后往UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR重新注册ServiceReporter

ServiceStatusSynchronizer

nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/misc/ServiceStatusSynchronizer.java

public class ServiceStatusSynchronizer implements Synchronizer {
    @Override
    public void send(final String serverIP, Message msg) {
        if(serverIP == null) {
            return;
        }

        Map<String,String> params = new HashMap<String, String>(10);

        params.put("statuses", msg.getData());
        params.put("clientIP", NetUtils.localServer());


        String url = "http://" + serverIP + ":" + RunningConfig.getServerPort() + RunningConfig.getContextPath() +
                UtilsAndCommons.NACOS_NAMING_CONTEXT + "/service/status";

        if (serverIP.contains(UtilsAndCommons.IP_PORT_SPLITER)) {
            url = "http://" + serverIP + RunningConfig.getContextPath() +
                    UtilsAndCommons.NACOS_NAMING_CONTEXT + "/service/status";
        }

        try {
            HttpClient.asyncHttpPostLarge(url, null, JSON.toJSONString(params), new AsyncCompletionHandler() {
                @Override
                public Integer onCompleted(Response response) throws Exception {
                    if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
                        Loggers.SRV_LOG.warn("[STATUS-SYNCHRONIZE] failed to request serviceStatus, remote server: {}", serverIP);

                        return 1;
                    }
                    return 0;
                }
            });
        } catch (Exception e) {
            Loggers.SRV_LOG.warn("[STATUS-SYNCHRONIZE] failed to request serviceStatus, remote server: " + serverIP, e);
        }

    }

    @Override
    public Message get(String serverIP, String key) {
        if(serverIP == null) {
            return null;
        }

        Map<String,String> params = new HashMap<>(10);

        params.put("key", key);

        String result;
        try {
            if (Loggers.SRV_LOG.isDebugEnabled()) {
                Loggers.SRV_LOG.debug("[STATUS-SYNCHRONIZE] sync service status from: {}, service: {}", serverIP, key);
            }
            result = NamingProxy.reqAPI(RunningConfig.getContextPath()
                + UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance/" + "statuses", params, serverIP);
        } catch (Exception e) {
            Loggers.SRV_LOG.warn("[STATUS-SYNCHRONIZE] Failed to get service status from " + serverIP, e);
            return null;
        }

        if(result == null || result.equals(StringUtils.EMPTY)) {
            return null;
        }

        Message msg = new Message();
        msg.setData(result);

        return msg;
    }
}
  • ServiceStatusSynchronizer实现了Synchronizer接口,其send方法会异步执行post请求,将statuses通知到目标server

小结

ServiceReporter实现Runnable接口,其run方法会遍历allServiceNames,取出distroMapper.responsible的serviceName,重新计算recalculateChecksum,然后添加到ServiceChecksum中,构造Message,遍历sameSiteServers使用synchronizer.send发送该消息;最后往UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR重新注册ServiceReporter

doc

  • (想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)

  • ServiceManager

Nacos是一个非常强大的服务发现和配置中心,它不仅可以实现服务注册与发现,还可以作为配置中心来管理应用程序的配置信息。在Spring Cloud中,我们可以使用Nacos作为配置中心,实现应用程序的动态配置。 关于Nacos配置不会动态刷新的问题,一般有以下几种原因: 1. 缓存问题 Nacos配置中心默认会有一层本地缓存,如果配置没有发生变化,客户端就不会刷新配置。可以通过设置配置缓存时间或者禁用缓存来解决该问题。 2. 配置监听器未开启 Nacos配置中心支持配置监听器,在配置发生变化时会自动通知客户端进行更新。如果监听器未开启,就无法实现动态刷新配置。可以通过在bootstrap.yml或bootstrap.properties中添加如下配置开启监听器: ``` spring.cloud.nacos.config.listener.enabled=true ``` 3. 配置文件未被监听 如果配置文件未被监听,即使监听器已经开启也无法实现动态刷新配置。在bootstrap.yml或bootstrap.properties中添加如下配置,即可监听指定的配置文件: ``` spring.cloud.nacos.config.file-extension=properties,yaml,yml spring.cloud.nacos.config.group=DEFAULT_GROUP spring.cloud.nacos.config.prefix=${spring.application.name} ``` 其中,file-extension指定配置文件的扩展名,group指定配置分组,默认为DEFAULT_GROUP,prefix指定配置文件的前缀,默认为应用程序的名称。 综上所述,如果遇到Nacos配置不会动态刷新的问题,可以先检查缓存设置、监听器和配置文件是否正确配置。如果仍无法解决问题,可以尝试升级Nacos版本或者进行调试排查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值