有对 nginx 熟悉的老哥吗?请教一下 nginx 代理 tcp 的一个问题?

2022-12-01 11:05:23 +08:00
 liuguangxuan

背景:

使用 nginx 代理 tcp 服务,假如后端有一个 tcp 的业务服务,中间用 nginx 做代理,前面有 1000 个客户端连接,那么每当一个客户端连接 nginx 的时候,nginx 就会发起一个 tcp 连接至后端的业务服务。

问题:

假设我的那个 tcp 后端服务是负责提供下载地图数据的,对所有的 1000 个客户端来说,从地图服务器下载的数据都是一样的。那么当一个客户端连接上 nginx 的时候,nginx 发起了一个 tcp 连接至地图服务器,地图服务器把地图数据推给了 nginx ,nginx 把数据转给了客户端,这样相当于把一份地图数据在网络中走了两遍(地图服务器到 nginx ,nginx 到客户端),当地图数据比较大的时候,带来的开销就很大了。

想要达到的效果:

能否对 nginx 做改造,在 nginx 中缓存一下地图数据,当第一个客户端连接 nginx 的时候,nginx 从后端的地图服务器获取了地图数据,一直缓存在内存里,后面 999 个客户端连接的时候,nginx 就直接把地图数据推给客户端,而不再朝后端的地图服务器下载地图数据。

如果想实现上述的效果,需要对 stream 模块做改造吗?还是有其他更好的解决办法?麻烦各位老哥赐教。

5477 次点击
所在节点    NGINX
75 条回复
villivateur
2022-12-01 13:01:07 +08:00
TCP 本身不能缓存,你得要一个更高层次的应用层服务。
然后,既然用到应用层服务了,为什么不直接用 HTTP ?
julyclyde
2022-12-01 13:26:52 +08:00
@ttvast 自己山寨个协议,是很多公司内卷的选择
要不然咋评职称啊
DefoliationM
2022-12-01 13:50:19 +08:00
自己写个 tcp 转发吧,不复杂
xuanbg
2022-12-01 14:17:35 +08:00
TCP 要什么代理?哦哦,你是想在代理服务器上缓存数据来加速访问。可 TCP 是流,这可怎么缓存?再说,没有应用层协议分包,你这边怎么知道数据读完了?这不就那个啥,“粘包”了吗?

你这必须要自己造个协议来传数据才行。既然是自己造的协议,那就要在 nginx 上加载一个识别这个协议的模块。既然模块都加载了,你想干点什么还不是你自己说了算?
liuguangxuan
2022-12-01 14:23:30 +08:00
@cnoder
@victorc
@killva4624 看到了 3 位老哥都推荐了 openrestry ,刚查了一下资料,openrestry 是 nginx+lua ,我用 lua 控制我想要实现的逻辑,是这样的吗?
liuguangxuan
2022-12-01 14:28:14 +08:00
@xuanbg 老哥,原有的地图服务是自定义协议和客户端进行传输的,传输 tcp 数据流,所以造协议这块儿已经有了,缺的是您说的这个模块,如何加在 nginx 上?
liuguangxuan
2022-12-01 14:34:25 +08:00
@DefoliationM tcp 转发之前写过一套,现在想把它和 nginx 统一到一起,这样就能统一 http 和 tcp 的入口。所以才有了我上面的提问。
seakingii
2022-12-01 14:41:25 +08:00
NGINX+LUA,NGINX 是 C 代码,不好改,LUA 是脚本,容易改一点,
不过, TCP 缓存不好做啊,像上面说的,TCP 是流,不好定边界

另外你们自己实现的协议 ,那你至少要在 LUA 这边解析你们的请求流,根据请求流返回原始数据或者返回缓存数据?

最简单的就是 NGINX+LUA 来缓存 HTTP,很好解析请求也很好缓存
liuguangxuan
2022-12-01 14:47:45 +08:00
@seakingii 是的,我目前了解到的也是这种,其中 lua 控制业务逻辑,来实现是从内存中取缓存数据推送给客户端,还是重新建立 socket 连接至地图服务器,进行数据的拉取。
seakingii
2022-12-01 15:54:16 +08:00
@liuguangxuan 如果只是这样的转发,是否自己用代码做个端口转发,用 C++或者 GO 这样的编译语言来实现,性能更高?而不是利用 NGINX+LUA 这样的组合
liuguangxuan
2022-12-01 16:10:29 +08:00
@seakingii 可能是我没有表达清楚哈,老哥。我们之前写了一个转发 tcp 的服务( C++的),中间缓存了地图的数据,所以对下面 1000 个客户端的话,它只向地图服务器请求一次数据即可,然后对下转发给 1000 个客户端。
现在我们又新增了一些 web 的服务,所以会有 http 请求。
我想把 web 的 http 请求和地图的 tcp 请求统一入口,都走 nginx ,或者都走我们之前写的 tcp 转发服务。所以就有了我今天问的问题,我想在 nginx 里面集成我们之前的 tcp 转发服务的功能(并且能对地图服务只保持 1 个 socket 连接,请求 1 次地图数据,节省带宽),但是不知道该怎么集成进去。😂
liuguangxuan
2022-12-01 16:11:47 +08:00
@seakingii 看看各位老哥,有没有什么更好的方案。
Twan
2022-12-01 17:02:18 +08:00
怎么感觉是个开发游戏的
ysc3839
2022-12-01 17:05:19 +08:00
游戏资源下载用 http 没什么问题吧?
xhinliang
2022-12-01 17:09:17 +08:00
TCP 是传输层协议,是一个流协议,没听说过在传输层协议做缓存的....
再者,这个「把一份地图数据在网络中走了两遍」,如果是内网的话,是不是开销可以忽略不计?
JingKeWu
2022-12-01 17:21:55 +08:00
tcp 是流,没办法缓存。建议还是采用 http ,用 p2p 分发
JingKeWu
2022-12-01 17:22:30 +08:00
或者自定义协议 加入缓存
seakingii
2022-12-01 17:36:42 +08:00
@liuguangxuan 我的建议是

一 要么不要整合,继续分成两个服务

二 要么地图请求改成 HTTP ,和其它 WEB 服务统一,然后 NGINX 上 HTTP/2
rrfeng
2022-12-01 17:51:06 +08:00
不用 HTTP ,那就在 Nginx 里把你 C++ 实现的『私有协议』搞一遍就行了。

Nginx Stream 就是纯 TCP 代理,做不到你想要的。
wangritian
2022-12-01 18:16:51 +08:00
也可以考虑用 go 自己写一个网关代替 nginx ,想搞啥都方便

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/899278

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX