gRPC 是由 Google 主导开发的 RPC 框架,使用 HTTP/2 协议并用 ProtoBuf 作为序列化工具。
gRPC官方对REST的声音是:
和REST一样遵循HTTP协议(明确的说是HTTP/2),但是gRPC提供了全双工流
和传统的REST不同的是gRPC使用了静态路径,从而提高性能
用一些格式化的错误码代替了HTTP的状态码更好的标示错误
背景
regist 是在微服务架构上再抽出的一层,用于服务注册,心跳机制,服务注销。
regist 和 微服务架构 之间使用的是 REST 协议进行通信,现需要改造成 gRPC
RPC 框架: gRPC
协议:HTTP/2
序列化工具: ProtoBuf
服务端: regist (golang)
客户端 :微服务架构(java)
一、服务端改造(golang)
1. protocal buffer安装
去官网下载 protoc 压缩包,解压后,将 protoc.exe
放在 GOPATH\bin
目录下面
2. 安装GoLang protoc 插件
gRPC-go可以通过golang 的get命令直接安装,非常方便。go get -a github.com/golang/protobuf/protoc-gen-go
3. 定义register.proto
文件
syntax = "proto3"; package proto; service Regist { rpc Register (ResponseService) returns (RegisterReply) {} rpc Deregister (ResponseService) returns (DeregisterReply) {} } message RegisterReply { string message = 1; } message DeregisterReply { string message = 1; } message ResponseService { string id = 1; string name = 2; string version = 3; string address = 4; int32 port = 5; map<string, string> metadata = 6; }
syntax = "proto3"
,声明protobuf版本为3,默认为2。定义了一个服务 Regist,其中有两个API
Register
和Register
。定义3个message为接受和返回的参数。
4. 生成 register.pb.go
文件
在register.proto
文件所在根目录下,执行:protoc --go_out=plugins=grpc:. register.proto
则会在同目录下生成对应的 register.pb.go
文件,相应的服务器端和客户端的GoLang代码。生成的代码中包含了客户端能够进行RPC的方法以及服务器端需要进行实现的接口。
5.服务端代码改造
register.pb.go
文件中提供的服务接口
type RegistClient interface { Register(ctx context.Context, in *ResponseService, opts ...grpc.CallOption) (*RegisterReply, error) Deregister(ctx context.Context, in *ResponseService, opts ...grpc.CallOption) (*DeregisterReply, error) }
服务端代码实现上面的接口
func (s *server) Register(ctx context.Context, in *pb.ResponseService) (*pb.RegisterReply, error) { // 定义注册的服务,组装 gRPC 传过来的参数 service := &rp.Service{ Name: in.GetName(), Version: in.GetVersion(), Metadata: in.GetMetadata(), NodeName: nodeName, Nodes: []*rp.Node{ &rp.Node{ ID: in.GetId(), Address: in.GetAddress(), Port: int(in.GetPort()), }, }, Endpoints: []*rp.Endpoint{ &rp.Endpoint{ Name: in.GetName(), Request: &rp.Value{}, Response: &rp.Value{}, Metadata: in.GetMetadata(), }, }, } // 调用 consul 注册接口 return &pb.RegisterReply{}, registry.Register(service, rp.RegisterTTL(time.Duration(ttl)*time.Second)) }
二、客户端改造(java)
1. pom.xml文件中添加 maven 依赖
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>1.7.0</version></dependency><dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.7.0</version></dependency><dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.7.0</version></dependency>
2. pom.xml文件中 配置protobuf maven插件
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.4.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.7.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
3. 定义regist.proto
文件
syntax = "proto3"; package proto; option java_multiple_files = true; option java_package = "com.fiberhome.smartms.grpc"; option java_outer_classname = "RegistProto"; service Regist { rpc Register (ResponseService) returns (RegisterReply) {} rpc Deregister (ResponseService) returns (DeregisterReply) {} } message RegisterReply { string message = 1; } message DeregisterReply { string message = 1; } message ResponseService { string id = 1; string name = 2; string version = 3; string address = 4; int32 port = 5; map<string, string> metadata = 6; }
4. 自动生成java接口代码
在pom.xml文件根目录中,执行mvn compile
(也可试下mvn install
),根据.proto文件自动生成一系列的接口文件。
- 若生成不成功,多试几次
5.客户端代码改造
public class ServiceRegistryGrpc implements ServiceRegistry<Registration> { private static final Logger logger = Logger.getLogger(ServiceRegistryGrpc.class.getName()); private final ManagedChannel channel; private final RegistGrpc.RegistBlockingStub blockingStub; public ServiceRegistryGrpc(String host, int port) { channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build(); blockingStub = RegistGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } @Override public void register(Registration reg) { Service service = reg.getService(); ServiceRegistryGrpc client = new ServiceRegistryGrpc("mos", 9999); ResponseService request = ResponseService.newBuilder().setId(service.getId()).setName(service.getName()) .setVersion(service.getVersion()).setAddress(service.getAddress()).setPort(service.getPort()).build(); RegisterReply response; try { response = blockingStub.register(request); } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } logger.info("Registering service success "); } }
public ServiceRegistryGrpc(String host, int port) {}
,这个函数是构造客户端 连接 服务response = blockingStub.register(request);
,调用服务接口
三、验证
启动服务端
服务端
启动客户端
客户端
数据通信成功
服务端获取客户端 传来的数据
consul注册成功
attachment服务
作者:angeChen
链接:https://www.jianshu.com/p/4e9935b3f721