在前面的文章之中我们介绍了基于Kubernetes及Istio如何一步一步把Service Mesh微服务架构玩起来!在该文章中,我们演示了一个非常贴近实战的案例,这里回顾下该案例的结构,如下图所示:
该案例所演示的就是我们日常使用微服务架构开发时,服务间最普遍的通信场景。在Spring Cloud微服务体系中,服务间可以通过Fegin+Ribbon组合的方式,实现服务间负载均衡方式的Http接口调用;但在Service Mesh架构中,服务发现及负载均衡等治理逻辑已经由SideCar代理,如果还希望延续Spring Cloud场景下服务间接口调用的代码体验,一般可以通过改写Feign组件,去掉其中关于服务治理的逻辑,只保留简单的接口声明式调用逻辑来实现。
上述案例中**“micro-api->micro-order”**之间的服务通信调用,就是基于该方式实现的(可参考之前的文章)。但在微服务架构中除了采用Http协议通信外,对于某些对性能有着更高要求的系统来说,采用通信效率更高的RPC协议往往是更合适的选择!
在基于Spring Cloud框架的微服务体系中,服务之间也可以通过RPC协议通信,但由于服务治理的需要,也需要一套类似于Fegin+Ribbon组合的SDK支持。例如gRPC框架就有针对Spring Boot框架的“grpc-client-spring-boot-starter”依赖支持!该项目是一个 gRPC 的 Spring Boot 模块,可以在 Spring Boot 中内嵌一个 gRPC Server 对外提供服务,并支持 Spring Cloud 的服务发现、注册、链路跟踪等等。
那么在Service Mesh微服务体系下,服务间基于gRPC框架的通信应该怎么实现呢?接下来,我将以案例中**“micro-order->micro-pay”**之间的服务调用为例,演示在Service Mesh微服务架构下实现服务间的gRPC通信调用,并将案例中Http+gRPC服务间通信的完整场景串起来!
gRPC概述
在演示Service Mesh微服务架构下的gRPC通信场景之前,我们先简单介绍下RPC协议及gRPC框架的基本知识。
RPC(Remote Procedure Call),又称远程过程调用,是一种通过掩藏底层网络通信复杂性,从而屏蔽远程和本地调用区别的通信方式。相比于Http协议,RPC协议属于一种自定义的TCP协议,从而在实现时避免了一些Http协议信息的臃肿问题,实现了更高效率的通信。
在主流实现RPC协议的框架中,比较著名的有Dubbo、Thrift及gRPC等。因为目前主流的容器发布平台Kubernetes,以及Service Mesh开源平台Istio都是通过gRPC协议来实现内部组件之间的交互,所以在Service Mesh微服务架构中,服务间通信采用gRPC协议,从某种角度上说会更具有原生优势。况且在此之前,gRPC框架已经在分布式、多语言服务场景中得到了大量应用,因此可以预测在Service Mesh微服务架构场景下,基于gRPC框架的微服务通信方式会逐步成为主流。
gRPC是Google发布的基于HTTP/2.0传输层协议承载的高性能开源软件框架,提供了支持多种编程语言的、对网络设备进行配置和纳管的方法。由于是开源框架,通信的双方可以进行二次开发,所以客户端和服务器端之间的通信会更加专注于业务层面的内容,减少了对由gRPC框架实现的底层通信的关注。
接下来的内容就具体演示在Service Mesh微服务架构下,实现微服务“micro-order->micro-pay”的gRPC通信调用!
构建gRPC服务端程序(micro-pay)
首先从gRPC服务端的角度,在微服务micro-pay项目中集成gRPC-Java,并实现一个gRPC服务端程序。具体如下:
1、构建Spring Boot基本工程(micro-pay/micro-pay-client)
使用Spring Boot框架构建基本的Maven工程,为了工程代码的复用,这里单独抽象一个micro-pay-client工程,并定义micro-pay微服务gRPC服务接口的protobuf文件(*/proto/paycore.proto),代码如下:
syntax = "proto3";
package com.wudimanong.pay.client;
option java_multiple_files = true;
option java_package = "com.wudimanong.micro.pay.proto";
service PayService {
//定义支付rpc方法
rpc doPay (PayRequest) returns (PayResponse);
}
message PayRequest {
string orderId = 1;
int32 amount=2;
}
message PayResponse {
int32 status = 1;
}
如上所示,创建了一个基于protobuf协议的支付接口定义文件,其中定义了支付服务PayService及其中的doPay支付rpc方法,并定义了其请求和返回参数对象,具体的语法遵循“proto3”协议。
为了能够正常编译和生成protobuf文件所定义服务接口的代码,需要在项目pom.xml文件中引入jar包依赖及Maven编译插件配置,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<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">
....
<dependencies>
....
<!--gRPC通信类库(截止目前的最新版本)-->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.36.1</version>
</dependency>
</dependencies>
<build>
<!--引入gRpc框架proto文件编译生产插件-->
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolst