go-micro是基于grpc的一个框架,一样也是用protobuf进行序列化,主要设计哲学是“可插拔”,主要是用于分布式系统开发。至于为什么用go-micro,主要是它对grpc封装的很好,让我们可以更便利。
下面是它的架构图
文章图片
【go-micro框架的QuickStart】同样的一开始也是要编写.proto 文件
hello.proto文件
syntax = "proto3";
//指定语法版本
package helloword;
//指定生成后的 hello.pb.go 的包名//一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法
service Hello {
// rpc 定义可远程调用服务
rpc HelloWorld (HelloRequest) returns (HelloReply) {}
}//消息定义的关键字,相当于struct
message HelloRequest {
// [修饰符] 类型 字段名 = 标识符;
//标识符是用来在二进制格式中识别各个字段的,可以简单理解为序列化后的二进制数据中的布局位置顺序
string name = 1;
}message HelloReply {
string message = 1;
}
和上一篇博客写的
hello.proto
没有任何变化,因为两者都是用protobuf接下来在终端键入
protoc -I . --micro_out=. --go_out=. ./hello.proto
文章图片
关于这条命令,在上一篇的博客中介绍过了,这里就不多说了,唯一不同的就是这里多了一个
--micro_out
参数,这个参数其实和--go_out
没有什么大的区别,是指定编译.proto文件后生成的.micro.go文件的路径可以看到在当前路径下会生成两个文件,与grpc不同,go-micro会多生成一个.micro.go文件,这个就是go-micro的接口文件
文章图片
下面就是实现服务端和客户端了
文章图片
服务端的实现
package main
import (
micro "github.com/micro/go-micro"
proto "helloworld"
"log"
"context"
)//用于实现HelloServer
type server struct{}//服务实现
func (s *server) HelloWorld(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloReply) (error) {
log.Printf("Received: %v", req.Name)
rsp.Message = "Hello " + req.Name
return nil
}func main() {
// 创建服务
service := micro.NewService(
micro.Name("helloworld"),
) // 初始化
service.Init() // 注册handler
proto.RegisterHelloHandler(service.Server(), new(server)) // 运行
if err := service.Run();
err != nil {
log.Println(err)
}}
和纯grpc实现的代码有点不一样,
func (s *server) HelloWorld
这个方法的参数和返回值和grpc实现的不一样了,在main()
中也不用自己来监听端口,由go-micro底层帮你实现了服务端主要有4个工作:
①实现在.proto 文件中定义的方法接口
②初始化服务
③注册handler
④运行
客户端的实现
package mainimport (
micro "github.com/micro/go-micro"
proto "helloworld"
"log"
"context"
"os"
)func main() {
// 创建服务
service := micro.NewService(micro.Name("helloworld"))
service.Init() // 创建客户端
hello := proto.NewHelloService("helloworld", service.Client()) name := "World"
//获取命令行参数
if len(os.Args) > 1 {
name = os.Args[1]
} // 唤起服务
rsp, err := hello.HelloWorld(context.TODO(), &proto.HelloRequest{Name: name})
if err != nil {
log.Println(err)
} // 响应
log.Println(rsp.Message)
}
和grpc实现的客户端基本一致,没有什么非常大的改动
运行
go run server/main.go
文章图片
这个节点就是我们在服务端里设置的
micro.Name()
,这个节点名还是很重要的,关乎我们的客户端能否找到它go run client/main.go
文章图片
注意
文章图片
在客户端实现的第17行,第一个参数是指定客户端所要找寻服务端的节点名,因此这个节点名一定要和服务端的保持一致,否则运行时就会报错说找不到节点。
比如说只将客户端实现的第17行改为
hello := proto.NewHelloService("hello", service.Client())
运行后,就会报错说找不到节点,就是因为客户端要找的节点在服务端中找不到,这是因为在这整个案例中,我们在服务端中只定义了一个节点
helloworld
,而修改后的客户端要找的节点hello
在服务端中没找到,两个节点名都不一致自然就找不到了,自然就报错了文章图片
参考
go-micro官方文档
推荐阅读
- 框架|Mybatis的一级缓存和二级缓存
- Android|OkHttp 异步网络请求流程
- SpringBoot的基础搭建
- 框架|springboot把配置实体和配置文件关联
- Android|Android网络框架-OkHttp使用
- shiro的一点记录(三)
- util|POI兼容读取Excel2003和Excel2007
- 分享mybatis的常见面试题
- 高并发系统三大利器之缓存
- 算法和数据结构|【回溯法】批处理作业调度问题