常见面试题-Netty专栏(一)

news/2024/5/5 19:42:12/文章来源:https://blog.csdn.net/qq_45260619/article/details/133999514

typora-copy-images-to: imgs

Netty 是什么呢?Netty 用于做什么呢?

答:

Netty 是一个 NIO 客户服务端框架,可以快速开发网络应用程序,如协议服务端和客户端,极大简化了网络编程,如 TCP 和 UDP 套接字服务(来自官网)

热门开源项目如 Dubbo、RocketMQ 底层都是用了 Netty

Netty怎么实现高性能设计?

答:

Netty 高性能的三个方面:

  1. 传输:用什么样的通道将数据发送给对方,BIO、NIO 或者 AIO,IO 模型在很大程度上决定了框架的性能。IO模型的选择
  2. 协议:采用什么样的通信协议,HTTP 或者内部私有协议。协议的选择不同,性能模型也不同。相比于公有协议,内部私有协议的性能通常可以被设计的更优。协议的选择
  3. 线程:数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发,Reactor 线程模型的不同,对性能的影响也非常大。线程模型的选择

介绍一下 AIO、BIO 和 NIO?

答:

  • AIO:

从 Java.1.7 开始,Java 提供了 AIO(异步IO),Java 的 AIO 也被称为 “NIO.2”

Java AIO 采用订阅-通知模式,应用程序向操作系统注册 IO 监听,之后继续做自己的事情,当操作系统发生 IO 事件并且已经准备好数据时,主动通知应用程序,应用程序再进行相关处理

(Linux 平台没有这种异步 IO 技术,而是使用 epoll 对异步 IO 进行模拟)

  • BIO:

BIO 即同步阻塞 IO,服务端实现模式为一个连接对应一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理

BIO简单工作流程:

  1. 服务器端启动一个 ServerSocket
  2. 客户端启动 Socket 对服务器进行通信,默认情况下服务器端需要对每个客户端建立一个线程与之通讯
  3. 客户端发出请求后, 先咨询服务器是否有线程响应,如果没有则会等待,或者被拒绝
  4. 如果有响应,客户端线程会等待请求结束后,再继续执行

BIO存在问题:

  1. 当并发量较大时,需要创建大量线程来处理连接,比较占用系统资源
  2. 连接建立之后,如果当前线程暂时没有数据可读,则线程会阻塞在 Read 操作上,造成线程资源浪费
  • NIO:

从 Java1.4 开始,Java 提供了 NIO,NIO 即 “Non-blocking IO”(同步非阻塞IO)

NIO 的几个核心概念:

  1. Channel、Buffer:BIO是基于字节流或者字符流的进行操作,而NIO 是基于缓冲区通道进行操作的,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中

  2. Selector:选择器用于监听多个通道的事件(如,连接打开,数据到达),因此,单个线程可以监听多个数据通道,极大提升了单机的并发能力

    当 Channel 上的 IO 事件未到达时,线程会在 select 方法被挂起,让出 CPU 资源,直到监听到 Channel 有 IO 事件发生,才会进行相应的处理

  • NIO和BIO有什么区别?
  1. NIO是以的方式处理数据,BIO是以字节流或者字符流的形式去处理数据。
  2. NIO是通过缓存区和通道的方式处理数据,BIO是通过InputStream和OutputStream流的方式处理数据。
  3. NIO的通道是双向的,BIO流的方向只能是单向的。
  4. NIO采用的多路复用的同步非阻塞IO模型,BIO采用的是普通的同步阻塞IO模型。
  5. NIO的效率比BIO要高,NIO适用于网络IO,BIO适用于文件IO。

NIO如何实现了同步非阻塞?

通过 Selector 和 Channel 来进行实现,一个线程使用一个 Selector 监听多个 Channel 上的 IO 事件,通过配置监听的通道Channel为非阻塞,那么当Channel上的IO事件还未到达时,线程会在select方法被挂起,让出CPU资源。直到监听到Channel有IO事件发生时,才会进行相应的响应和处理。

介绍一下 Netty 使用的线程模型?

答:

Netty 主要基于主从 Reactor 多线程模型,其中主从 Reactor 多线程模型将 Reactor 分为两部分:

  • mainReactor:监听 Server Socket,用来处理网络 IO 连接建立操作,将建立的 SocketChannel 指定注册给 subReactor
  • subReactor:和建立起来的 socket 做数据交互和业务处理操作

因为客户端的连接数量相对来说比较少,而数据的读和写会比较多一点,使用 mainReactor 只接受客户端连接,由其他线程 subReactor 负责读和写,将业务处理剥离出,让线程池来处理,降低了 Reactor 的性能开销

扩展:单 Reactor 单线程模型、单 Reactor 多线程模型

  • 单 Reactor 单线程模型

    通过 1 个线程负责客户端连接、网络数据的读写、业务处理

    缓存 Redis 就是单 Reactor 单线程模型

  • 单 Reactor 多线程模型

    通过 1 个线程负责客户端的连接、网络数据的读写,将业务处理剥离出去,通过线程池来进行处理

三种 Reactor 模型的优缺点:

  • 单 Reactor 单线程模型是单线程进行业务处理,当负载过重时,处理速度将会变慢,影响系统性能,因此引出单 Reactor 多线程模型
  • 单 Reactor 多线程模型时多个线程处理业务,业务处理速度上来了,但是单 Reactor 承担了所有时间的监听和响应,可能存在性能问题。当有数百万客户端进行连接或者服务端需要对客户端握手进行安全认证,认证本身非常消耗性能,因此出现了主从 Reactor 多线程模型
  • 主从 Reactor 多线程模型中 1 个主 Reactor 只用来处理网络 IO 的连接建立操作,而对于接入认证、IP 黑白名单过滤、握手等操作由从 Reactor 进行处理,这样进一步提升性能,在主从 Reactor 多线程模型中,从 Reactor 有多个,可以与 CPU 个数相同

TCP 粘包、拆包是什么?如何解决?

答:

TCP本身的机制决定了一定会有粘包、拆包,因为 TCP 传输协议时基于数据流传输的,而流化的数据没有界限,因此 TCP 作为传输层协议并不了解上层业务数据的具体含义,会根据 TCP 缓冲区的实际情况进行数据包的划分,所以业务上认为的一个完整的包,可能被 TCP 拆成多个包或者把多个小的包封装成一个大的包进行发送。

产生原因:

  • 粘包:客户端发送的包的大小比socket的缓存小或者接收方读取socket缓存不及时,因此多个包一起发送了
  • 拆包:客户端发送的包的大小比socket的缓存大或者发送的数据大于协议的MTU(最大传输单元)必须拆包,那么这个包就被拆分成了多个包进行发送

解决方法:

有三种方式:

  • 通过指定分隔符来进行分割
  • 通过指定固定长度来进行分割
  • 上边两种方式灵活性不好,因此常用的是通过指定接收数据的长度来解决,也就是LengthFieldBasedFrameDecoder()这个类

Netty 中常用组件?

答:

  • Channel:Netty 网络操作抽象类,包括了基本的 IO 操作,如 bind、connect、read、write 等等
  • EventLoop:主要是配合 Channel 处理 IO 操作,用来处理连接的生命周期中所发生的事件
  • ChannelFuture:Netty 中的所有 IO 操作都是异步的,我们通过 ChannelFuture 的 addListener() 注册一个 ChannelFutureListener 监听事件,当操作执行完毕后,监听就会返回结果
  • ChannelHandler:作为处理器,用于处理入站和出战的数据
  • ChannelHandlerContext:用于包裹 ChannelHandler,维护了 pipeline 这个双向链表中的 pre 和 next 指针,这样可以方便的找到与其相邻的 ChannelHandler,并且过滤出一些符合执行条件的 ChannelHandler,Netty 的异步事件在 pipeline 中传播就是依靠 ChannelHandlerContext
  • ChannelPipeline:每一个 Channel 都会分配一个 ChannelPipeline,pipeline 是一个双向链表的结构,Netty 中产生的 IO 异步事件都会在这个 pipeline 中传播

Netty 如何发送消息?

答:

有两种发送消息的方式:

  • 直接写入 Channel,消息从 ChannelPipeline 的尾节点开始向前传播至头节点,代码channelHandlerContext.write()
  • 使 write 事件从当前 ChannelHandler 开始沿着 pipeline 向前传播,代码channelHandlerContext.channel().write()

这里解释一下,上边发送消息为什么是向前传播:

在 Netty 中,IO 异步事件基本上分为两类:inbound(入站) 事件、outbound(出站) 事件,那么入站事件是沿着 pipeline 的头结点一直向后传播,因此出站事件就是沿着 pipeline 的尾结点一直向前传播,而上边发送消息也就是出站事件,因此是沿着 pipeline 从后向前进行传播

直接内存比堆内存快在了哪里?

答:

首先直接内存不是 Java 虚拟机中的内存,是直接向系统内存申请的空间,来源于 NIO,通过 Java 堆中的 DirectByteBuffer 来进行操作。

直接内存相比于堆内存,避免了数据的二次拷贝。

  • 我们先来分析不使用直接内存的情况,我们发送数据需要将数据先写入 Socket 的缓冲区内,那么如果数据存储在 JVM 的堆内存中的话,会先将堆内存中的数据复制一份到直接内存中,再将直接内存中的数据写入到 Socket 缓冲区中,之后进行数据的发送

    • 为什么不能直接将 JVM 堆内存中的数据写入 Socket 缓冲区中呢?

      在 JVM 堆内存中有 GC 机制,GC 后可能会导致堆内存中数据位置发生变化,那么如果直接将 JVM 堆内存中的数据写入 Socket 缓冲区中,如果写入过程中发生 GC,导致我们需要写入的数据位置发生变化,就会将错误的数据写入 Socket 缓冲区

  • 那么如果使用直接内存的时候,我们将数据直接存放在直接内存中,在堆内存中只存放了对直接内存中数据的引用,这样在发送数据时,直接将数据从直接内存取出,放入 Socket 缓冲区中即可,减少了一次堆内存到直接内存的拷贝

请添加图片描述

什么是 Netty 的零拷贝?什么是 TCP 缓冲区?

答:

Netty 的零拷贝主要包含三个方面:

  • Netty 的接收和发送使用堆外(直接内存)进行 Socket 读写,不需要进行字节缓冲区的二次拷贝。

  • Netty 提供 CompositeByteBuf 组合缓冲区类,可以将多个 ByteBuf合并为一个逻辑上的ByteBufer,避免了各个ByteBufer之间的拷贝,将几个小buffer合并成一个大buffer的繁琐操作。

  • Netty 的文件传输使用了 FileChanneltransferTo 方法,该方法底层使用了 sendfile 函数实现了 cpu 零拷贝。

    sendfile 函数通过网络发送数据的流程为:

    磁盘 ----DMA拷贝---->文件读取缓冲区 ----CPU拷贝----> 套接字发送缓冲区(SO_SNDBUF) ----DMA拷贝----> 网络设备缓冲区(网卡)

    图片流程如下:(3次拷贝、2次上下文切换,这里上下文切换是在用户空间发起write操作,此时用户态切换为内核态,write调用完毕后又会从内核态切换回用户态)

    请添加图片描述

什么是TCP 缓冲区?

每个 TCP 的 Socket 的内核中都有一个发送缓冲区(SO_SNDBUF)和一个接收缓冲区(SO_RECVBUF)(在通过 TCP 需要进行网络数据传输时,数据都是会写入 Socket 的缓冲区中的,之后再通过网络协议发送出去)

了解 Netty 中的 ByteBuf 类吗?

答:

在 Java NIO 编程中,Java 提供了 ByteBuffer 作为字节缓冲区类型(缓冲区可以理解为一段内存区域),来表示一个连续的字节序列。

Netty 中并没有使用 Java 的 ByteBuffer,而是使用了新的缓冲类型 ByteBuf,特性如下:

  • 允许自定义缓冲类型

  • 复合缓冲类型中内置的透明的零拷贝实现

  • 开箱即用的动态缓冲类型,具有像 StringBuffer 一样的动态缓冲能力

  • 不再需要调用 flip() 方法

    Java 的 ByteBuffer 类中,需要使用 flip() 来进行读写两种模式的切换

  • 正常情况下具有比 ByteBuffer 更快的响应速度

Java 中的 ByteBuffer:

主要需要注意有 3 个属性:position、limit、capacity

  • capacity:当前数组的容量大小
  • position:写入模式的可写入数据的下标,读取模式的可读取数据下标
  • limit:写入模式的可写入数组大小,读取模式的最多可以读取数据的下标

假如说数组容量是 10,那么三个值初始值为:

position = 0
limit = 10
capacity = 10

假如写入 4 个字节的数据,此时三个值如下:

position = 4
limit = 10
capacity = 10

如果切换到读取数据模式(使用 flip()),会改变上边的三个值,会从 position 的位置开始读取数据到 limit 的位置

position = 0
limit = 4
capacity = 10

Netty 中的 ByteBuf:

ByteBuf 主要使用两个指针来完成缓冲区的读写操作,分别是: readIndexwriteIndex

  • 当写入数据时,writeIndex 会增加
  • 当读取数据时,readIndex 会增加,但不会超过 writeIndex

ByteBuf 的使用:

public static void main(String[] args) {ByteBuf buffer = Unpooled.buffer(10);System.out.println("----------初始化ByteBuf----------");printByteBuffer(buffer);System.out.println("----------ByteBuf写入数据----------");String str = "hello world!";buffer.writeBytes(str.getBytes());printByteBuffer(buffer);System.out.println("----------ByteBuf读取数据----------");while (buffer.isReadable()) {System.out.print((char)buffer.readByte());}System.out.println();printByteBuffer(buffer);System.out.println("----------ByteBuf释放无用空间----------");buffer.discardReadBytes();printByteBuffer(buffer);System.out.println("----------ByteBuf清空----------");buffer.clear();printByteBuffer(buffer);
}
private static void printByteBuffer(ByteBuf buffer) {System.out.println("readerIndex:" + buffer.readerIndex());System.out.println("writerIndex:" + buffer.writerIndex());System.out.println("capacity:" + buffer.capacity());
}
/**输出**/
----------初始化ByteBuf----------
readerIndex:0
writerIndex:0
capacity:10
----------ByteBuf写入数据----------
readerIndex:0
writerIndex:12
capacity:64
----------ByteBuf读取数据----------
hello world!
readerIndex:12
writerIndex:12
capacity:64
----------ByteBuf释放无用空间----------
readerIndex:0
writerIndex:0
capacity:64
----------ByteBuf清空----------
readerIndex:0
writerIndex:0
capacity:64

ByteBuf 的 3 种使用模式:

ByteBuf 共有 3 种使用模式:

  • 堆缓冲区模式(Heap Buffer)

    堆缓冲区模式又称为 “支撑数据”,其数据存放在 JVM 的堆空间

    优点:

    • 数据在 JVM 堆中存储,可以快速创建和释放,并且提供了数组直接快速访问的方法

    缺点:

    • 每次数据与 IO 进行传输时,都需要将数据复制到直接缓冲区(这里为什么要将数据复制到直接缓冲区的原因在上边的 直接内存比堆内存快在了哪里? 问题中已经讲过)

    创建代码:

    ByteBuf buffer = Unpooled.buffer(10);
    
  • 直接缓冲区模式(Direct Buffer)

    直接缓冲区模式属于堆外分配的直接内存,不占用堆的容量

    优点:

    • 使用 socket 传输数据时性能很好,避免了数据从 JVM 堆内存复制到直接缓冲区

    缺点:

    • 相比于堆缓冲区,直接缓冲区分配内存空间和释放更为昂贵

    创建代码:

    ByteBuf buffer = Unpooled.directBuffer(10);
    
  • 复合缓冲区模式(Composite Buffer)

    本质上类似于提供一个或多个 ByteBuf 的组合视图

    优点:

    • 提供一种方式让使用者自由组合多个 ByteBuf,避免了复制和分配新的缓冲区

    缺点:

    • 不支持访问其支撑数据,如果要访问,需要先将内容复制到堆内存,再进行访问

    创建代码:

    public static void main(String[] args) {
    //        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test.class);// 创建一个堆缓冲区ByteBuf heapBuf = Unpooled.buffer(2);String str1 = "hi";heapBuf.writeBytes(str1.getBytes());// 创建一个直接缓冲区ByteBuf directBuf = Unpooled.directBuffer(5);String str2 = "nihao";directBuf.writeBytes(str2.getBytes());// 创建一个复合缓冲区CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer(10);compositeByteBuf.addComponents(heapBuf, directBuf);// 检查是否支持支撑数组,发现并不支持if (!compositeByteBuf.hasArray()) {for (ByteBuf buf : compositeByteBuf) {// 第一个字节偏移量int offset = buf.readerIndex();// 总共数据长度int length = buf.readableBytes();byte[] bytes = new byte[length];// 不支持访问支撑数组,需要将内容复制到堆内存中,即 bytes 数组中,才可以进行访问buf.getBytes(offset, bytes);printByteBuffer(bytes, offset, length);}}
    }private static void printByteBuffer(byte[] array, int offset, int length) {System.out.println("array:" + array);System.out.println("array->String:" + new String(array));System.out.println("offset:" + offset);System.out.println("len:" + length);
    }
    /**输出**/
    array:[B@4f8e5cde
    array->String:hi
    offset:0
    len:2
    array:[B@504bae78
    array->String:nihao
    offset:0
    len:5
    

Netty 中 ByteBuf 如何分配?有池化的操作吗?

答:

ByteBuf 的分配接口定义在了 ByteBufAllocator 中,他的直接抽象类是 AbstracByteBufAllocator,而 AbstractByteBufAllocator 有两种实现:PooledByteBufAllocatorUnpooledByteBufAllocator
请添加图片描述

  • PooledByteBufAllocator 提供了池化的操作,将 ByteBuf 实例放入池中,提升了性能,将内存碎片化减到了最小UnpooledByteBufAllocator。(这个实现采用了一种内存分配的高效策略,成为 jemalloc,已经被好几种现代操作系统所采用)
  • UnpooledByteBufAllocator 在每次创建缓冲区时,都会返回一个新的 ByteBuf 实例,这些实例由 JVM 负责 gc 回收

NioEventLoopGroup 默认启动了多少线程?

答:

NioEventLoopGroup 是一个多线程的事件循环器,默认启动了电脑可用线程数的两倍,在调用 NioEventLoopGroup 的构造方法之后,如果不传入线程数,最后启动的默认线程数的计算公式为:
请添加图片描述

Netty 如何解决 Selector 空轮询 Bug 的策略

答:

空轮询 Bug 也就是网络上发生了唤醒 Selector 的事件,但是 Selector 去取事件取不到,就一直去取,发生了空轮询,导致 CPU 使用率达到 100%

Netty解决机制:

判断如果发生了 N(默认是512次) 次空轮询,就新建一个Selector,把原来Selector事件都迁移过来

为什么没有使用 Netty 5?

答:

Netty版本分别是netty3.x、netty4.x、netty5.x
Netty5出现重大bug,已经被官网废弃,目前推荐使用Netty4.x稳定版本

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

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

相关文章

【智能家居】

面向Apple developer学习:AirPlay | Apple Developer Documentation Airplay AirPlay允许人们将媒体内容从iOS、ipad、macOS和tvOS设备无线传输到支持AirPlay的Apple TV、HomePod以及电视和扬声器上。 网页链接的最佳实践 首选系统提供的媒体播放器。内置的媒体播…

IPD集成产品开发TR技术评审详解

IPD(Integrated Product Development)集成产品开发是一种跨部门协同的、利用先进技术和管理方法来快速推出新产品并满足客户需求的开发模式。华为利用IPD也非常出名。在IPD集成产品开发的过程中,TR(Technical Review)技…

Spring Boot中RedisTemplate的使用

当前Spring Boot的版本为2.7.6&#xff0c;在使用RedisTemplate之前我们需要在pom.xml中引入下述依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><vers…

【力扣刷题】只出现一次的数字、多数元素、环形链表 II、两数相加

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 刷题篇 一、只出现一次的数字1.1 题目描述1…

【Linux系统编程】命令模式2

目录 一&#xff0c;Linux下的初阶认识 1&#xff0c;管道 2&#xff0c;时间戳 二&#xff0c;Liunx系统命令操作 1&#xff0c;date时间指令 2&#xff0c;cal日历指令 3&#xff0c;which和find查找指令 3-1&#xff0c;which指令&#xff1a; 3-2&#xff0c;find…

分享一个python无人超市管理系统django项目实战源码调试 lw 开题

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

[Linux 基础] make、Makefile自动化构建代码工具

文章目录 1、make与Makefile是什么2、为什么要有make与Makefile3、怎么实现一个Makefile文件3.1 如何编写Makefile文件3.1.1 依赖关系3.1.2 依赖方法 3.2 如何清理项目3.2.1 如何编写3.2.2 clean详解 3.3 make的使用3.4 原理3.4.1 查看文件修改时间 1、make与Makefile是什么 m…

【王道代码】【2.3链表】d3

关键字&#xff1a; 奇偶序号拆分、a1&#xff0c;b1&#xff0c;a2&#xff0c;b2...an&#xff0c;bn拆分a1&#xff0c;a2...&#xff0c;bn&#xff0c;...b2&#xff0c;b1、删除相同元素

比例运算放大电路为什么要加平衡电阻

这个是反相比例运算放大电路&#xff0c;输出电压等于-Rf/R1乘以输入电压。 这个是同相比例运算放大电路&#xff0c;输出电压等于1Rf/R1乘以输入电压。 大家可以看到这两个电路中&#xff0c;都有一个电阻R2&#xff0c;反相比例运算放大电路放在同相端到地&#xff0c;同相比…

二叉排序树(BST)

二叉排序树 基本介绍 二叉排序树创建和遍历 class Node:"""创建 Node 节点"""value: int 0left Noneright Nonedef __init__(self, value: int):self.value valuedef add(self, node):"""添加节点node 表示要添加的节点&quo…

【C++】继承 ⑧ ( 继承 + 组合 模式的类对象 构造函数 和 析构函数 调用规则 )

文章目录 一、继承 组合 模式的类对象 构造函数和析构函数调用规则1、场景说明2、调用规则 二、完整代码示例分析1、代码分析2、代码示例 一、继承 组合 模式的类对象 构造函数和析构函数调用规则 1、场景说明 如果一个类 既 继承了 基类 ,又 在类中 维护了一个 其它类型 的…

找不到conda可执行文件:解决方法

1.在新版本的pycharm出现的问题如下&#xff1a; 2.解决方法: 2.1 将anaconda\Scripts\conda.exe选中 2.2选择自己的anconda自己的环境&#xff0c;之后就可以正常创建conda环境

2023-10-23 LeetCode每日一题(老人的数目)

2023-10-23每日一题 一、题目编号 2678. 老人的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的字符串 details 。details 中每个元素都是一位乘客的信息&#xff0c;信息用长度为 15 的字符串表示&#xff0c;表示方式如下&#xff1a; 前十…

橙河网络:国外问卷调查赚钱的项目可靠吗?

国外问卷调查项目是可靠的&#xff0c;是一个长期稳定的互联网项目。 大家好&#xff0c;我是橙河网络&#xff0c;今天聊一聊国外问卷调查赚钱的项目可靠吗&#xff1f; 在海外地区&#xff0c;很多公司和机构&#xff0c;它们为了收集一些关于产品和服务的消费者意见&#…

深入浅出Apache SeaTunnel SQL Server Sink Connector

在大数据时代&#xff0c;数据的迁移和流动已经变得日益重要。为了使数据能够更加高效地从一个源流向另一个目标&#xff0c;我们需要可靠、高效和易于配置的工具。今天&#xff0c;我们将介绍 JDBC SQL Server Sink Connector&#xff0c;这是一个专为 SQL Server 设计的连接器…

MyBatis-Plus实现逻辑删除[MyBatis-Plus系列] - 492篇

历史文章&#xff08;文章累计490&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 M…

【鸿蒙软件开发】文本输入(TextInput/TextArea)

文章目录 前言一、输入框1.1 创建输入框单行输入框多行输入框单行和多行输入框的区别 1.2 设置输入框的类型有哪些类型基本输入模式&#xff08;默认类型&#xff09;密码输入模式 1.3 自定义样式设置无输入时的提示文本设置输入框当前的文本内容。添加backgroundColor改变输入…

MECE分析法

1、前言 前段时间在对项目进行问题分析的时候&#xff0c;领导要求要符合MECE原则&#xff0c;做到逻辑完整而不能遗漏。虽然没听过这个原则&#xff0c;但是总感觉很有道理&#xff08;领导说的都对&#xff09;。于是乎&#xff0c;就找了一些资料了解了一下。 MECE分析法是…

【Rust】4 一文讲解重点 pattern matching | trait | 生命周期 | 闭包 | 迭代器 | 智能指针 | 并发与并行

文章目录 一、pattern matching二、trait2.1 常见 trait2.1.1 Copy 和 Clone2.1.2 PartialEq 和 Eq2.1.3 PartialOrd 和 Ord2.1.4 Hash2.1.5 From, Into, TryFrom, TryInto 2.2 概念2.2.1 关联类型2.2.2 关联常量2.3.3 泛型关联类型2.3.3.1 示例: 用泛型关联类型, 创建集合工厂…

快手进与退,快手董事长在辞任前套现37.78亿港元

快手科技&#xff08;1024.HK&#xff09;在港交所发布公告&#xff0c;宣布自2023年10月29日起&#xff0c;公司创始人宿华将不再担任董事会董事长&#xff0c;而继续担任执行董事和薪酬委员会成员&#xff0c;而他的不同投票权将保持不变。与此同时&#xff0c;快手科技的现任…