RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务。
为微服务时代,rpc是常用的技术方案,区别于单体服务内的本地调用,rpc需要解决的是不同进程间的调用,往往会是跨机器调用(区别于同一机器下通道等IPC解决方案),跨机器主要解决的是网络通讯。
那么跨机器的网络通讯方式主要通过TCP/IP,而rpc更多关注的是应用层的协议。常用的RPC通讯协议有json(http)、二进制(grpc、dubbo)。
json的话便于解析,但需要占用带宽。
二进制的话需要特殊的解析过程,带宽占用小,但又依赖协议解析性能,解析过程也叫:序列化、反序列化
grpc是谷歌出品的二进制通讯框架
A high-performance, open source universal RPC framework。开源高性能RPC框架
gRPC基于HTTP/2协议标准设计,采用protobuf序列化开发,且支持多种开发语言。在gRPC里客户端可以像调用本地对象一样直接调用另一台不通的机器上服务端应用的方法,使得更容易地创建分布式应用和服务。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>ECRS_jav_demoartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>io.grpcgroupId>
<artifactId>grpc-netty-shadedartifactId>
<version>1.16.1version>
dependency>
<dependency>
<groupId>io.grpcgroupId>
<artifactId>grpc-protobufartifactId>
<version>1.16.1version>
dependency>
<dependency>
<groupId>io.grpcgroupId>
<artifactId>grpc-stubartifactId>
<version>1.16.1version>
dependency>
dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.mavengroupId>
<artifactId>os-maven-pluginartifactId>
<version>1.5.0.Finalversion>
extension>
extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.pluginsgroupId>
<artifactId>protobuf-maven-pluginartifactId>
<version>0.5.1version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}protocArtifact>
<pluginId>grpc-javapluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.16.1:exe:${os.detected.classifier}pluginArtifact>
configuration>
<executions>
<execution>
<goals>
<goal>compilegoal>
<goal>compile-customgoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
在src/main/proto/下新建xx.proto文件,这是实现跨语言的关键,python和Java都使用这个文件。传输过程中通过该文件进行序列化和反序列化
as.proto
// as.proto
syntax = "proto3";
import "item_info.proto";
import "user_info.proto";
package as;
option cc_generic_services = false;
message ASRequest{
string log_id = 1;
string user_id = 2;
user_info.UserInfo user_info = 3;
}
message ASResponse {
message Error {
uint32 code = 1;
string text = 2;
}
Error error = 1;
repeated item_info.ItemInfo item_infos = 2;
}
service ASService {
rpc as_call(ASRequest) returns (ASResponse);
};
item_info.proto
syntax = "proto3";
package item_info;
message ItemInfo {
string sku_id = 1;
string brand = 2;
string shopid = 3;
string cate = 4;
float rank_score = 5;
}
user_info.proto
// user_info.proto
syntax = "proto3";
package user_info;
message UserInfo {
string user_id = 1;
string age = 2;
string sex = 3;
string city_level = 4;
string province = 5;
string city = 6;
string country = 7;
}
然后在控制台输入
mvn compile
Client.java
package as;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import item_info.ItemInfoOuterClass;
import user_info.UserInfoOuterClass;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author jingyi
* @Classname Client
* @description TODO
* @date 2022/5/6 15:30
*/
public class Client {
private final ManagedChannel channel;
private final ASServiceGrpc.ASServiceBlockingStub blockingStub;
/**
* Construct client connecting to HelloWorld server at {@code host:port}.
*/
public Client(String host, int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();
blockingStub = ASServiceGrpc.newBlockingStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
/**
* Say hello to server.
*/
public void ApplicationServer(String uid) {
As.ASRequest request = As.ASRequest.newBuilder().setUserId(uid).build();
As.ASResponse response;
try {
response = blockingStub.asCall(request);
} catch (StatusRuntimeException e) {
System.out.println("RPC failed: {0}"+ e.getStatus());
return;
}
System.out.println("Application服务结果为:");
System.out.println(response.getError());
List<ItemInfoOuterClass.ItemInfo> list = response.getItemInfosList();
for (ItemInfoOuterClass.ItemInfo item:list){
System.out.println(item);
}
}
public void ApplicationServer(String uid,String age,String sex,String city_level,String province,String city,String country) {
UserInfoOuterClass.UserInfo.Builder builder = UserInfoOuterClass.UserInfo.newBuilder().setUserId(uid).setAge(age).setSex(sex).setCityLevel(city_level).setProvince(province).setCity(city).setCountry(country);
As.ASRequest request = As.ASRequest.newBuilder().setUserInfo(builder).build();
As.ASResponse response;
try {
response = blockingStub.asCall(request);
} catch (StatusRuntimeException e) {
System.out.println("RPC failed: {0}"+ e.getStatus());
return;
}
System.out.println("Application服务结果为:");
System.out.println(response.getError());
List<ItemInfoOuterClass.ItemInfo> list = response.getItemInfosList();
for (ItemInfoOuterClass.ItemInfo item:list){
System.out.println(item);
}
}
/**
* Greet server. If provided, the first element of {@code args} is the name to use in the
* greeting.
*/
public static void main(String[] args) throws Exception {
Client client = new Client("127.0.0.1", 8930);
try {
client.ApplicationServer(String.valueOf(0),String.valueOf(1),String.valueOf(0),String.valueOf(2),String.valueOf(2),String.valueOf(348),String.valueOf(741));
//client.ApplicationServer(String.valueOf(1));
} finally {
client.shutdown();
}
}
}
def get_as(request):
channel = grpc.insecure_channel("127.0.0.1:8930")
stub = as_pb2_grpc.ASServiceStub(channel)
response = stub.as_call(request)
return response
if __name__ == "__main__":
if sys.argv[1] == 'as':
start=time.process_time()
req = as_pb2.ASRequest()
if len(sys.argv) == 3:
uid = sys.argv[2]
req.user_id = uid
else:
age = sys.argv[2]
sex = sys.argv[3]
city_level = sys.argv[4]
province = sys.argv[5]
city = sys.argv[6]
country = sys.argv[7]
req.user_info.user_id, req.user_info.age, req.user_info.sex, req.user_info.city_level, req.user_info.province, req.user_info.city, req.user_info.country = "0", age, sex, city_level , province, city, country
print(get_as(req))
end=time.process_time()
print('as service response time:'+str(end-start))