nacos单机源码解析-服务发现和心跳检测

目录

1 服务发现

1.1 客户端

1.1.1 入口

1.1.2 定时拉取

1.1.3 总结

1.2 服务端

2 心跳检测

2.1 客户端

2.2 服务端

2.2.1 处理心跳请求

2.2.2 开启定时任务进行心跳检测

2.2.3 总结


1 服务发现

  • 服务列表:Nacos 维护一个服务列表,记录所有已注册的服务实例。

  • 动态更新:当服务实例发生变化(如新增、删除、健康状态变化)时,Nacos 会实时更新服务列表,并通知订阅了该服务的服务消费者。

1.1 客户端
1.1.1 入口

核心类:NacosNamingService.class 核心方法:getAllInstances


public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters,boolean subscribe) throws NacosException {ServiceInfo serviceInfo;//默认是trueif (subscribe) {//1 获取实例列表serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),StringUtils.join(clusters, ","));} else {serviceInfo = hostReactor.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName),StringUtils.join(clusters, ","));}List<Instance> list;if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {return new ArrayList<Instance>();}return list;
}public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {NAMING_LOGGER.debug("failover-mode: " + failoverReactor.isFailoverSwitch());String key = ServiceInfo.getKey(serviceName, clusters);if (failoverReactor.isFailoverSwitch()) {return failoverReactor.getService(key);}//1 从本地内存中获取实例信息ServiceInfo serviceObj = getServiceInfo0(serviceName, clusters);if (null == serviceObj) {//2 如果没有获取到 调用远程接口获取实例信息serviceObj = new ServiceInfo(serviceName, clusters);serviceInfoMap.put(serviceObj.getKey(), serviceObj);updatingMap.put(serviceName, new Object());//调用服务端接口获取实例信息///instance/list HttpMethod.GETupdateServiceNow(serviceName, clusters);updatingMap.remove(serviceName);} else if (updatingMap.containsKey(serviceName)) {if (UPDATE_HOLD_INTERVAL > 0) {// hold a moment waiting for update finishsynchronized (serviceObj) {try {serviceObj.wait(UPDATE_HOLD_INTERVAL);} catch (InterruptedException e) {NAMING_LOGGER.error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" + clusters, e);}}}}//3 开启定时任务获取实例信息scheduleUpdateIfAbsent(serviceName, clusters);return serviceInfoMap.get(serviceObj.getKey());
}public void scheduleUpdateIfAbsent(String serviceName, String clusters) {//1 如果已经有定时任务 不再重新创建if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {return;}synchronized (futureMap) {if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {return;}//2 添加定时任务 拉取实例信息ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters));futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);}
}
1.1.2 定时拉取

定时任务拉取实例信息

核心类:HostReactor.class 核心方法:run


public void run() {long delayTime = DEFAULT_DELAY;try {//1 从本地缓存获取实例信息ServiceInfo serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters));//2 没有获取到就远程获取if (serviceObj == null) {updateService(serviceName, clusters);return;}//3 如果数据已经过期 也去重新获取if (serviceObj.getLastRefTime() <= lastRefTime) {updateService(serviceName, clusters);serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters));} else {// if serviceName already updated by push, we should not override it// since the push data may be different from pull through force pushrefreshOnly(serviceName, clusters);}lastRefTime = serviceObj.getLastRefTime();if (!notifier.isSubscribed(serviceName, clusters) && !futureMap.containsKey(ServiceInfo.getKey(serviceName, clusters))) {// abort the update taskNAMING_LOGGER.info("update task is stopped, service:" + serviceName + ", clusters:" + clusters);return;}if (CollectionUtils.isEmpty(serviceObj.getHosts())) {incFailCount();return;}delayTime = serviceObj.getCacheMillis();resetFailCount();} catch (Throwable e) {incFailCount();NAMING_LOGGER.warn("[NA] failed to update serviceName: " + serviceName, e);} finally {executor.schedule(this, Math.min(delayTime << failCount, DEFAULT_DELAY * 60), TimeUnit.MILLISECONDS);}
}public void updateService(String serviceName, String clusters) throws NacosException {ServiceInfo oldService = getServiceInfo0(serviceName, clusters);try {//调用http请求获取服务列表String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUdpPort(), false);if (StringUtils.isNotEmpty(result)) {processServiceJson(result);}} finally {if (oldService != null) {synchronized (oldService) {oldService.notifyAll();}}}
}
1.1.3 总结
  1. 首先是从本地内存获取实例列表 如果不存在 就去调用远程接口获取实例列表

  2. 然后开启一个定时循环任务 首先判断本地内存有没有过期 如果没有过期就不拉取 如果过期了 调用远程接口获取实例列表 循环往复

1.2 服务端

核心类:InstanceController.java 核心方法:list


public ObjectNode list(HttpServletRequest request) throws Exception {String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);NamingUtils.checkServiceNameFormat(serviceName);String agent = WebUtils.getUserAgent(request);String clusters = WebUtils.optional(request, "clusters", StringUtils.EMPTY);String clientIP = WebUtils.optional(request, "clientIP", StringUtils.EMPTY);int udpPort = Integer.parseInt(WebUtils.optional(request, "udpPort", "0"));String env = WebUtils.optional(request, "env", StringUtils.EMPTY);boolean isCheck = Boolean.parseBoolean(WebUtils.optional(request, "isCheck", "false"));String app = WebUtils.optional(request, "app", StringUtils.EMPTY);String tenant = WebUtils.optional(request, "tid", StringUtils.EMPTY);boolean healthyOnly = Boolean.parseBoolean(WebUtils.optional(request, "healthyOnly", "false"));//1 获取服务实例集合return doSrvIpxt(namespaceId, serviceName, agent, clusters, clientIP, udpPort, env, isCheck, app, tenant,healthyOnly);
}public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent, String clusters, String clientIP,int udpPort, String env, boolean isCheck, String app, String tid, boolean healthyOnly) throws Exception {ClientInfo clientInfo = new ClientInfo(agent);ObjectNode result = JacksonUtils.createEmptyJsonNode();//1 从内存中获取服务集合Service service = serviceManager.getService(namespaceId, serviceName);long cacheMillis = switchDomain.getDefaultCacheMillis();
}    

2 心跳检测

心跳检测是指服务提供者定期向 Nacos 服务器发送心跳包,以表明自身仍然处于健康状态。Nacos 服务器接收到心跳包后,会更新服务实例的健康状态。如果某个服务实例在一定时间内没有发送心跳包,Nacos 会认为该实例不健康,并将其从服务列表中移除。

心跳检测的主要作用

  1. 健康状态管理:

    1. 检测不健康实例:通过心跳检测,Nacos 可以及时发现不健康的服务实例。

    2. 移除不健康实例:不健康的服务实例会被从服务列表中移除,避免服务消费者的请求路由到这些实例。

  2. 动态更新服务列表:

    1. 实时更新:当服务实例的健康状态发生变化时,Nacos 会实时更新服务列表,并通知订阅了该服务的服务消费者。

    2. 高可用性:通过及时移除不健康实例,Nacos 确保服务消费者的请求总是路由到健康的实例,提高系统的高可用性。

2.1 客户端

核心类:NacosNamingService.class 核心方法:registerInstance


public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {NamingUtils.checkInstanceIsLegal(instance);String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);if (instance.isEphemeral()) {//1 如果是临时实例 就开启心跳检测BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);beatReactor.addBeatInfo(groupedServiceName, beatInfo);}serverProxy.registerService(groupedServiceName, groupName, instance);
}public void addBeatInfo(String serviceName, BeatInfo beatInfo) {NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);//1 创建唯一标识String key = buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());BeatInfo existBeat = null;//fix #1733if ((existBeat = dom2Beat.remove(key)) != null) {existBeat.setStopped(true);}dom2Beat.put(key, beatInfo);//2 开启定时任务 每5秒执行一次executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}public void run() {if (beatInfo.isStopped()) {return;}long nextTime = beatInfo.getPeriod();try {//1 发送http请求发送心跳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);
}

总结:

  1. 如果是临时实例 那么注册的时候就会发送心跳信息给服务端

  2. 同时开启一个定时任务 定期给服务端发送心跳

2.2 服务端
2.2.1 处理心跳请求

核心类:InstanceController.java 核心方法:beat

 

public ObjectNode beat(HttpServletRequest request) throws Exception {ObjectNode result = JacksonUtils.createEmptyJsonNode();result.put(SwitchEntry.CLIENT_BEAT_INTERVAL, switchDomain.getClientBeatInterval());String beat = WebUtils.optional(request, "beat", StringUtils.EMPTY);RsInfo clientBeat = null;if (StringUtils.isNotBlank(beat)) {clientBeat = JacksonUtils.toObj(beat, RsInfo.class);}String clusterName = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME);String ip = WebUtils.optional(request, "ip", StringUtils.EMPTY);int port = Integer.parseInt(WebUtils.optional(request, "port", "0"));if (clientBeat != null) {if (StringUtils.isNotBlank(clientBeat.getCluster())) {clusterName = clientBeat.getCluster();} else {// fix #2533clientBeat.setCluster(clusterName);}ip = clientBeat.getIp();port = clientBeat.getPort();}String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);NamingUtils.checkServiceNameFormat(serviceName);Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}", clientBeat, serviceName);Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port);if (instance == null) {if (clientBeat == null) {result.put(CommonParams.CODE, NamingResponseCode.RESOURCE_NOT_FOUND);return result;}Loggers.SRV_LOG.warn("[CLIENT-BEAT] The instance has been removed for health mechanism, "+ "perform data compensation operations, beat: {}, serviceName: {}", clientBeat, serviceName);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);if (service == null) {throw new NacosException(NacosException.SERVER_ERROR,"service not found: " + serviceName + "@" + namespaceId);}if (clientBeat == null) {clientBeat = new RsInfo();clientBeat.setIp(ip);clientBeat.setPort(port);clientBeat.setCluster(clusterName);}//1 处理心跳请求service.processClientBeat(clientBeat);result.put(CommonParams.CODE, NamingResponseCode.OK);if (instance.containsMetadata(PreservedMetadataKeys.HEART_BEAT_INTERVAL)) {result.put(SwitchEntry.CLIENT_BEAT_INTERVAL, instance.getInstanceHeartBeatInterval());}result.put(SwitchEntry.LIGHT_BEAT_ENABLED, switchDomain.isLightBeatEnabled());return result;
}public void processClientBeat(final RsInfo rsInfo) {ClientBeatProcessor clientBeatProcessor = new ClientBeatProcessor();clientBeatProcessor.setService(this);clientBeatProcessor.setRsInfo(rsInfo);//1 处理心跳请求HealthCheckReactor.scheduleNow(clientBeatProcessor);
}public void run() {Service service = this.service;if (Loggers.EVT_LOG.isDebugEnabled()) {Loggers.EVT_LOG.debug("[CLIENT-BEAT] processing beat: {}", rsInfo.toString());}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) {if (Loggers.EVT_LOG.isDebugEnabled()) {Loggers.EVT_LOG.debug("[CLIENT-BEAT] refresh beat: {}", rsInfo.toString());}//1 将上次心跳事件修改为现在instance.setLastBeat(System.currentTimeMillis());if (!instance.isMarked()) {if (!instance.isHealthy()) {//2 如果服务之前状态为不健康 将服务状态设置为健康instance.setHealthy(true);Loggers.EVT_LOG.info("service: {} {POS} {IP-ENABLED} valid: {}:{}@{}, region: {}, msg: client beat ok",cluster.getService().getName(), ip, port, cluster.getName(),UtilsAndCommons.LOCALHOST_SITE);//3 发布状态变更事件                getPushService().serviceChanged(service);}}}}
}
2.2.2 开启定时任务进行心跳检测

核心类:ServiceManager.java 核心方法:registerInstance


public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {//1 创建一个空服务 如果不存在就直接创建 存在就什么都不做createEmptyService(namespaceId, serviceName, instance.isEphemeral());//2 获取内存中存储该服务的相关信息Service service = getService(namespaceId, serviceName);if (service == null) {throw new NacosException(NacosException.INVALID_PARAM,"service not found, namespace: " + namespaceId + ", service: " + serviceName);}//3 添加服务addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
}public void createEmptyService(String namespaceId, String serviceName, boolean local) throws NacosException {createServiceIfAbsent(namespaceId, serviceName, local, null);
}public void createServiceIfAbsent(String namespaceId, String serviceName, boolean local, Cluster cluster)throws NacosException {//1 通过命名空间和服务名从内存中获取服务信息Service service = getService(namespaceId, serviceName);//2 获取失败if (service == null) {//3 组装服务信息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//4 注册最新心跳时间service.setLastModifiedMillis(System.currentTimeMillis());service.recalculateChecksum();if (cluster != null) {cluster.setService(service);service.getClusterMap().put(cluster.getName(), cluster);}service.validate();//5 存储服务并初始化putServiceAndInit(service);if (!local) {addOrReplaceService(service);}}
}private void putServiceAndInit(Service service) throws NacosException {//1 存储服务putService(service);//2 初始化服务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());
}public void init() {//注册心跳任务HealthCheckReactor.scheduleCheck(clientBeatCheckTask);for (Map.Entry<String, Cluster> entry : clusterMap.entrySet()) {entry.getValue().setService(this);entry.getValue().init();}
}public void run() {try {if (!getDistroMapper().responsible(service.getName())) {return;}if (!getSwitchDomain().isHealthCheckEnabled()) {return;}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()) {//1 如果15秒内没有心跳 状态设置为不健康instance.setHealthy(false);Loggers.EVT_LOG.info("{POS} {IP-DISABLED} valid: {}:{}@{}@{}, region: {}, msg: client timeout after {}, last beat: {}",instance.getIp(), instance.getPort(), instance.getClusterName(),service.getName(), UtilsAndCommons.LOCALHOST_SITE,instance.getInstanceHeartBeatTimeOut(), instance.getLastBeat());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 instanceLoggers.SRV_LOG.info("[AUTO-DELETE-IP] service: {}, ip: {}", service.getName(),JacksonUtils.toJson(instance));//2 30秒内没有心跳 删除实例 通过http请求调用自身删除接口        deleteIp(instance);}}} catch (Exception e) {Loggers.SRV_LOG.warn("Exception while processing client beat time out.", e);}}
2.2.3 总结
  1. 服务端接收到了请求之后 会修改实例的上一次心跳事件

  2. 服务注册时 就开启了一个定时任务 检测心跳 15秒内没有心跳设置实例状态为不健康 30秒内没有心跳就删除实例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/12111.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[JAVAEE] 面试题(五) - HashMap, Hashtable, ConcurrentHashMap

目录 一. Hashtable1.1 Hashtable效率低下的原因: 二. ConcurrentHashMap2.1 ConcurrentHashMap更高效的原因: 三. HashMap, Hashtable, ConcurrentHashMap 之间的区别 HashMap是线程不安全的. 在多线程环境下, 使用: HashtableConcurrentHashMap 来确保线程安全. 一. Hashta…

Vue 2 —Vue Router 页面导航和参数传递

当从A页面跳转到B页面的时候把数据也一起传递过去&#xff0c;可用Vue Router 功能&#xff1a; 一、. this.$router.push 方法 Vue Router 是 Vue.js 的官方路由管理器&#xff0c;允许你在应用中进行页面导航&#xff08;即跳转到不同的 URL 路径&#xff09;。 this.$rout…

Local Transfer 致力于更加便捷地共享传输文件

软件主页&#xff1a;https://illusionna.github.io/LocalTransfer

[AcWing算法基础课]动态规划之01背包

题目链接&#xff1a;01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi&#xff0c;价值是 wi。求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。输出最大价值。 首先&#xff0c;我们…

标准、高效的管理测试用例和活动

送您一份新人礼&#xff0c;自动化测试平台限时免费体验~ 本文主要介绍测试用例管理的基础知识和基本使用方法&#xff0c;帮助您快速管理测试用例及活动。 操作流程 用例管理的主要使用流程如下&#xff1a; 1.新建测试用例 2.评审测试用例 3.创建测试计划 4.执行测试计划 5…

如何在jupyter notebook切换python环境

目录 1、切换到目标python环境&#xff0c;假设我的是叫“tf” C:\Users\hello>activate tf(tf) C:\Users\hello>2、安装notebook内核包 (tf) C:\Users\hello>pip install ipykernel3、将环境加入到notebook中 python -m ipykernel install --user --name pytorch --…

windows工具 -- 使用SpaceSniffer查看哪些文件夹占用那么大空间, 再也不用右键属性了

目的 C盘不知道哪些文件夹占用了那么多空间, 右键属性扫描太慢了 效果 运行效果 静态截图 下载使用 下载 SpaceSniffer https://github.com/redtrillix/SpaceSniffer/releases 解压到文件夹后, 双击运行

[DEBUG] 服务器 CORS 已经允许所有源,仍然有 304 的跨域问题

背景 今天有一台服务器到期了&#xff0c;准备把后端迁移到另一台服务器上&#xff0c;结果前端在测试的时候&#xff0c;出现了 304 的跨域问题。 调试过程中出现的问题&#xff0c;包括但不限于&#xff1a; set the request’s mode to ‘no-cors’Redirect is not allow…

智慧园区解决方案:科技赋能,打造未来管理新典范

智慧园区作为城市发展的重要组成部分&#xff0c;正以前所未有的速度蓬勃发展。随着5G、云计算、大数据、物联网&#xff08;IoT&#xff09;、BIM&#xff08;建筑信息模型&#xff09;、人工智能&#xff08;AI&#xff09;及区块链等前沿技术的日益成熟与融合应用&#xff0…

CTF记录

1. [SWPUCTF 2022 新生赛]android 用jadx打开&#xff0c;然后搜索NSS关键字 NSSCTF{a_simple_Android} 2. [SWPU 2024 新生引导]ez_SSTI 模板注入题目&#xff0c;直接焚靖可以秒了 填入数据 ls / 然后 cat /flag即可 获取成功 NSSCTF{2111e7ad-97c5-40d5-9a3b-a2f657bd45e8…

Vue使用富文本编辑器vue-quill-editor

Vue使用富文本编辑器 1. 安装 npm install vue-quill-editor -S2. 引入到项目中 有两种挂载方式&#xff1a; 全局挂载 和 在组件中挂载&#xff0c;根据自己的项目需求选择&#xff0c;一般用到富文本编辑都是在某一个项目中&#xff0c;我们这里为了方便大家选择&#xff…

AUTOSAR_EXP_ARAComAPI的7章笔记(2)

☞返回总目录 相关总结&#xff1a;服务发现实现策略总结 7.2 服务发现的实现策略 如前面章节所述&#xff0c;ara::com 期望产品供应商实现服务发现的功能。服务发现功能基本上是在 API 级别通过 FindService、OfferService 和 StopOfferService 方法定义的&#xff0c;协议…

windows yolo11 自定义训练

一、在yolo11源码文件夹创建一个train.py 内容如下&#xff1a; from ultralytics import YOLOif __name__ __main__:model YOLO(rultralytics/cfg/models/11/yolo11.yaml)model.train(datarD:/yolo11/WiderPerson_yolo/WiderPerson_yolo/WiderPerson_yolo.yaml,imgsz(640,3…

简述 synchronized 和 java.util.concurrent.locks.Lock 的异同?

大家好&#xff0c;我是锋哥。今天分享关于【简述 synchronized 和 java.util.concurrent.locks.Lock 的异同&#xff1f;】面试题。希望对大家有帮助&#xff1b; 简述 synchronized 和 java.util.concurrent.locks.Lock 的异同&#xff1f; 在Java编程中&#xff0c;synchro…

C语言中,“extern”关键字的含义与用法

在C语言中&#xff0c;extern 关键字用于声明一个已经在其他地方定义的变量或函数。它的主要作用是告诉编译器&#xff0c;某个变量或函数是在当前文件之外定义的&#xff0c;编译器应该在链接阶段找到这个变量或函数的实际定义。以下是 extern 的一些常见用途和用法&#xff1…

TCP最后一次握⼿连接阶段,如果ACK包丢失会怎样?

2024年10月NJSD技术盛典暨第十届NJSD软件开发者大会、第八届IAS互联网架构大会在南京召开。百度文心快码总经理臧志分享了《AI原生研发新范式的实践与思考》&#xff0c;探讨了大模型赋能下的研发变革及如何在公司和行业中落地&#xff0c;AI原生研发新范式的内涵和推动经验。 …

【大数据学习 | HBASE】hbase的读数据流程与hbase读取数据

1. hbase的读数据流程 在解析读取流程之前我们还需要知道两个功能性的组件和HFIle的格式信息 HFILE 存储在hdfs中的hbase文件&#xff0c;这个文件中会存在hbase中的数据以kv类型显示&#xff0c;同时还会存在hbase的元数据信息&#xff0c;包括整个hfile文件的索引大小&…

AI基础知识

目录 1.激活函数:one: 激活函数的作用:two: sigmoid函数:three: tanh函数:four: ReLu:five: Leaky ReLU 2.Softmax函数3.优化器:one: 优化器的作用:two: BGD&#xff08;批梯度下降&#xff09;:three: SGD&#xff08;随机梯度下降&#xff09;:four: MBGD&#xff08;Mini Ba…

01背包问题(DP)

2. 01背包问题 - AcWing题库 DP做题思路分析 实现代码&#xff1a; #include <iostream> #include <algorithm>using namespace std;const int N 1010;int n , m; int v[N],w[N],dp[N][N];int main() {cin >> n >> m;for (int i 1;i < n;i) {ci…

如何提升自媒体发稿效果,必须掌握的几个技巧

在自媒体时代&#xff0c;发稿效果直接关系到内容的传播力与影响力。为了提升自媒体发稿效果&#xff0c;有几个关键技巧是每位自媒体人必须掌握的。以下是对这些技巧的详细阐述&#xff1a; 一、明确受众定位 首先&#xff0c;自媒体人需要明确自己的受众群体。这包括受众的…