a68c3c01ae9742fe38b04ba6139b4b590848a9de
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 |