有对 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 模块做改造吗?还是有其他更好的解决办法?麻烦各位老哥赐教。

5448 次点击
所在节点    NGINX
75 条回复
killva4624
2022-12-01 11:10:51 +08:00
一个问题,nginx 如何识别这 999 个客户端里,哪些需要缓存,哪些是需要请求新的数据呢?
liuguangxuan
2022-12-01 11:13:40 +08:00
@killva4624 老哥精准的理解了我的困惑,我需要解决的就是这部分。
如果想要精准的识别哪些需要缓存,哪些是需要请求新的数据,我需要怎么做?对 nginx 的 stream 模块改造,加自定义协议吗?是否还有更好的办法?
cnoder
2022-12-01 11:14:54 +08:00
有反向代理缓存,proxy_cache
ng1nx
2022-12-01 11:16:51 +08:00
能否把地图上数据推到 Redis ,设置数据有效期(time to live); nginx 从 Redis 取数据,如果取不到就从后端再取一次。
cnoder
2022-12-01 11:18:13 +08:00
想复杂一点可以用 openresty 这样的,自己实现一下
victorc
2022-12-01 11:19:19 +08:00
nginx+lua 就是干这个的,不建议直接修改 nginx 的 c 代码,可维护性太差了

去翻 openrestry 的文档吧,能解决
jiangzm
2022-12-01 11:21:44 +08:00
地图服务应该下发一个更新包链接(文件服务或者 OSS 存储),给客户端下载下来。
wzy44944
2022-12-01 11:23:16 +08:00
文件小的话 nginx 自己就有个内存缓存,一般十几 KB 的数据可以用,再多会有些性能和功能上的问题,文件比较多或者比较大就需要 nginx+缓存软件比如 ATS ,squid 。是否需要 cache 这个在 http 交互里有标准的,比如请求头里的 no-cache,响应头里的过期时间
seers
2022-12-01 11:24:25 +08:00
起一个 mem 数据库,ng 从里面拿数据
killva4624
2022-12-01 11:25:52 +08:00
@liuguangxuan 如果是 HTTP 这种高层协议是有缓存的,自己包 TCP 方法的话可能就像楼上老哥推荐的,走 openrestry 自己实现缓存协议,或者把重的下载数据逻辑放到另外的存储层去下载。
leafre
2022-12-01 11:25:59 +08:00
在 nginx 中缓存不如在服务端缓存,nginx 和服务端同个内网,哪来的大开销
lambdaq
2022-12-01 11:31:05 +08:00
为什么人们不基于 tcp 直接做浏览器,而是要搞个 http 。。就是为了解决 LZ 这问题的。。http 特点之一就是为了方便中间盒子来缓存。。。。
iphoneXr
2022-12-01 11:31:07 +08:00
我的做法一般都是 负载均衡做 4 层代理转发 Nginx 做 7 层代理转发和静态文件
其他下载类的尽量用 OSS 便宜且稳定
iphoneXr
2022-12-01 11:32:41 +08:00
还没有写完 提前提交了
缓存类走 CDN 主要是流量便宜的多
ttvast
2022-12-01 11:33:37 +08:00
@lambdaq 真是让人觉得奇怪,下载数据不用 http 还要用自己的 tcp
gstqc
2022-12-01 11:36:10 +08:00
nginx 的 stream 模块不识别 TCP 协议的上一层协议
所以无法对数据进行缓存
如果要实现缓存,你得在 nginx 里写个模块,识别你的协议,然后才能解包出原数据并对数据进行缓存

搞这么麻烦不如换 HTTP 算了
rrfeng
2022-12-01 11:36:54 +08:00
1. TCP 是数据流,不存在『缓存』这种东西,你没法缓存一个『数据流』
2. 所以要做的是把『数据流』变为『数据块』,有边界的数据就能够缓存了
3. 那么在 TCP 里自己切分一下数据,做一个『自定义协议』来实现『数据块』
4. 所以为什么不用 HTTP ?
pjntt
2022-12-01 11:37:08 +08:00
这样做让 nginx 完成的事情就很多了,比如用户鉴权。或者你可以想想在应用服务端上做这个缓存处理。代理就只做代理工作就好。
lambdaq
2022-12-01 12:01:08 +08:00
@lambdaq 估计有可能是 minecraft 一类的游戏服。。。
xyjincan
2022-12-01 12:05:49 +08:00
这是服务器下载地图,发送地图都使用公网带宽是吗,开发一个地图客户端代理服务,地图数据缓存在硬盘上吧

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

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

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

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

© 2021 V2EX