背景

最近在做一个 web 版的展示大屏,前端靠 HTTP(S)+JSON 和后端交互,部分图形是密集的地理点位和时间序列,HTTP 返回数据量较大,公网上加载速度不佳。

调研

考虑压缩 HTTP 返回,选了 gzip 这个常规选项。

gzip 在压缩时,得考虑几点:

  • 内容类型是否对压缩友好:例如 JPEG 本身已经压缩过,再次压缩收益太小,费力不讨好;
  • 内容大小是否值得压缩:太小的内容压缩效果不好(甚至有可能比原文还大,毕竟有字典等开销),另外小内容本身传输时间短,直接放过去还能节约 CPU 和内存。

先考察了 Nginx

ngx_http_gzip_moduleContent-TypeContent-Length
Content-Lengthngx_http_gzip_module

又考察了下 gin-contrib/gzip

  • 根据扩展名判断内容类型是否对压缩友好;
  • 根据 Path 判断是否启用压缩;
  • 不支持判断内容大小是否值得压缩。

根据 Path 来判断确实可行,但太死板,业务和中间件耦合了。

自己造了个轮子

特性

看了 gin-contrib/gzip 和 Caddy 的实现后,我造了个自己的轮子,欢迎试用、Star 以及反馈:

Content-TypeContent-Length

更进一步

还记得返回的 JSON 大于 2KB 时,Golang 会使用 chunk 的形式传输,这个时候没有 Content-Length 带来无法判断内容是否值得压缩的问题吗?

http.ResponseWriter.Write(data []byte)len(data)len(data)

调优

这里分享在造轮子时的两个调优点。

AC 自动机

Strings.Contains()
Sync.Pool
Sync.PoolSync.Pool

两个调优之后,CPU 时间下降为调优前的 40%,内存使用量下降为原先的一半。