Nginx 反代 Gzip 内容时, sub_filter 等 content filter 无效的另一种解决

2015-11-09 23:28:27 +08:00
 ryd994
大家Nginx 反代时很常见的一个问题就是 sub_filter 无效。因为浏览器都是允许压缩的,所以请求头都是带 Accept-Encoding: gzip 的。而 Nginx 的 sub_filter 无法处理压缩过的请求, Nginx 自身也不会解压。事实上,要想写一个解压的插件也是不可能的,因为 Nginx 目前并没有 input filtering 相关的接口。

一般网上的解决办法都是 proxy_set_header Accept-Encoding "";禁用上游的压缩,对客户端的压缩不受影响。但是这样入站带宽就多很多了。一个可行的改进是活用 map ,只禁用常见的 html 内容的压缩。但是这样对纯网页效果依然有限。 CrystalACG 上即使缓存命中率过半(对纯网页几乎没有静态内容的 dmm 来说很高了),入站带宽依然超过出站。

最近尝试了另一种办法,效果不错。尽管 Nginx 没有 input filtering ,但我们可以反代自身,利用 gunzip 模块先解压。这样会有本地流量,但用 unix socks 的话额外开销只有 nginx 重新解析一次请求以及数据内存拷贝一次。几乎可以忽略。gzip 本身是很低开销的算法。就算将来Nginx加入了input filtering的支持,性能也不会比这个方案好很多。而且大多数反代站瓶颈都在带宽,CPU多一点无所谓。

新建一个 gunzip.conf : https://gist.github.com/renyidong/bf8ebdff6a2d48e05324
修改原来的代理配置:
proxy_pass http://unix:/var/run/nginx-gunzip.sock:$request_uri;
proxy_set_header Host $host;
proxy_set_header Accept-Encoding "";

这个办法可以结合map,只反代要替换的内容,进一步减少开销。现在 CrystalACG 入站流量只有原来的一半略多,出站的 2/3 不到。
16514 次点击
所在节点    NGINX
20 条回复
auzeonfung
2015-11-09 23:35:21 +08:00
想不到還有這種方法,學習了
Pastsong
2015-11-09 23:35:30 +08:00
Nice one!
maemual
2015-11-10 00:32:35 +08:00
好机智
feather12315
2015-11-10 00:45:08 +08:00
Nice !
BOYPT
2015-11-10 00:49:38 +08:00
其实是因为 gunzip 模块默认是尊重客户端请求,如果是 accept gzip 的就不解压;
我的方案是 patch 了 gunzip 模块,添加了一个 gunzip 的 force 指令,然后输出的时候再由 gzip 模块压回去

不过楼主这个思路还是挺不错的。
br00k
2015-11-10 08:30:23 +08:00
mark
Orzpls
2015-11-10 09:46:01 +08:00
马克,备用。
lovedboy
2015-11-10 09:48:23 +08:00
好机制。
phithon
2015-11-10 10:31:01 +08:00
是个好办法。。当年没想到,还用 lua 手工解压。。。
cmheia
2015-11-10 12:00:25 +08:00
@ryd994

@auzeonfung
@Pastsong
@maemual
@feather12315
@BOYPT
@br00k
@Orzpls
@lovedboy
@phithon

昨晚研究了一下搂住的配置,部分成功,还有些问题。
用的是这个配置:
http://jude.me/2014/10/04/twitter-mirror-2.html

今天按照 @BOYPT 的思路改了一下 ngx 的代码,是不是这样写?
https://null.cmheia.com/nginx-1.9.6-gunzip_always-patch.diff.7z
ryd994
2015-11-10 15:08:44 +08:00
@cmheia
不要用 if 判断 80 ,所有 80 直接 301 https ,根本不需要 if
你这一堆一堆的 subs_filter ,不能用 regex 么?既然有野卡,不能用泛域名么?
有问题贴一下具体的问题配置,你的博客与本主题无关
没事 @ 所有人很好玩么?
BOYPT
2015-11-10 21:44:00 +08:00
@cmheia 其实没什么技术含量,就是加了一个 if 在外面,我摘取修改部分的源码:
http://pastebin.com/hev12rvn
cmheia
2015-11-10 23:08:07 +08:00
@BOYPT 我也是这样改的代码。不过测试结果是 subs_filter 失效了。

后来我在这个 if 块前后增加了 debug
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "gunzip always: %d", conf->always);
输出的日志中也看到了相应的文字:
gunzip always: 1
gunzip always--
但是其中 subs_filter 还是失效,目前还未解决。
相关 diff 及 conf 见 10L 的 7z 链接。

------
to ryd994 :那个博客不是我的。
不,你该是误解了。
ryd994
2015-11-11 00:01:52 +08:00
@cmheia 你检查一下模块调用的顺序,确认 gunzip 在 subs 前面
fengjianxinghun
2015-11-14 20:33:15 +08:00
nginx lua 模块可以 input filter 。。我现在把客户端的加密数据在 nginx 解密丢给后端,然后把后端的数据加密后压缩给客户端
a1044634486
2017-10-16 10:09:30 +08:00
因为有人问了,有个大哥把你的链接写上去了,https://www.v2ex.com/t/397854#reply7
xiaoxiaocai1
2018-10-10 11:13:08 +08:00
楼主,gunzip.conf 的配置已经无法访问了
EMLink
2019-08-19 09:02:28 +08:00
受教了,这个思路很可以
iyangyuan
2019-09-11 14:17:31 +08:00
gunzip.conf 的内容可以直接贴出来吗?
hb751968840
2021-07-29 20:02:18 +08:00
有用

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

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

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

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

© 2021 V2EX