Golang RPC 实践

本贴最后更新于 1957 天前,其中的信息可能已经斗转星移

摘要: 总体上来说,HTTP 每次请求比较浪费资源的。虽然 HTTP 也是走在 TCP 上面的,但是 HTTP 请求自己添加了很多自己的信息,因此会消耗带宽资源。所以一些公司就是用 RPC 作为内部应用的通信协议。

如果你对 Go 感兴趣, 可以关注我的公众号: GoGuider

RPC

RPC(Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络细节的应用程序通信协议。RPC 协议构建于 TCP 或 UDP,或者是 HTTP 上。

在 Go 中,标准库提供的 net/rpc 包实现了 RPC 协议需要的相关细节,开发者可以很方便的使用该包编写 RPC 的服务端和客户端程序。

从上图看, RPC 本身就是一个 client-server 模型。

下面列举一个实例代码, 来了解 RPC 调用过程

server.go

package main import ( "fmt" "log" "net" "net/http" "net/rpc" "os" "time" ) type Args struct { A, B int } type Math int // 计算乘积 func (t *Math) Multiply(args *Args, reply *int) error { time.Sleep(time.Second * 3) //睡1秒,同步调用会等待,异步会先往下执行 *reply = args.A * args.B fmt.Println("Multiply") return nil } // 计算和 func (t *Math) Sum(args *Args, reply *int) error { time.Sleep(time.Second * 3) *reply = args.A + args.B fmt.Println("Sum") return nil } func main() { //创建对象 math := new(Math) //rpc服务注册了一个Math对象 公开方法供客户端调用 rpc.Register(math) //指定rpc的传输协议 这里采用http协议作为rpc调用的载体 也可以用rpc.ServeConn处理单个连接请求 rpc.HandleHTTP() l, e := net.Listen("tcp", ":1234") if e != nil { log.Fatal("listen error", e) } go http.Serve(l, nil) os.Stdin.Read(make([]byte, 1)) }

client.go

运行命令 go run server.go go run client.go ​ 运行结果 Multiply:7*8=56 继续等待.... 继续等待.... 继续等待.... 7+8=15,出执行 ​ 调用过程解析 server 端 rpc 服务注册了一个 Math 对象 公开方法供客户端调用 采用 http 协议作为 rpc 调用的载体, 处理请求 client 端 调用 rpc 服务端提供的方法之前,先与 rpc 服务端建立连接 使用 Call 方法调用远程方法 延伸 其实细心的朋友会注意到 client.go 里面有 client.Call 和 client.Go 调用; 查看源码可以看到 client.Call 底层就是调用的 client.Go // 部分源码: / Go invokes the function asynchronously. It returns the Call structure representing // the invocation. The done channel will signal when the call is complete by returning // the same Call object. If done is nil, Go will allocate a new channel. // If non-nil, done must be buffered or Go will deliberately crash. func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call { call := new(Call) call.ServiceMethod = serviceMethod call.Args = args call.Reply = reply if done == nil { done = make(chan *Call, 10) // buffered. } else { // If caller passes done != nil, it must arrange that // done has enough buffer for the number of simultaneous // RPCs that will be using that channel. If the channel // is totally unbuffered, it's best not to run at all. if cap(done) == 0 { log.Panic("rpc: done channel is unbuffered") } } call.Done = done client.send(call) return call } // Call invokes the named function, waits for it to complete, and returns its error status. func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error { call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done return call.Error } ​ 参考文章 gRPC 官方文档 gRPC 中文文档
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1388 回帖 • 261 关注
  • RPC
    16 引用 • 22 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...