Nacos源码—4.Nacos集群高可用分析四

大纲

6.CAP原则与Raft协议

7.Nacos实现的Raft协议是如何写入数据的

8.Nacos实现的Raft协议是如何选举Leader节点的

9.Nacos实现的Raft协议是如何同步数据的

10.Nacos如何实现Raft协议的简版总结

8.Nacos实现的Raft协议是如何选举Leader节点的

(1)初始化RaftCore实例时会开启两个异步任务

(2)选举Leader节点的MasterElection异步任务

(1)初始化RaftCore实例时会开启两个异步任务

在RaftCore的init()方法中,会开启两个异步任务。第一个异步任务的作用是选举Leader节点,第二个异步任务的作用是发送心跳同步数据。

@Deprecated
@DependsOn("ProtocolManager")
@Component
public class RaftCore implements Closeable {...//Init raft core.@PostConstructpublic void init() throws Exception {Loggers.RAFT.info("initializing Raft sub-system");final long start = System.currentTimeMillis();//从本地文件中加载数据raftStore.loadDatums(notifier, datums);setTerm(NumberUtils.toLong(raftStore.loadMeta().getProperty("term"), 0L));Loggers.RAFT.info("cache loaded, datum count: {}, current term: {}", datums.size(), peers.getTerm());initialized = true;Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start));//开启一个异步任务选举Leader节点masterTask = GlobalExecutor.registerMasterElection(new MasterElection());//开启一个异步任务通过心跳同步数据heartbeatTask = GlobalExecutor.registerHeartbeat(new HeartBeat());versionJudgement.registerObserver(isAllNewVersion -> {stopWork = isAllNewVersion;if (stopWork) {try {shutdown();raftListener.removeOldRaftMetadata();} catch (NacosException e) {throw new NacosRuntimeException(NacosException.SERVER_ERROR, e);}}}, 100);//给NotifyCenter注册一个监听PersistentNotifierNotifyCenter.registerSubscriber(notifier);Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}", GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS);}...
}public class GlobalExecutor {//线程池的线程数是可用线程的一半private static final ScheduledExecutorService NAMING_TIMER_EXECUTOR =ExecutorFactory.Managed.newScheduledExecutorService(ClassUtils.getCanonicalName(NamingApp.class),Runtime.getRuntime().availableProcessors() * 2,new NameThreadFactory("com.alibaba.nacos.naming.timer"));...public static ScheduledFuture registerMasterElection(Runnable runnable) {//以固定的频率来执行某项任务,它不受任务执行时间的影响,到时间就会执行任务return NAMING_TIMER_EXECUTOR.scheduleAtFixedRate(runnable, 0, TICK_PERIOD_MS, TimeUnit.MILLISECONDS);}public static ScheduledFuture registerHeartbeat(Runnable runnable) {//以相对固定的频率来执行某项任务,即只有等这一次任务执行完了(不管执行了多长时间),才能执行下一次任务return NAMING_TIMER_EXECUTOR.scheduleWithFixedDelay(runnable, 0, TICK_PERIOD_MS, TimeUnit.MILLISECONDS);}...
}

(2)选举Leader节点的MasterElection异步任务

MasterElection的run()方法就体现了Raft协议进行Leader选举的第一步。即每个节点会进行休眠,如果时间没到则返回然后重新执行异步任务。等休眠时间到了才会调用MasterElection的sendVote()方法发起投票。

一旦执行MasterElection的sendVote()方法发起投票:会先把选举周期+1,然后投票给自己,接着修改节点状态为Candidate。做完这些准备工作后,才会以HTTP形式向其他节点发送投票请求。

其他节点返回投票信息时,会调用RaftPeerSet的decideLeader()方法处理。这个方法会处理其他节点返回的投票信息,具体逻辑如下:

首先用一个Map记录每个节点返回的投票信息,然后遍历这个Map去统计投票数量,最后比较当前节点的累计票数,是否已超过集群节点半数。如果超过,则把当前节点的状态修改为Leader。

@Deprecated
@DependsOn("ProtocolManager")
@Component
public class RaftCore implements Closeable {private RaftPeerSet peers;...public class MasterElection implements Runnable {@Overridepublic void run() {try {if (stopWork) {return;}if (!peers.isReady()) {return;}//随机休眠RaftPeer local = peers.local();local.leaderDueMs -= GlobalExecutor.TICK_PERIOD_MS;//休眠时间没到就直接返回if (local.leaderDueMs > 0) {return;}//reset timeoutlocal.resetLeaderDue();local.resetHeartbeatDue();//发起投票sendVote();} catch (Exception e) {Loggers.RAFT.warn("[RAFT] error while master election {}", e);}}private void sendVote() {RaftPeer local = peers.get(NetUtils.localServer());Loggers.RAFT.info("leader timeout, start voting,leader: {}, term: {}", JacksonUtils.toJson(getLeader()), local.term);peers.reset();//选举周期+1local.term.incrementAndGet();//投票给自己local.voteFor = local.ip;//自己成为候选者,设置当前节点状态为Candidate状态local.state = RaftPeer.State.CANDIDATE;Map<String, String> params = new HashMap<>(1);params.put("vote", JacksonUtils.toJson(local));//遍历其他集群节点for (final String server : peers.allServersWithoutMySelf()) {final String url = buildUrl(server, API_VOTE);try {//发送HTTP的投票请求HttpClient.asyncHttpPost(url, null, params, new Callback<String>() {@Overridepublic void onReceive(RestResult<String> result) {if (!result.ok()) {Loggers.RAFT.error("NACOS-RAFT vote failed: {}, url: {}", result.getCode(), url);return;}RaftPeer peer = JacksonUtils.toObj(result.getData(), RaftPeer.class);Loggers.RAFT.info("received approve from peer: {}", JacksonUtils.toJson(peer));//处理返回的投票结果peers.decideLeader(peer);}@Overridepublic void onError(Throwable throwable) {Loggers.RAFT.error("error while sending vote to server: {}", server, throwable);}@Overridepublic void onCancel() {}});} catch (Exception e) {Loggers.RAFT.warn("error while sending vote to server: {}", server);}}}}...
}@Deprecated
@Component
@DependsOn("ProtocolManager")
public class RaftPeerSet extends MemberChangeListener implements Closeable {private volatile Map<String, RaftPeer> peers = new HashMap<>(8);...//Calculate and decide which peer is leader. If has new peer has more than half vote, change leader to new peer.public RaftPeer decideLeader(RaftPeer candidate) {//记录本次投票结果peers.put(candidate.ip, candidate);SortedBag ips = new TreeBag();int maxApproveCount = 0;String maxApprovePeer = null;//统计累计票数for (RaftPeer peer : peers.values()) {if (StringUtils.isEmpty(peer.voteFor)) {continue;}ips.add(peer.voteFor);if (ips.getCount(peer.voteFor) > maxApproveCount) {maxApproveCount = ips.getCount(peer.voteFor);maxApprovePeer = peer.voteFor;}}//判断投票数量是否超过半数,如果已超半数则把自己节点的状态改为Leaderif (maxApproveCount >= majorityCount()) {RaftPeer peer = peers.get(maxApprovePeer);//设置当前节点的状态为Leader状态peer.state = RaftPeer.State.LEADER;if (!Objects.equals(leader, peer)) {leader = peer;ApplicationUtils.publishEvent(new LeaderElectFinishedEvent(this, leader, local()));Loggers.RAFT.info("{} has become the LEADER", leader.ip);}}return leader;}...
}

9.Nacos实现的Raft协议是如何同步数据的

(1)Leader节点如何发送心跳来同步数据

(2)Follower节点如何处理心跳来同步数据

(1)Leader节点如何发送心跳来同步数据

RaftCore的init()方法会开启另外一个异步任务HeartBeat。HeartBeat的run()方法会调用HeartBeat的sendBeat()方法来发送心跳请求。

其中只有Leader节点才会发送心跳请求。Leader在调用HeartBeat的sendBeat()方法发送心跳同步数据请求时,会将Instance的key作为心跳的参数发送给其他Follower节点。Follower节点接收到Leader的心跳请求后,会比较请求中的数据与自身数据的差异,如果存在差异则向Leader同步。

HeartBeat的sendBeat()方法主要包括三部分:

第一部分:判断当前节点是不是Leader,如果不是Leader则不能发送心跳。

第二部分:组装发送心跳包的参数。只会把datum.key放入进去,并不会把整个Instance信息传输过去。Follower节点拿到心跳包中的key之后,发现部分key在自身节点是不存在的,那么这时Follower节点就会根据这些key向Leader节点获取Instance的详细信息进行同步。

第三部分:向其他Follower节点发送心跳数据,是通过HTTP的方式来发起心跳请求的,请求地址为:/v1/ns/raft/beat。

@Deprecated
@DependsOn("ProtocolManager")
@Component
public class RaftCore implements Closeable {...public class HeartBeat implements Runnable {@Overridepublic void run() {try {if (stopWork) {return;}if (!peers.isReady()) {return;}RaftPeer local = peers.local();local.heartbeatDueMs -= GlobalExecutor.TICK_PERIOD_MS;if (local.heartbeatDueMs > 0) {return;}local.resetHeartbeatDue();//发送心跳同步数据sendBeat();} catch (Exception e) {Loggers.RAFT.warn("[RAFT] error while sending beat {}", e);}}private void sendBeat() throws IOException, InterruptedException {RaftPeer local = peers.local();//第一部分:判断当前节点是不是Leader,如果不是Leader则不能发送心跳if (EnvUtil.getStandaloneMode() || local.state != RaftPeer.State.LEADER) {return;}if (Loggers.RAFT.isDebugEnabled()) {Loggers.RAFT.debug("[RAFT] send beat with {} keys.", datums.size());}local.resetLeaderDue();//build dataObjectNode packet = JacksonUtils.createEmptyJsonNode();packet.replace("peer", JacksonUtils.transferToJsonNode(local));ArrayNode array = JacksonUtils.createEmptyArrayNode();if (switchDomain.isSendBeatOnly()) {Loggers.RAFT.info("[SEND-BEAT-ONLY] {}", switchDomain.isSendBeatOnly());}if (!switchDomain.isSendBeatOnly()) {//第二部分:组装发送心跳包的参数//组装数据,只会把datum.key放入进去,并不会把整个Instance信息传输过去for (Datum datum : datums.values()) {ObjectNode element = JacksonUtils.createEmptyJsonNode();if (KeyBuilder.matchServiceMetaKey(datum.key)) {//只放入key的信息element.put("key", KeyBuilder.briefServiceMetaKey(datum.key));} else if (KeyBuilder.matchInstanceListKey(datum.key)) {element.put("key", KeyBuilder.briefInstanceListkey(datum.key));}element.put("timestamp", datum.timestamp.get());array.add(element);}}packet.replace("datums", array);//broadcastMap<String, String> params = new HashMap<String, String>(1);params.put("beat", JacksonUtils.toJson(packet));String content = JacksonUtils.toJson(params);        ByteArrayOutputStream out = new ByteArrayOutputStream();GZIPOutputStream gzip = new GZIPOutputStream(out);gzip.write(content.getBytes(StandardCharsets.UTF_8));gzip.close();byte[] compressedBytes = out.toByteArray();String compressedContent = new String(compressedBytes, StandardCharsets.UTF_8);if (Loggers.RAFT.isDebugEnabled()) {Loggers.RAFT.debug("raw beat data size: {}, size of compressed data: {}", content.length(), compressedContent.length());}//第三部分:向其他Follower节点发送心跳数据,通过HTTP的方式来发起心跳,请求地址为:/v1/ns/raft/beat//发送心跳 + 同步数据for (final String server : peers.allServersWithoutMySelf()) {try {final String url = buildUrl(server, API_BEAT);if (Loggers.RAFT.isDebugEnabled()) {Loggers.RAFT.debug("send beat to server " + server);}//通过HTTP发送心跳HttpClient.asyncHttpPostLarge(url, null, compressedBytes, new Callback<String>() {@Overridepublic void onReceive(RestResult<String> result) {if (!result.ok()) {Loggers.RAFT.error("NACOS-RAFT beat failed: {}, peer: {}", result.getCode(), server);MetricsMonitor.getLeaderSendBeatFailedException().increment();return;}peers.update(JacksonUtils.toObj(result.getData(), RaftPeer.class));if (Loggers.RAFT.isDebugEnabled()) {Loggers.RAFT.debug("receive beat response from: {}", url);}}@Overridepublic void onError(Throwable throwable) {Loggers.RAFT.error("NACOS-RAFT error while sending heart-beat to peer: {} {}", server, throwable);MetricsMonitor.getLeaderSendBeatFailedException().increment();}@Overridepublic void onCancel() {}});} catch (Exception e) {Loggers.RAFT.error("error while sending heart-beat to peer: {} {}", server, e);MetricsMonitor.getLeaderSendBeatFailedException().increment();}}}}...
}

(2)Follower节点如何处理心跳来同步数据

Follower节点收到Leader节点发送过来的HTTP请求"/v1/ns/raft/beat"时,会执行RaftController类中的beat()方法,接着会执行RaftCore的receivedBeat()方法来进行具体的心跳处理。

RaftCore.receivedBeat()方法的具体逻辑如下:

一.首先会进行一些判断

第一个判断:Follower节点接收到的心跳请求如果不是Leader节点发出的会直接抛出异常。

第二个判断:Follower节点的term只会小于等于Leader节点的term,如果大于,则直接抛出异常。

第三个判断:如果自身节点的状态不是Follower,需要把状态改为Follower。因为有可能自身节点之前是Leader,但因为网络原因出现了脑裂问题。等网络恢复后,自身节点收到新Leader发来的心跳,新Leader的term比自身节点要大,那么它就需要切换成Follower节点。

二.然后对自身节点的datums中的key和心跳请求中的key进行比对

如果发现自身节点数据缺少了,那么就会记录到batch中,然后把batch中的key进行拆分包装成请求参数,最后通过HTTP方式向Leader节点查询这些key对应的Instance详细信息。

Follower节点拿到Leader节点返回的Instance服务实例信息后,会继续调用RaftStore.write()、PersistentNotifier.notify()这两个方法,一个将数据持久化到本地文件、一个将数据同步到内存注册表,从而最终完成以Leader节点为准的心跳请求同步数据的流程。

@Deprecated
@RestController
@RequestMapping({UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft", UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft"})
public class RaftController {private final RaftCore raftCore;...@PostMapping("/beat")public JsonNode beat(HttpServletRequest request, HttpServletResponse response) throws Exception {if (versionJudgement.allMemberIsNewVersion()) {throw new IllegalStateException("old raft protocol already stop");}String entity = new String(IoUtils.tryDecompress(request.getInputStream()), StandardCharsets.UTF_8);String value = URLDecoder.decode(entity, "UTF-8");value = URLDecoder.decode(value, "UTF-8");JsonNode json = JacksonUtils.toObj(value);//处理心跳RaftPeer peer = raftCore.receivedBeat(JacksonUtils.toObj(json.get("beat").asText()));return JacksonUtils.transferToJsonNode(peer);}...
}@Deprecated
@DependsOn("ProtocolManager")
@Component
public class RaftCore implements Closeable {public final PersistentNotifier notifier;...//Received beat from leader. // TODO split method to multiple smaller method.public RaftPeer receivedBeat(JsonNode beat) throws Exception {...//第一个判断:如果发送心跳不是Leader,则直接抛出异常if (remote.state != RaftPeer.State.LEADER) {Loggers.RAFT.info("[RAFT] invalid state from master, state: {}, remote peer: {}", remote.state, JacksonUtils.toJson(remote));throw new IllegalArgumentException("invalid state from master, state: " + remote.state);}//第二个判断:如果本身节点的term还大于Leader的term,也直接抛出异常if (local.term.get() > remote.term.get()) {Loggers.RAFT.info("[RAFT] out of date beat, beat-from-term: {}, beat-to-term: {}, remote peer: {}, and leaderDueMs: {}", remote.term.get(), local.term.get(), JacksonUtils.toJson(remote), local.leaderDueMs);throw new IllegalArgumentException("out of date beat, beat-from-term: " + remote.term.get() + ", beat-to-term: " + local.term.get());}//第三个判断:自己的节点状态是不是FOLLOWER,如果不是则需要更改为FOLLOWERif (local.state != RaftPeer.State.FOLLOWER) {Loggers.RAFT.info("[RAFT] make remote as leader, remote peer: {}", JacksonUtils.toJson(remote));//mk followerlocal.state = RaftPeer.State.FOLLOWER;local.voteFor = remote.ip;}...//遍历Leader传输过来的Instance key,和本地的Instance进行对比for (Object object : beatDatums) {...try {if (datums.containsKey(datumKey) && datums.get(datumKey).timestamp.get() >= timestamp && processedCount < beatDatums.size()) {continue;}if (!(datums.containsKey(datumKey) && datums.get(datumKey).timestamp.get() >= timestamp)) {//记录需要同步的datumKeybatch.add(datumKey);}//到达一定数量才进行批量数据同步if (batch.size() < 50 && processedCount < beatDatums.size()) {continue;}...//使用batch组装参数String url = buildUrl(remote.ip, API_GET);Map<String, String> queryParam = new HashMap<>(1);queryParam.put("keys", URLEncoder.encode(keys, "UTF-8"));//发送HTTP请求给Leader,根据keys参数获取Instance详细信息HttpClient.asyncHttpGet(url, null, queryParam, new Callback<String>() {@Overridepublic void onReceive(RestResult<String> result) {if (!result.ok()) {return;}//序列化result结果List<JsonNode> datumList = JacksonUtils.toObj(result.getData(), new TypeReference<List<JsonNode>>() { });//遍历Leader返回的Instance详细信息for (JsonNode datumJson : datumList) {Datum newDatum = null;OPERATE_LOCK.lock();try {...//Raft写本地数据raftStore.write(newDatum);//同步内存数据datums.put(newDatum.key, newDatum);//和服务实例注册时的逻辑一样,最终会调用listener.onChange()方法notifier.notify(newDatum.key, DataOperation.CHANGE, newDatum.value);} catch (Throwable e) {Loggers.RAFT.error("[RAFT-BEAT] failed to sync datum from leader, datum: {}", newDatum, e);} finally {OPERATE_LOCK.unlock();}}...return;}...});batch.clear();} catch (Exception e) {Loggers.RAFT.error("[NACOS-RAFT] failed to handle beat entry, key: {}", datumKey);}}...}    ...
}

10.Nacos如何实现Raft协议的简版总结

Nacos实现的Raft协议主要包括三部分内容:

一.Nacos集群如何使用Raft协议写入数据

二.Nacos集群如何选举Leader节点

三.Nacos集群如何让Leader实现心跳请求同步数据

Nacos早期版本实现的只是Raft协议的简化版本,并没有两阶段提交的处理。而是Leader节点处理数据完成后,直接就去同步给其他集群节点。哪怕集群节点同步失败或没有过半节点成功,Leader的数据也不会回滚而只抛出异常。所以,Nacos早期版本的Raft实现,后期也会废弃使用。

如下是Nacos实现的Raft协议在注册服务实例时集群处理数据的流程:

如下是Nacos实现的Raft协议处理Leader选举和通过心跳同步数据的流程:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

拟南芥T2T基因组-文献精读127

A near-complete assembly of an Arabidopsis thaliana genome 拟南芥基因组的近乎完整组装 拟南芥&#xff08;Arabidopsis thaliana&#xff09;基因组序列作为广泛应用的模式物种&#xff0c;为植物分子生物学研究提供了巨大的推动力。在基因组序列首次发布后的20多年&…

一个关于fsaverage bem文件的说明

MNE文档&#xff1a;基于模板 MRI 的 EEG 前向算子 Head model and forward computation 在了解了脑图谱发展的过程之后&#xff0c;对脑的模版有了更深的认识&#xff0c;所以&#xff0c;对于之前使用的正向的溯源文件&#xff0c;进行一下解析&#xff0c;查看包含的信息&a…

C#学习第21天:安全与加密(Security and Cryptography)

核心概念 1. 什么是加密&#xff1f; 加密&#xff1a;加密是一种将数据转换为一种不可读形式的方法&#xff0c;只有持有相应密钥的人才能解密并读取数据。目的&#xff1a;确保数据的机密性和安全性&#xff0c;特别是在传输过程中过防止未授权访问。 2. 加密类型 对称加密…

OpenCV 图形API(77)图像与通道拼接函数-----对图像进行几何变换函数remap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 对图像应用一个通用的几何变换。 函数 remap 使用指定的映射对源图像进行变换&#xff1a; dst ( x , y ) src ( m a p x ( x , y ) , m a p y…

在线时间戳转换工具

给大家推荐一个在线时间戳转换工具 点击跳转-鸽鸽在线工具 这个工具除了时间戳转换&#xff0c;到首页还能选择使用很多其他小工具&#xff0c;欢迎使用

WPF之面板特性

文章目录 1. 概述2. WPF布局系统基础2.1 布局过程概述2.2 布局重新计算的触发条件2.3 布局重新计算的核心方法 3. WPF内置面板类型及特性3.1 面板类型概览3.2 Canvas面板3.3 StackPanel面板3.4 WrapPanel面板3.5 DockPanel面板3.6 Grid面板3.7 UniformGrid面板3.8 Virtualizing…

【技术追踪】通过潜在扩散和先验知识增强时空疾病进展模型(MICCAI-2024)

向扩散模型中引入先验知识&#xff0c;实现疾病进展预测&#xff0c;扩散模型开始细节作业了~ 论文&#xff1a;Enhancing Spatiotemporal Disease Progression Models via Latent Diffusion and Prior Knowledge 代码&#xff1a;https://github.com/LemuelPuglisi/BrLP 0、摘…

[ linux-系统 ] 常见指令2

1. man 指令 语法&#xff1a;man [选项] 命令 功能&#xff1a;查看联机手册获取帮助。 选项说明-k根据关键字搜索联机帮助。num只在第num章节找。-a显示所有章节的内容。 man是 Unix 和类 Unix 系统中的一个命令&#xff0c;用于查看操作系统和软件的手册页面&#xff08;ma…

STL之stackqueue

stack的介绍&#xff08;可以想象成栈&#xff09; 1.stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作 2.stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特点类封装作为其…

【现代深度学习技术】现代循环神经网络06:编码器-解码器架构

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…

宏电全新升级单北斗5G电力DTU,为每一公里电力线路注入可靠连接

在配网自动化改造与数字化转型的双重驱动下&#xff0c;宏电股份推出全新升级版H7710-DLWZ系列5G电力DTU&#xff0c;聚焦配网通信链路冗余、国产自主可控、复杂环境适应性三大核心需求&#xff0c;为配电自动化、台区智能运维、分布式能源接入等场景提供高可靠通信底座。 国产…

学习海康VisionMaster之间距检测

一&#xff1a;进一步学习了 今天学习下VisionMaster中的间距检测工具&#xff1a;主要类似于卡尺工具&#xff0c;测量物体的长度或者宽度或者间距 二&#xff1a;开始学习 1&#xff1a;什么是间距检测&#xff1f; 间距测量模块用于检测两特征边缘之间的间距&#xff0c;首…

蓝桥杯 18. 积木

积木 原题目链接 题目描述 小明用积木搭了一个城堡。为了方便&#xff0c;小明使用的是大小相同的正方体积木&#xff0c;并将其搭建在一个 n 行 m 列的方格图上。每个积木占据方格图中的一个小格子。 小明的城堡是立体的&#xff0c;可以将积木垒在其他积木上。当某个格子…

C++负载均衡远程调用学习之基础TCP服务

目录 1.LARS课程模块介绍 2.LARS的功能演示机场景作用 3.LARS的reactor框架的组成部分 4.Lars_reactor的项目目录构建 5.Lars_tcp_server的基础服务开发 6.Lars_tcp_server的accept实现 7.LarsV0.1总结 1.LARS课程模块介绍 2.LARS的功能演示机场景作用 # Lars系统开发 …

EasyExcel使用总结

EasyExcel 文章目录 EasyExcel1、导入1.1、基本方式导入1.导入依赖2. 加载源文件基本语法 3. 读取数据行4. 读取结果 1.2、模型映射导入1.定义实体映射类2. 操作读取基本语法 3. 读取数据行4. 读取结果 1.3、导入类型转换器语法 1.4、导入监听器基本语法&#xff1a; 1.5、多行…

【愚公系列】《Manus极简入门》022-艺术创作顾问:“艺术灵感使者”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…

蓝桥杯15届国赛 最小字符串

问题描述 给定一个长度为 N 且只包含小写字母的字符串 S&#xff0c;和 M 个小写字母 c1,c2,...,cM​。现在你要把 M 个小写字母全部插入到字符串 S 中&#xff0c;每个小写字母都可以插入到任意位置。请问能得到的字典序最小的字符串是什么&#xff1f; 输入格式 第一行包含…

【东枫科技】代理英伟达产品:DPU

NVIDIA BlueField-3 DPU 400Gb/s 基础设施计算平台 NVIDIA BlueField -3 数据处理单元 (DPU) 是第三代基础设施计算平台&#xff0c;使企业能够构建从云端到核心数据中心再到边缘的软件定义、硬件加速的 IT 基础设施。借助 400Gb/s 以太网或 NDR 400Gb/s InfiniBand 网络连接…

依图科技C++后端开发面试题及参考答案

请介绍你所了解的分布式系统 分布式系统是由多个独立的计算节点通过网络连接组成的系统&#xff0c;这些节点共同协作以完成特定的任务。分布式系统的设计目标在于提升系统的性能、可扩展性、可靠性和容错性。 从性能方面来看&#xff0c;分布式系统能够把任务分配到多个节点…

Python cv2滤波与模糊处理:从原理到实战

在图像处理领域&#xff0c;滤波与模糊是预处理阶段的两大核心操作&#xff0c;既能消除噪声干扰&#xff0c;又能实现艺术化效果。本文将结合OpenCV的cv2库&#xff0c;系统讲解滤波与模糊的原理及Python实现&#xff0c;带你从理论到实战全面掌握这项技术。 一、滤波与模糊的…