Golang之rpc框架rpcx
时间:2022-07-25
本文章向大家介绍Golang之rpc框架rpcx,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前言
远程过程调用(Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。通过该协议程序员可以实现像调取本地函数一样,调取远程服务的函数。这里介绍一个高效的rpc库(rpcx)。
rpcx 是一个分布式的Go语言的 RPC 框架,支持Zookepper、etcd、consul多种服务发现方式,多种服务路由方式, 是目前性能最好的 RPC 框架之一。
官方资料:https://books.studygolang.com...
项目:https://github.com/smallnest/...
功能
- 支持原始Go功能。无需定义原型文件。
- 可插拔 可以扩展功能,例如服务发现,跟踪。
- 支持TCP,HTTP,QUIC和KCP
- 支持多种编解码器,例如JSON,Protobuf,MessagePack和原始字节。
- 服务发现。支持peer2peer,已配置的peer,zookeeper,etcd,consul和mDNS。
- 容错:故障转移,故障转移,故障转移。
- 负载平衡:支持随机,轮循,一致哈希,加权,网络质量和地理位置。
- 支持压缩。
- 支持传递元数据。
- 支持授权。
- 支持心跳和单向请求。
- 其他功能:指标,日志,超时,别名,断路器。
- 支持双向通讯。
- 支持通过HTTP访问,因此您可以使用任何编程语言编写客户端。
- 支持API网关。
- 支持备份请求,分叉和广播。
rpcx使用二进制协议且与平台无关,这意味着您可以使用其他语言(例如Java,Python,nodejs)开发服务,还可以使用其他编程语言来调用Go中开发的服务。
性能
测试结果表明,除了标准rpc库之外,rpcx的性能要优于其他rpc框架。
快速开始
基本安装
go get -v github.com/smallnest/rpcx/...
服务端
新建server.go
package main
import (
"context"
"flag"
"fmt"
example "github.com/rpcxio/rpcx-examples"
"github.com/smallnest/rpcx/server"
)
var (
addr = flag.String("addr", "localhost:8972", "server address")
)
type Arith struct{}
// the second parameter is not a pointer
func (t *Arith) Mul(ctx context.Context, args example.Args, reply *example.Reply) error {
reply.C = args.A * args.B
fmt.Println("C=", reply.C)
return nil
}
func main() {
flag.Parse()
s := server.NewServer()
//s.Register(new(Arith), "")
s.RegisterName("Arith", new(Arith), "")
err := s.Serve("tcp", *addr)
if err != nil {
panic(err)
}
}
客户端
client.go
package main
import (
"context"
"flag"
"fmt"
"log"
"github.com/smallnest/rpcx/protocol"
example "github.com/rpcxio/rpcx-examples"
"github.com/smallnest/rpcx/client"
)
var (
addr = flag.String("addr", "localhost:8972", "server address")
)
func main() {
flag.Parse()
d := client.NewPeer2PeerDiscovery("tcp@"+*addr, "")
opt := client.DefaultOption
opt.SerializeType = protocol.JSON
xclient := client.NewXClient("Arith", client.Failtry, client.RandomSelect, d, opt)
defer xclient.Close()
args := example.Args{
A: 10,
B: 20,
}
reply := &example.Reply{}
err := xclient.Call(context.Background(), "Mul", args, reply)
if err != nil {
log.Fatalf("failed to call: %v", err)
}
log.Printf("%d * %d = %d", args.A, args.B, reply.C)
}
运行
服务端
go run server.go
客户端
go run client.go
这时服务端输出:
C= 200
2020/07/21 15:19:02 server.go:358: INFO : client has closed this connection: 127.0.0.1:50186
客户端输出:
2020/07/21 15:19:02 10 * 20 = 200
跨语言
rpcx还提供了rpcx-gateway,您可以使用任何编程语言编写客户端,以通过rpcx-gateway调用rpcx服务。
安装rpcx-gateway
go get github.com/rpcxio/rpcx-gateway
示例
新建gateway.go文件,代码如下:
package main
import (
"errors"
"flag"
"fmt"
"log"
"strings"
"time"
gateway "github.com/rpcxio/rpcx-gateway"
"github.com/rpcxio/rpcx-gateway/gin"
"github.com/smallnest/rpcx/client"
)
var (
addr = flag.String("addr", ":9981", "http server address")
registry = flag.String("registry", "peer2peer://127.0.0.1:8972", "registry address")
basePath = flag.String("basepath", "/rpcx", "basepath for zookeeper, etcd and consul")
failmode = flag.Int("failmode", int(client.Failover), "failMode, Failover in default")
selectMode = flag.Int("selectmode", int(client.RoundRobin), "selectMode, RoundRobin in default")
)
func main() {
flag.Parse()
d, err := createServiceDiscovery(*registry)
if err != nil {
log.Fatal(err)
}
httpServer := gin.New(*addr)
gw := gateway.NewGateway("/", httpServer, d, client.FailMode(*failmode), client.SelectMode(*selectMode), client.DefaultOption)
gw.Serve()
}
func createServiceDiscovery(regAddr string) (client.ServiceDiscovery, error) {
i := strings.Index(regAddr, "://")
if i < 0 {
return nil, errors.New("wrong format registry address. The right fotmat is [registry_type://address]")
}
regType := regAddr[:i]
regAddr = regAddr[i+3:]
switch regType {
case "peer2peer": //peer2peer://127.0.0.1:8972
return client.NewPeer2PeerDiscovery("tcp@"+regAddr, ""), nil
case "multiple":
var pairs []*client.KVPair
pp := strings.Split(regAddr, ",")
for _, v := range pp {
pairs = append(pairs, &client.KVPair{Key: v})
}
return client.NewMultipleServersDiscovery(pairs), nil
case "zookeeper":
return client.NewZookeeperDiscoveryTemplate(*basePath, []string{regAddr}, nil), nil
case "etcd":
return client.NewEtcdDiscoveryTemplate(*basePath, []string{regAddr}, nil), nil
case "etcdv3":
return client.NewEtcdV3DiscoveryTemplate(*basePath, []string{regAddr}, nil), nil
case "consul":
return client.NewConsulDiscoveryTemplate(*basePath, []string{regAddr}, nil), nil
case "redis":
return client.NewRedisDiscoveryTemplate(*basePath, []string{regAddr}, nil), nil
case "mdns":
return client.NewMDNSDiscoveryTemplate(10*time.Second, 10*time.Second, ""), nil
default:
return nil, fmt.Errorf("wrong registry type %s. only support peer2peer,multiple, zookeeper, etcd, consul and mdns", regType)
}
}
运行 gateway.go
go run gateway.go
注意:运行网关前,要保证rpcx服务端(server.go)启动,这里以php客户端为例
新建client.php
代码如下:
<?php
$url = 'http://localhost:9981/';
$data = '{"A":10, "B":20}';
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/rpcxrn" .
// "X-RPCX-MessageID: 12345678rn" .
// "X-RPCX-MesssageType: 0rn" .
"X-RPCX-SerializeType: 1rn" .
"X-RPCX-ServicePath: Arithrn" .
"X-RPCX-ServiceMethod: Mulrn",
'method' => 'POST',
'content' => $data
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
var_dump($result);
?>
结果:
string(9) "{"C":200}"
server.go 输出
C= 200
这样就实现跨语言了。
其他语言示例
https://github.com/rpcxio/rpc...
rpcx 3.0已针对以下目标进行了重构:
- 简单:易于学习,易于开发,易于交互和易于部署
- 性能:高性能(> = grpc-go)
- 跨平台:支持字节,JSON,Protobuf和MessagePack的原始切片。从理论上讲,它可以与java,php,python,c / c ++,node.js,c#和其他平台一起使用
- 服务发现和服务治理:支持zookeeper,etcd和consul。
相关资料
https://github.com/rpcxio/rpc...
https://github.com/smallnest/...
- Spring Properties 文件读取
- 【学术】你真的知道什么是随机森林吗?本文是关于随机森林的直观解读
- Spring boot 将 Session 放入 Redis
- 【教程】估算一个最佳学习速率,以更好地训练深度神经网络
- SNS 数据库设计
- CentOS7 下 MySQL 5.7 重置root密码
- 通过简单的线性回归理解机器学习的基本原理
- 消息队列在使用中的注意事项
- 【教程】OpenCV—Node.js教程系列:用Tensorflow和Caffe“做游戏”
- 验证码,再见!利用机器学习在15分钟内破解验证码
- Spring boot with Redis
- SOA 面向服务框架设计与实现
- Java·日期时间处理
- MySQL·身份证校验
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 2万字,实战 Docker 部署:完整的前后端,主从热备高可用服务!!
- http & request & response的学习
- JavaScript 错误处理大全【建议收藏】
- Java8 用 Stream 快速实现List转Map 、分组、过滤等操作
- swoole框架异常处理
- 使用composer本地开发项目
- GDAL数据集写入空间坐标参考
- html & CSS & JavaScript的学习
- 打卡群刷题总结0824——电话号码的字母组合
- 打卡群刷题总结0825——括号生成
- Ajax与Json的学习
- pytest文档48-切换环境(pytest-base-url)
- 打卡群刷题总结0826——组合总和
- 排序之简单排序
- 打卡群刷题总结0827——组合总和 II