fasthttp + `page partial gziped cache`: 页面输出服务性能提升20%

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


接上一篇:http 中使用 gzip 输出内容时,如何预先压缩前一半页面?

经过实测,对线上一个输出 html 的服务进行了改造,通过预先压缩页面前半部分的方法,此接口的性能提升了 20%.

对比项 无 gzip 压缩 gzip 压缩+前半部分预压缩
输出字节数 4399 2246
每核 qps 14052.63 16924.75

具体的写法如下:

1.获取改造后的库

go get github.com/ahfuzhang/compress@v1.17.2

2.在 go.mod 中修改:

replace (
	github.com/klauspost/compress => github.com/ahfuzhang/compress v1.17.2
)

require (
	github.com/klauspost/compress v1.16.3
    github.com/valyala/bytebufferpool v1.0.0
	github.com/valyala/fasthttp v1.50.0
)

3.代码:

go 复制代码
package main

import (
	"bytes"
	_ "embed"
	"fmt"
	"log"
	"os"

	"github.com/klauspost/compress/gzip"
	"github.com/valyala/bytebufferpool"
	"github.com/valyala/fasthttp"
)

//go:embed raw.html
var html string

//go:embed raw.js
var js string


func testGzipedHttp() {
    topHalf, digest := gzip.GetGzipedData([]byte(html))  // cache 页面的前一半, digest 是这些内容的 crc32 的校验和
	requestHandler := func(ctx *fasthttp.RequestCtx) {
		ctx.Response.Header.Add("Content-Type", "text/plain")
		ctx.Response.Header.Add("Content-Encoding", "gzip")

		switch string(ctx.Request.URI().RequestURI()) {
		case "/1":   // direct output
			w, _ := gzip.NewWriterLevel(ctx, gzip.BestCompression)
			w.Write([]byte(html))
			w.Write([]byte(js))
			w.Close()
		case "/2":
			w := gzip.GetWriter(ctx)  // 使用对象池
		    w.WriteHeader()  // 写 gzip 的头部信息,10 字节
            w.WriteGzipedData([]byte(html), topHalf, digest)  
            // 当这个缓存是第一次输出的时候,可以传入 digest 值,这样可以少算一次  crc32
            // 当不是第一次输出的时候, 第三个参数 digest 填  0

            w.Write([]byte(js))
            gzip.PutWriter(w)  // 必须调用,写入尾部信息,并放回对象池
		}
	}

	s := &fasthttp.Server{
		Handler: requestHandler,
	}
	if err := s.ListenAndServe(":8080"); err != nil {
		log.Fatalf("error in ListenAndServe: %v", err)
	}
}

func main() {
	testGzipedHttp()
}

希望对你有用 😃


这个 case 已经分享到 fasthttp github, 希望未来能够集成这个能力进去:https://github.com/valyala/fasthttp/issues/1631