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

Ruby & Friends - Taking Go as an example

Ruby & Friends - Taking Go as an example

Presented at RubyConf TW 2014

Richard Lee

April 26, 2014
Tweet

More Decks by Richard Lee

Other Decks in Technology

Transcript

  1. Ruby & Friends
    Taking Go as an example

    View full-size slide

  2. ... In this talk, I'm going to
    present several ways to
    make such two-way
    communications between
    Ruby & Go language.

    View full-size slide

  3. Richard Lee
    • CTO @ Polydice, Inc
    • iCook.tw dev & ops
    • Open source lover
    • @dlackty everywhere

    View full-size slide

  4. Agenda
    1. Why Go language?
    2. Go with Ruby using asynchronous workers
    3. Remote Procedure Code
    4. Advanced tools

    View full-size slide

  5. Go
    Why choose another language when you have Ruby?
    1. Static typing
    2. Compiled language
    3. Higher level concurrency abstraction (goroutines)
    4. No object oriented design

    View full-size slide

  6. Use cases
    1. Command line tools - Heroku's hk
    2. System softwares - Docker
    3. DevOps tools - ngrok / packer

    View full-size slide

  7. Heroku's CLI benchmark
    ## version
    $ time heroku version >/dev/null
    real 0m1.813s
    $ time hk version >/dev/null
    real 0m0.016s
    ## list
    $ time heroku apps >/dev/null
    real 0m3.830s
    $ time hk apps >/dev/null
    real 0m0.785s

    View full-size slide

  8. You don't really understand
    a language until you use it in
    production

    View full-size slide

  9. Then you might want to use
    Go in your system with Ruby

    View full-size slide

  10. My First Law of
    Distributed
    Object Design:
    Don't distribute
    your objects
    — Martin Fowler

    View full-size slide

  11. Async processing
    Use Redis or any message queue based processing.
    Resque / Sidekiq friends:
    • From Ruby to Go
    • go-workers
    • goworkers
    • go-sidekiq
    • From Go to Ruby
    • go-resque

    View full-size slide

  12. go-workers for Resque in action
    func myFunc(queue string, args ...interface{}) error {
    fmt.Printf("From %s, %v", queue, args)
    return
    }
    func init() {
    goworker.Register("MyClass", myFunc)
    }

    View full-size slide

  13. ...and in Resque
    class MyClass
    @queue = :myqueue
    end
    Resque.enqueue MyClass, ['hi', 'there']

    View full-size slide

  14. Async processing (cont'd)
    • Pros:
    • Not fast enough but quite reliable
    • easy to scale out
    • Cons:
    • Async
    • Additional setup for queues

    View full-size slide

  15. Be careful about typing
    // Expecting (int, string)
    func myFunc(queue, args ...interface{}) error {
    id, ok := args[0].(int)
    if !ok {
    return errorInvalidParam
    }
    name, ok := args[1].(string)
    if !ok {
    return errorInvalidParam
    }
    doSomething(id, name)
    return nil
    }

    View full-size slide

  16. Compared to Ruby code
    class MyClass
    @queue = :myqueue
    def self.perform(i, str)
    doSomething(i, str)
    end
    end

    View full-size slide

  17. Performance boost
    • Benchmarked using matrix
    multiplication
    a = Matrix[...]
    b = Matrix[...]
    c = a * b
    puts a * b
    • 9x faster than Resque
    • 4x faster than Sidekiq

    View full-size slide

  18. In some cases, you might
    need immediate result
    Then you need RPC

    View full-size slide

  19. Remote Procedure Calls
    Just like function invokation but remotely
    • Dynamically-typed
    • JSON-RPC
    • MsgPack-RPC
    • Statically format
    • Protobuf
    • Thrift

    View full-size slide

  20. Dynamically-typed
    Which means:
    1. No need to predefine data format
    2. No generated codes for both client & server
    3. Quite easy to migrate

    View full-size slide

  21. JSON-RPC
    1. Everybody love JSON!
    2. Golang has built-in library
    3. Ruby has nice wrappers

    View full-size slide

  22. JSON-RPC Protocol
    Can be built on simple TCP connection or HTTP
    Request:
    {"method": "echo", "params": ["Hello JSON-RPC"], "id": 1}
    Response:
    {"result": "Hello JSON-RPC", "error": null, "id": 1}

    View full-size slide

  23. It's demo time.

    View full-size slide

  24. Client
    sock = TCPSocket.new "localhost", "5566"
    call = { method:"RPCMethods.Say", params:[{"text"=>"Hello, world!"}], id:rand(100) }
    sock.write JSON.dump call
    JSON.load sock.readline

    View full-size slide

  25. Server
    func (m *RPCMethods) Say(args Args, results *Results) error {
    results.Text = args.Text
    fmt.Println(results.Text)
    return nil // no error
    }
    func (m *RPCMethods) Ping(args Args, results *Results) error {
    results.Text = "Pong"
    fmt.Println(results.Text)
    return nil // no error
    }

    View full-size slide

  26. MsgPack
    1. MsgPack is efficient binary
    serialization format
    2. Quite similar to JSON but
    with binary type
    3. Nice packages for most
    language

    View full-size slide

  27. MsgPack-RPC
    1. MsgPack-RPC is ...RPC using MsgPack
    2. Again, nice packages for different languages

    View full-size slide

  28. It's demo time.

    View full-size slide

  29. Client code
    cli = MessagePack::RPC::Client.new("127.0.0.1", 5566)
    cli.timeout = 5
    v = cli.call(:echo, "Ruby Conference Taiwan!")
    cli.close

    View full-size slide

  30. Statically-typed
    Which means:
    1. Predefine format with special language (IDL)
    2. Usually with generated codes
    3. Good when you have nice plan

    View full-size slide

  31. Protobuf
    1. Widely used by Google
    2. Built in with Golang
    3. However, there's no official RPC mechanism

    View full-size slide

  32. Thrift
    1. Open sourced by Facebook
    2. Officially support a wide range of language
    3. Have built in RPC mechanism

    View full-size slide

  33. Thrift IDL
    RpcService.thrift
    namespace go demo.rpc
    namespace ruby demo.rpc
    enum TweetType {
    TWEET, // 1
    RETWEET // 2
    }
    struct Tweet {
    1: required i32 userId;
    2: required string userName;
    3: required string text;
    4: optional Location loc;
    5: optional TweetType tweetType = TweetType.TWEET
    }

    View full-size slide

  34. Thrift in aciton
    1. Usually your first start from defining you service
    in IDL
    2. Generate server / client code using thrift
    commands
    3. Copy that to both side and integrate

    View full-size slide

  35. But wait, why not just use
    REST?

    View full-size slide

  36. RPC v.s. HTTP / RESTful APIs
    • Persistent connection
    • Smaller in size
    • Easier to implement

    View full-size slide

  37. Most importantly, learning a
    new language is always fun
    and inspiring

    View full-size slide

  38. Thank you!
    Let's Keep in touch
    Twitter / GitHub: @dlackty

    View full-size slide