资讯专栏INFORMATION COLUMN

gRPC实现跨语言的微服务间通信 -- 精通外语的电报员与煲电报粥的小怪兽

waltr / 1999人阅读

摘要:插画牛肉框架小怪兽的电报员一旦系统怪物被拆分成了多个服务小怪兽,小怪兽们如何沟通协作就成了我们最关心的问题。插画牛肉实现客户端小怪兽发送今晚的月色真美,服务端小怪兽收到电报内容,并回复。

作者:亚瑟、文远

1. 微服务框架 -- 从系统怪物到服务小怪兽

一个小巧的单体应用会随着公司业务的扩张而慢慢成长,逐渐演化成一个庞大且复杂的系统怪物,系统任何一处的问题都将影响整个怪物的表现,很少有多带带的开发者能理清系统怪物所有的肌理脉络,导致bug的定位和新功能的扩展都变得越来越困难,对系统的任一改动都要求整个怪物一起回归测试并重新部署,效率必然不高。所以公司发展到了一定阶段,总会需要从架构上寻找解决系统怪物之道,而微服务就是目前最流行的架构方案之一,它将系统怪物拆分成多个独立自治的服务小怪兽,让我们有能力分而治之。


插画:牛肉

2. RPC框架 -- 小怪兽的电报员

一旦系统怪物被拆分成了多个服务小怪兽,小怪兽们如何沟通协作就成了我们最关心的问题。服务小怪兽间的通信就好像发电报一样,涉及到数据序列化、反序列化、连接管理、收发线程、超时处理等多个问题,RPC框架的出现解决了这些问题,就好像通过电报员发电报一样,使用RPC框架让小怪兽们不必关心通信的底层细节。


插画:牛肉

RPC调用细节

服务消费方(小怪兽A)以本地调用方式调用服务

client stub(小怪兽A的电报员)接受到调用后负责将方法、参数等编码成能够进行网络传输的消息体(电报)

client stub(小怪兽A的电报员)找到服务地址,并将消息发送到服务端

server stub(小怪兽B的电报员)收到消息(电报)后进行解码

server stub(小怪兽B的电报员)根据解码结果调用本地的服务(小怪兽B)

本地服务(小怪兽B)执行并将结果返回给server stub(小怪兽B的电报员)

server stub(小怪兽B的电报员)将结果编码成消息(电报)并发送至客户端

client stub(小怪兽A的电报员)接受到消息(电报)并进行解码

服务消费方(小怪兽A)得到最终的结果

3. gRPC -- 这位电报员是语言天才

如果通信的小怪兽们语言不通,那么我们需要对电报员(亦即RPC框架)的人选提出更高的要求,无论小怪兽们用的是什么语言,协助通信的两位电报员都必须把它们的话翻译成电报员彼此能理解的同一种语言,亦即IDL(Interface Description Language),是的,电报员在这种情况下还必须承担翻译的角色,而gRPC就是一位如此优秀的电报员。


插画:牛肉

4. gRPC Demo

实现Node客户端小怪兽发送"今晚的月色真美",Java服务端小怪兽收到电报内容,并回复"I love you too"。

通过Spring Boot创建Java项目,pom.xml中加入如下依赖


    
        org.springframework.boot
        spring-boot-starter
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
        io.grpc
        grpc-netty-shaded
        1.21.0
    
    
        io.grpc
        grpc-protobuf
        1.21.0
    
    
        io.grpc
        grpc-stub
        1.21.0
    



    
        
            kr.motd.maven
            os-maven-plugin
            1.5.0.Final
        
    
    
        
            org.xolstice.maven.plugins
            protobuf-maven-plugin
            0.5.1
            
                com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}
                grpc-java
                io.grpc:protoc-gen-grpc-java:1.21.0:exe:${os.detected.classifier}
                
                src/main/java
                
                false
            
            
                
                    
                        compile
                        compile-custom
                    
                
            
        
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    

定义IDL文件

syntax = "proto3";

option java_multiple_files = true;
option java_package = "net.changjinglu.proto";
option java_outer_classname = "TelegraphProto";

package telegraph;

// The greeting service definition.
service TelegraphService {
    // Sends a greeting
    rpc SayLove (LoveRequest) returns (LoveReply) {}
}

// The request message containing the user"s name.
message LoveRequest {
    string message = 1;
}

// The response message containing the greetings
message LoveReply {
    string message = 1;
}

编译生成IDL定义的Java服务接口,相关代码会生成到配置对应的路径下

mvn clean install


 

实现IDL定义的Java服务接口

public class TelegraphGreeterImpl extends TelegraphServiceGrpc.TelegraphServiceImplBase {

    @Override
    public void sayLove(LoveRequest request, StreamObserver responseObserver) {
        System.out.println("收到Node小怪兽的消息:"+request.getMessage());

        responseObserver.onNext(LoveReply.newBuilder().setMessage("I Love U Too").build());

        //结束
        responseObserver.onCompleted();
    }
}

编写并启动Java服务端

public class GrpcServer {

    /** GRPC 服务端 */
    private Server server;

    public static void main(String[] args) throws IOException, InterruptedException {
        GrpcServer grpcService = new GrpcServer();

        grpcService.start();
        System.out.println("GRPC 服务端启动成功");

        //GRPC 服务端需要手动阻塞线程
        grpcService.waitTermination();


    }

    private void start() throws IOException {
        //绑定接口、启动服务
        this.server = ServerBuilder.forPort(8899)
                .addService(new TelegraphGreeterImpl())
                .build()
                .start();

        System.out.println("server start!");

        //这里是为了防止jvm关闭了,但是tcp还没有关闭的情况
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            System.out.println("关闭jvm");
            GrpcServer.this.stop();
        }));
    }

    private void stop() {
        if (this.server != null) {
            this.server.shutdown();
        }
    }

    private void waitTermination() throws InterruptedException {

        if (this.server != null) {
            server.awaitTermination();
        }
    }
}


 

编写并启动Nodejs客户端,客户端使用相同的IDL

var PROTO_FILE_PATH = "/Users/wenyuan/Nodejs/grpc/proto/telegraph.proto";
var grpc = require("grpc");
var grpcService = grpc.load(PROTO_FILE_PATH).telegraph;


function main() {
    var stub = new grpcService.TelegraphService("localhost:8899",grpc.credentials.createInsecure());

    stub.sayLove({message:"今晚的月色真美"},function (error, result) {
        console.log("收到Java小怪兽的消息: " + result.message);
    });
}

main();

Java服务端收到消息并回复

 

Nodejs客户端收到Java服务端的回复

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74701.html

相关文章

  • [零基础学Python]坑爹字符编码

    摘要:所以,哪怕是初学者,都要了解并能够解决字符编码问题。在这个世界上,有好多不同的字符编码。目前最新的版本为,已收入超过十万个字符第十万个字符在年获采纳。涵盖的数据除了视觉上的字形编码方法标准的字符编码外,还包含了字符特性,如大小写字母。 字符编码,在编程中,是一个让学习者比较郁闷的东西,比如一个str,如果都是英文,好说多了。但恰恰不是如此,中文是我们不得不用的。所以,哪怕是初学者,都要...

    rozbo 评论0 收藏0
  • 重学计算机组成原理(十一)- 门电路"千里传音"

    摘要:公元前年,在雅典附近的马拉松海边,发生了波斯和希腊之间的希波战争。因为电报员要熟记每一个字母对应的摩尔斯电码,并且需要快速按键来进行输入。 showImg(https://image-static.segmentfault.com/548/184/548184927-5d5962191cbce_articlex); 人用纸和笔来做运算,都是用十进制,直接用十进制和我们最熟悉的符号不是最...

    Shihira 评论0 收藏0
  • 【历史上今天】10 月 12 日:C 语言之父逝世;西门子诞生;乔布斯推出 NeXT 电脑

    摘要:月日发生了许多关键事件,西门子的建立面向对象编程之父英特尔和之父的出生乔布斯推出语言之父的逝世,无一不在影响着今天的科技进程。年月日,达尔在与淋巴癌的长期斗争中逝世,享年岁。年月日,英特尔公司公告称,公司前保罗欧德宁在睡梦中去世,享年岁。 ...

    Neilyo 评论0 收藏0
  • 用Node.js查询余票信息并用邮件通知

    摘要:因为自己在学校还有些事情,不知道具体哪天回家,于是就自己写了一个监控的小程序一功能命令行输入火车站名和日期,修改查询周期定时器时间,即可实现周期性的余票查询并用邮件通知二流程概述命令行输入信息利用信息,发起请求,查询余票信息使用模块来发送邮 因为自己在学校还有些事情,不知道具体哪天回家,于是就自己写了一个监控的小程序 一.功能: 命令行输入火车站名和日期,修改查询周期(定时器时间),即...

    tuomao 评论0 收藏0
  • Telegram(电报)代理MTproxy一键脚本

    摘要:原文链接写一个专门用于搭建代理的脚本支持版本如何使用复制到服务器中自动编译安装输入用于客服端连接的端口号可以直接自动生成输入一个位进制的密码用于客服端用来验证服务器,回车自动生成完成安装客服端链接到代理服务器可以手动输入地址,端口 原文链接 https://github.com/shellhub/b... 写一个专门用于搭建Telegram代理MTProxy的脚本 https://gi...

    suosuopuo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<