sie-snest-gw\350\256\276\350\256\241\344\270\216\345\256\236\347\216\260.md
... ...
@@ -0,0 +1,308 @@
1
+# sie-snest-gw 网关设计与实现
2
+
3
+## 1. 需求分析
4
+
5
+### 1.1 背景
6
+当前系统已经长期使用Nginx作为代理网关,且已有许多代理接口运行在Nginx上,包括前端资源文件html、API文档、前端配置文件、WebGME等。Nginx作为成熟的代理服务器,具有高性能和稳定性。然而,现有的Nginx网关仅能提供静态代理服务,无法满足应用维度的动态服务注册与发现需求。但是sie-snest-engine需要app维度的路由分发功能。
7
+
8
+### 1.2 需求
9
+1. **保留现有Nginx能力**:现有的Nginx配置和代理接口需要保留,但代理到引擎的 /api 接口可以调整。
10
+2. **动态服务注册与发现**:需要基于app维度提供服务注册与发现能力,实现动态分发和路由。
11
+3. **非侵入式增强Nginx**:希望通过非侵入式的方式增强Nginx的能力,不修改已有的Nginx代码。
12
+4. **高效通信**:采用Unix Domain Socket通信,提升通信性能。
13
+
14
+## 2. 方案设计
15
+
16
+### 2.1 保留现有Nginx能力
17
+- **现有Nginx配置**:保持现有Nginx的配置文件和代理接口不变,确保现有服务的正常运行。
18
+- **代理接口保留**:除代理到引擎的 /api 接口外,其他代理接口保持不变。
19
+
20
+### 2.2 动态服务注册与发现
21
+- **app维度的服务注册与发现**:通过实现基于 app 维度的服务注册与发现机制,实现动态寻址和路由。
22
+
23
+### 2.3 非侵入式增强Nginx
24
+- **边车模式**:采用边车(sidecar)模式,编写 sie-snest-gw 的边车服务,与Nginx共同运行,共享同一个pod。
25
+- **Unix Domain Socket通信**:由于它们共享网络,边车服务与Nginx通过Unix Domain Socket进行通信,提升通信性能,相比于创通的网络socket具有更好的性能。
26
+
27
+### 2.4 方案架构图
28
+
29
+```
30
++-----------+ +-----------+
31
+| | | |
32
+| Client +---------->+ Nginx |
33
+| | | |
34
++-----------+ +-----------+
35
+ |
36
+ |
37
+ +-----------+
38
+ | Unix DS |
39
+ +-----------+
40
+ |
41
+ |
42
+ +-----------+
43
+ | sie-snet |
44
+ | -gw |
45
+ +-----------+
46
+ |
47
+ |
48
+ +-----------+
49
+ | Backend |
50
+ +-----------+
51
+```
52
+
53
+已有的方案:
54
+
55
+[[http://iidp.chinasie.com:9999/iidpminio/sie-snest-gw/img_4.png]]
56
+
57
+
58
+增强后方案:
59
+
60
+[[http://iidp.chinasie.com:9999/iidpminio/sie-snest-gw/img_5.png]]
61
+
62
+## 3. 技术实现
63
+
64
+### 3.1 Golang实现
65
+- **高性能**:使用 Golang 编写 sie-snest-gw,保证高性能和低内存占用。
66
+- **完善的网关生态**:利用 Golang 的丰富生态系统,增强网关功能。
67
+
68
+### 3.2 Kubernetes资源监听
69
+- **k8s client-go SDK**:使用Kubernetes官方的client-go SDK监听资源变化,实时更新内存中的路由信息。
70
+- **动态更新**:根据监听到的资源变化,动态更新 app 维度的服务注册信息,实现动态路由。
71
+
72
+### 3.3 高性能代理库
73
+- **Go标准库代理**:使用Go标准库提供的代理库,实现高性能、高可用的代理功能。
74
+- **负载均衡**:实现负载均衡策略,确保流量的均匀分配和服务的高可用性。
75
+
76
+### 3.4 详细实现步骤
77
+1. **初始化 sie-snest-gw 服务**:
78
+ - 使用Golang编写主程序,初始化服务。
79
+ - 配置Unix Domain Socket,用于与Nginx通信。
80
+
81
+2. **监听Kubernetes资源**:
82
+ - 使用client-go SDK监听Kubernetes中的服务资源变化。
83
+ - 更新内存中的app维度的服务注册信息。
84
+
85
+3. **实现动态路由**:
86
+ - 根据服务注册信息,动态生成路由规则。
87
+ - 使用Go标准库的代理库,处理客户端请求并转发到相应的后端服务。
88
+
89
+4. **与Nginx通信**:
90
+ - 配置Nginx,通过Unix Domain Socket将请求转发给 sie-snest-gw。
91
+ - 在 sie-snest-gw 中处理请求并返回响应给Nginx。
92
+
93
+5. **部署与测试**:
94
+ - 将 sie-snest-gw 部署为Nginx的边车服务。
95
+ - 进行全面的功能和性能测试,确保系统稳定性和高性能。
96
+
97
+## 4. 总结
98
+通过上述设计与实现方案,sie-snest-gw 网关能够在不修改现有Nginx代码的前提下,提供 app 维度的动态服务注册与发现能力,并通过高效的Unix Domain Socket通信机制,提升系统的整体性能。采用Golang实现的高性能边车服务,与Nginx共同运行,确保系统的高可用性和可扩展性。
99
+
100
+## 5. 测试
101
+
102
+### 5.1 性能测试
103
+
104
+整体上在低并发低请求量的情况下,Unix Domain Socket的性能要优于网络socket。但是在高并发高请求量的情况下,Unix Domain Socket的优势不会特别大,因为业务对于数据的处理时间会占用更多的时间,那么传输时间的优势就不会特别明显。
105
+
106
+基于 UDS 的数据的收发过程非常的简单,发送方是直接将数据写到接收方的接收队列里的,不走内核协议栈。
107
+
108
+[[http://iidp.chinasie.com:9999/iidpminio/sie-snest-gw/img_1.png]]
109
+
110
+
111
+延迟测试:
112
+
113
+[[http://iidp.chinasie.com:9999/iidpminio/sie-snest-gw/img_2.png]]
114
+
115
+
116
+[[http://iidp.chinasie.com:9999/iidpminio/sie-snest-gw/img_3.png]]
117
+
118
+#### 使用 unix domain socket
119
+
120
+- ##### 并发50
121
+```
122
+--------------------- 并发 50 ---------------------------------
123
+122/lzb/test> ./bench -c 50 -n 10000
124
+INFO[0000] total: 10000 concurrency: 50 requests per client: 200
125
+INFO[0002] took 2133 ms for 10000 requests
126
+INFO[0002] sent requests : 10000
127
+INFO[0002] received requests : 10000
128
+INFO[0002] received requests_OK : 10000
129
+INFO[0002] throughput (TPS) : 5688
130
+INFO[0002] mean: 10474865 ns, median: 8584496 ns, max: 62494839 ns, min: 546029 ns, p99.9: 49550780 ns
131
+INFO[0002] mean: 8 ms, median: 6 ms, max: 52 ms, min: 0 ms, p99.9: 29 ms
132
+
133
+
134
+122/lzb/test> ./bench -c 50 -n 20000
135
+INFO[0000] total: 20000 concurrency: 50 requests per client: 400
136
+INFO[0008] took 8744 ms for 20000 requests
137
+INFO[0008] sent requests : 20000
138
+INFO[0008] received requests : 20000
139
+INFO[0008] received requests_OK : 20000
140
+INFO[0008] throughput (TPS) : 3287
141
+INFO[0008] mean: 21662669 ns, median: 9012562 ns, max: 393328734 ns, min: 706598 ns, p99.9: 357892903 ns
142
+INFO[0008] mean: 11 ms, median: 8 ms, max: 293 ms, min: 0 ms, p99.9: 57 ms
143
+
144
+
145
+
146
+122/lzb/test> ./bench -c 50 -n 40000
147
+INFO[0000] total: 40000 concurrency: 50 requests per client: 800
148
+INFO[0061] took 61471 ms for 40000 requests
149
+INFO[0061] sent requests : 40000
150
+INFO[0061] received requests : 40000
151
+INFO[0061] received requests_OK : 40000
152
+INFO[0061] throughput (TPS) : 1650
153
+INFO[0061] mean: 74883410 ns, median: 11363670 ns, max: 947822594 ns, min: 447573 ns, p99.9: 689353520 ns
154
+INFO[0061] mean: 54 ms, median: 11 ms, max: 747 ms, min: 0 ms, p99.9: 589 ms
155
+
156
+```
157
+
158
+- ##### 并发100
159
+```
160
+------------------------------ 并发 100 ---------------------------------
161
+
162
+122/lzb/test> ./bench -c 100 -n 10000
163
+INFO[0000] total: 10000 concurrency: 100 requests per client: 100
164
+INFO[0001] took 1941 ms for 10000 requests
165
+INFO[0001] sent requests : 10000
166
+INFO[0001] received requests : 10000
167
+INFO[0001] received requests_OK : 10000
168
+INFO[0001] throughput (TPS) : 6151
169
+INFO[0001] mean: 18612570 ns, median: 15089722 ns, max: 99981825 ns, min: 640579 ns, p99.9: 77418796 ns
170
+INFO[0001] mean: 18 ms, median: 15 ms, max: 99 ms, min: 0 ms, p99.9: 77 ms
171
+
172
+
173
+
174
+122/lzb/test> ./bench -c 100 -n 20000
175
+INFO[0000] total: 20000 concurrency: 100 requests per client: 200
176
+INFO[0003] took 3460 ms for 20000 requests
177
+INFO[0003] sent requests : 20000
178
+INFO[0003] received requests : 20000
179
+INFO[0003] received requests_OK : 20000
180
+INFO[0003] throughput (TPS) : 5780
181
+INFO[0003] mean: 16859393 ns, median: 14338056 ns, max: 130512875 ns, min: 611710 ns, p99.9: 79118046 ns
182
+INFO[0003] mean: 16 ms, median: 14 ms, max: 130 ms, min: 0 ms, p99.9: 79 ms
183
+
184
+
185
+122/lzb/test> ./bench -c 100 -n 40000
186
+INFO[0000] total: 40000 concurrency: 100 requests per client: 400
187
+INFO[0058] took 58969 ms for 40000 requests
188
+INFO[0058] sent requests : 40000
189
+INFO[0058] received requests : 40000
190
+INFO[0058] received requests_OK : 40000
191
+INFO[0058] throughput (TPS) : 1678
192
+INFO[0058] mean: 140379894 ns, median: 22283178 ns, max: 1493640861 ns, min: 589891 ns, p99.9: 1090024161 ns
193
+INFO[0058] mean: 140 ms, median: 22 ms, max: 1493 ms, min: 0 ms, p99.9: 1090 ms
194
+
195
+```
196
+
197
+#### 换成 localhost:18060
198
+
199
+- ##### 并发50
200
+```
201
+122/lzb/test> ./bench -c 50 -n 10000
202
+INFO[0000] total: 10000 concurrency: 50 requests per client: 200
203
+INFO[0001] took 1995 ms for 10000 requests
204
+INFO[0001] sent requests : 10000
205
+INFO[0001] received requests : 10000
206
+INFO[0001] received requests_OK : 10000
207
+INFO[0001] throughput (TPS) : 5012
208
+INFO[0001] mean: 9809687 ns, median: 8410406 ns, max: 63636117 ns, min: 656349 ns, p99.9: 44334232 ns
209
+INFO[0001] mean: 9 ms, median: 8 ms, max: 63 ms, min: 0 ms, p99.9: 44 ms
210
+
211
+
212
+
213
+
214
+
215
+122/lzb/test> ./bench -c 50 -n 20000
216
+INFO[0000] total: 20000 concurrency: 50 requests per client: 400
217
+INFO[0007] took 7197 ms for 20000 requests
218
+INFO[0007] sent requests : 20000
219
+INFO[0007] received requests : 20000
220
+INFO[0007] received requests_OK : 20000
221
+INFO[0007] throughput (TPS) : 2778
222
+INFO[0007] mean: 17742685 ns, median: 12823960 ns, max: 229250773 ns, min: 951364 ns, p99.9: 143942836 ns
223
+INFO[0007] mean: 17 ms, median: 12 ms, max: 229 ms, min: 0 ms, p99.9: 143 ms
224
+
225
+
226
+
227
+122/lzb/test> ./bench -c 50 -n 40000
228
+INFO[0000] total: 40000 concurrency: 50 requests per client: 800
229
+INFO[0060] took 60706 ms for 40000 requests
230
+INFO[0060] sent requests : 40000
231
+INFO[0060] received requests : 40000
232
+INFO[0060] received requests_OK : 40000
233
+INFO[0060] throughput (TPS) : 658
234
+INFO[0060] mean: 72863090 ns, median: 13186213 ns, max: 627875408 ns, min: 777760 ns, p99.9: 466958052 ns
235
+INFO[0060] mean: 72 ms, median: 13 ms, max: 627 ms, min: 0 ms, p99.9: 466 ms
236
+
237
+```
238
+
239
+- ##### 并发100
240
+```
241
+-------------------- 并发为 100
242
+
243
+122/lzb/test> ./bench -c 100 -n 10000
244
+INFO[0000] total: 10000 concurrency: 100 requests per client: 100
245
+INFO[0002] took 2446 ms for 10000 requests
246
+INFO[0002] sent requests : 10000
247
+INFO[0002] received requests : 10000
248
+INFO[0002] received requests_OK : 10000
249
+INFO[0002] throughput (TPS) : 4088
250
+INFO[0002] mean: 23438591 ns, median: 19675704 ns, max: 133427069 ns, min: 961182 ns, p99.9: 107706982 ns
251
+INFO[0002] mean: 23 ms, median: 19 ms, max: 133 ms, min: 0 ms, p99.9: 107 ms
252
+
253
+
254
+122/lzb/test> ./bench -c 100 -n 20000
255
+INFO[0000] total: 20000 concurrency: 100 requests per client: 200
256
+INFO[0005] took 5919 ms for 20000 requests
257
+INFO[0005] sent requests : 20000
258
+INFO[0005] received requests : 20000
259
+INFO[0005] received requests_OK : 20000
260
+INFO[0005] throughput (TPS) : 3378
261
+INFO[0005] mean: 29085037 ns, median: 23538610 ns, max: 313951227 ns, min: 981326 ns, p99.9: 191517186 ns
262
+INFO[0005] mean: 29 ms, median: 23 ms, max: 313 ms, min: 0 ms, p99.9: 191 ms
263
+
264
+
265
+
266
+122/lzb/test> ./bench -c 100 -n 40000
267
+INFO[0000] total: 40000 concurrency: 100 requests per client: 400
268
+INFO[0063] took 63539 ms for 40000 requests
269
+INFO[0063] sent requests : 40000
270
+INFO[0063] received requests : 40000
271
+INFO[0063] received requests_OK : 40000
272
+INFO[0063] throughput (TPS) : 629
273
+INFO[0063] mean: 157058698 ns, median: 31084441 ns, max: 1529706480 ns, min: 990788 ns, p99.9: 1178707764 ns
274
+INFO[0063] mean: 157 ms, median: 31 ms, max: 1529 ms, min: 0 ms, p99.9: 1178 ms
275
+
276
+```
277
+
278
+### 5.2 radix 压测
279
+
280
+radix与map压测,通过下面压测结果可以发现,radix的性能要优于map,尤其是查询性能,接近两倍的提升,因为map是通过hash表实现的,需要处理碰撞等问题,而radix是通过前缀树实现的,对于词组来说前缀树的查找效率要高于hash表。
281
+
282
+```shell
283
+> go test -bench=BenchmarkInsert
284
+
285
+BenchmarkInsert-16 4102198 378.5 ns/op
286
+BenchmarkInsertMap-16 5822322 236.5 ns/op
287
+PASS
288
+ok test 3.597s
289
+
290
+
291
+> go test -bench=BenchmarkGet
292
+
293
+BenchmarkGet-16 11889345 121.1 ns/op
294
+BenchmarkGetMap-16 9763209 158.8 ns/op
295
+PASS
296
+ok test 12.258s
297
+
298
+```
299
+
300
+```shell
301
+> go test -bench=BenchmarkInsert
302
+
303
+BenchmarkInsert-16 1382823 784.6 ns/op
304
+BenchmarkInsertMap-16 3293953 375.9 ns/op
305
+PASS
306
+ok test 3.714s
307
+
308
+```
... ...
\ No newline at end of file