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

    View full-size slide

  2. @cubicdaiya / Tatsuhiko Kubo
    Principal Engineer, SRE @ Mercari, Inc.
    ngx_small_light, ngx_dynamic_upstream,
    nginx-build, slackboard,cachectl, gaurun, etc…

    View full-size slide

  3. nginxຊΛࣥච͠·ͨ͠ʢ2016/01/16ൃചʣ

    View full-size slide

  4. https://www.mercari.com/
    Mercari - Your Friendly Mobile Marketplace

    View full-size slide

  5. Agenda
    • Use cases Go @
    • Widebullet - proxying RESTful APIs with
    JSON-RPC

    View full-size slide

  6. Use cases for Go @

    View full-size slide

  7. 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)

    View full-size slide

  8. 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…)

    View full-size slide

  9. 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…)

    View full-size slide

  10. Widebullet - Proxying RESTful
    APIs with JSON-RPC in Go

    View full-size slide

  11. 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

    View full-size slide

  12. 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

    View full-size slide

  13. 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

    View full-size slide

  14. 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

    View full-size slide

  15. 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

    View full-size slide

  16. 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ʂ

    View full-size slide

  17. 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

    View full-size slide

  18. 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.

    View full-size slide

  19. Widebullet
    • The proxy server between JSON-RPC and
    RESTful API server
    • Protocol
    • based JSON-RPC ( a little extended)
    • Configuration with TOML
    • Not published yetʂ

    View full-size slide

  20. Overview
    NFSDBSJ
    "1*
    TVCTZT
    JSON-RPC
    XJEFCVMMFU

    View full-size slide

  21. Start Widebullet
    $ wbt -c wbt.toml

    View full-size slide

  22. 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"],
    ]

    View full-size slide

  23. 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 }
    }
    ]

    View full-size slide

  24. Convert to RESTful API requests
    GET http://ep-1/goods/get?id=1234&status=alive HTTP/1.1
    GET http://ep-2/users/get?id=5678 HTTP/1.1

    View full-size slide

  25. 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
    }

    View full-size slide

  26. 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

    View full-size slide

  27. Result
    PHP
    wait API response
    from widebullet
    consumed time graph
    introduced Widebullet

    View full-size slide

  28. We are hiring
    Go Engineer!
    https://www.mercari.com/jp/jobs/

    View full-size slide