QQ群:397745473
fasthttp的使用案例
fasthttp是由valyala编写,并宣称比Go官方标准库net/http快十倍。fasthttp采用了许多性能优化上的最佳实践,尤其是在内存对象的重用上,大量使用sync.Pool以降低对Go GC的压力。
1
| 原文: http://liuqh.icu/2022/04/13/go/package/34-fasthttp/
|
1. 介绍
fasthttp是由valyala
编写,并宣称比Go
官方标准库net/http
快十倍。fasthttp
采用了许多性能优化上的最佳实践,尤其是在内存对象的重用上,大量使用sync.Pool以降低对Go GC
的压力。
推荐文章: Go标准库http与fasthttp服务端性能比较:https://tonybai.com/2021/04/25/server-side-performance-nethttp-vs-fasthttp/
2.工作原理
2.1 net/http
工作原理示意图
a. 流程说明
http
包作为server
端的原理很简单,那就是accept
到一个连接(conn
)之后,将这个conn
甩给一个worker goroutine
去处理,后者一直存在,直到该conn
的生命周期结束:即连接关闭。
2.2 fasthttp
工作原理示意图
fasthttp
高性能主要源自于复用,fasthttp
设计了一套机制,目的是尽量复用goroutine
,而不是每次都创建新的goroutine
。
a. 流程说明
当fasthttp
的Server
接到一个conn
之后,会尝试从workerpool
中的ready
切片中取出一个channel
,该channel
与某个worker goroutine
一一对应。
一旦取出channel
,就会将accept
到的conn
写到该channel
里,而channel
另一端的worker goroutine
就会处理该conn
上的数据读写。
当处理完该conn
后,该worker goroutine
不会退出,而是会将自己对应的那个channel
重新放回workerpool中的ready
切片中,等待这下一次被取出。
3. 安装
1 2
| go get -u github.com/valyala/fasthttp
|
4. 使用
4.1 自定义客户端配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| Go 复制成功 /** * @Description: 获取http客户端 * @Author: LiuQHui * @Date 2022-04-13 18:53:22 **/ func getFastReqClient() *fasthttp.Client { reqClient := &fasthttp.Client{ // 读超时时间,不设置read超时,可能会造成连接复用失效 ReadTimeout: time.Second * 5, // 写超时时间 WriteTimeout: time.Second * 5, // 5秒后,关闭空闲的活动连接 MaxIdleConnDuration: time.Second * 5, // 当true时,从请求中去掉User-Agent标头 NoDefaultUserAgentHeader: true, // 当true时,header中的key按照原样传输,默认会根据标准化转化 DisableHeaderNamesNormalizing: true, //当true时,路径按原样传输,默认会根据标准化转化 DisablePathNormalizing: true, Dial: (&fasthttp.TCPDialer{ // 最大并发数,0表示无限制 Concurrency: 4096, // 将 DNS 缓存时间从默认分钟增加到一小时 DNSCacheDuration: time.Hour, }).Dial, } return reqClient }
|
4.2 发起GET
请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| Go /** * @Description: 发起Get请求 * @Author: LiuQHui * @Date 2022-04-13 19:08:33 **/ func FastGetWithDo() string { // 获取客户端 client := getFastReqClient() // 从请求池中分别获取一个request、response实例 req, resp := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() // 回收实例到请求池 defer func() { fasthttp.ReleaseRequest(req) fasthttp.ReleaseResponse(resp) }() // 设置请求方式 req.Header.SetMethod(fasthttp.MethodGet) // 设置请求地址 req.SetRequestURI("http://127.0.0.1/test") // 设置参数 var arg fasthttp.Args arg.Add("name", "张三") arg.Add("id", "10001") req.URI().SetQueryString(arg.String()) // 设置header信息 req.Header.Add(HAppIdKey, HAppIdVal) // 设置Cookie信息 req.Header.SetCookie("key", "val") // 发起请求 if err := client.Do(req, resp); err != nil { fmt.Println("req err ", err) return err.Error() } // 读取结果 return string(resp.Body()) }
|
4.3 发起POST
请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| Go
type postParamExample struct { Id int `json:"id,omitempty"` Name string `json:"app_id_list,omitempty"` }
func FastPostRawWithDo() string { client := getFastReqClient() req, resp := fasthttp.AcquireRequest(), fasthttp.AcquireResponse() defer func() { fasthttp.ReleaseRequest(req) fasthttp.ReleaseResponse(resp) }() req.Header.SetMethod(fasthttp.MethodPost) req.SetRequestURI("http://127.0.0.1/test") req.Header.SetContentType("application/json") param := postParamExample{ Id: 10001, Name: "小明", } marshal, _ := json.Marshal(param) req.SetBodyRaw(marshal) if err := client.Do(req, resp); err != nil { fmt.Println("req err ", err) return err.Error() } return string(resp.Body()) }
|
QQ群:397745473