使用HertZ框架进行chunked流式传输

HertZ简介

Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 fasthttp、gin、echo 的优势, 并结合字节跳动内部的需求,使其具有高易用性、高性能、高扩展性等特点,目前在字节跳动内部已广泛使用。 如今越来越多的微服务选择使用 Golang,如果对微服务性能有要求,又希望框架能够充分满足内部的可定制化需求,Hertz 会是一个不错的选择。

性能对比

hertz.png

上图为HertZ, Gin, Fiber, FastHttp性能的对比

  • 由图一可以看到HertZ在大部分情况下的QPS(每秒请求数)均有所领先
  • 由图二图三可以看到TP999和TP99, HertZ在大部分情况下低于对手, 领先于对手

QPS为每秒请求数, 越高越好 TP999和TP99和1%lowFPS概念类似, TP99代表 99% 的 HTTP 请求的响应时间都小于TP99的值

优势

  • 高性能, 高效的框架与调度, 配合netpoll底层, 得以展现出优质的性能
  • 可扩展, 分层架构, 易于扩展
  • 分层架构, 易于添加更多支持, 例如增加额外传输协议与更换底层网络库

使用HertZ进行chunked流式传输

io.Reader传入

c.SetBodyStream接受一个io.Reader和一个int, 前者为数据来源, 后者指定数据大小, -1则为未知大小进行流式

1
2
3
4
5
6
7
8
9
func chunked() {
    client := httpc.New()
    url := "example.com"
    resp, err := clinet.Get(url)
    if err != nil {
        c.Status(500)
    }
    c.SetBodyStream(resp.Body, -1)
}

io.Writer输出

r.Encode需要一个io.Writer, 而c.SetBodyStream接受io.Reader, 所以我们使用io.Pipe将两者连接起来

pr,pw分别为Reader和Writer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
pr, pw := io.Pipe()
go func() {
	defer pw.Close()
	err = r.Encode(pw)
	if err != nil {
        return err
	}
}()

c.SetBodyStream(pr, -1)

如此即可实现流式传输, 本文旨在分享我所需要的实现方式, 避免被hertz文档误导 参看HertZ Issues #1309