• 其它 Go RPC 库介绍
    • Thrift
    • 参考文档

    其它 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