1. 程式人生 > >GraphQL的踩坑之路

GraphQL的踩坑之路

為了更好的支援前端能夠自由組合、展示收到的資料,筆者使用graphql-go 框架開發了負責的模組,但測試過程中發現,使用GraphQL會有n+1 query的問題。經過調研發現兩種解決方案:

  • 使用graphql-gophers下的graphql-go,已經支援如下特性:
    • minimal API
    • support for context.Context
    • support for the OpenTracing standard
    • schema type-checking against resolvers
    • resolvers are matched to the schema based on method sets (can resolve a GraphQL schema with a Go interface or Go struct).
    • handles panics in resolvers
    • parallel execution of resolvers
  • 在使用graphql-go的同時使用facebook開源的dataloader工具,詳細例子見dataloader的issues: Example to use with graphql-go

n + 1 query解釋

Scheme (simplified):

““
type Query {
orders: [Order]
}

type Order {
id: ID
client: Client
}

type Client {
id: ID
name: String
}
““

Query:

query GetOrders {
  orders {
    client {
      name
    }
  }
}

解釋

為了返回100個orders,必須傳送101個請求給微服務(1個請求獲取批量的orders,100個獲取它的client資訊(每個order都需要執行一次client資訊查詢)。詳細資訊見issues: No way to get requested fields inside resolver

效能分析過程

使用vegeta工具向服務傳送流量,然後使用pprof和go-torch工具對服務進行分析。

vegeta命令說明

向服務傳送流量命令

 echo "POST http://localhost:8080/graphql" | vegeta attack -body /vegeta/rqst.txt -duration=30s -rate=200 > r.bin

傳送流量結果分析

 vegeta vegeta report -inputs=r.bin
Requests      [total, rate]            6000, 200.03
Duration      [total, attack, wait]    29.998652838s, 29.994999868s, 3.65297ms
Latencies     [mean, 50, 95, 99, max]  3.740812ms, 3.649598ms, 4.53176ms, 5.088892ms, 22.366809ms
Bytes In      [total, mean]            222000, 37.00
Bytes Out     [total, mean]            2802000, 467.00
Success       [ratio]                  100.00%
Status Codes  [code:count]             200:6000  
Error Set:
  • 向服務傳送流量命令解釋: 向部署在本地的埠號為8080的服務傳送POST請求,持續時間為30s,每秒傳送200個請求,請求的內容存放在vegeta目錄下的rqst.txt檔案中。
  • 傳送流量結果分析解釋: 對壓測的結果以報表的形式展示出來。

pprof命令說明

在使用vegeta命令壓測的同時使用go tool的pprof工具分析CPU的耗時go tool pprof -seconds 25 http://localhost:8080/debug/pprof/profile,持續25s後輸入web ,生成如下所示的內容:

這裡寫圖片描述
雖然go1.9在使用pprof工具生成CPU耗時分析的時候較之前的版本已經加入了顏色,但是看起來仍不是很直觀,這個時候就需要使用火焰圖了。

go-torch生成火焰圖

在使用vegeta命令壓測的同時使用go-torch工具生成火焰圖,命令go-torch -u http://192.168.189.168 -t 25 生成的火焰圖如下圖所示:(192.168.189.168為本地的localhost)
這裡寫圖片描述

通過火焰圖分析,graphql-go框架的佔用很多的CPU耗時,查詢資料發現,主要原因是graphql的Resolver函式的解析並非併發解析,所以會產生上面描述的n + 1 query的問題。