Golang实践:RPC
Remote Procedure Call,远程过程调用,即通过网络从远程计算机上请求服务而不需要了解底层网络技术的协议; 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程;
常用于分布式系统中不同系统之间的远程通信和调用;
helloworld
RPC框架
产品级的RPC框架除了点对点的RPC协议的具体实现外,还应包括服务的发现与注销、提供服务的多台Server的负载均衡、服务的高可用等更多的功能;
目前的RPC框架大致有两种不同的侧重方向,一种偏重于服务治理,另一种偏重于跨语言调用。
服务治理型:
dubbo、dubbox、motan
多语言型:
rpcx:Go语言版Dubbo
rpcx是一个分布式的Go语言的RPC框架,支持Zookepper、etcd、consul多种服务发现方式,多种服务路由方式,是目前性能最好的RPC框架之一。
gRPC:gRPC是Google开发的高性能、通用的开源RPC框架
由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言;
它的目标是跨语言开发,支持多种语言,服务治理方面需要自己去实现,所以要实现一个综合的产品级的分布式RPC平台还需要扩展开发;
Google内部使用的也不是gRPC,而是Stubby;
thrift:Apache跨语言的高性能的服务框架
thrift是Apache的一个跨语言的高性能的服务框架,也得到了广泛的应用;
它的功能类似gRPC, 支持跨语言,不支持服务治理;
RPC与RESTful
特性 | RPC | REST |
---|---|---|
耦合性 | 强耦合 | 松散耦合 |
消息协议 | 二进制thrift、protobuf、avro | XML、JSON |
通讯协议 | TCP为主 | HTTP/HTTP2 |
性能 | 高 | 一般低于RPC |
接口契约IDL | thrift、protobuf idl | swagger |
Client | 强类型客户端 | http client |
案例 | dubbo、gRPC、thrift | spring boot/MVC |
开发者友好 | 二进制消息 | 文本消息、浏览器可以直接访问 |
对外开放 | 需转成REST/文本协议 | 直接对外开放 |
REST:
Representational State-transfer表述性状态转移
具象状态传输
是一种架构风格;
REST特点:
1.资源由URI指定;
2.对资源的操作包括get、post、put、delete
3.通过资源的表现形式来操作资源;
4.资源的表现形式是XML或HTML、JSON
优点:
1.可更高效利用缓存来提高响应速度;
2.提高服务可扩展性(通讯本身无状态);
3.浏览器可作为Client;
4.依赖更小;
5.不需要额外发现机制;
thrift安装
Linux
wget http://www-us.apache.org/dist/thrift/0.13.0/thrift-0.13.0.tar.gz tar -xzvf thrift-0.13.tar.gz cd thrift-0.13.0 ./configure –prefix=/usr make -j8 make install
Mac
brew install thrift
查看版本:
thrift -version
Thrift version 0.13.0
生成Python代码
thrift -r –gen py helloworld.thrift
生成Golang代码
thrift -r –gen go helloworld.thrift
服务端示例
package main
import (
"fmt"
"log"
"net"
"net/rpc"
)
const HelloServiceName = "HelloService"
type HelloServicer = interface {
HelloWorld(request string, reply *string) error
}
func RegisterHelloService(svc HelloServicer) error {
return rpc.RegisterName(HelloServiceName, svc)
}
type HelloService struct {
}
func (h *HelloService) HelloWorld(request string, reply *string) error {
*reply = fmt.Sprintf("hello: %s.", request)
fmt.Println("reply: ", *reply)
return nil
}
func RPCServer() {
RegisterHelloService(new(HelloService))
listener, err := net.Listen("tcp", ":9090")
if err != nil {
log.Fatal("Listen TCP error: ", err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error: ", err)
}
fmt.Println("accept.")
go rpc.ServeConn(conn)
}
}
func main() {
RPCServer()
}
数据传输方式(TTransport)
if useHttp {
trans, err = thrift.NewTHttpClient(parsedUrl.String())
}else{
trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))
}
defer trans.Close()
传输协议(TProtocol):
TBinaryProtocol:二进制编码格式 TCompactProtocol:高效率密集的二进制编码格式 TJSONProtocol:JSON数据编码 TDebugProtocol:可读文本格式,可以debug
case "compact":
protocolFactory = thrift.NewTCompactProtocolFactory()
break
case "simplejson":
protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
break
case "json":
protocolFactory = thrift.NewTJSONProtocolFactory()
break
case "binary", "":
protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
break
客户端示例
func RPCClient() {
conn, err := net.DialTimeout("tcp", "127.0.0.1:9090", time.Second*10)
if err != nil {
log.Fatal("net.Dial:", err)
}
client := rpc.NewClient(conn)
fmt.Println("rpc client.")
var reply string
err = client.Call("HelloService.HelloWorld", "hello", &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
}
注册中心
插件
网关
refs
http://books.studygolang.com/go-rpc-programming-guide/
https://juejin.im/post/6844903938706112520
https://ops.tips/gists/example-go-rpc-client-and-server/
https://medium.com/rungo/building-rpc-remote-procedure-call-network-in-go-5bfebe90f7e9