加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

优雅的读取http请求或响应的数据

发布时间:2019-02-01 12:40:44 所属栏目:教程 来源:戚银
导读:从 http.Request.Body 或 http.Response.Body 中读取数据要领或者许多,尺度库中大大都行使 ioutil.ReadAll 要领一次读取全部数据,假如是 json 名目标数据还可以行使 json.NewDecoder 从 io.Reader 建设一个理会器,倘使行使 pprof 来说明措施老是会发明
副问题[/!--empirenews.page--]

从 http.Request.Body 或 http.Response.Body 中读取数据要领或者许多,尺度库中大大都行使 ioutil.ReadAll 要领一次读取全部数据,假如是 json 名目标数据还可以行使 json.NewDecoder 从 io.Reader 建设一个理会器,倘使行使 pprof 来说明措施老是会发明 bytes.makeSlice 分派了大量内存,且老是排行第一,,本日就这个题目来说一下怎样高效优雅的读取 http 中的数据。

优雅的读取http哀求或相应的数据

配景先容

我们有很多 api 处事,所有回收 json 数据名目,哀求体就是整个 json 字符串,当一个哀求随处事端会颠末一些营业处理赏罚,然后再哀求后头更多的处事,全部的处事之间都用 http 协议来通讯(啊, 为啥不消 RPC,由于全部的处事城市对第三方开放,http + json 更好对接),大大都哀求数据巨细在 1K~4K,相应的数据在 1K~8K,早期全部的处事都行使 ioutil.ReadAll 来读取数据,跟着流量增进行使 pprof 来说明发明 bytes.makeSlice 老是排在第一,而且占用了整个措施 1/10 的内存分派,我抉择针对这个题目举办优化,下面是整个优化进程的记录。

pprof 说明

这里行使 https://github.com/thinkeridea/go-extend/blob/master/exnet/exhttp/expprof/pprof.go 中的 API 来实现出产情形的 /debug/pprof 监测接口,没有行使尺度库的 net/http/pprof 包由于会自动注册路由,且恒久开放 API,这个包可以设定 API 是否开放,并在规按时刻后自动封锁接口,停止存在器材嗅探。

处事陈设上线不变后(约莫过了一天半),通过 curl 下载 allocs 数据,然后行使下面的呼吁查察说明。

  1. $ go tool pprof allocs 
  2. File: xxx 
  3. Type: alloc_space 
  4. Time: Jan 25, 2019 at 3:02pm (CST) 
  5. Entering interactive mode (type "help" for commands, "o" for options) 
  6. (pprof) top 
  7. Showing nodes accounting for 604.62GB, 44.50% of 1358.61GB total 
  8. Dropped 776 nodes (cum <= 6.79GB) 
  9. Showing top 10 nodes out of 155 
  10.       flat  flat%   sum%        cum   cum% 
  11.   111.40GB  8.20%  8.20%   111.40GB  8.20%  bytes.makeSlice 
  12.   107.72GB  7.93% 16.13%   107.72GB  7.93%  github.com/sirupsen/logrus.(*Entry).WithFields 
  13.    65.94GB  4.85% 20.98%    65.94GB  4.85%  strings.Replace 
  14.    54.10GB  3.98% 24.96%    56.03GB  4.12%  github.com/json-iterator/go.(*frozenConfig).Marshal 
  15.    47.54GB  3.50% 28.46%    47.54GB  3.50%  net/url.unescape 
  16.    47.11GB  3.47% 31.93%    48.16GB  3.55%  github.com/json-iterator/go.(*Iterator).readStringSlowPath 
  17.    46.63GB  3.43% 35.36%   103.04GB  7.58%  handlers.(*AdserviceHandler).returnAd 
  18.    42.43GB  3.12% 38.49%    84.62GB  6.23%  models.LogItemsToBytes 
  19.    42.22GB  3.11% 41.59%    42.22GB  3.11%  strings.Join 
  20.    39.52GB  2.91% 44.50%    87.06GB  6.41%  net/url.parseQuery 

从功效中可以看出收罗时代一共分派了 1358.61GB top 10 占用了 44.50% 个中 bytes.makeSlice 占了靠近 1/10,那么看看都是谁在挪用 bytes.makeSlice 吧。

  1. (pprof) web bytes.makeSlice 

优雅的读取http哀求或相应的数据

从上图可以看出挪用 bytes.makeSlice 的最终要领是 ioutil.ReadAll, (受篇幅影响就没有截取 ioutil.ReadAll 上面的要领了),而 90% 都是 ioutil.ReadAll 读取 http 数据挪用,找随处所先别急想优化方案,先看看为啥 ioutil.ReadAll 会导致这么多内存分派。

  1. func readAll(r io.Reader, capacity int64) (b []byte, err error) { 
  2.     var buf bytes.Buffer 
  3.     // If the buffer overflows, we will get bytes.ErrTooLarge. 
  4.     // Return that as an error. Any other panic remains. 
  5.     defer func() { 
  6.         e := recover() 
  7.         if e == nil { 
  8.             return 
  9.         } 
  10.         if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge { 
  11.             err = panicErr 
  12.         } else { 
  13.             panic(e) 
  14.         } 
  15.     }() 
  16.     if int64(int(capacity)) == capacity { 
  17.         buf.Grow(int(capacity)) 
  18.     } 
  19.     _, err = buf.ReadFrom(r) 
  20.     return buf.Bytes(), err 
  21.  
  22. func ReadAll(r io.Reader) ([]byte, error) { 
  23.     return readAll(r, bytes.MinRead) 

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读