gRPC实现微服务之间的跨语言通信——一个精通外语的电报员和煮电报粥的小怪兽一个单一的应用会随着公司业务的扩大而缓慢增长,逐渐演化成一个庞大的、复杂的系统怪物。系统出现任何问题都会影响整个怪兽的性能,很少有独立开发者能够解决的。系统怪物的所有纹理使定位错误和扩展新功能变得越来越困难。系统的任何改动都需要整个怪物一起重新测试和重新部署,这势必效率低下。因此,当公司发展到一定阶段,总会想办法从架构上解决系统这个怪物,而微服务是目前最流行的架构解决方案之一。它将系统怪物拆分成多个独立自治的服务怪物,让我们具备了分而治之的能力。图解:牛2.RPC框架——小怪兽的电报员一旦系统怪兽被拆分成多个服务小怪兽,小怪兽之间如何沟通、协作就成了我们最关心的问题。服务怪物之间的通信就像发电报一样,涉及到数据序列化、反序列化、连接管理、收发线程、超时处理等多个问题,RPC框架的出现解决了这些问题,就像通过电报员送电一样报道称,RPC框架的使用让小怪兽不用关心通信的底层细节。图解:牛RPC调用详解服务消费者(小怪兽A)以本地调用的方式调用服务客户端存根(小怪兽A的电报员),负责将方法、参数等编码成消息体,可以被调用收到调用后通过网络传输(Telegram)clientstub(小怪兽A的电报员)找到服务地址,将消息发送给serverserverstub(小怪兽B的电报员)解码消息(telegram)serverstub(小怪B的电报)收到消息后,根据解码结果,调用本地服务(小怪B)执行本地服务(小怪B),返回结果给serverstub(小怪B的电报)operator)serverstub(小怪兽B的电报员)将结果编码形成消息(telegram)发送给客户端怪物A)得到最终结果3.gRPC——电报员他是个语言天才。如果通信怪兽不懂语言,那么我们就需要对电报员(即RPC框架)的候选人提出更高的要求。不管怪物们使用什么语言,这两个协助沟通的电报员都必须将他们的话翻译成电报员能够互相听懂的同一种语言,即IDL(InterfaceDescriptionLanguage)。是的,在这种情况下,电报员也必须承担翻译的角色,而gRPC就是这样一个优秀的电报员。图解:牛4.gRPCDemo实现Node客户端小怪兽发送“今晚的月光好美”,Java服务器端小怪兽收到电报内容回复“我也爱你”。通过SpringBoot创建Java项目,pom.xml中加入如下依赖org.springframework.bootspring-boot-starterorg.springframework.bootspring-boot-starter-test测试io.grpcgrpc-netty-shaded<版本>1.21.0io.grpcgrpc-protobuf1.21.0io.grpcgrpc-stub<版本>1.21.0版本>kr.motd.mavenos-maven-plugin1.5.0.Finalorg.xolstice.maven.pluginsprotobuf-maven-plugin0.5.1com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}grpc-javaio.grpc:protoc-gen-grpc-java:1.21.0:exe:${os.detected.classifier}src/main/javafalsecompilecompile-customorg.springframework.bootspring-boot-maven-plugin定义IDL文件syntax="proto3";选项java_multiple_files=true;选项java_package="net.changjinglu.proto";选项java_outer_classname="TelegraphProto";packagetelegraph;//问候语服务定义.serviceTelegraphService{//发送问候语rpcSayLove(LoveRequest)returns(LoveReply){}}//包含用户名的请求消息.messageLoveRequest{stringmessage=1;}//包含greetingsmessageLoveReply的响应消息{stringmessage=1;}编译生成IDL定义的Java服务接口,相关代码会在配置对应的路径下生成mvncleaninstall实现Java服务IDL定义的接口publicclassTelegraphGreeterImplextendsTelegraphServiceGrpc.TelegraphServiceImplBase{@OverridepublicvoidsayLove(LoveRequestrequest,StreamObserverresponseObserver){System.out.println("ReceivedthemessagefromNodemonster:"+request.getMessage());responseObserver.onNext(LoveReply.newBuilder().setMessage("ILoveUToo").build());//EndresponseObserver.onCompleted();}}编写并启动Java服务器publicclassGrpcServer{/**GRPC服务器*/privateServer服务器;publicstaticvoidmain(String[]args)通过wsIOException,InterruptedException{GrpcServergrpcService=newGrpcServer();grpcService.start();System.out.println("GRPC服务器启动成功");//GRPCserver需要手动阻塞线程grpcService.waitTermination();}privatevoidstart()throwsIOException{//绑定接口,启动服务this.server=ServerBuilder.forPort(8899).addService(newTelegraphGreeterImpl()).build().start();System.out.println("服务器启动!");//这里是为了防止jvm关闭,但是tcp还没有关闭Runtime.getRuntime().addShutdownHook(newThread(()->{System.out.println("Closejvm");GrpcServer.this。停止();}));}privatevoidstop(){if(this.server!=null){this.server.shutdown();}}privatevoidwaitTermination()throwsInterruptedException{if(this.server!=null){server.awaitTermination();}}}编写并启动Nodejs客户端,客户端使用相同的IDLvarPROTO_FILE_PATH='/Users/wenyuan/Nodejs/grpc/proto/telegraph.proto';vargrpc=require('grpc');vargrpcService=grpc.load(PROTO_FILE_PATH).telegraph;functionmain(){varstub=newgrpcService.TelegraphService('localhost:8899',grpc.credentials.createInsecure());stub.sayLove({message:'今晚的月光好美'},function(error,result){console.log('收到了java怪物的消息:'+result.message);});}main();Java服务器收到消息并回复Nodejs客户端收到Java服务器的回复