微服务:剖析一下源码,Nacos的健康检查竟如此简单

六、Nacos源码系列:Nacos健康检查 / 启动了一个定时任务,无延迟,每隔5s执行一次// 具体就是执行ExpiredClientCleaner.run()方法@Override// 判断客户端是否超时if (null!// 超时连接处理客户端释放连接事件、客户端断开连接事件。 阅读详情

前面我们多次提到Nacos的健康检查,比如《微服务之:服务挂的太干脆,Nacos还没反应过来,怎么办?》一文中还对健康检查进行了自定义调优。那么,Nacos的健康检查和心跳机制到底是如何实现的呢?在项目实践中是否又可以参考Nacos的健康检查机制,运用于其他地方呢?

这篇文章,就带大家来揭开Nacos健康检查机制的面纱。

Nacos的健康检查

Nacos中临时实例基于心跳上报方式维持活性,基本的健康检查流程基本如下:Nacos客户端会维护一个定时任务,每隔5秒发送一次心跳请求,以确保自己处于活跃状态。Nacos服务端在15秒内如果没收到客户端的心跳请求,会将该实例设置为不健康,在30秒内没收到心跳,会将这个临时实例摘除。

原理很简单,关于代码层的实现,下面来就逐步来进行解析。

客户端的心跳

实例基于心跳上报的形式来维持活性,当然就离不开心跳功能的实现了。这里以客户端心跳实现为基准来进行分析。

Spring Cloud提供了一个标准接口ServiceRegistry,Nacos对应的实现类为NacosServiceRegistry。Spring Cloud项目启动时会实例化NacosServiceRegistry,并调用它的register方法来进行实例的注册。

@Override
public void register(Registration registration) { 
   // ...
   NamingService namingService = namingService();
   String serviceId = registration.getServiceId();
   String group = nacosDiscoveryProperties.getGroup();

   Instance instance = getNacosInstanceFromRegistration(registration);

   try {
      namingService.registerInstance(serviceId, group, instance);
      log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
            instance.getIp(), instance.getPort());
   }catch (Exception e) {
      // ...
   }
}

在该方法中有两处需要注意,第一处是构建Instance的
getNacosInstanceFromRegistration方法,该方法内会设置Instance的元数据(metadata),通过源元数据可以配置服务器端健康检查的参数。比如,在Spring Cloud中配置的如下参数,都可以通过元数据项在服务注册时传递给Nacos的服务端。

spring:
  application:
    name: user-service-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        heart-beat-interval: 5000
        heart-beat-timeout: 15000
       ip-delete-timeout: 30000

 其中的heart-beat-interval、heart-beat-timeout、ip-delete-timeout这些健康检查的参数,都是基于元数据上报上去的。

register方法的第二处就是调用NamingService#registerInstance来进行实例的注册。NamingService是由Nacos的客户端提供,也就是说Nacos客户端的心跳本身是由Nacos生态提供的。

在registerInstance方法中最终会调用到下面的方法:

@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    NamingUtils.checkInstanceIsLegal(instance);
    String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
    if (instance.isEphemeral()) {
        BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
        beatReactor.addBeatInfo(groupedServiceName, beatInfo);
    }
    serverProxy.registerService(groupedServiceName, groupName, instance);
}

其中BeatInfo#addBeatInfo便是进行心跳处理的入口。当然,前提条件是当前的实例需要是临时(瞬时)实例。

对应的方法实现如下:

public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
    NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);
    String key = buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());
    BeatInfo existBeat = null;
    //fix #1733
    if ((existBeat = dom2Beat.remove(key)) != null) {
        existBeat.setStopped(true);
    }
    dom2Beat.put(key, beatInfo);
    executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
    MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}

 在倒数第二行可以看到,客户端是通过定时任务来处理心跳的,具体的心跳请求有BeatTask完成。定时任务的执行频次,封装在BeatInfo,回退往上看,会发现BeatInfo的Period来源于Instance#
getInstanceHeartBeatInterval()。该方法具体实现如下:

public long getInstanceHeartBeatInterval() {
    return this.getMetaDataByKeyWithDefault("preserved.heart.beat.interval", Constants.DEFAULT_HEART_BEAT_INTERVAL);
}

可以看出定时任务的执行间隔就是配置的metadata中的数据
preserved.heart.beat.interval,与上面提到配置heart-beat-interval本质是一回事,默认是5秒。

BeatTask类具体实现如下:

class BeatTask implements Runnable {
    
    BeatInfo beatInfo;
    
    public BeatTask(BeatInfo beatInfo) {
        this.beatInfo = beatInfo;
    }
    
    @Override
    public void run() {
        if (beatInfo.isStopped()) {
            return;
        }
        long nextTime = beatInfo.getPeriod();
        try {
            JsonNode result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);
            long interval = result.get("clientBeatInterval").asLong();
            boolean lightBeatEnabled = false;
            if (result.has(CommonParams.LIGHT_BEAT_ENABLED)) {
                lightBeatEnabled = result.get(CommonParams.LIGHT_BEAT_ENABLED).asBoolean();
            }
            BeatReactor.this.lightBeatEnabled = lightBeatEnabled;
            if (interval > 0) {
                nextTime = interval;
            }
            int code = NamingResponseCode.OK;
            if (result.has(CommonParams.CODE)) {
                code = result.get(CommonParams.CODE).asInt();
            }
            if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {
                Instance instance = new Instance();
                instance.setPort(beatInfo.getPort());
                instance.setIp(beatInfo.getIp());
                instance.setWeight(beatInfo.getWeight());
                instance.setMetadata(beatInfo.getMetadata());
                instance.setClusterName(beatInfo.getCluster());
                instance.setServiceName(beatInfo.getServiceName());
                instance.setInstanceId(instance.getInstanceId());
                instance.setEphemeral(true);
                try {
                    serverProxy.registerService(beatInfo.getServiceName(),
                            NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
                } catch (Exception ignore) {
                }
            }
        } catch (NacosException ex) {
            NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",
                    JacksonUtils.toJson(beatInfo), ex.getErrCode(), ex.getErrMsg());
            
        }
        executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
    }
}

 在run方法中通过NamingProxy#sendBeat完成了心跳请求的发送,而在run方法的最后,再次开启了一个定时任务,这样周期性的进行心跳请求。

NamingProxy#sendBeat方法实现如下:

public JsonNode sendBeat(BeatInfo beatInfo, boolean lightBeatEnabled) throws NacosException {
    
    if (NAMING_LOGGER.isDebugEnabled()) {
        NAMING_LOGGER.debug("[BEAT] {} sending beat to server: {}", namespaceId, beatInfo.toString());
    }
    Map<String, String> params = new HashMap<String, String>(8);
    Map<String, String> bodyMap = new HashMap<String, String>(2);
    if (!lightBeatEnabled) {
        bodyMap.put("beat", JacksonUtils.toJson(beatInfo));
    }
    params.put(CommonParams.NAMESPACE_ID, namespaceId);
    params.put(CommonParams.SERVICE_NAME, beatInfo.getServiceName());
    params.put(CommonParams.CLUSTER_NAME, beatInfo.getCluster());
    params.put("ip", beatInfo.getIp());
    params.put("port", String.valueOf(beatInfo.getPort()));
    String result = reqApi(UtilAndComs.nacosUrlBase + "/instance/beat", params, bodyMap, HttpMethod.PUT);
    return JacksonUtils.toObj(result);
}

实际上,就是调用了Nacos服务端提供的"
/nacos/v1/ns/instance/beat"服务。

在客户端的常量类Constants中定义了心跳相关的默认参数:

static {
    DEFAULT_HEART_BEAT_TIMEOUT = TimeUnit.SECONDS.toMillis(15L);
    DEFAULT_IP_DELETE_TIMEOUT = TimeUnit.SECONDS.toMillis(30L);
    DEFAULT_HEART_BEAT_INTERVAL = TimeUnit.SECONDS.toMillis(5L);
}

 这样就呼应了最开始说的Nacos健康检查机制的几个时间维度。

服务端接收心跳

分析客户端的过程中已经可以看出请求的是
/nacos/v1/ns/instance/beat这个服务。Nacos服务端是在Naming项目中的InstanceController中实现的。

@CanDistro
@PutMapping("/beat")
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public ObjectNode beat(HttpServletRequest request) throws Exception {

    // ...
    Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port);

    if (instance == null) {
        // ...
        instance = new Instance();
        instance.setPort(clientBeat.getPort());
        instance.setIp(clientBeat.getIp());
        instance.setWeight(clientBeat.getWeight());
        instance.setMetadata(clientBeat.getMetadata());
        instance.setClusterName(clusterName);
        instance.setServiceName(serviceName);
        instance.setInstanceId(instance.getInstanceId());
        instance.setEphemeral(clientBeat.isEphemeral());

        serviceManager.registerInstance(namespaceId, serviceName, instance);
    }

    Service service = serviceManager.getService(namespaceId, serviceName);
    // ...
    service.processClientBeat(clientBeat);
    // ...
    return result;
}

服务端在接收到请求时,主要做了两件事:第一,如果发送心跳的实例不存在,则将其进行注册;第二,调用其Service的processClientBeat方法进行心跳处理。

processClientBeat方法实现如下:

public void processClientBeat(final RsInfo rsInfo) {
    ClientBeatProcessor clientBeatProcessor = new ClientBeatProcessor();
    clientBeatProcessor.setService(this);
    clientBeatProcessor.setRsInfo(rsInfo);
    HealthCheckReactor.scheduleNow(clientBeatProcessor);
}

ClientBeatProcessor同样是一个实现了Runnable的Task,通过HealthCheckReactor定义的scheduleNow方法进行立即执行。

scheduleNow方法实现:

public static ScheduledFuture<?> scheduleNow(Runnable task) {
    return GlobalExecutor.scheduleNamingHealth(task, 0, TimeUnit.MILLISECONDS);
}

 再来看看ClientBeatProcessor中对具体任务的实现:

@Override
public void run() {
    Service service = this.service;
    // logging    
    String ip = rsInfo.getIp();
    String clusterName = rsInfo.getCluster();
    int port = rsInfo.getPort();
    Cluster cluster = service.getClusterMap().get(clusterName);
    List<Instance> instances = cluster.allIPs(true);
    
    for (Instance instance : instances) {
        if (instance.getIp().equals(ip) && instance.getPort() == port) {
            // logging
            instance.setLastBeat(System.currentTimeMillis());
            if (!instance.isMarked()) {
                if (!instance.isHealthy()) {
                    instance.setHealthy(true);
                    // logging
                    getPushService().serviceChanged(service);
                }
            }
        }
    }
}

 

在run方法中先检查了发送心跳的实例和IP是否一致,如果一致则更新最后一次心跳时间。同时,如果该实例之前未被标记且处于不健康状态,则将其改为健康状态,并将变动通过PushService提供事件机制进行发布。事件是由Spring的ApplicationContext进行发布,事件为ServiceChangeEvent。

通过上述心跳操作,Nacos服务端的实例的健康状态和最后心跳时间已经被刷新。那么,如果没有收到心跳时,服务器端又是如何判断呢?

服务端心跳检查

客户端发起心跳,服务器端来检查客户端的心跳是否正常,或者说对应的实例中的心跳更新时间是否正常。

服务器端心跳的触发是在服务实例注册时触发的,同样在InstanceController中,register注册实现如下:

@CanDistro
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
    // ...
    final Instance instance = parseInstance(request);

    serviceManager.registerInstance(namespaceId, serviceName, instance);
    return "ok";
}

ServiceManager#registerInstance实现代码如下:

public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
    
    createEmptyService(namespaceId, serviceName, instance.isEphemeral());
    // ...
}

心跳相关实现在第一次创建空的Service中实现,最终会调到如下方法:

public void createServiceIfAbsent(String namespaceId, String serviceName, boolean local, Cluster cluster)
        throws NacosException {
    Service service = getService(namespaceId, serviceName);
    if (service == null) {
        
        Loggers.SRV_LOG.info("creating empty service {}:{}", namespaceId, serviceName);
        service = new Service();
        service.setName(serviceName);
        service.setNamespaceId(namespaceId);
        service.setGroupName(NamingUtils.getGroupName(serviceName));
        // now validate the service. if failed, exception will be thrown
        service.setLastModifiedMillis(System.currentTimeMillis());
        service.recalculateChecksum();
        if (cluster != null) {
            cluster.setService(service);
            service.getClusterMap().put(cluster.getName(), cluster);
        }
        service.validate();
        
        putServiceAndInit(service);
        if (!local) {
            addOrReplaceService(service);
        }
    }
}

 

 在putServiceAndInit方法中对Service进行初始化:

private void putServiceAndInit(Service service) throws NacosException {
    putService(service);
    service = getService(service.getNamespaceId(), service.getName());
    service.init();
    consistencyService
            .listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
    consistencyService
            .listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
    Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJson());
}

service.init()方法实现:

public void init() {
    HealthCheckReactor.scheduleCheck(clientBeatCheckTask);
    for (Map.Entry<String, Cluster> entry : clusterMap.entrySet()) {
        entry.getValue().setService(this);
        entry.getValue().init();
    }
}

 HealthCheckReactor#scheduleCheck方法实现:

public static void scheduleCheck(ClientBeatCheckTask task) {
    futureMap.computeIfAbsent(task.taskKey(),
            k -> GlobalExecutor.scheduleNamingHealth(task, 5000, 5000, TimeUnit.MILLISECONDS));
}

延迟5秒执行,每5秒检查一次。

在init方法的第一行便可以看到执行健康检查的Task,具体Task是由ClientBeatCheckTask来实现,对应的run方法核心代码如下:

@Override
public void run() {
    // ...        
    List<Instance> instances = service.allIPs(true);
    
    // first set health status of instances:
    for (Instance instance : instances) {
        if (System.currentTimeMillis() - instance.getLastBeat() > instance.getInstanceHeartBeatTimeOut()) {
            if (!instance.isMarked()) {
                if (instance.isHealthy()) {
                    instance.setHealthy(false);
                    // logging...
                    getPushService().serviceChanged(service);
                    ApplicationUtils.publishEvent(new InstanceHeartbeatTimeoutEvent(this, instance));
                }
            }
        }
    }
    
    if (!getGlobalConfig().isExpireInstance()) {
        return;
    }
    
    // then remove obsolete instances:
    for (Instance instance : instances) {
        
        if (instance.isMarked()) {
            continue;
        }
        
        if (System.currentTimeMillis() - instance.getLastBeat() > instance.getIpDeleteTimeout()) {
            // delete instance
            deleteIp(instance);
        }
    }
}

 在第一个for循环中,先判断当前时间与上次心跳时间的间隔是否大于超时时间。如果实例已经超时,且为被标记,且健康状态为健康,则将健康状态设置为不健康,同时发布状态变化的事件。

在第二个for循环中,如果实例已经被标记则跳出循环。如果未标记,同时当前时间与上次心跳时间的间隔大于删除IP时间,则将对应的实例删除。

小结

通过本文的源码分析,我们从Spring Cloud开始,追踪到Nacos Client中的心跳时间,再追踪到Nacos服务端接收心跳的实现和检查实例是否健康的实现。想必通过整个源码的梳理,你已经对整个Nacos心跳的实现有所了解。

nacos心跳报文,随机抽出一条格式化看看 nacos用了挺久了,今天记录一下控制台打印的1.4.1心跳报文,随机抽出一条格式化看看 { "type": "dom", "data": { "name ": "DEFAULT_GROUP @ @order-service", "clusters ": "", "cacheMillis ": 10000, "hosts ": [{ "instanceId": "192.168.120.123 #7001# DEFAULT# DEFAULT_GROUP @ @order-se. 阅读详情

相关推荐

Nacos心跳机制实现快速上下线

数据库的重要性不言而喻,不管是什么系统,什么应用软件,也不管它们是 Windows 上的应用程序,还是 Web 应用程序,存储(持久化)和查询(检索)数据都是核心的功能。大家学习数据库时,比如 MySQL 这个数据库管理系统,都是在 CLI(Command Line Interface)上操作数据库的,现在,我们看看,在 Java Web 中,我们如何使用 Java 去操作数据库。

m0_71777195的博客 3087

Nacos简单了解

确认数据源使用内置数据源无需进行任何配置使用外置数据源生产使用建议至少主备模式,或者采用高可用数据库。初始化 MySQL 数据库sql语句源文件application . properties 配置application . properties配置文件(这里直接复制之前配置好的使用外部数据源的配置)

settng style 1695

Nacos服务注册与发现原理详解:从源码到实践的深度剖析

Nacos服务注册与发现原理分析 摘要:本文深入解析Nacos作为服务注册与发现平台的核心机制。Nacos采用客户端发现模式,服务实例通过Nacos Client将元数据注册到Nacos Server并维持心跳;服务消费者获取实例列表并实现负载均衡。系统架构包含Nacos Server集群、Client SDK和服务注册表等组件,使用Distro协议保证数据一致性。服务注册流程包含实例注册、心跳维持、元数据管理等环节,支持临时/持久化两种实例类型。服务发现采用推拉结合模式,通过健康检查和集群同步确保服务可用

weixin_42593797的博客 1907

nacos核心源码深度剖析

2.x版本:同一个服务下,节点必须是相同的(临时/非临时)。nacos2.0使用大量的事件驱动方式。

秃了也弱了 3645

Nacos 2.x健康检查机制全解析:从GRPC长连接到源码级探活逻辑

本文深入解析了Nacos 2.x基于GRPC长连接的健康检查机制。通过剖析核心组件ConnectionManager的源码,详细阐述了其如何通过“20秒无通信则探活,3秒周期检测”的逻辑,结合主动探测与连接状态感知,实现高效、实时的服务实例探活与剔除,从而提升微服务架构的稳定性与可靠性。

weixin_29268331的博客 1018

【CIC-IDS数据集+机器学习】实现网络流量异常检测

本项目基于CIC-IDS数据集,使用多种机器学习算法实现网络流量异常检测系统。项目采用了完整的机器学习工作流程,从数据预处理到模型部署,实现了高精度的网络入侵检测。

XiaoMu_001的博客 1936

九:Alibaba Nacos注册中心源码剖析

Nacos&Ribbon&Feign核心微服务架构图 架构原理 微服务系统在启动时将自己注册到服务注册中心,同时外发布 Http 接口供其它系统调用(一般都是基于Spring MVC) 服务消费者基于 Feign 调用服务提供者对外发布的接口,先对调用的本地接口加上注解@FeignClient,Feign会针对加了该注解的接口生成动态代理,服务消费者针对 Feign 生成的动态代理去调用方法时,会在底层生成Http协议格式的请求,类似 /stock/deduct?productId

Xx__WangQi的博客 2235

道闸不自动落杆故障排查:从传感器原理到控制器调试全解析

在工业自动化和物联网系统中,传感器与控制器构成的闭环控制是保障设备可靠运行的核心。其基本原理是通过传感器采集环境状态,控制器依据预设逻辑做出决策并驱动执行器动作。这一技术价值在于实现了无人值守下的安全、高效自动化,广泛应用于智能交通、安防和智能楼宇等领域。以停车场道闸系统为例,其自动落杆功能高度依赖地感线圈与防砸雷达的协同。地感线圈作为触发单元,负责感知车辆接近;而防砸雷达则作为持续监测的安全单元,通过微波探测防砸区域内是否有障碍物,其信号是控制器执行落杆决策的关键依据。当系统出现车辆通过后闸杆不落的典型故

weixin_29190651的博客 313

Nacos心跳机制与健康检查源码深度解析

本文深度解析了Nacos心跳机制与健康检查的源码实现,详细介绍了临时实例与持久化实例的不同心跳策略,以及客户端和服务端的关键代码逻辑。通过分析心跳参数配置、常见问题排查方案和高级特性,帮助开发者优化微服务注册中心的稳定性与性能,特别适合使用SpringCloud和Nacos作为注册中心的架构师参考。

hadoop5ranger的博客 894

新手学习Vivado XDMA (1) - 配置详细分析

PCIe 在 Vivado XDMA 中的配置分析。

qq_18553915的博客 9712

大模型长对话中上下文无法承载全部历史,如何压缩或提取重点

如果说截断和滑动窗口是“硬性”压缩,那摘要生成技术就显得“软”多了,也更接近于智能化的解决方案。它的思路是:不直接丢弃历史,而是通过自然语言处理(NLP)技术,把冗长的对话记录浓缩成一段简短的摘要,保留核心信息。这样既能大幅减少token数量,又不至于丢失关键内容。这种方法通常会借助预训练模型,比如BART或T5,它们擅长从长文本中提取重点内容。

大模型大数据攻城狮的专栏 1591

Alibaba Nacos注册中心源码剖析

文章目录一、Nacos&Ribbon&Feign核心微服务架构图二、架构原理三、Nacos架构图四、Nacos核心功能点五、Nacos核心功能源码架构图Nacos服务注册表结构:Map一、Nacos&Ribbon&Feign核心微服务架构图 二、架构原理 1、微服务系统在启动时将自己注册到服务注册中心,同时外发布 Http 接口供其它系统调用(一般都是基于Spring MVC) 2、服务消费者基于 Feign 调用服务提供者对外发布的接口,先对调用的本地接口加上注解@Fei

沮丧的南瓜 1429

YooAsset 学习

YooAssets使用教程

weixin_44884538的博客 1659

Nacos 源码分析 —— 健康检查机制详解

Nacos健康检查机制解析:本文详细剖析了Nacos作为服务发现和配置管理平台的核心健康检查功能。系统采用客户端心跳上报(默认5秒间隔)与服务端主动探测(TCP/HTTP/MySQL检查)双模式,通过心跳超时检测(15秒阈值)和失效实例自动清理(30秒过期)确保服务可用性。架构设计包含健康检查引擎、集群状态同步、事件通知机制等模块,支持SPI扩展自定义检查器。系统通过批量处理、任务分配等优化性能,并提供完善的监控指标。该机制有效解决了微服务架构中实例动态变化导致的请求失败问题,保障了服务注册中心的稳定性和可

油墨香^-^的博客 914

openbmc mctp i3c适配步骤

本文介绍了在Intel OKS平台下,BMC作为I3C从设备如何适配MCTP over I3C的实现方法。主要内容包括:1)关键术语解释,如MDB(Mandatory Data Byte)值为0xAE,DCR(Device Characteristics Register)和BCR(Bus Characteristics Register)的设置;2)适配流程说明,包括BMC作为控制器主节点分配地址后成为MCTP端点,CPU作为总线所有者的角色转换;3)测试验证步骤,展示通过mctp-client工具发送指

wit_yuan的专栏 132

本地快速部署谷歌开放模型Gemma教程(基于Ollama)

谷歌最近发布了新一代开源AI模型Gemma,此次发布的 Gemma 相比自家的 Gemini 更加轻量级,模型权重也一并开源。不仅可以在笔记本电脑上运行,而且还免费可商用,支持中文。运行速度飞快。

特立独行的博客 6722

【微服务】Nacos 注册中心的设计原理

注册中心的核心数据是服务的名字和它对应的网络地址,当服务注册了多个实例时,我们需要对不健康的实例进行过滤或者针对实例的⼀些特征进行流量的分配,那么就需要在实例上存储⼀些例如健康状态、权重等属性。

qq_57756904的博客 9817

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【微服务】【Nacos 3】 ① 深度解析:架构演进、核心组件与源码剖析

本文基于Nacos 3.x最新版本,系统介绍了其整体架构与核心功能。Nacos 3.x在多语言支持、服务治理模型、插件化架构等方面进行了重大升级,新增了元数据中心组件,实现了业务配置与服务元数据的解耦。文章详细分析了注册中心、配置中心的核心能力,并介绍了Multi-Raft Group、gRPC通信等新特性。通过架构图和源码解析,展示了Nacos的一致性协议实现机制及其插件化设计,为开发者提供了深入理解Nacos 3.x的完整视角。

xiezhiyi007的专栏 1183

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Nacos服务发现与注册源码剖析

Nacos&Ribbon&Feign核心微服务架构图 架构原理 1、微服务系统在启动时将自己注册到服务注册中心,同时外发布 Http 接口供其它系统调用(一般都是基于Spring MVC) 2、服务消费者基于 Feign 调用服务提供者对外发布的接口,先对调用的本地接口加上注解@FeignClient,Feign会针对 加了该注解的接口生成动态代理,服务消费者会针对 Feign 生成的动态代理去调用方法时,会在底层生成Http协议格式 的请求,类似 /stock/deduct?pr

小强同志的博客 753

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: MySQL主从复制与读写分离
下一篇: SpringSecurity+JWT认证流程解析
java_lujj
博客等级 码龄4年 18粉丝 152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值