Skip to content

Commit e8f544b

Browse files
committed
更新面试题
1 parent 3b5f2bd commit e8f544b

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

22. ShardingJDBC.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 22.Sharding-JDBC
1+
# 22.分库分表
22

33
[toc]
44

@@ -10,6 +10,8 @@
1010
>
1111
> 数据库分库分表思路:https://www.cnblogs.com/butterfly100/p/9034281.html
1212
13+
## Sharding-JDBC
14+
1315
### 分库分表的方式
1416

1517
- 垂直分库

25.Netty.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# 25.Netty
2+
3+
### TCP 的粘包和拆包
4+
5+
TCP 是以流的方式来处理数据的,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送。
6+
7+
### BIO、NIO、AIO的区别
8+
9+
BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理,线程开销大。是面向流的,阻塞流,流是单向的。
10+
11+
NIO: 一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理。面向缓存区,非阻塞,channe是双向的。
12+
13+
AIO:一个有效请求一个线程,客户端的IO请求都是由OS先完成了再通知服务器应用去启动线程进行处理
14+
15+
### NIO 的组成
16+
17+
Buffer:与Channel进行交互,数据从Channel读入缓冲区,从缓冲区写入Channel中
18+
19+
flip方法:反转缓冲区,将position给limit,然后将position置为0,就是读写切换
20+
21+
clear方法:清除此缓冲区,将position置为0,把capacity的值给limit
22+
23+
rewind方法:重置此缓冲区,将position置为0
24+
25+
DirectByteBuffer:可减少一次系统空间到用户空间的拷贝
26+
27+
Channel:与数据源的连接,是双向的,只能与Buffer交互
28+
29+
Selector:允许单个线程管理多个Channel
30+
31+
Pipe:两个线程之间的单向数据连接,数据会被写到sink通道,从source通道读取
32+
33+
34+
35+
NIO服务端建立过程:
36+
37+
1. ServerSocketChannel.open 创建服务端Channel
38+
2. bind 绑定服务端端口
39+
3. 配置非阻塞模式
40+
4. Selector.open 打开一个selector
41+
5. 注册关注的事件到selector上
42+
43+
```java
44+
// 服务端代码
45+
public class NioServer {
46+
47+
public static void main(String[] args) {
48+
try(ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
49+
serverSocketChannel.socket().bind(new InetSocketAddress(3388));
50+
51+
Selector selector = Selector.open();
52+
serverSocketChannel.configureBlocking(false);
53+
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
54+
55+
System.out.println("服务器准备就绪,开始监听,端口3388");
56+
57+
58+
while (true) {
59+
int wait = selector.select();
60+
if (wait == 0)
61+
continue;
62+
63+
Set<SelectionKey> keys = selector.selectedKeys();
64+
Iterator<SelectionKey> iterator = keys.iterator();
65+
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
66+
67+
while (iterator.hasNext()) {
68+
69+
SelectionKey key = iterator.next();
70+
71+
if (key.isAcceptable()) {
72+
ServerSocketChannel server = (ServerSocketChannel) key.channel();
73+
SocketChannel channel = server.accept();
74+
channel.configureBlocking(false);
75+
channel.register(selector, SelectionKey.OP_READ);
76+
} else if(key.isReadable()) {
77+
SocketChannel server = (SocketChannel) key.channel();
78+
int len = server.read(byteBuffer);
79+
if (len > 0) {
80+
byteBuffer.flip();
81+
String content = new String(byteBuffer.array(), 0, len);
82+
System.out.println(content);
83+
84+
server.configureBlocking(false);
85+
server.register(selector, SelectionKey.OP_WRITE);
86+
}
87+
byteBuffer.clear();
88+
} else if (key.isWritable()) {
89+
SocketChannel server = (SocketChannel) key.channel();
90+
server.write(ByteBuffer.wrap("Hello Client!".getBytes()));
91+
}
92+
93+
iterator.remove();
94+
}
95+
96+
}
97+
98+
} catch (Exception e) {
99+
e.printStackTrace();
100+
}
101+
}
102+
}
103+
104+
105+
//客户端代码
106+
public class NIOClient {
107+
108+
public static void main(String[] args) {
109+
try(SocketChannel channel = SocketChannel.open()) {
110+
channel.connect(new InetSocketAddress(3388));
111+
112+
//发送数据
113+
if (channel.isConnected()) {
114+
channel.write(ByteBuffer.wrap("Hello Server!".getBytes()));
115+
}
116+
117+
ByteBuffer buffer = ByteBuffer.allocate(1024);
118+
int len = channel.read(buffer);
119+
String content = new String(buffer.array(), 0, len);
120+
System.out.println(content);
121+
}catch (Exception e) {
122+
123+
}
124+
125+
}
126+
}
127+
```
128+
129+
### Netty 的特点
130+
131+
一个高性能、异步事件驱动的NIO框架。
132+
133+
使用更高效的socket底层,处理了epoll空轮询引起的cpu占用飙升(Netty检测到空轮询的时候,主动重建Selector)
134+
135+
采用decoder/encoder 支持,对TCP粘包/拆包进行自动化处理
136+
137+
可配置IO线程数、TCP参数,TCP 接收和发送缓冲区使用直接内存代替堆内存,通过内存池的方式循环利用 ByteBuf
138+
139+
通过引用计数器及时申请释放不再引用的对象,降低了 GC 频率
140+
141+
使用单线程串行化的方式,高效的 Reactor 线程模型
142+
143+
大量使用了 volitale、使用了 CAS 和原子类、线程安全类的使用、读写锁的使用
144+
145+
### Netty 使用的线程模型
146+
147+
Netty 通过 Reactor 线程模型基于多路复用器接收并处理用户请求,内部实现了两个线程池,boss 线程池和 work 线程池,
148+
149+
其中 boss 线程池的线程负责处理请求的 accept 事件,当接收到 accept 事件的请求时,把对应的 socket 封装到一个,
150+
151+
NioSocketChannel 中,并交给 work线程池,其中 work 线程池负责请求的 read 和 write 事件,由对应的 Handler 处理。
152+
153+
### Netty 的零拷贝实现
154+
155+
- Direct Buffer
156+
157+
使用堆外内存进行Socket读写,避免JVM堆内存与内核缓存之间的拷贝
158+
159+
- CompositeByteBuf
160+
161+
​ 将多个缓存区“逻辑上”合并为一个缓冲区,避免物理上的数据拷贝
162+
163+
- 文件传输的零拷贝 FileRegion
164+
165+
​ 利用操作系统的 `sendfile` 系统调用,直接在文件描述符和套接字之间传输数据,完全跳过用户态
166+
167+
- 缓存区包装 Wrapped Buffers
168+
169+
​ 通过包装现有数据(如字节数组、`ByteBuffer`)创建 `ByteBuf`,避免数据贝,`Unpooled.wrappedBuffer(...)` 方法直接引用原始数据,而非复制
170+
171+
- 延迟缓冲区拷贝 Lazy Copy
172+
173+
​ 在某些场景下(如缓冲区切片 `slice()`),仅记录原始缓冲区的引用和偏移量,不立即拷贝数据,直到必要时才执行拷贝。

0 commit comments

Comments
 (0)