其它 Go RPC 库介绍

当然,其它的一些 RPC框架也有提供了Go的绑定,知名的比如Thrift

Thrift

2007年开源,2008看5月进入Apache孵化器,2010年10月成为Apache的顶级项目。

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。
它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。
它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)、Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk编程语言开发。
2007由Facebook开源,2008年5月进入Apache孵化器, 2010年10月成为Apache的顶级项目。

Thrift包含一套完整的栈来创建客户端和服务端程序。[7]顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现。

来自wikipedia

Thrift一些已经明确的优点包括:[

  • 跟一些替代选择,比如SOAP相比,跨语言序列化的代价更低,因为它使用二进制格式。
  • 它有一个又瘦又干净的库,没有编码框架,没有XML配置文件。
  • 绑定感觉很自然。例如,Java使用java/util/ArrayList.html ArrayList;C++使用std::vector
  • 应用层通讯格式与序列化层通讯格式是完全分离的。它们都可以独立修改。
  • 预定义的序列化格式包括:二进制、对HTTP友好的和压缩的二进制。
  • 兼作跨语言文件序列化。
  • 支持协议的[需要解释]。Thrift不要求一个集中的和明确的机制,象主版本号/次版本号。松耦合的团队可以自由地进化RPC调用。
  • 没有构建依赖或非标软件。不混合不兼容的软件许可证。

首先你需要安装 thrift编译器: download
然后安装thift-go库:

  1. git.apache.org/thrift.git/lib/go/thrift

对于一个服务,你需要定义thrift文件 (helloworld.thrift):

  1. namespace go greeter
  2. service Greeter {
  3. string sayHello(1:string name);
  4. }

编译创建相应的stub,它会创建多个辅助文件:

  1. thrift -r --gen go -out src thrift/helloworld.thrift

服务端的代码:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "git.apache.org/thrift.git/lib/go/thrift"
  6. "greeter"
  7. )
  8. const (
  9. NetworkAddr = "localhost:9090"
  10. )
  11. type GreeterHandler struct {
  12. }
  13. func NewGreeterHandler() *GreeterHandler {
  14. return &GreeterHandler{}
  15. }
  16. func (p *GreeterHandler) SayHello(name string)(r string, err error) {
  17. return "Hello " + name, nil
  18. }
  19. func main() {
  20. var protocolFactory thrift.TProtocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
  21. var transportFactory thrift.TTransportFactory = thrift.NewTBufferedTransportFactory(8192)
  22. transport, err := thrift.NewTServerSocket(NetworkAddr)
  23. if err != nil {
  24. fmt.Println("Error!", err)
  25. os.Exit(1)
  26. }
  27. handler := NewGreeterHandler()
  28. processor := greeter.NewGreeterProcessor(handler)
  29. server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory)
  30. fmt.Println("Starting the simple server... on ", NetworkAddr)
  31. server.Serve()
  32. }

客户端的测试代码:

  1. package main
  2. import (
  3. "os"
  4. "fmt"
  5. "time"
  6. "strconv"
  7. "sync"
  8. "greeter"
  9. "git.apache.org/thrift.git/lib/go/thrift"
  10. )
  11. const (
  12. address = "localhost:9090"
  13. defaultName = "world"
  14. )
  15. func syncTest(client *greeter.GreeterClient, name string) {
  16. i := 10000
  17. t := time.Now().UnixNano()
  18. for ; i>0; i-- {
  19. client.SayHello(name)
  20. }
  21. fmt.Println("took", (time.Now().UnixNano() - t) / 1000000, "ms")
  22. }
  23. func asyncTest(client [20]*greeter.GreeterClient, name string) {
  24. var locks [20]sync.Mutex
  25. var wg sync.WaitGroup
  26. wg.Add(10000)
  27. i := 10000
  28. t := time.Now().UnixNano()
  29. for ; i>0; i-- {
  30. go func(index int) {
  31. locks[index % 20].Lock()
  32. client[ index % 20].SayHello(name)
  33. wg.Done()
  34. locks[index % 20].Unlock()
  35. }(i)
  36. }
  37. wg.Wait()
  38. fmt.Println("took", (time.Now().UnixNano() - t) / 1000000, "ms")
  39. }
  40. func main() {
  41. transportFactory := thrift.NewTBufferedTransportFactory(8192)
  42. protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
  43. var client [20]*greeter.GreeterClient
  44. //warm up
  45. for i := 0; i < 20; i++ {
  46. transport, err := thrift.NewTSocket(address)
  47. if err != nil {
  48. fmt.Fprintln(os.Stderr, "error resolving address:", err)
  49. os.Exit(1)
  50. }
  51. useTransport := transportFactory.GetTransport(transport)
  52. defer transport.Close()
  53. if err := transport.Open(); err != nil {
  54. fmt.Fprintln(os.Stderr, "Error opening socket to localhost:9090", " ", err)
  55. os.Exit(1)
  56. }
  57. client[i] = greeter.NewGreeterClientFactory(useTransport, protocolFactory)
  58. client[i].SayHello(defaultName)
  59. }
  60. sync := true
  61. if len(os.Args) > 1 {
  62. sync, _ = strconv.ParseBool(os.Args[1])
  63. }
  64. if sync {
  65. syncTest(client[0], defaultName)
  66. } else {
  67. asyncTest(client, defaultName)
  68. }
  69. }

其它一些Go RPC框架如

  1. http://www.gorillatoolkit.org/pkg/rpc
  2. https://github.com/valyala/gorpc
  3. https://github.com/micro/go-micro
  4. https://github.com/go-kit/kit

参考文档

  1. https://thrift.apache.org/tutorial/go
  2. https://github.com/smallnest/RPC-TEST