
gRPC 是由 Google 主導(dǎo)開發(fā)的 RPC 框架,使用 HTTP/2 協(xié)議并用 ProtoBuf 作為序列化工具。
gRPC官方對(duì)REST的聲音是:
- 和REST一樣遵循HTTP協(xié)議(明確的說(shuō)是HTTP/2),但是gRPC提供了全雙工流
- 和傳統(tǒng)的REST不同的是gRPC使用了靜態(tài)路徑,從而提高性能
- 用一些格式化的錯(cuò)誤碼代替了HTTP的狀態(tài)碼更好的標(biāo)示錯(cuò)誤
背景
regist 是在微服務(wù)架構(gòu)上再抽出的一層,用于服務(wù)注冊(cè),心跳機(jī)制,服務(wù)注銷。
regist 和 微服務(wù)架構(gòu) 之間使用的是 REST 協(xié)議進(jìn)行通信,現(xiàn)需要改造成 gRPC
RPC 框架: gRPC
協(xié)議:HTTP/2
序列化工具: ProtoBuf
服務(wù)端: regist (golang)
客戶端 :微服務(wù)架構(gòu)(java)
一、服務(wù)端改造(golang)
1. protocal buffer安裝
去官網(wǎng)下載 protoc 壓縮包,解壓后,將 protoc.exe放在 GOPATH\bin目錄下面
2. 安裝GoLang protoc 插件
gRPC-go可以通過(guò)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,默認(rèn)為2。 - 定義了一個(gè)服務(wù) Regist,其中有兩個(gè)API
Register和Register。 - 定義3個(gè)message為接受和返回的參數(shù)。
4. 生成 register.pb.go 文件
在register.proto文件所在根目錄下,執(zhí)行:
protoc --go_out=plugins=grpc:. register.proto
則會(huì)在同目錄下生成對(duì)應(yīng)的 register.pb.go 文件,相應(yīng)的服務(wù)器端和客戶端的GoLang代碼。生成的代碼中包含了客戶端能夠進(jìn)行RPC的方法以及服務(wù)器端需要進(jìn)行實(shí)現(xiàn)的接口。
5.服務(wù)端代碼改造
-
register.pb.go文件中提供的服務(wù)接口
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)
}
- 服務(wù)端代碼實(shí)現(xiàn)上面的接口
func (s *server) Register(ctx context.Context, in *pb.ResponseService) (*pb.RegisterReply, error) {
// 定義注冊(cè)的服務(wù),組裝 gRPC 傳過(guò)來(lái)的參數(shù)
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(),
},
},
}
// 調(diào)用 consul 注冊(cè)接口
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. 自動(dòng)生成java接口代碼
在pom.xml文件根目錄中,執(zhí)行mvn compile(也可試下mvn install),根據(jù).proto文件自動(dòng)生成一系列的接口文件。
- 若生成不成功,多試幾次
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) {},這個(gè)函數(shù)是構(gòu)造客戶端 連接 服務(wù)response = blockingStub.register(request);,調(diào)用服務(wù)接口
三、驗(yàn)證
-
啟動(dòng)服務(wù)端
服務(wù)端 -
啟動(dòng)客戶端
客戶端 -
數(shù)據(jù)通信成功
服務(wù)端獲取客戶端 傳來(lái)的數(shù)據(jù)
-
consul注冊(cè)成功
attachment服務(wù)



