Nacos简介—4.Nacos架构和原理二
大纲
1.Nacos的定位和优势
2.Nacos的整体架构
3.Nacos的配置模型
4.Nacos内核设计之一致性协议
5.Nacos内核设计之自研Distro协议
6.Nacos内核设计之通信通道
7.Nacos内核设计之寻址机制
8.服务注册发现模块的注册中心的设计原理
9.服务注册发现模块的注册中心的服务数据模型
10.服务注册发现模块的健康检查机制
11.配置管理模块的配置一致性模型
12.Zookeeper、Eureka和Nacos的对比总结
5.Nacos内核设计之自研Distro协议
(1)Distro协议的背景和设计思想
(2)Distro协议的工作原理之数据初始化
(3)Distro协议的工作原理之数据校验
(4)Distro协议的工作原理之写操作
(5)Distro协议的工作原理之读操作
(6)总结
(1)Distro协议的背景和设计思想
一.Distro协议的背景
Distro协议是Nacos自研的⼀种AP分布式协议,也是面向临时实例设计的⼀种分布式协议。它保证了在某些Nacos节点宕机后,整个临时实例处理系统依旧可正常工作。
作为⼀种有状态的中间件应用的内嵌协议,Distro协议保证了各个Nacos节点对于海量注册请求的统⼀协调和存储。
二.Distro协议的设计思想
设计一:Nacos每个节点是平等的
每个节点都会处理写请求,以及都会把新数据同步到其他节点。
设计二:每个节点只负责部分数据
每个节点都会定时发送自己负责数据的校验值到其他节点来保持数据⼀致性。
设计三:每个节点独立处理读请求
所以每个节点都能够及时从本地发出响应。
(2)Distro协议的工作原理之数据初始化
新加入的Nacos节点会拉取全量数据。具体操作就是轮询所有Nacos节点,向其他节点发送请求来拉取全量数据。
完成拉取全量数据后,Nacos的每个节点都拥有了当前所有注册上来的非持久化实例数据。
(3)Distro协议的工作原理之数据校验
在Nacos集群启动后,各节点间会定期发送心跳。心跳信息主要是当前节点上的所有数据的元信息,使用元信息的原因是要保证在网络中传输的数据量维持在⼀个较低水平。
这种数据校验会以心跳的形式进行。即每个节点会在固定时间间隔,向其他节点发起⼀次数据校验请求。在数据校验过程中,一旦某节点发现其他节点上的数据与本地数据不⼀致,则会发起⼀次全量拉取请求,将数据补齐。
(4)Distro协议的工作原理之写操作
对于⼀个已经启动完成的Nacos集群,在⼀次客户端发起写操作的流程中,当注册非持久化的服务实例的写请求发送到某台Nacos节点时,Nacos集群处理的流程如下:
一.前置的Filter拦截写请求
首先,收到写请求的Nacos节点,其前置Filter会拦截写请求。然后根据请求中包含的IP和Port信息计算其所属的Nacos责任节点,并将该请求转发到所属的Nacos责任节点上。
二.Controller会解析写请求
所属的Nacos责任节点收到写请求后,会让其Controller解析写请求。
三.Distro协议下Nacos节点会定时执行同步任务
定时同步任务会将本机所负责的所有实例信息同步到其他节点上。
(5)Distro协议的工作原理之读操作
由于Nacos的每个节点上都存放了全量数据,因此在每⼀次读操作中,Nacos节点会直接从本地拉取数据进行快速响应。
这种机制保证了Distro协议作为⼀种AP协议,能及时响应读操作的请求。在网络分区情况下,对于所有的读操作也能够正常返回。当网络分区恢复时,各Nacos节点都会把各数据分片的数据进行合并恢复。
(6)总结
Distro协议是Nacos对临时服务实例数据开发的⼀致性协议。其数据存储在缓存中,在启动时进行全量数据同步,并定期进行数据校验。在Distro协议的设计思想下,每个节点都可以接收和处理读写请求。
Distro协议的请求场景主要分为如下三种情况:
情况一:当节点接收到属于自己负责的服务实例的写请求时,直接写入。
情况二:当节点接收到不属于自己负责的服务实例的写请求时,首先在集群内部路由,然后转发给对应的节点,从而完成写请求。
情况三:当节点接收到任何读请求时,都直接在本机查询并返回,因为所有服务实例的数据都被同步到了各机器节点上。
Distro协议作为Nacos临时服务实例的⼀致性协议,保证了分布式环境下各节点上的服务信息状态,都能及时通知其他节点。Distro协议可让Nacos维持数十万量级的服务实例数据的存储和⼀致性。
6.Nacos内核设计之通信通道
(1)现状背景
(2)场景分析
(3)长连接核心诉求
(4)长连接选型对比
(1)现状背景
Nacos 1.x版本的Config/Naming模块,各自的推送通道都是按照自己的设计模型来实现的。配置和服务器模块的数据推送通道不统⼀,HTTP短连接性能压力巨大,未来Nacos需构建能同时支持配置及服务的长连接通道,以标准的通信模型重构推送通道。
(2)场景分析
场景一:配置管理
一.Client和Server之间的通信
客户端Client需要感知服务端Server的节点列表,需要按照某种策略选择其中⼀个Server节点进行连接。当底层连接断开时,客户端Client就需要切换Server进行重连。
客户端基于当前可用的长连接,进行配置的查询、发布、删除、监听等RPC语义的接口通信。
服务端需要将配置变更消息推送给当前监听的客户端。当网络不稳定时,客户端接收失败,就需要支持重推并告警。
服务端需要感知客户端连接断开事件,将连接注销,并且清空连接对应的上下文。
二.Server之间的通信
每个Server都需要能够获取集群所有Server的地址列表,然后为每个Server创建独立的长连接。当长连接断开时,需要进行重连。当节点列表变更时,需要创建新节点的长连接和销毁下线节点的长连接。
Server间需要进行数据同步,包括配置信息、当前连接数信息、系统负载信息、负载调节信息等同步。
场景二:服务注册发现
一.Client和Server之间的通信
客户端Client需要感知服务端Server的节点列表,需要按照某种策略选择其中⼀个Server节点进行连接。当底层连接断开时,客户端Client就需要切换Server进行重连。
客户端基于当前可用的长连接,进行服务的查询、注册、注销、订阅等RPC语义的接口通信。
服务端需要将服务变更消息推送新给客户端,完成推送后客户端需要ACK,方便服务端进行metrics统计和重推判定等。
服务端需要感知客户端连接断开事件,将连接注销,并且清空连接对应的上下文。
二.Server之间的通信
服务端之间需要通过长连接感知对端存活状态,需要通过长连接汇报服务状态(同步RPC能力)。
服务端之间进行AP Distro数据同步,需要异步RPC带ACK能力。
(3)长连接核心诉求
一.功能性诉求
二.性能要求
三.负载均衡
四.连接生命周期
一.功能性诉求
客户端的诉求:
诉求一:实时感知连接生命周期的能力,包括连接建立、连接断开事件。
诉求二:客户端调用服务端支持同步阻塞、异步Future、异步CallBack三种模式。
诉求三:底层连接自动切换能力。
诉求四:响应服务端连接重置消息进行连接切换。
诉求五:选址/服务发现。
服务端的诉求:
诉求一:实时感知连接生命周期的能力,包括连接建立、连接断开事件。
诉求二:服务端往客户端主动进行数据推送,需要客户端进行ACK返回以支持可靠推送,并且需要进行失败重试。
诉求三:服务端主动推送负载调节能力。
二.性能要求
性能方面,需要能够满足阿里的生产环境可用性要求,能支持百万级的长连接规模及请求量和推送量,并且要保证足够稳定。
三.负载均衡
说明一:常见的负载均衡策略
随机、Hash、轮询、权重、最小连接数、最快响应速度等。
说明二:短连接和长连接负载均衡的异同
由于短连接会快速建立和销毁,所以"随机、Hash、轮询、权重"四种策略下服务端重启也不会影响均衡,而"最小连接数、最快响应速度",如果数据延时则容易造成堆积问题。
长连接建立连接后,如果没有异常情况,连接会⼀直保持。如果出现断连,需要重新选择⼀个新的服务节点。当服务节点出现重启后,最终会出现连接不均衡的情况。"随机、轮询、权重"的策略在客户端重连切换时可以使用。"最小连接数、最快响应速度",同样会出现数据延时造成堆积问题。
说明三:长连接和短连接的差别
在于在整体连接稳定时,服务端需要⼀个重平衡的机制。将集群视角的连接数重新洗牌分配,趋向另外⼀种稳态。
说明四:客户端随机 + 服务端柔性调整
核心的策略是客户端 + 服务端双向调节策略,也就是客户端随机选择 + 服务端运行时柔性调整。
说明五:什么是客户端随机选择
客户端在启动时获取服务列表,按照随机规则进行节点选择。逻辑比较简单,整体能够保持随机。
说明六:什么是服务端柔性调整
(当前实现版本)人工管控方案:集群视角的系统负载控制台,提供连接数、负载等视图,实现人工调节每个Server节点的连接数,人工触发重平衡,人工削峰填谷。比如展示总节点数量,总长链接数量、平均数量、系统负载信息、每个节点的地址、长链接数量、与平均数量的差值、对高于平均值的节点进行数量调控、设置数量上限(临时和持久化),并且可以指定服务节点进行切换。
(未来终态版本)自动化管控方案:基于每个Server间连接数及负载自动计算节点合理连接数,自动触发Reblance、自动削峰填谷,实现周期长,比较依赖算法准确性。
四.连接生命周期
Nacos需要什么:
第一:低成本快速感知
客户端要在服务端不可用时尽快切换到新的服务节点,降低不可用时间。并且客户端要能够感知底层连接切换事件,重置上下文。服务端需要在客户端断开连接时剔除客户端连接对应的上下文,包括配置监听、服务订阅上下文,且处理客户端连接对应的实例上下线。客户端正常重启:客户端主动关闭连接,服务端实时感知。服务端正常重启:服务端主动关闭连接,客户端实时感知。
第二:防抖
当网络短暂不可用时,客户端需要能接受短暂网络抖动。超过阈值后,需要自动切换Server,但要防止请求风暴。
第三:断网演练
断网场景下以合理的频率进行重试,断网结束时可以快速重连恢复。
(4)长连接选型对比
在上述的备选框架中:从功能的契合度上,RSocket比较贴切Nacos的功能性诉求。RSocket性能上比gRPC要强,社区活跃度相对gRPC要逊色很多。
7.Nacos内核设计之寻址机制
(1)寻址机制的设计抽象
(2)当前Nacos内部实现的几种寻址机制
(1)寻址机制的设计抽象
Nacos支持单机部署以及集群部署。对于单机模式,Nacos只是自己和自己通信。对于集群模式,则集群内的每个Nacos节点都需要相互通信。因此这就带来⼀个问题,应该如何管理集群内的Nacos节点信息。而这,就需要Nacos内部的寻址机制。
单机模式和集群模式的根本区别是Nacos成员节点个数是单个还是多个,而Nacos集群需要能感知节点变更情况:节点是增加了还是减少了。当前最新的成员列表信息是什么,以何种方式去管理成员列表信息,如何快速的支持新的、更优秀的成员列表管理模式等等。针对上述需求点,Nacos抽象出了⼀个MemberLookup接口如下:
public interface MemberLookup { //start.void start() throws NacosException;//Inject the ServerMemberManager property.void injectMemberManager(ServerMemberManager memberManager);//The addressing pattern finds cluster nodes.void afterLookup(Collection<Member> members);//Addressing mode closed.void destroy() throws NacosException;
}
ServerMemberManager存储着本节点所知道的所有成员节点信息、提供了针对成员节点的增删改查操作、维护了⼀个MemberLookup列表。
MemberLookup接口的核心方法是:injectMemberManager()和afterLookup()。前者的作用是将ServerMemberManager注入到MemberLookup中,以方便利用ServerMemberManager 的存储、查询能力。后者则是⼀个事件接口,当MemberLookup需要进行成员节点信息更新时,会将当前最新的成员节点信息通知给ServerMemberManager,具体的节点管理方式,则是隐藏到具体的MemberLookup实现中。
(2)当前Nacos内部实现的几种寻址机制
一.单机寻址
二.文件寻址
三.地址服务器寻址
四.未来扩展点之集群节点自动扩容缩容
一.单机寻址
com.alibaba.nacos.core.cluster.lookup.StandaloneMemberLookup
单机模式的寻址模式很简单,其实就是找到自己的IP:PORT组合信息,然后格式化为⼀个节点信息,接着调用afterLookup()将信息存储到ServerMemberManager中。
public class StandaloneMemberLookup extends AbstractMemberLookup {@Overridepublic void start() {if (start.compareAndSet(false, true)) {String url = InetUtils.getSelfIp() + ":" + ApplicationUtils.getPort();afterLookup(MemberUtils.readServerConf(Collections.singletonList(url)));}}
}
二.文件寻址
com.alibaba.nacos.core.cluster.lookup.FileConfigMemberLookup
文件寻址模式是Nacos集群模式下的默认寻址实现。文件寻址模式也很简单,就是每个Nacos节点需要维护⼀个叫cluster.conf的文件。
该文件默认只需填写每个成员节点的IP信息即可,端口会自动选择Nacos的默认端口8848。如果有特殊需求更改了Nacos的端口信息,则需要在该文件将该节点的完整网路地址信息补充完整(IP:PORT)。
//cluster.conf文件内容如下:192.168.16.101:8847
192.168.16.102
192.168.16.103
当Nacos节点启动时,会读取cluster.conf文件的内容,然后将文件内的IP解析为节点列表,接着调用afterLookup()方法将节点列表存入ServerMemberManager。
private void readClusterConfFromDisk() {Collection<Member> tmpMembers = new ArrayList<>();try {List<String> tmp = ApplicationUtils.readClusterConf();tmpMembers = MemberUtils.readServerConf(tmp);} catch (Throwable e) {Loggers.CLUSTER.error("nacos-XXXX[serverlist] failed to get serverlist from disk!, error : {}", e.getMessage());}afterLookup(tmpMembers);
}
如果集群扩容缩容,那么就要修改每个Nacos节点下的cluster.conf文件,然后Nacos内部的文件变动监听中心会自动发现文件修改,接着重新读取文件内容、加载IP列表信息、更新新增的节点。
private FileWatcher watcher = new FileWatcher() {@Overridepublic void onChange(FileChangeEvent event) {readClusterConfFromDisk();}@Overridepublic boolean interest(String context) {return StringUtils.contains(context, "cluster.conf");}
};public void start() throws NacosException {if (start.compareAndSet(false, true)) {readClusterConfFromDisk();// Use the inotify mechanism to monitor file changes and automatically trigger the reading of cluster.conftry {WatchFileCenter.registerWatcher(ApplicationUtils.getConfFilePath(), watcher);} catch (Throwable e) {Loggers.CLUSTER.error("An exception occurred in the launch file monitor : {}", e.getMessage());}}
}
但是这种默认寻址模式有⼀个缺点——运维成本较大。当新增⼀个Nacos节点时,需要手动修改每个节点下的cluster.conf文件。而且由于每个Nacos节点都存在⼀份cluster.conf文件,如果其中⼀个节点的 cluster.conf 文件修改失败,就容易造成了集群间成员节点列表数据的不⼀致性。因此,Nacos引入了新的寻址模式——地址服务器寻址模式。
三.地址服务器寻址
com.alibaba.nacos.core.cluster.lookup.AddressServerMemberLookup
地址服务器寻址模式是Nacos官方推荐的⼀种集群成员节点信息管理。该模式利用了⼀个Web服务器来管理cluster.conf文件的内容信息,这样运维人员只需要管理这⼀份集群成员节点内容即可。
每个Nacos节点,只需要定时向Web请求当前最新的集群成员节点列表信息。通过地址服务器这种模式,就可以大大简化Nacos集群节点管理的成本。同时,地址服务器是⼀个非常简单的Web程序,其稳定性能得到很好保障。
四.未来扩展点之集群节点自动扩容缩容
目前Nacos的集群节点管理,还属于人工操作。因此,未来期望能够基于寻址模式,实现集群节点自动管理的功能。
能够实现新节点上线时,只需要知道原有集群中的⼀个节点信息。这样就可以在⼀定时间内,顺利加入原有的Nacos集群中。同时也能够自行发现不存活的节点,自动将其从集群可用节点列表中剔除。这其中的逻辑实现,其实就类似Consul的Gossip协议。
8.服务注册发现模块的注册中心的设计原理
(1)服务注册发现简介
(2)数据模型
(3)数据一致性
(4)负载均衡
(5)健康检查
(6)性能与容量
(7)易用性
(8)集群扩展性
(9)用户扩展性
(1)服务注册发现简介
服务注册发现是⼀个古老的话题,当应用开始脱离单机运行和访问时,服务注册发现就诞生了。
目前的网络架构是每个主机都有⼀个独立的IP地址,那么服务注册发现基本上都是通过某种方式获取到服务所部署的IP地址。
DNS协议是最早将⼀个网络名称翻译为网络IP的协议。在最初的架构选型中,DNS + LVS + Nginx基本可满足所有服务的发现,此时服务的IP列表通常配置在Nginx或LVS。
后来出现了RPC服务,服务的上下线更加频繁,人们开始寻求⼀种能支持动态上下线 + 推送IP列表变化的注册中心产品。
互联网软件行业普遍热捧开源产品,个人开发者或中小型公司往往会将开源产品作为选型首选。Zookeeper是⼀款经典的服务注册中心产品(虽然它最初定位并不在于此),在很长⼀段时间里,它是提起RPC服务注册中心时想到的唯⼀选择,这很大程度上与Dubbo在的普及程度有关。
Consul和Eureka都出现于2014年。Consul在设计上把很多分布式服务治理上要用到的功能都包含在内,可以支持服务注册、健康检查、配置管理、Service Mesh等。Eureka借着微服务的流行,与SpringCloud生态深度结合,也曾流行起来。
Nacos则携带着阿里巴巴大规模服务生产经验,试图在服务注册和配置管理这个市场上,提供给用户⼀个新的选择。
(2)数据模型
一.服务注册中心数据模型的演进
二.Zookeeper、Eureka、Consul和Nacos的数据模型对比
三.服务实例数据的隔离模型
四.Nacos的临时服务实例和持久化服务实例
一.服务注册中心数据模型的演进
服务注册中心的核心数据是服务的名字和它对应的网络地址。
当服务注册了多个实例时,需要对不健康的实例进行过滤或针对实例的⼀些特征进行流量的分配,那么就要在服务实例上存储⼀些如健康状态、权重等属性。
随着服务规模的扩大,渐渐的又需要在整个服务级别设定⼀些权限规则,以及对所有实例都生效的⼀些开关,于是在服务级别又会设立⼀些属性。
再往后,又发现单个服务的实例又会有划分为多个子集的需求。例如⼀个服务是多机房部署的,那么可能要对每个机房的实例做不同配置,这样又需要在服务和服务实例之间再设定⼀个数据级别。
二.Zookeeper、Eureka、Consul和Nacos的数据模型对比
Zookeeper没有针对服务发现设计数据模型,它的数据以⼀种抽象的树形KV结构来组织,理论上可存储任何语义数据。
Eureka或Consul都设计了服务实例级别的数据模型,可满足大部分场景,不过无法满足大规模和多环境的服务数据存储。
Nacos经过多年经验提炼出的数据模型是⼀种服务-集群-实例的三层模型,这样基本可以满足服务在所有场景下的数据存储和管理。
Nacos的数据模型虽然相对复杂,但是它并不强制使用它里面的所有数据。在大多数场景下,可以选择忽略这些数据属性,此时可以降维成和Eureka或Consul⼀样的数据模型。
三.服务实例数据的隔离模型
另外⼀个需要考虑的是数据的隔离模型。作为⼀个共享服务型的组件,需要能够在多个用户或业务方使用的情况下,保证数据的隔离和安全,这在稍微大⼀点的业务场景中非常常见。
此外服务注册中心往往支持云上部署,此时就要求服务注册中心的数据模型能够适配云上的通用模型。
Zookeeper、Consul和Eureka都没有很明确针对服务隔离的模型。Nacos则在⼀开始就考虑到如何让用户能以多种维度进行数据隔离,同时能够平滑的迁移到阿里云上对应的商业化产品。
Nacos提供了四层的数据逻辑隔离模型。
第一层:用户账号
用户账号对应的是⼀个企业或个体,该数据⼀般不会透传到服务注册中心。
第二层:命名空间
⼀个用户账号可以新建多个命名空间。这个命名空间对应的注册中心物理集群可以根据规则进行路由,这样可以让注册中心内部的升级和迁移对用户是无感知的。同时可以根据用户的级别,为用户提供不同服务级别的物理集群。
第三层:服务分组
服务分组和服务名组成的二维服务标识,通过二维服务标识可以满足接口级别的服务隔离。
第四层:服务实例名称
每个命名空间会对应⼀个服务实例名称。
四.Nacos的临时服务实例和持久化服务实例
Nacos 1.0.0介绍的另外⼀个新特性是:临时服务实例和持久化服务实例。在定义上区分临时服务实例和持久化服务实例的关键是健康检查的方式。
临时服务实例使用客户端上报模式,持久化服务实例使用服务端反向探测模式。
临时服务实例需要能够自动摘除不健康实例,而且无需持久化存储服务实例,那么这种服务实例就适用于类Gossip的协议。
持久化服务实例使用服务端探测的健康检查方式。因为客户端不会上报心跳,那么就不能自动摘除下线的实例,所以这种实例就适用于类Raft的协议。
在大中型的公司里,这两种类型的服务往往都有。
类型一:⼀些基础的组件例如数据库、缓存等,这些往往不能上报心跳。这种类型的服务在注册时,就需要作为持久化实例注册。
类型二:一些上层的业务服务例如微服务、Dubbo服务,服务提供者支持添加汇报心跳的逻辑,此时就可作为临时实例注册。
Nacos 2.0中继续沿用了持久化及非持久化的设定,但有了⼀些调整。Nacos 1.0中持久化及非持久化属性是作为实例的元数据进行存储和识别,这导致了同⼀个服务下可同时存在持久化实例和非持久化实例。但在实际使用中,这种模式会给运维人员带来极大的困惑和运维复杂度。从系统架构看,⼀个服务同时存在持久化及非持久化实例是矛盾的,这就导致该能力事实上并未被广泛使用。
为了简化Nacos的服务数据模型,降低运维复杂度,提升Nacos的易用性,在Nacos2.0中已将是否持久化的数据,抽象至服务级别,而且不再允许⼀个服务同时存在持久化实例和非持久化实例,实例的持久化属性继承自服务的持久化属性。
(3)数据一致性
一.不同的服务注册场景使用不同的一致性协议
二.Nacos支持AP和CP两种⼀致性协议并存
一.不同的服务注册场景使用不同的一致性协议
数据⼀致性是分布式系统永恒的话题,Paxos协议的复杂更让数据⼀致性成为大牛们吹水的常见话题。
不过从协议层面上看,⼀致性的选型已经很长时间没有新的成员加入了。目前来看基本可以归为两种:⼀种是基于Leader的非对等部署的单点写⼀致性,⼀种是对等部署的多点写⼀致性。
当我们选用服务注册中心的时候,并没有⼀种协议能够覆盖所有场景。
场景一:服务节点不会定时发送心跳到注册中心
由于无法通过心跳来进行数据的补偿注册,所以第⼀次注册就必须保证数据不会丢失,从而让强⼀致协议看起来是唯⼀选择。
场景二:客户端会定时发送心跳来汇报健康状态
第⼀次注册的成功率并不是非常关键,当然也很关键,只是相对来说可以容忍数据少量的写失败,因为后续还可以通过心跳再把数据补偿回来。此时Paxos协议的单点瓶颈就不太划算,这也是Eureka为什么不采用Paxos协议而采用自定义的Renew机制的原因。可见不同的服务注册需求,会用不同的协议。
根据Dubbo对Zookeeper的处理,其实采用Eureka的Renew机制更合适。因为Dubbo服务往Zookeeper注册的就是临时节点,Dubbo服务需要定时发送心跳到Zookeeper来续约节点。当Dubbo服务下线时,需要将Zookeeper上的节点摘除。
二.Nacos支持AP和CP两种⼀致性协议并存
Zookeeper虽然用ZAB协议保证了数据的强⼀致,但它缺乏机房容灾能力,无法适应⼀些大型场景。
Nacos因为要支持多种服务类型的注册,并能够具有机房容灾、集群扩展等必不可少的能力,所以在1.0.0起正式支持AP和CP两种⼀致性协议并存。
Nacos1.0.0重构了数据的读写和同步逻辑:首先将与业务相关的CRUD与底层的⼀致性同步逻辑进行了分层隔离。然后将业务的读写(主要是写,因为读会直接使用业务层的缓存)抽象为Nacos定义的数据类型。接着调用⼀致性服务进行数据同步。在决定使用CP还是AP⼀致性时,通过代理 + 可控制的规则进行转发。
Nacos目前的⼀致性协议实现:⼀个是基于简化的Raft协议的CP⼀致性,⼀个是基于自研的Distro协议的AP⼀致性。
Raft协议,基于Leader进行写入,其CP也并不是严格的。只是能保证⼀半所见⼀致,以及数据丢失的概率较小而已。
Distro协议,则是参考了ConfigServer和开源Eureka。在不借助第三方存储的情况下,实现基本大同小异。Distro重点做了⼀些逻辑优化和性能调优。
(4)负载均衡
一.客户端进行负载均衡
二.服务端进行负载均衡
三.服务端负载均衡和客户端负载均衡的优缺点
四.Ribbon设计的客户端负载均衡
五.基于标签的负载均衡策略
六.其他
一.客户端进行负载均衡
严格来说,负载均衡并不算是传统注册中心的功能。
⼀般服务发现的完整流程应该是:客户端先从注册中心获取到服务的实例列表,然后根据自身需求来选择其中的部分实例,或者按⼀定的流量分配机制(负载均衡机制)来选择访问不同的服务提供者。
因此服务注册中心本身⼀般不限定服务消费者的访问策略。Eureka、Zookeeper、Consul,本身都没有实现可配置及可扩展的负载均衡机制。Eureka的负载均衡是由Ribbon来完成的,而Consul的负载均衡则是由Fabio来完成。
二.服务端进行负载均衡
在阿里内部,却是使用的相反的思路。服务消费者往往并不关心所访问的服务提供者的负载均衡,它们只关心如何高效和正确地访问服务提供者的服务。服务提供者则非常关注自身被访问的流量的调配。这其中的一个原因是,阿里内部服务访问流量巨大,稍有不慎就会导致流量异常压垮服务提供者的服务。因此服务提供者需要能够完全掌控服务的流量调配,并可以动态调整。
三.服务端负载均衡和客户端负载均衡的优缺点
服务端的负载均衡,给服务提供者更强的流量控制权,但是无法满足不同消费者希望使用不同负载均衡策略的需求,而不同负载均衡策略的场景却是存在的。
客户端的负载均衡则提供了这种灵活性,并对用户扩展提供更友好的支持。但客户端负载均衡策略如果配置不当,可能会导致服务提供者出现热点,或者压根就拿不到任何服务提供者。
抛开负载均衡到底是在服务提供者实现还是在服务消费者实现,目前的负载均衡有基于权重、服务提供者负载、响应时间、标签等策略。
四.Ribbon设计的客户端负载均衡
Ribbon设计的客户端负载均衡,主要是选择合适现有的IRule、ServerListFilter等接口实现,或者自己继承这些接口,实现自己的过滤逻辑。
Ribbon设计的客户端负载均衡,采用的是两步负载均衡:第⼀步先过滤掉不会采用的服务提供者实例,第二步在过滤后的服务提供者实例里实施负载均衡策略。
Ribbon内置的几种负载均衡策略功能还是比较强大的,同时又因为允许用户去扩展,这可以说是⼀种比较好的设计。
五.基于标签的负载均衡策略
基于标签的负载均衡策略可以做到非常灵活。Kubernetes和Fabio都已经将标签运用到了对资源的过滤中。使用标签几乎可以实现任意比例和权重的服务流量调配。但是标签本身需要单独的存储以及读写功能,不管是放在注册中心本身或者对接第三方的CMDB。
Nacos 0.7.0版本除了提供基于健康检查和权重的负载均衡方式外,还新提供了基于第三方CMDB的标签负载均衡器。
使用基于标签的负载均衡器,可实现同标签优先访问的流量调度策略。在实际应用场景中,可用来实现服务的就近访问。当服务部署在多个地域时,这非常有用。使用这个标签负载均衡器,可以支持非常多的场景。虽然目前Nacos支持的标签表达式不丰富,不过会逐步扩展它支持的语法。
六.其他
除此之外,Nacos定义了Selector作为负载均衡的统⼀抽象。
理想的负载均衡实现应该是什么样的呢?不同人会有不同答案。Nacos试图将服务端负载均衡与客户端负载均衡通过某种机制结合起来,提供用户扩展性,并给予用户充分的自主选择权和轻便的使用方式。
负载均衡是⼀个很大的话题,当我们关注注册中心提供的负载均衡策略时,需要注意该注册中心是否有我们需要的负载均衡方式,使用方式是否复杂。如果没有,那么是否允许我们方便地扩展来实现我们需求的负载均衡策略。
(5)健康检查
一.客户端进行健康检查—TTL机制发送心跳
二.服务端进行健康检查—TCP端口和HTTP接口探测
三.客户端健康检查和服务端健康检查的关注点
一.客户端进行健康检查—TTL机制发送心跳
Zookeeper和Eureka都实现了⼀种TTL机制。即如果客户端在⼀定时间内没有向注册中心发送心跳,则会摘除该客户端。
Eureka做的更好的⼀点在于:它允许在注册服务时,自定义检查自身状态的健康检查方法。这在服务实例能够保持心跳上报的场景下,有比较好的体验。
Nacos也支持这种TTL机制,不过这与ConfigServer的机制又有⼀些区别。Nacos目前支持临时服务实例使用心跳上报方式维持活性。临时服务实例发送心跳的周期默认是5秒。如果Nacos服务端在15秒没收到心跳,则会将该临时实例设置为不健康。如果Nacos服务端在30秒没收到心跳,则会将该临时实例摘除。
不过有⼀些服务是无法上报心跳的,但可提供⼀个检测接口由外部去探测。这样的服务广泛存在,且这些服务对服务发现和负载均衡的需求同样强烈。
二.服务端进行健康检查—TCP端口和HTTP接口探测
服务端健康检查最常见的方式是TCP端口探测和HTTP接口返回码探测,这两种探测方式因为其协议的通用性可以支持绝大多数的健康检查场景。
在其他⼀些特殊场景,可能还需要执行特殊的接口才能判断服务是否可用。例如部署了数据库的主备,数据库的主备可能会在某些情况下进行切换,需要通过服务名对外提供访问,保证当前访问的库是主库。此时的健康检查接口,可能是⼀个检查数据库是否是主库的MySQL命令。
三.客户端健康检查和服务端健康检查的关注点
客户端健康检查和服务端健康检查有不同的关注点。
客户端健康检查主要关注:客户端上报心跳的方式、服务端摘除不健康客户端的机制。
服务端健康检查主要关注:探测客户端的方式、灵敏度以及设置客户端健康状态的机制。
从实现复杂性来说,服务端探测肯定是要更加复杂的。因为服务端需要根据注册服务所配置的健康检查方式,去执行相应的接口、判断相应的返回结果、并做好重试机制和线程池管理。这与客户端探测,只需要等待心跳,然后刷新TTL是不⼀样的。
同时服务端健康检查无法摘除不健康的实例。这意味着注册过的服务实例,如果不调用接口向服务端主动进行注销,那么这些服务实例都需要服务端去维持执行健康检查的探测任务。而客户端健康检查则可以随时摘除不健康实例,减轻服务端的压力。
Nacos既支持客户端的健康检查,也支持服务端的健康检查。同⼀个服务可以切换健康检查模式。这种健康检查方式的多样性很重要,这样可以支持各种类型的服务,并且让这些服务都可以使用Nacos的负载均衡能力。
Nacos下⼀步要做的是实现健康检查方式的用户扩展机制,不管是服务端探测还是客户端探测。这样可以支持用户传入⼀条业务语义的请求,然后由Nacos去执行,做到健康检查的定制。
(6)性能与容量
一.影响性能的因素
二.Zookeeper的性能及其限制分析
三.Zookeeper、Eureka和Nacos的容量分析
一.影响性能的因素
影响读写性能的因素有:⼀致性协议、机器配置、集群规模、数据规模、数据结构、读写逻辑等。
在服务发现的场景中,读写性能是非常关键的,但是并非性能越高就越好,因为追求性能往往需要其他方面做出牺牲。
二.Zookeeper的性能及其限制分析
Zookeeper的写性能可以达上万TPS,这得益于Zookeeper精巧的设计,不过这显然是因为有⼀系列的前提存在。
首先Zookeeper的写逻辑就是进行KV写入的,内部没有聚合。其次Zookeeper舍弃了服务发现的基本功能如健康检查、友好的查询接口。它在支持这些功能时,显然需要增加⼀些逻辑,甚至弃用现有的数据结构。最后Paxos协议本身就限制了Zookeeper集群的规模,3或5个Zookeeper节点是不能应对大规模的服务订阅和查询的。
三.Zookeeper、Eureka和Nacos的容量分析
在对容量的评估时,不仅要评估现有的服务规模,也要预测未来3到5年的扩展规模。阿里的中间件在内部支撑着集团百万级别服务实例,在容量上遇到的挑战可以说不会小于任何互联网公司,这个容量不仅仅意味着整体注册的实例数,也同时包含单个服务的实例数、整体的订阅者的数目以及查询QPS等。
Nacos在淘汰Zookeeper和Eureka的过程中,容量是⼀个非常重要的因素。Zookeeper的容量,从存储实例数来说,可以达到百万级别。
但是随着容量的扩大,性能问题也会随之而来。当大量的实例上下线时,Zookeeper的表现并不稳定。同时在推送机制上的缺陷,会导致客户端的资源占用上升,从而导致客户端性能急剧下降。
Eureka在服务实例规模在5000左右时,就已经出现服务不可用的问题。甚至在压测过程中,如果并发线程数过高,就会造成Eureka崩溃。不过如果服务实例规模在1000上下,目前所有注册中心都可满足。
Nacos可以支撑的服务实例规模约为100万,服务规模可达10万+。在实际环境中,这个数字还会因为机器、网络配置、JVM参数而有所差别。下图展示了使用Nacos 1.0.0版本进行压测后的结果总结,针对容量、并发、扩展性和延时等进行了测试和统计。
(7)易用性
易用性包括多方面的工作。比如API和客户端接入是否简单,文档是否齐全,控制台界面是否完善等。对于开源产品来说,还有⼀块是社区是否活跃。
从使用的经验和调研来看:Zookeeper的易用性是比较差的,其客户端的使用也比较复杂。而且没有针对服务发现的模型设计及相应的API封装,需要自己处理。对多语言的支持也不太好,同时没有比较好用的控制台进行运维管理。
Eureka和Nacos相比较Zookeeper而言,已经改善很多。都有针对服务注册与发现的客户端,及基于Spring Cloud体系的Starter,可以帮助用户以非常低的成本无感知的做到服务注册与发现。同时还暴露标准的HTTP接口,支持多语言和跨平台访问。
Eureka和Nacos都提供官方的控制台来查询服务注册情况,不过Eureka 2.0已停止开发,而Nacos目前依然在建设中。
(8)集群扩展性
一.集群扩展性与集群容量及读写性能的关系
当使用⼀个较小的集群规模就能支撑远高于现有数量的服务注册及访问时,集群的扩展能力暂时就不会那么重要。
从协议的层面上来说:Zookeeper使用的ZAB协议,由于是单点写,在集群扩展性上不具备优势。Eureka在协议上来说理论上可以扩展到很大规模,但因为都是点对点的数据同步,Eureka集群在扩容后,性能上有很大问题。
二.集群扩展性与多地域部署和容灾支持的关系
集群扩展一:双机房容灾
如果不对基于Leader写的协议进行改造,那么是无法支持双机房容灾的。这意味着Zookeeper不能在没有人工干预的情况下做到双机房容灾。
在单机房断网情况下,使机房内服务可用并不难,难的是如何在断网恢复后做数据聚合。Zookeeper的单点写模式就会有断网恢复后的数据对账问题。
Eureka的部署模式天然支持多机房容灾。因为Eureka采用的是纯临时实例的注册模式:不持久化、所有数据都可以通过客户端心跳上报进行补偿。
由于临时实例和持久化实例都有它的应用场景,为了能够兼容这两种场景,Nacos支持两种模式的部署。⼀种是和Eureka⼀样的AP协议的部署,这种模式只支持临时实例,可以完美替代当前的Zookeeper、Eureka,并支持机房容灾。另⼀种是支持持久化实例的CP模式,这种情况下不支持双机房容灾。
集群扩展二:异地多活
很多业务组件的异地多活正是依靠服务注册中心和配置中心来实现的,这其中包含流量的调度和集群访问规则的修改等。
机房容灾是异地多活的⼀部分,但是要让业务能够在访问服务注册中心时,动态调整访问的集群节点,这需要第三方的组件来做路由。
异地多活往往是⼀个包含所有产品线的总体方案,很难说单个产品是否支持异地多活。
集群扩展三:多数据中心
多数据中心其实也算是异地多活的⼀部分。Zookeeper和Eureka都没有给出官方的多数据中心方案,Nacos则提供了采用Nacos-Sync组件来做数据中心之间的数据同步,这意味着每个数据中心的Nacos集群都会有多个数据中心的全量数据。
Nacos-Sync是Nacos生态组件里的重要⼀环,不仅承担Nacos集群与Nacos集群之间的数据同步,也承担与Eureka、Zookeeper、Kubernetes及Consul间的数据同步。
(9)用户扩展性
在框架的设计中,扩展性是⼀个重要的设计原则。Spring、Dubbo、Ribbon等框架都在用户扩展性上做了比较好的设计。这些框架的扩展性往往由面向接口及动态类加载等技术,来运行用户扩展约定的接口,实现用户自定义的逻辑。
在Server的设计中,用户扩展是比较审慎的。因为引入用户扩展代码,可能会影响原有Server服务的可用性。同时如果出问题,排查的难度也比较大。
设计良好的SPI是可能的,但由此带来的稳定性和运维风险需要仔细考虑。在开源软件中,往往通过直接贡献代码的方式来实现用户扩展。好的扩展会被很多人不停的更新和维护,这也是⼀种好的开发模式。
Zookeeper和Eureka目前Server端都不支持用户扩展。⼀个支持用户扩展的服务发现产品是CoreDNS,CoreDNS整体架构就是通过插件来串联起来的,通过将插件代码以约定的方式放到CoreDNS工程下,重新构建就可以将插件添加到CoreDNS整体功能链路的⼀环中。
那么这样的扩展性是否是有必要的呢?假如要添加⼀种新的健康检查方式,连接数据库执行⼀条MySQL命令,通常是在代码里增加MySQL类型的健康检查方法、构建、测试然后发布。但如果允许用户上传⼀个jar包放到Server部署目录下的某个位置,Server就会自动扫描并识别到这张新的健康检查方式呢?这样不仅更酷,也让整个扩展的流程与Server的代码解耦,变得非常简单。
所以对于系统的⼀些功能,如果能通过精心的设计,开放给用户进行扩展,那么其扩展性是极强的,毕竟增加扩展的支持不会让原有功能有任何损失。
所有产品都应该尽量支持用户进行扩展,这需要Server端的SPI机制设计得足够健壮和容错。
Nacos已经通过SPI机制开放了对第三方CMDB的扩展支持,后续很快会开放健康检查及负载均衡等核心功能的用户扩展,目的就是为了能够以⼀种解耦的方式支持用户各种各样的需求。
相关文章:
Nacos简介—4.Nacos架构和原理二
大纲 1.Nacos的定位和优势 2.Nacos的整体架构 3.Nacos的配置模型 4.Nacos内核设计之一致性协议 5.Nacos内核设计之自研Distro协议 6.Nacos内核设计之通信通道 7.Nacos内核设计之寻址机制 8.服务注册发现模块的注册中心的设计原理 9.服务注册发现模块的注册中心的服务数…...
Web服务器技术选型指南:主流方案、核心对比与策略选择
Web服务器技术选型指南:主流方案、核心对比与策略选择 一、主流Web服务器概览 在当今互联网架构中,Web服务器承担着处理HTTP请求、管理资源分配和保障服务稳定性的核心职责。根据应用场景和技术特性的不同,主流的Web服务器可分为以下五类&a…...
Git和Gitlab的部署和操作
一。GIT的基本操作 1.GIT的操作和查看内容 [rootmaster ~]# yum install git -y [rootmaster ~]# git config --list:查看所有配置 2.GIT仓库初始化 [rootmaster ~]# mkdir /gittest:创建目录 [rootmaster ~]# cd /gittest/:进入目录 [rootm…...
【Git】初始Git及入门命令行
目录 为什么学习 Git 这么重要? 1. 安装 Git 2. 配置 Git 3. 创建本地 Git 仓库 1. git初始化远程仓库: git init 2. 就是要新增两个必须要配置的选项: name 和 email 3. 查看当前本地仓库的配置情况: git config -l 4. 删…...
自然语言to SQL的评估
一、怎么进行一个自然语言to SQL评估? 1.DB——准备可用的数据表 2.准备问题集,自然语言|正确的预期SQL 3.大模型执行完成的SQL 4.Table.json——一个存储表格数据或者数据库表结构信息的 JSON 文件。当前是存储的表结构信息的,存储数据库…...
详解React Fiber架构中,reconcile阶段的具体工作流程
在 React Fiber 架构里,协调(Reconcile)阶段处于虚拟 DOM(VDOM)与实际 DOM 渲染之间,主要承担着把 VDOM 转化为 Fiber 节点树、开展 Diff 比较并标记节点变化的任务。下面详细阐述协调阶段的具体工作流程&a…...
迅雷精简绿色融合版【高速下载版】12.1.9.2870【11.2.2.1716】【20250426】
迅雷Thunder 11官方版会提示敏感需升级不能使用,本人制作的迅雷 12.1.9.2870【11.2.2.1716】精简绿色融合版是在11.2.2.1716版本的基础上制作的,实际版本号显示为12.1.9.2870,不是真正意义的迅雷12.1.9.2870精简绿色版,本实质上还…...
决策树相关案例
全流程 以下是一个更复杂、全流程的决策树和随机森林示例,不仅包括模型训练和预测,还涵盖了数据预处理、超参数调优以及模型评估的可视化。我们依旧使用鸢尾花数据集,并额外引入 GridSearchCV 进行超参数调优,使用 matplotlib 进…...
AI音频核爆!Kimi开源“六边形战士”Kimi-Audio,ChatGPT语音版?
音频处理领域的天花板被撕开了。 刚刚,kimi 发布全新通用音频基础模型 Kimi-Audio,这款由月之暗面(Moonshot AI)推出的开源模型,在 24 小时内收获 3.2 万星标,不仅以 1.28% 词错率刷新语音识别纪录…...
vscode vue 的插件点击组件不能跳转到文件问题解决
ctrl shift p 打开命令行,搜索 更改语言模式 选择第二项 选择 vue 现在可以了...
二叉树的前序、中序和后序遍历:详解与实现
1. 前序遍历(Pre-order Traversal) 1.1 定义 前序遍历的顺序是:先访问根节点,然后递归地遍历左子树,最后递归地遍历右子树。 1.2 访问顺序 对于任意节点: 访问根节点。 递归遍历左子树。 递归遍历右子…...
5、Rag基础:RAG 专题
RAG 简介 什么是检索增强生成? 检索增强生成(RAG)是指对大型语言模型输出进行优化,使其能够在生成响应之前引用训练数据来源之外的权威知识库。大型语言模型(LLM)用海量数据进行训练,使用数十亿个参数为回答问题、翻译语言和完成句子等任务生成原始输出。在 LLM 本就强…...
FISCO BCOS 智能合约开发详解
一、FISCO BCOS 智能合约开发概览 FISCO BCOS 是一个国产开源联盟链平台,支持两种类型的智能合约:FISCO BCOS Documentation Solidity 合约:与以太坊兼容,使用 Solidity 语言编写,适用于灵活的业务逻辑开发。 预…...
Linux操作系统从入门到实战(四)Linux基础指令(下)
Linux操作系统从入门到实战(四)Linux基础指令(下) 前言一、date 指令二、cal 指令三、find 指令四、which 指令五、whereis 指令六、alias 指令七、grep 指令八、zip/unzip 指令九、tar 指令(重要)十、bc 指…...
使用 LLM助手进行 Python 数据可视化
在数据科学中,数据可视化是一项至关重要的任务,旨在揭示数据背后的模式和洞察,并向观众传达这些信息。然而,在编程语言(如 Python)中创建有洞察力的图表有时可能会耗时且复杂。本文介绍了一种借助 AI 助手&…...
docker安装jenkins自动化测试
#搭建gitlab docker pull gitlab/gitlab-ce docker run -d\--hostname localhost \-p 443:443 -p 80:80 -p 2222:22 \--name gitlab \-v /myproject/gitlab/config:/etc/gitlab \-v /myproject/gitlab/logs:/var/log/gitlab \-v /myproject/gitlab/data:/var/opt/gitlab \gitla…...
Python3:面向对象编程
这里写目录标题 🧩 面向对象编程:让代码化身为积木世界一、核心概念:类与对象二、四大基石:面向对象的核心特性1️⃣ 封装(Encapsulation):包装复杂性,提供简单接口2️⃣ 继承(Inheritance):站在…...
数据可视化 —— 饼图
一、饼图的所有常用使用场景 饼图是一种直观展示数据占比关系的图表,适用于以下常见场景: 1. 市场与商业分析 市场份额:展示不同品牌/产品在市场中的占有率。 收入构成:分析公司各业务线或产品的收入占比。 客户分布࿱…...
OpenLayers WebGL与3D渲染 (进阶一)
1. WebGL概述 WebGL是一种JavaScript API,它基于OpenGL ES 2.0/3.0标准,允许在不使用插件的情况下在兼容的Web浏览器中呈现高性能的交互式3D和2D图形。在地理信息系统(GIS)领域,WebGL为地图渲染和空间数据可视化提供了强大的性能支持。 1.1…...
ARP协议(地址解析协议)
ARP协议是用来把IP地址转换成MAC地址的。 因为在局域网里,真正通信靠的是MAC地址,但我们平时只知道目标的IP地址,所以需要一个办法把IP地址变成MAC地址 —— 这个过程就是靠ARP完成的。 举个超简单的例子: 你电脑要发数据给192.1…...
深度学习常见框架:TensorFlow 与 PyTorch 简介与对比
🐇明明跟你说过:个人主页 🏅个人专栏:《深度探秘:AI界的007》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、为什么需要深度学习框架? 2、框架的发展背…...
iOS 类与对象底层原理
iOS 类与对象底层原理 文章目录 iOS 类与对象底层原理探索对象本质objc_setProperty 源码cls与类的关联原理联合体isa的类型isa_t 原理探索initIsa方法通过setClass方法中的shiftcls来验证绑定的一个流程通过 isa & ISA_MSAK通过object_getClass通过位运算 类&类的结构…...
Babel、core-js、Loader之间的关系和作用全解析
在现代前端开发中,Babel、polyfill(如 core-js)和 Loader 是非常常见又容易混淆的几个概念。为了彻底搞明白它们的作用、关系和使用方法,下面一篇文章详细梳理。 一、Babel的作用 Babel 是一个 JavaScript 的编译器,主…...
总线位宽不变,有效数据位宽变化的缓存方案
总线位宽不变,有效数据位宽变化的缓存方案 譬如总线位宽为64bit,但是有时候只有高32bit有效,有时只有低32bit有效,有时64bit都有效。总线上收到的数据要先缓存到FIFO中,那么这个FIFO的宽度和深度如何设置呢࿱…...
若依脱敏功能升级:接口返回想脱就脱,想不脱就不脱(实现灵活可控制的数据脱敏)
若依原生框架中的脱敏功能不够灵活(默认超级管理员不脱敏,其他则脱敏)。 有时候,我们有些接口想要脱敏,但是有些接口又不想脱敏。(例如列表查询的时候脱敏。修改的时候,不想数据脱敏࿰…...
【Azure Redis 缓存】在Azure Redis中,如何限制只允许Azure App Service访问?
问题描述 在Azure Redis服务中,如何实现只允许Azure App Service访问呢? 问题解答 Azure Redis 开启 防火墙的功能,并在防火墙中添加上App Service的出口IP地址即可。两步即可实现此目的! 1)查询 App Service 的出口IP…...
如何解决无训练数据问题:一种更为智能化的解决方案
手动标注数据真的很费时间,而且买数据集又贵得要命,还不一定能完全符合你的需求。但这里有个令人兴奋的好消息,为啥不用 AI 来解决这个问题呢? 别再依赖传统方法了,你可以用像 LLM(大型语言模型)和图像生成器这样的 AI 工具,为你的特定目标创建合成训练数据。如今有那…...
AI 应用同质化:一场看不见的资源 “吞噬战”
大家好,我是涛涛,今天聊聊令人担心的事情。 一、同质化的“繁荣”背后 当ChatGPT在2022年掀起全球AI热潮时,中国互联网行业迅速进入“All in AI”模式。根据艾瑞咨询数据,2023年国内AI应用市场新增注册企业超2.3万家,…...
Java + Spring Boot + MyBatis获取以及持久化sql语句的方法
在Java的Spring Boot项目中结合MyBatis获取实际执行的SQL语句,可以通过以下几种方法实现: 方法一:配置MyBatis日志级别 通过调整日志级别,MyBatis会输出执行的SQL语句及参数,适用于快速调试。 修改application.prope…...
「浏览器即OS」:WebVM技术栈如何用Wasm字节码重构冯·诺依曼体系?
一、冯诺依曼架构的维度坍塌 1. 传统计算模型的能量耗散 浏览器执行效率瓶颈分析: 操作x86指令周期Wasm指令周期能效比提升矩阵乘法3894.2x内存访问1234x系统调用120012100x 二、WebVM的量子纠缠架构 1. 浏览器内核的重构 // 基于WASI的系统调用处理 #[no_mangl…...
Vue3项目目录结构规范建议
以下是一个推荐的 Vue 3 项目目录结构规范,适用于中大型项目并遵循最佳实践: 基础目录结构 bash src/ ├─ assets/ # 静态资源 │ ├─ images/ # 图片文件 │ ├─ fonts/ # 字体文件 │ └─ styles/ …...
【计算机视觉】CV实战项目- Four-Flower:基于TensorFlow的花朵分类实战指南
深度解析Four-Flower:基于TensorFlow的花朵分类实战指南 项目概述与技术背景技术栈组成 完整实战流程环境配置1. 基础环境安装2. 项目环境搭建3. 环境验证 数据准备模型架构解析训练过程优化1. 训练配置2. 关键参数建议3. 训练监控 常见问题与解决方案1. 内存不足错…...
4.27 JavaScript核心语法+事件监听
JavaScript负责网页的行为(交互行为) JS基本语法: 引用方式 变量&常量&数据类型: alert()标签输出弹出框,如以上代码会输出true。 函数: 自定义对象: 属性方法行为 JS中的全局变量是window。 js…...
于键值(KV)的表
基于键值(KV)的表 将行编码为键值(KVs) 索引查询:点查询和范围查询 在关系型数据库中,数据被建模为由行和列组成的二维表。用户通过SQL表达他们的意图,而数据库则神奇地提供结果。不那么神奇的…...
Matlab算例运行
1. 使用终端命令运行算例: 2. 如果点击Run 按钮就是会一直报错,所以直接改成终端运行算例...
package.json script 中的 prepare 脚本的作用是什么
在 package.json 的 scripts 中,prepare 脚本是一个特殊的生命周期脚本,主要作用和执行时机如下: prepare 脚本的作用和执行时机 执行时机: 在执行 npm publish 命令之前运行。在执行不带参数的 npm install 命令时运行ÿ…...
图论---最大流(Dinic)
最大流一定是阻塞流,阻塞流不一定是最大流。 阻塞流---从起点到终点的管道已经阻塞了。 时间复杂度: 一般情况:O(n2m)O(n2m)(但实际运行效率较高,尤其在稀疏图上)。 使用当前弧优化后,效率接近…...
FastAPI系列06:FastAPI响应(Response)
FastAPI响应(Response) 1、Response入门2、Response基本操作设置响应体(返回数据)设置状态码设置响应头设置 Cookies 3、响应模型 response_model4、响应类型 response_classResponse派生类自定义response_class 在“FastAPI系列0…...
双目RealSense系统配置rs_camera.launch----实现D435i自制rosbag数据集到离线场景的slam建图
引言 Intel RealSense系列相机因其出色的深度感知能力和灵活的配置选项,在机器视觉与应用中得到广泛应用。大家在后期的slam学习中,无论是对算法本身的性能要求还是实验的泛化性都有一定的要求,那么公开的数据集如kitti、tum、Eourc不能满足…...
【MCP-2】MCP是什么,利用智普大模型在MaxKB中调用自己开发的MCP服务
在上一篇【MCP-1】MCP是什么,从DEMO入手文章中我们介绍了MCP是什么、他能干啥,以及简单的Demo示例等,这篇文章我们使用MaxKB这个工具,利用智普大模型,看看MCP到底怎么用。 创建SSE协议的MCP服务 在上篇文章中的Demo是…...
Allegro23.1新功能之如何单独关闭铜皮显示效果操作指导
Allegro23.1新功能之如何单独关闭铜皮显示效果操作指导 Allegro升级到了23.1的时候,支持单独关闭铜皮显示 ,如下图 如何仅关闭shape的显示,单独显示线,具体操作如下 点击setup...
《从分遗产说起:JS 原型与继承详解》
“天天开心就好” 先来讲讲概念: 原型(Prototype) 什么是原型? 原型是 JavaScript 中实现对象间共享属性和方法的机制。每个 JavaScript 对象(除了 null)都有一个内部链接指向另一个对象,这…...
【Part 2安卓原生360°VR播放器开发实战】第二节|基于等距圆柱投影方式实现全景视频渲染
《VR 360全景视频开发》专栏 将带你深入探索从全景视频制作到Unity眼镜端应用开发的全流程技术。专栏内容涵盖安卓原生VR播放器开发、Unity VR视频渲染与手势交互、360全景视频制作与优化,以及高分辨率视频性能优化等实战技巧。 📝 希望通过这个专栏&am…...
Android——RecyclerView
RecyclerView的使用 依赖 implementation("androidx.recyclerview:recyclerview:1.4.0")activity_recyclerview.xml <androidx.recyclerview.widget.RecyclerViewandroid:id"id/rv"android:layout_width"match_parent"android:layout_height…...
跨域问题(Cross-Origin Problem)
跨域问题(Cross-Origin Problem)是浏览器出于安全考虑,对不同源(协议、域名、端口)之间的资源访问进行限制而引发的限制。以下是详细解释: 1. 核心定义 跨域:当一个网页(源A&#x…...
阿里云直接对系统云盘扩容
阿里云直接对系统云盘扩容 登录阿里云控制台,进入ECS实例管理页面,检查目标磁盘的容量是否已更新为扩容后的数值。通过SSH远程连接服务器,使用命令 lsblk 或 fdisk -l 查看当前磁盘分区和容量,确认扩容后的物理磁盘已被系统识别。…...
Java大厂面试突击:从Spring Boot自动配置到Kafka分区策略实战解析
第一轮核心知识 面试官:请解释Spring Boot中自动配置的工作原理并演示如何自定义一个ConfigurationProperties组件? xbhog:自动配置通过EnableAutoConfiguration注解触发,结合当前环境判断(如是否检测到MyBatis依赖&…...
【python】lambda用法(结合例子理解)
目录 lambda 是什么? 为什么叫 lambda? 语法 举例 1. 最简单的 lambda:单个数字处理 2. 用 lambda 排序一组字符串(按照长度排序) 3. 在列表里找出绝对值最小的数字 4. 给 map() 用 lambda 5. 组合使用:筛选出偶数 lambda 和 def 的对比 lambda 适合用在什么地…...
前端Ui设计工具
PS 稿、蓝湖、Sketch 和 Figma 前端 UI 设计工具的对比分析 PS 稿(Adobe Photoshop) 提供精准设计细节:PS 稿能让前端更精准地理解页面布局、元素尺寸、颜色等,通过精确测量和查看信息面板,把握设计元素的空间关系、…...
深入探索Python Pandas:解锁数据分析的无限可能
放在前头 深入探索Python Pandas:解锁数据分析的无限可能 深入探索Python Pandas:解锁数据分析的无限可能 在当今数据驱动的时代,高效且准确地处理和分析数据成为了各个领域的关键需求。而Python作为一门强大且灵活的编程语言,…...