Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Widebullet - Proxying RESTful APIs with JSON-RPC in Go

Widebullet - Proxying RESTful APIs with JSON-RPC in Go

Tatsuhiko Kubo

February 17, 2016
Tweet

More Decks by Tatsuhiko Kubo

Other Decks in Technology

Transcript

  1. Widebullet - Proxying RESTful APIs with JSON-RPC in Go Tatsuhiko

    Kubo@cubicdaiya Go 1.6 Release Party 2016/02/17
  2. @cubicdaiya / Tatsuhiko Kubo Principal Engineer, SRE @ Mercari, Inc.

    ngx_small_light, ngx_dynamic_upstream, nginx-build, slackboard,cachectl, gaurun, etc…
  3. Use cases for Go @ • nginx-build - seamless nginx

    builder (github.com/cubicdaiya/nginx-build) • cachectl - page cache controller (github.com/cubicdaiya/cachectl) • Slackboard - proxying message to Slack (github.com/cubicdaiya/slackboard) • Gaurun - proxying push notification (github.com/mercari/gaurun) • fluent-agent-hydra - A Fluentd log agent (github.com/fujiwara/fuluent-agent-hydra)
  4. Use cases for Go @ • zabbix-cli - CLI tool

    for Zabbix • CLI tools and plugins for Mackerel • Widebullet - proxying multi API requests • etc… (e.g. internal CLIs and daemons…)
  5. Use cases for Go @ • zabbix-cli - CLI tool

    for Zabbix • CLI tools and plugins for Mackerel • Widebullet - proxying multi API requests • etc… (e.g. internal CLIs and daemons…)
  6. Overview of mercari API call - Before NFSDBSJ "1* Multimedia

    Corporate data center Traditional server Mobile Client Example: IAM Add-on Requester Workers HTTPS HTTP private network global network
  7. Overview of mercari API call - Now NFSDBSJ "1* Multimedia

    Corporate data center Traditional server Mobile Client Example: IAM Add-on Requester Workers HTTPS HTTP HTTP TVCTZT private network global network
  8. Overview of mercari API call - Now NFSDBSJ "1* Multimedia

    Corporate data center Traditional server Mobile Client Example: IAM Add-on Requester Workers HTTPS HTTP HTTP TVCTZT TVCTZT HTTP private network global network
  9. Overview of mercari API call - Now NFSDBSJ "1* Multimedia

    Corporate data center Traditional server Mobile Client Example: IAM Add-on Requester Workers HTTPS HTTP HTTP TVCTZT TVCTZT HTTP TVCTZT HTTP private network global network
  10. Overview of mercari API call - Now NFSDBSJ "1* Multimedia

    Corporate data center Traditional server Mobile Client Example: IAM Add-on Requester Workers HTTPS HTTP HTTP TVCTZT TVCTZT HTTP TVCTZT HTTP … private network global network
  11. Performance reduction due to API mismatch • mercari API is

    not always constructed optimally for every situation • some subsystem must call multiple APIs at once • Call APIs concurrently for high performance • BTW, some subsystem is powered by PHPʂ
  12. Call APIs concurrently in PHP • We tried with Guzzle

    ( internally curl_exec_multi) • succeed a bit optimization • But overhead is not negligible switched concurrent API call PHP wait API response consumed time graph
  13. Next step • Try to call multiple APIs with single

    request • Nice to have anyway • JSON-RPC is reasonable choice • But mercari API does not provides JSON-RPC • I tried to write the proxy server in Go • It’s the Widebullet.
  14. Widebullet • The proxy server between JSON-RPC and RESTful API

    server • Protocol • based JSON-RPC ( a little extended) • Configuration with TOML • Not published yetʂ
  15. Configuration with TOML Port = "29300" LogLevel = "error" Timeout

    = 5 MaxIdleConnsPerHost = 100 DisableCompression = false [[Endpoints]] Name = "ep-1" Ep = “ep-1:30001" ProxySetHeaders = [ ["Host", "ep1.example.com"], ] [[Endpoints]] Name = "ep-2" Ep = “ep-2:30001" ProxySetHeaders = [ ["Host", "ep2.example.com"], ]
  16. JSON-RPC request example [ { “jsonrpc”: “2.0”, “ep”: “ep-1”, “method”:

    “/goods/get”, “params”: { “id”: 1234, “status”: “alive” } }, { “jsonrpc”: “2.0”, “ep”: “ep-2”, “method”: “/users/get”, “params”: { “id”: 5678 } } ]
  17. Sending HTTP requests concurrently // error handling is eliminated for

    simplicity func jsonRpc2Http(reqs *[]jsonrpc.Request) ([]jsonrpc.Response) { wg := new(sync.WaitGroup) resps := make([]jsonrpc.Response, len(reqs) for i, reqj := range *reqs { wg.Add(1) go func(i int, reqj jsonrpc.Request) { defer wg.Done() reqh := buildHttpRequest(&reqj) resp, _ := HttpClient.Do(reqh) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) resps[i] = buildJsonRpcResponse(string(body), reqj.ID) }(i, reqj) } wg.Wait() return resps }
  18. Overview NFSDBSJ "1* TVCTZT JSON-RPC 8JEFCVMMFU REST [ { “jsonrpc”:

    “2.0”, “ep”: “ep-1”, “method”: “/goods/get”, “params”: { “id”: 1234, “status”: “alive” } }, { “jsonrpc”: “2.0”, “ep”: “ep-2”, “method”: “/users/get”, “params”: { “id”: 5678 } } ] GET http://ep-1/goods/get?id=1234&status=alive HTTP/1.1 GET http://ep-2/users/get?id=5678 HTTP/1.1