【源码分析】Nacos实例注册流程分析-事件驱动框架

【踩坑记录】

本人下载的Nacos 服务端版本是2.3.2,在开始进行源码编译便遇到问题,下面是各个问题记录

源码大量爆红

在最开始用Idea加载Maven项目的时候,发现项目中大量的代码爆红,提示其类或者包不存在,后来结果查阅资料发现,是Nacos在2.x的版本引入了Grpc通信方式,并且采用Protobuf作为序列化协议。
导致源码中有一些类是采用其进行编写的,我们需要对其进行编译,才能生成对应的包和Class,大家如果在阅读其他源码时遇到这种情况,可以向这个方面去想一想。
在这里插入图片描述
具体来说有图中两个模块,需要编译,但是直接在父项目进行Compile即可,编译后重新刷新项目或者重新构建即可。

断点失效?

在成功启动Nacos服务的时候,是采用断点调试方式启动的
在这里插入图片描述
同时也对其进行设置了单机模式
在这里插入图片描述
最后也成功启动了,就在我创建Demo项目后,进行启动。
在这里插入图片描述
控制台也有了对应的服务(这里需要提示一下,Nacos的客户端必须要有 name 这个配置,否则不会注册

spring:application:name: nacos-democloud:nacos:discovery:server-addr: 127.0.0.1:8841ephemeral: true // 是否临时注册,默认为true

通过上一篇客户端的文章,跨域知道,其底层进行注册时是调用

 this.reqApi(UtilAndComs.nacosUrlInstance, params, "POST");

在这里插入图片描述
可以知道,其接口地址是/nacos/v1/ns/instance,于是我兴高采烈的去服务的打断点,如下
在这里插入图片描述
然后重新启动客户端,奇怪的是,并没有在断点处阻塞,而是直接注册成功了,这我非常蒙,就在绞尽脑汁的时候,突然想到前面不是说了,引入了Grpc吗,后面一搜,果然,2.x版本默认采用grpc进行交互。那这个坑到这就解决了。
对于Nacos 2.x版本,默认是通过gRPC协议进行通信的
在这里插入图片描述
正确的入口在这。

实例注册源码分析

1.0 入口

客户端调用入口,首先通过传入的元信息,插件Service,然后根据操作类型,进入对应的函数;
在这里插入图片描述

2.0注册流程开始

private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)throws NacosException {clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),meta.getClientIp(), true, service.getNamespace(), service.getGroup(), service.getName(),request.getInstance().getIp(), request.getInstance().getPort()));return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);}

2.1 注册并发布事件

  @Overridepublic void registerInstance(Service service, Instance instance, String clientId) throws NacosException {NamingUtils.checkInstanceIsLegal(instance);// 通过单例模式 + map 获取对应的服务(没有就添加到对应的map中)Service singleton = ServiceManager.getInstance().getSingleton(service);if (!singleton.isEphemeral()) {throw new NacosRuntimeException(NacosException.INVALID_PARAM,String.format("Current service %s is persistent service, can't register ephemeral instance.",singleton.getGroupedServiceName()));}// 获取当前连接ID,也是通过并发map 管理连接,注意不要长时间阻塞断点,否则连接会断开,导致拿不到Client client = clientManager.getClient(clientId);checkClientIsLegal(client, clientId);InstancePublishInfo instanceInfo = getPublishInfo(instance);client.addServiceInstance(singleton, instanceInfo);// 设置当前连接最新更新的时间client.setLastUpdatedTime();// 重新设置版本号,用于版本控制client.recalculateRevision();// 发布事件NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));}

3.0 NotifyCenter - 统一事件通知中心。


/** Copyright 1999-2018 Alibaba Group Holding Ltd.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import static com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR;
/*** Unified Event Notify Center.* 统一事件通知中心 - 实现了一个事件发布-订阅框架,用于处理系统内的事件通知** @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>* @author zongtanghu*/
public class NotifyCenter {// 日志记录器private static final Logger LOGGER = LoggerFactory.getLogger(NotifyCenter.class);// 环形缓冲区大小 - 用于普通事件发布器的队列大小public static int ringBufferSize;// 共享缓冲区大小 - 用于慢速事件共享发布器的队列大小public static int shareBufferSize;// 通知中心关闭状态标志 - 使用原子布尔值确保线程安全private static final AtomicBoolean CLOSED = new AtomicBoolean(false);// 默认事件发布器工厂 - 用于创建不同类型的事件发布器private static final EventPublisherFactory DEFAULT_PUBLISHER_FACTORY;// NotifyCenter单例实例 - 通过静态final保证单例private static final NotifyCenter INSTANCE = new NotifyCenter();// 共享发布器实例 - 用于处理所有SlowEvent慢速事件private DefaultSharePublisher sharePublisher;// 事件发布器类型 - 通过SPI加载或使用默认实现private static Class<? extends EventPublisher> clazz;/*** 发布器管理容器 - 存储不同事件类型对应的发布器* key: 事件类的规范名称* value: 对应的事件发布器*/private final Map<String, EventPublisher> publisherMap = new ConcurrentHashMap<>(16);// 静态初始化块 - 在类首次加载时执行初始化static {// 从系统属性读取环形缓冲区大小,默认为16384// 对于写入吞吐量高的应用,需要适当增加这个值String ringBufferSizeProperty = "nacos.core.notify.ring-buffer-size";ringBufferSize = Integer.getInteger(ringBufferSizeProperty, 16384);// 从系统属性读取共享缓冲区大小,默认为1024// 用于公共发布器的消息暂存队列缓冲区大小String shareBufferSizeProperty = "nacos.core.notify.share-buffer-size";shareBufferSize = Integer.getInteger(shareBufferSizeProperty, 1024);// 通过SPI机制加载EventPublisher的实现类final Collection<EventPublisher> publishers = NacosServiceLoader.load(EventPublisher.class);Iterator<EventPublisher> iterator = publishers.iterator();// 如果找到自定义实现类,使用第一个;否则使用默认实现if (iterator.hasNext()) {clazz = iterator.next().getClass();} else {clazz = DefaultPublisher.class;}// 初始化默认发布器工厂 - 使用lambda表达式实现工厂接口DEFAULT_PUBLISHER_FACTORY = (cls, buffer) -> {try {// 创建发布器实例并初始化EventPublisher publisher = clazz.newInstance();publisher.init(cls, buffer);return publisher;} catch (Throwable ex) {LOGGER.error("Service class newInstance has error : ", ex);throw new NacosRuntimeException(SERVER_ERROR, ex);}};try {// 创建并初始化共享发布器实例 - 用于处理所有SlowEventINSTANCE.sharePublisher = new DefaultSharePublisher();INSTANCE.sharePublisher.init(SlowEvent.class, shareBufferSize);} catch (Throwable ex) {LOGGER.error("Service class newInstance has error : ", ex);}// 添加JVM关闭钩子,确保系统关闭时能够正确释放资源ThreadUtils.addShutdownHook(NotifyCenter::shutdown);}/*** 获取发布器映射表 - 仅用于测试** @return 发布器映射表*/@JustForTestpublic static Map<String, EventPublisher> getPublisherMap() {return INSTANCE.publisherMap;}/*** 根据事件类型获取对应的发布器** @param topic 事件类型* @return 对应的事件发布器*/public static EventPublisher getPublisher(Class<? extends Event> topic) {// 如果是SlowEvent类型,使用共享发布器if (ClassUtils.isAssignableFrom(SlowEvent.class, topic)) {return INSTANCE.sharePublisher;}// 否则从映射表中获取对应的发布器return INSTANCE.publisherMap.get(topic.getCanonicalName());}/*** 获取共享发布器实例** @return 共享发布器实例*/public static EventPublisher getSharePublisher() {return INSTANCE.sharePublisher;}/*** 关闭通知中心及其包含的所有发布器实例* 使用CAS操作确保只执行一次*/public static void shutdown() {// 如果已经关闭,则直接返回,避免重复关闭if (!CLOSED.compareAndSet(false, true)) {return;}LOGGER.warn("[NotifyCenter] Start destroying Publisher");// 关闭所有普通发布器for (Map.Entry<String, EventPublisher> entry : INSTANCE.publisherMap.entrySet()) {try {EventPublisher eventPublisher = entry.getValue();eventPublisher.shutdown();} catch (Throwable e) {LOGGER.error("[EventPublisher] shutdown has error : ", e);}}// 关闭共享发布器try {INSTANCE.sharePublisher.shutdown();} catch (Throwable e) {LOGGER.error("[SharePublisher] shutdown has error : ", e);}LOGGER.warn("[NotifyCenter] Destruction of the end");}/*** 注册订阅者(使用默认发布器工厂)* 如果发布器不存在,会使用默认工厂创建一个新的发布器** @param consumer 订阅者实例*/public static void registerSubscriber(final Subscriber consumer) {registerSubscriber(consumer, DEFAULT_PUBLISHER_FACTORY);}/*** 使用指定工厂注册订阅者* 如果发布器不存在,会使用指定工厂创建一个新的发布器** @param consumer 订阅者实例* @param factory  发布器工厂*/public static void registerSubscriber(final Subscriber consumer, final EventPublisherFactory factory) {// 处理智能订阅者 - 可以订阅多种事件类型// 如果要监听多个事件,需要分别进行处理// 基于子类的subscribeTypes方法返回的列表,可以注册到发布器if (consumer instanceof SmartSubscriber) {for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {// 对于慢速事件,注册到共享发布器if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {INSTANCE.sharePublisher.addSubscriber(consumer, subscribeType);} else {// 对于普通事件,注册到对应的发布器addSubscriber(consumer, subscribeType, factory);}}return;}// 处理普通订阅者 - 只订阅一种事件类型final Class<? extends Event> subscribeType = consumer.subscribeType();// 如果是慢速事件,注册到共享发布器if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {INSTANCE.sharePublisher.addSubscriber(consumer, subscribeType);return;}// 对于普通事件,注册到对应的发布器addSubscriber(consumer, subscribeType, factory);}/*** 将订阅者添加到发布器中* 如果发布器不存在,会先创建发布器** @param consumer      订阅者实例* @param subscribeType 订阅的事件类型* @param factory       发布器工厂*/private static void addSubscriber(final Subscriber consumer, Class<? extends Event> subscribeType,EventPublisherFactory factory) {// 获取事件类型的规范名称作为topicfinal String topic = ClassUtils.getCanonicalName(subscribeType);synchronized (NotifyCenter.class) {// 确保发布器存在,如果不存在则创建// 注释说MapUtils.computeIfAbsent是不安全的方法,这里使用自定义的MapUtilMapUtil.computeIfAbsent(INSTANCE.publisherMap, topic, factory, subscribeType, ringBufferSize);}// 获取发布器并添加订阅者EventPublisher publisher = INSTANCE.publisherMap.get(topic);if (publisher instanceof ShardedEventPublisher) {// 如果是分片发布器,需要传入订阅类型((ShardedEventPublisher) publisher).addSubscriber(consumer, subscribeType);} else {// 普通发布器直接添加订阅者publisher.addSubscriber(consumer);}}/*** 取消订阅者的注册** @param consumer 订阅者实例* @throws NoSuchElementException 如果订阅者没有对应的发布器*/public static void deregisterSubscriber(final Subscriber consumer) {// 处理智能订阅者 - 需要逐一取消多个事件类型的订阅if (consumer instanceof SmartSubscriber) {for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {// 从共享发布器中移除订阅INSTANCE.sharePublisher.removeSubscriber(consumer, subscribeType);} else {// 从普通发布器中移除订阅removeSubscriber(consumer, subscribeType);}}return;}// 处理普通订阅者 - 只有一个订阅类型final Class<? extends Event> subscribeType = consumer.subscribeType();if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {// 从共享发布器中移除订阅INSTANCE.sharePublisher.removeSubscriber(consumer, subscribeType);return;}// 从普通发布器中移除订阅,如果移除失败则抛出异常if (removeSubscriber(consumer, subscribeType)) {return;}throw new NoSuchElementException("The subscriber has no event publisher");}/*** 从发布器中移除订阅者** @param consumer      订阅者实例* @param subscribeType 订阅的事件类型* @return 移除是否成功*/private static boolean removeSubscriber(final Subscriber consumer, Class<? extends Event> subscribeType) {// 获取事件类型的规范名称作为topicfinal String topic = ClassUtils.getCanonicalName(subscribeType);// 查找对应的发布器EventPublisher eventPublisher = INSTANCE.publisherMap.get(topic);if (null == eventPublisher) {return false;}// 根据发布器类型调用不同的移除方法if (eventPublisher instanceof ShardedEventPublisher) {((ShardedEventPublisher) eventPublisher).removeSubscriber(consumer, subscribeType);} else {eventPublisher.removeSubscriber(consumer);}return true;}/*** 请求发布器发布事件* 发布器采用懒加载模式,只有在实际发布事件时才会调用publisher.start()** @param event 事件实例* @return 发布是否成功*/public static boolean publishEvent(final Event event) {try {// 通过事件实例获取事件类型,并调用内部发布方法return publishEvent(event.getClass(), event);} catch (Throwable ex) {// 捕获所有异常,确保不影响调用方LOGGER.error("There was an exception to the message publishing : ", ex);return false;}}/*** 请求发布器发布事件的内部实现** @param eventType 事件类型* @param event     事件实例* @return 发布是否成功*/private static boolean publishEvent(final Class<? extends Event> eventType, final Event event) {// 如果是慢速事件,使用共享发布器发布if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {return INSTANCE.sharePublisher.publish(event);}// 获取事件类型的规范名称作为topicfinal String topic = ClassUtils.getCanonicalName(eventType);// 查找对应的发布器并发布事件EventPublisher publisher = INSTANCE.publisherMap.get(topic);if (publisher != null) {return publisher.publish(event);}// 对于插件事件,允许没有对应发布器if (event.isPluginEvent()) {return true;}// 找不到发布器,记录警告日志LOGGER.warn("There are no [{}] publishers for this event, please register", topic);return false;}/*** 注册到共享发布器* 用于将慢速事件类型注册到共享发布器** @param eventType 慢速事件类型* @return 共享发布器实例*/public static EventPublisher registerToSharePublisher(final Class<? extends SlowEvent> eventType) {return INSTANCE.sharePublisher;}/*** 使用默认工厂注册发布器** @param eventType    事件类型* @param queueMaxSize 发布器队列最大大小* @return 注册的发布器实例*/public static EventPublisher registerToPublisher(final Class<? extends Event> eventType, final int queueMaxSize) {return registerToPublisher(eventType, DEFAULT_PUBLISHER_FACTORY, queueMaxSize);}/*** 使用指定工厂注册发布器** @param eventType    事件类型* @param factory      发布器工厂* @param queueMaxSize 发布器队列最大大小* @return 注册的发布器实例*/public static EventPublisher registerToPublisher(final Class<? extends Event> eventType,final EventPublisherFactory factory, final int queueMaxSize) {// 如果是慢速事件,直接返回共享发布器if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {return INSTANCE.sharePublisher;}// 获取事件类型的规范名称作为topicfinal String topic = ClassUtils.getCanonicalName(eventType);synchronized (NotifyCenter.class) {// 确保发布器存在,如果不存在则创建// 注释说MapUtils.computeIfAbsent是不安全的方法,这里使用自定义的MapUtilMapUtil.computeIfAbsent(INSTANCE.publisherMap, topic, factory, eventType, queueMaxSize);}return INSTANCE.publisherMap.get(topic);}/*** 注册指定的发布器* 允许用户提供自定义的发布器实例** @param eventType 事件类型* @param publisher 指定的事件发布器*/public static void registerToPublisher(final Class<? extends Event> eventType, final EventPublisher publisher) {// 空检查,避免空指针异常if (null == publisher) {return;}// 获取事件类型的规范名称作为topicfinal String topic = ClassUtils.getCanonicalName(eventType);synchronized (NotifyCenter.class) {// 只有在不存在时才放入,避免覆盖已有发布器INSTANCE.publisherMap.putIfAbsent(topic, publisher);}}/*** 取消注册发布器* 将指定事件类型的发布器从管理容器中移除并关闭** @param eventType 事件类型*/public static void deregisterPublisher(final Class<? extends Event> eventType) {// 获取事件类型的规范名称作为topicfinal String topic = ClassUtils.getCanonicalName(eventType);// 从管理容器中移除发布器EventPublisher publisher = INSTANCE.publisherMap.remove(topic);try {// 关闭发布器,释放资源publisher.shutdown();} catch (Throwable ex) {LOGGER.error("There was an exception when publisher shutdown : ", ex);}}}

Nacos NotifyCenter 核心设计与功能

一、整体架构

NotifyCenter 是 Nacos 中的统一事件通知中心,实现了一个高效的事件发布-订阅框架,用于系统内部组件间的解耦通信。它采用单例模式,集中管理事件的发布和订阅,支持高吞吐量的事件处理。

┌────────────────────────────────────────────────────────┐
│                    NotifyCenter                         │
├────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────┐     ┌─────────────┐     ┌───────────┐ │
│  │ 事件发布管理 │     │ 订阅者管理  │     │ 资源管理  │ │
│  └─────────────┘     └─────────────┘     └───────────┘ │
│                                                         │
└────────────────────────────────────────────────────────┘▲                    ▲                 ▲│                    │                 │
┌─────────┴──────┐   ┌────────┴────────┐   ┌────┴─────┐
│   Publisher    │   │   Subscriber    │   │  Event   │
└────────────────┘   └─────────────────┘   └──────────┘

二、核心设计特点

1. 双类型事件机制

NotifyCenter 将事件分为两类,并采用不同的处理策略:

  • 普通事件:每种事件类型对应一个专用发布器,存储在 publisherMap
  • 慢速事件(SlowEvent):所有慢速事件共享一个发布器 sharePublisher,避免阻塞普通事件处理
// 决定事件路由到哪个发布器
if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {return INSTANCE.sharePublisher.publish(event);
} else {EventPublisher publisher = INSTANCE.publisherMap.get(topic);return publisher.publish(event);
}

2. 延迟加载与按需创建

发布器采用懒加载模式,仅在需要时才创建,节约系统资源:

// 发布器不存在时才创建
synchronized (NotifyCenter.class) {MapUtil.computeIfAbsent(INSTANCE.publisherMap, topic, factory, eventType, ringBufferSize);
}

3. 可配置的缓冲区大小

通过系统属性支持自定义缓冲区大小,适应不同场景的性能需求:

// 读取系统配置设置缓冲区大小
String ringBufferSizeProperty = "nacos.core.notify.ring-buffer-size";
ringBufferSize = Integer.getInteger(ringBufferSizeProperty, 16384);String shareBufferSizeProperty = "nacos.core.notify.share-buffer-size";
shareBufferSize = Integer.getInteger(shareBufferSizeProperty, 1024);

4. SPI 扩展机制

使用 Java SPI 机制支持自定义发布器实现,提高框架扩展性:

// 通过SPI加载自定义发布器实现
final Collection<EventPublisher> publishers = NacosServiceLoader.load(EventPublisher.class);

5. 线程安全设计

使用并发工具和同步机制确保多线程环境下的正确性:

  • 采用 ConcurrentHashMap 存储发布器
  • 使用 synchronized 块保护关键操作
  • 使用 AtomicBoolean 确保关闭操作仅执行一次

三、核心功能模块

1. 订阅者管理

支持注册和注销订阅者,支持两类订阅者:

  • 普通订阅者(Subscriber):只订阅一种事件类型
  • 智能订阅者(SmartSubscriber):可同时订阅多种事件类型
public static void registerSubscriber(final Subscriber consumer) {// 针对SmartSubscriber,遍历其所有订阅类型if (consumer instanceof SmartSubscriber) {for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {// 分别注册每种事件类型// ...}} else {// 针对普通Subscriber处理单一事件类型// ...}
}

2. 发布器管理

维护事件类型到发布器的映射,支持注册、获取和注销发布器:

// 发布器容器
private final Map<String, EventPublisher> publisherMap = new ConcurrentHashMap<>(16);// 注册发布器
public static EventPublisher registerToPublisher(final Class<? extends Event> eventType, final int queueMaxSize) {// ...
}// 获取发布器
public static EventPublisher getPublisher(Class<? extends Event> topic) {// ...
}// 注销发布器
public static void deregisterPublisher(final Class<? extends Event> eventType) {// ...
}

3. 事件发布

提供统一的事件发布入口,根据事件类型路由到对应发布器:

public static boolean publishEvent(final Event event) {try {return publishEvent(event.getClass(), event);} catch (Throwable ex) {LOGGER.error("There was an exception to the message publishing : ", ex);return false;}
}

4. 资源管理

提供优雅的资源释放机制,确保系统关闭时能正确清理资源:

public static void shutdown() {if (!CLOSED.compareAndSet(false, true)) {return;}// 关闭所有普通发布器for (EventPublisher publisher : publisherMap.values()) {publisher.shutdown();}// 关闭共享发布器sharePublisher.shutdown();
}

四、使用流程示例

1. 定义事件

// 普通事件
public class ConfigChangeEvent extends Event {// 事件内容
}// 慢速事件
public class ServiceChangeEvent extends SlowEvent {// 事件内容
}

2. 创建订阅者

// 普通订阅者
public class ConfigChangeListener implements Subscriber<ConfigChangeEvent> {@Overridepublic void onEvent(ConfigChangeEvent event) {// 处理事件}@Overridepublic Class<? extends Event> subscribeType() {return ConfigChangeEvent.class;}
}

3. 注册订阅者

NotifyCenter.registerSubscriber(new ConfigChangeListener());

4. 发布事件

ConfigChangeEvent event = new ConfigChangeEvent();
NotifyCenter.publishEvent(event);

五、设计优势

  1. 高性能:通过区分快慢事件、使用环形缓冲区提高事件处理吞吐量
  2. 高可靠:完善的异常处理和资源管理,确保系统稳定性
  3. 良好扩展性:通过SPI机制支持定制发布器实现
  4. 灵活配置:可通过系统属性调整性能参数
  5. 解耦设计:发布者和订阅者完全解耦,提高系统模块化程度

NotifyCenter 作为 Nacos 中的核心基础设施,为整个系统提供了高效可靠的事件通知机制,是理解 Nacos 内部通信机制的关键组件。

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

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

相关文章

51单片机指令系统入门

目录 基本概念讲解 一、机器指令​ 二、汇编指令​ &#xff08;一&#xff09;汇编指令的一般格式 &#xff08;二&#xff09;按字节数分类的指令 三、高级指令 总结​ 基本概念讲解 指令是计算机&#xff08;或单片机&#xff09;中 CPU 能够识别并执行的基本操作命令…

mysql5.x和mysql8.x查看和设置隔离级别

MySQL的隔离级别 级别标志值描述读未提交READ-UNCOMMITTED0存在脏读、不可重复读、幻读的问题读已提交READ-COMMITTED1解决脏读的问题&#xff0c;存在不可重复读、幻读的问题可重复读REPEATABLE-READ2mysql 默认级别&#xff0c;解决脏读、不可重复读的问题&#xff0c;存在幻…

【函数式编程】【C#/F#】第四讲:单子与函子 - 抽象的编程模式

在第二讲中我们探讨了一个诚实的函数应该要做到什么事&#xff0c;并运用了一种方法&#xff0c;让我们可以去准确的描述数据。 不过有一种情况让我们始料未及&#xff0c;例如网站需要收集一些信息&#xff0c;但有些信息不是必须的&#xff0c;是可有可无的。如果我们要去准…

【vue2 + Cesium】使用Cesium、添加第三方地图、去掉商标、Cesium基础配置、地图放大缩小事件、获取可视区域、层级、高度

参考文章&#xff1a; vue2 使用 cesium 篇【第一篇】 vue2 使用 cesium 【第二篇-相机视角移动添加模型】 vue2 项目模版&#xff1a; vue2-common 安装 cesium npm install cesium --save这个就很简单&#xff0c;只需要一句简简单单的命令就可以实现在 vue 项目中安装 ce…

vllm-openai多服务器集群部署AI模型

服务器配置是两台ubantu系统电脑,每台电脑安装两张4090-48G显存的显卡,共计192G显存。 服务器1 服务器2 准备工作: 1.两台电脑都已经安装了docker 2.两台电脑都已经安装了nvidia驱动 参考vllm官方资料 https://docs.vllm.ai/en/latest/serving/distributed_serving.html…

【电源】斩波电路

文章目录 前言定义概念 缩写降压斩波电路使用步骤总结参考文献 前言 进行大创项目开发的学习 bilibili 定义概念 缩写 斩波电路&#xff1a;分为降压&#xff0c;电荷泵&#xff0c;升压&#xff0c;升降压&#xff0c;Cuk&#xff0c;Speic&#xff0c;Zeta 等等 降压斩…

Hadoop集群组成

&#xff08;一&#xff09;Hadoop的组成 对普通用户来说&#xff0c; Hadoop就是一个东西&#xff0c;一个整体&#xff0c;它能给我们提供无限的磁盘用来保存文件&#xff0c;可以使用提供强大的计算能力。 在Hadoop3.X中&#xff0c;hadoop一共有三个组成部…

c++基础知识-图论进阶

一、拓扑排序 1、基础知识 1&#xff09;什么是拓扑排序 对一个有向无环图G进行拓扑排序&#xff0c;是将G中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点u和v&#xff0c;若&#xff0c;则u在线性序列中出现在v之前。 2&#xff09;拓扑排序的操作方法 重复执行…

从Scaling Laws中解析大模型训练的边际递减临界点

前言 当我们拆解GPT-4到DeepSeek的演进路径&#xff0c;会发现一个反直觉的真相&#xff1a;​AI的智能跃迁不依赖参数堆砌&#xff0c;而取决于对"结构-能量-信息"三元关系的精准把控。就像人类大脑在进化中通过皮层折叠而非单纯增大体积来实现智能突破&#xff0c…

Word 小黑第20套

对应大猫21 特定一页设为横向 上下用分页符

【从0到1搞懂大模型】RNN基础(4)

先说几个常用的可以下载数据集的地方 平台&#xff1a;kaggle&#xff08;https://www.kaggle.com/datasets&#xff09; 和鲸社区&#xff08;https://www.heywhale.com/home&#xff09; 阿里天池&#xff08;https://tianchi.aliyun.com/&#xff09; 其他&#xff1a;海量公…

openEuler24.03 LTS下安装MySQL8

前提条件 拥有openEuler24.03 LTS环境&#xff0c;可参考&#xff1a;Vmware下安装openEuler24.03 LTS 步骤 卸载原有mysql及mariadb sudo systemctl stop mysql mysqld 2>/dev/null sudo rpm -qa | grep -i mysql\|mariadb | xargs -n1 sudo rpm -e --nodeps 2>/dev/…

如何在Odoo 18中实现OWL通知服务

如何在Odoo 18中实现OWL通知服务 OWL&#xff08;Odoo Web Library&#xff09;是Odoo的前端框架&#xff0c;用于构建现代化的动态响应式用户界面。在早期版本中&#xff0c;Odoo 前端设计与开发使用的是诸如 QWeb 这类较为老旧的框架&#xff0c;而随着 Odoo 每发布一个新版本…

Unet nn-Unet

Unet && nn-Unet&#xff1a; 文章题目&#xff1a;U-Net: Convolutional Networks for Biomedical Image Segmentation 代码&#xff1a;https://lmb.informatik.uni-freiburg.de/people/ronneber/u-net/ 文章题目&#xff1a;nnU-Net: Self-adapting Framework for U…

【扩散模型入门】Latent Diffusion

1. 概述 扩散模型为公众所知的一个主要原因是Stable Diffusion(SD)的推出展现出了远超以往的图像合成效果,而SD的主要技术就是Latent Diffusion Model(LDM)。 实际上,LDM的核心idea非常简单: 为了确保生成质量,LDM尽可能提升去噪模型的规模。提升模型规模往往也会同步…

搭建主从服务器

任务需求 客户端通过访问 www.nihao.com 后&#xff0c;能够通过 dns 域名解析&#xff0c;访问到 nginx 服务中由 nfs 共享的首页文件&#xff0c;内容为&#xff1a;Very good, you have successfully set up the system. 各个主机能够实现时间同步&#xff0c;并且都开启防…

SAP HANA on AWS Amazon Web Services

SAP HANA on AWS Amazon Web Services

vue项目如何实现条件查询?

目录 1.前端 2.后端 3.mybatis的sql语句 结语 1.前端 说白了就是&#xff0c;无论该参数是否是空字符串&#xff0c;都会传递到后端。&#xff08;反正不是null就行&#xff09;。 2.后端 在controller层中&#xff0c;使用RequestParam注解接收名为registerName的参数&…

C++:类对象的存储方式

如何计算类对象的大小 class A { public: void PrintA() { cout<<_a<<endl; } private: char _a; }; 类中既可以有成员变量&#xff0c;又可以有成员函数&#xff0c;那么一个类的对象中包含了什么&#xff1f;如何计算 一个类的大小&#xff1f; 类对象的存储方…

Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(一)

WDDM 3.0 之前的翻转队列模型 许多新式显示控制器支持对按顺序显示的多个帧排队的能力。 从 WDDM 2.1 开始&#xff0c;OS 支持将在下一个 VSync 中显示的多个未完成的翻转覆盖请求。 显示微型端口驱动程序 (KMD) 通过 DXGK_DRIVERCAPS 中的 MaxQueuedMultiPlaneOverlayFlipVS…