Pro Yearly is on sale from $80 to $50! »

Ruby & Friends - Taking Go as an example

Ruby & Friends - Taking Go as an example

Presented at RubyConf TW 2014

Aa0358f6740f1bf02911e5300e08e800?s=128

Richard Lee

April 26, 2014
Tweet

Transcript

  1. Ruby & Friends Taking Go as an example

  2. ... In this talk, I'm going to present several ways

    to make such two-way communications between Ruby & Go language.
  3. Richard Lee • CTO @ Polydice, Inc • iCook.tw dev

    & ops • Open source lover • @dlackty everywhere
  4. Agenda 1. Why Go language? 2. Go with Ruby using

    asynchronous workers 3. Remote Procedure Code 4. Advanced tools
  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
  6. Use cases 1. Command line tools - Heroku's hk 2.

    System softwares - Docker 3. DevOps tools - ngrok / packer
  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
  8. You don't really understand a language until you use it

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

    with Ruby
  10. My First Law of Distributed Object Design: Don't distribute your

    objects — Martin Fowler
  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
  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) }
  13. ...and in Resque class MyClass @queue = :myqueue end Resque.enqueue

    MyClass, ['hi', 'there']
  14. Async processing (cont'd) • Pros: • Not fast enough but

    quite reliable • easy to scale out • Cons: • Async • Additional setup for queues
  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 }
  16. Compared to Ruby code class MyClass @queue = :myqueue def

    self.perform(i, str) doSomething(i, str) end end
  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
  18. In some cases, you might need immediate result Then you

    need RPC
  19. Remote Procedure Calls Just like function invokation but remotely •

    Dynamically-typed • JSON-RPC • MsgPack-RPC • Statically format • Protobuf • Thrift
  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
  21. JSON-RPC 1. Everybody love JSON! 2. Golang has built-in library

    3. Ruby has nice wrappers
  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}
  23. It's demo time.

  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
  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 }
  26. MsgPack 1. MsgPack is efficient binary serialization format 2. Quite

    similar to JSON but with binary type 3. Nice packages for most language
  27. MsgPack-RPC 1. MsgPack-RPC is ...RPC using MsgPack 2. Again, nice

    packages for different languages
  28. It's demo time.

  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
  30. Statically-typed Which means: 1. Predefine format with special language (IDL)

    2. Usually with generated codes 3. Good when you have nice plan
  31. Protobuf 1. Widely used by Google 2. Built in with

    Golang 3. However, there's no official RPC mechanism
  32. Thrift 1. Open sourced by Facebook 2. Officially support a

    wide range of language 3. Have built in RPC mechanism
  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 }
  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
  35. But wait, why not just use REST?

  36. RPC v.s. HTTP / RESTful APIs • Persistent connection •

    Smaller in size • Easier to implement
  37. Conclusion

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

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