快速了解Service Mesh微服務(wù)架構(gòu)實(shí)現(xiàn)服務(wù)間gRPC通信

在前面的文章之中我們介紹了基于Kubernetes及Istio如何一步一步把Service Mesh微服務(wù)架構(gòu)玩起來(lái)!在該文章中,我們演示了一個(gè)非常貼近實(shí)戰(zhàn)的案例,這里回顧下該案例的結(jié)構(gòu),如下圖所示:

該案例所演示的就是我們?nèi)粘J褂梦⒎?wù)架構(gòu)開(kāi)發(fā)時(shí),服務(wù)間最普遍的通信場(chǎng)景。在Spring Cloud微服務(wù)體系中,服務(wù)間可以通過(guò)Fegin+Ribbon組合的方式,實(shí)現(xiàn)服務(wù)間負(fù)載均衡方式的Http接口調(diào)用;但在Service Mesh架構(gòu)中,服務(wù)發(fā)現(xiàn)及負(fù)載均衡等治理邏輯已經(jīng)由SideCar代理,如果還希望延續(xù)Spring Cloud場(chǎng)景下服務(wù)間接口調(diào)用的代碼體驗(yàn),一般可以通過(guò)改寫(xiě)Feign組件,去掉其中關(guān)于服務(wù)治理的邏輯,只保留簡(jiǎn)單的接口聲明式調(diào)用邏輯來(lái)實(shí)現(xiàn)。

上述案例中“micro-api->micro-order”之間的服務(wù)通信調(diào)用,就是基于該方式實(shí)現(xiàn)的(可參考之前的文章)。但在微服務(wù)架構(gòu)中除了采用Http協(xié)議通信外,對(duì)于某些對(duì)性能有著更高要求的系統(tǒng)來(lái)說(shuō),采用通信效率更高的RPC協(xié)議往往是更合適的選擇!

在基于Spring Cloud框架的微服務(wù)體系中,服務(wù)之間也可以通過(guò)RPC協(xié)議通信,但由于服務(wù)治理的需要,也需要一套類似于Fegin+Ribbon組合的SDK支持。例如gRPC框架就有針對(duì)Spring Boot框架的“grpc-client-spring-boot-starter”依賴支持!該項(xiàng)目是一個(gè) gRPC 的 Spring Boot 模塊,可以在 Spring Boot 中內(nèi)嵌一個(gè) gRPC Server 對(duì)外提供服務(wù),并支持 Spring Cloud 的服務(wù)發(fā)現(xiàn)、注冊(cè)、鏈路跟蹤等等。

那么在Service Mesh微服務(wù)體系下,服務(wù)間基于gRPC框架的通信應(yīng)該怎么實(shí)現(xiàn)呢?接下來(lái),我將以案例中"micro-order->micro-pay"之間的服務(wù)調(diào)用為例,演示在Service Mesh微服務(wù)架構(gòu)下實(shí)現(xiàn)服務(wù)間的gRPC通信調(diào)用,并將案例中Http+gRPC服務(wù)間通信的完整場(chǎng)景串起來(lái)!

gRPC概述

在演示Service Mesh微服務(wù)架構(gòu)下的gRPC通信場(chǎng)景之前,我們先簡(jiǎn)單介紹下RPC協(xié)議及gRPC框架的基本知識(shí)。

RPC(Remote Procedure Call),又稱遠(yuǎn)程過(guò)程調(diào)用,是一種通過(guò)掩藏底層網(wǎng)絡(luò)通信復(fù)雜性,從而屏蔽遠(yuǎn)程和本地調(diào)用區(qū)別的通信方式。相比于Http協(xié)議,RPC協(xié)議屬于一種自定義的TCP協(xié)議,從而在實(shí)現(xiàn)時(shí)避免了一些Http協(xié)議信息的臃腫問(wèn)題,實(shí)現(xiàn)了更高效率的通信。

在主流實(shí)現(xiàn)RPC協(xié)議的框架中,比較著名的有Dubbo、Thrift及gRPC等。因?yàn)槟壳爸髁鞯娜萜靼l(fā)布平臺(tái)Kubernetes,以及Service Mesh開(kāi)源平臺(tái)Istio都是通過(guò)gRPC協(xié)議來(lái)實(shí)現(xiàn)內(nèi)部組件之間的交互,所以在Service Mesh微服務(wù)架構(gòu)中,服務(wù)間通信采用gRPC協(xié)議,從某種角度上說(shuō)會(huì)更具有原生優(yōu)勢(shì)。況且在此之前,gRPC框架已經(jīng)在分布式、多語(yǔ)言服務(wù)場(chǎng)景中得到了大量應(yīng)用,因此可以預(yù)測(cè)在Service Mesh微服務(wù)架構(gòu)場(chǎng)景下,基于gRPC框架的微服務(wù)通信方式會(huì)逐步成為主流。

gRPC是Google發(fā)布的基于HTTP/2.0傳輸層協(xié)議承載的高性能開(kāi)源軟件框架,提供了支持多種編程語(yǔ)言的、對(duì)網(wǎng)絡(luò)設(shè)備進(jìn)行配置和納管的方法。由于是開(kāi)源框架,通信的雙方可以進(jìn)行二次開(kāi)發(fā),所以客戶端和服務(wù)器端之間的通信會(huì)更加專注于業(yè)務(wù)層面的內(nèi)容,減少了對(duì)由gRPC框架實(shí)現(xiàn)的底層通信的關(guān)注。

接下來(lái)的內(nèi)容就具體演示在Service Mesh微服務(wù)架構(gòu)下,實(shí)現(xiàn)微服務(wù)“micro-order->micro-pay”的gRPC通信調(diào)用!

構(gòu)建gRPC服務(wù)端程序(micro-pay)

首先從gRPC服務(wù)端的角度,在微服務(wù)micro-pay項(xiàng)目中集成gRPC-Java,并實(shí)現(xiàn)一個(gè)gRPC服務(wù)端程序。具體如下:

1、構(gòu)建Spring Boot基本工程(micro-pay/micro-pay-client)

使用Spring Boot框架構(gòu)建基本的Maven工程,為了工程代碼的復(fù)用,這里單獨(dú)抽象一個(gè)micro-pay-client工程,并定義micro-pay微服務(wù)gRPC服務(wù)接口的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;
}

如上所示,創(chuàng)建了一個(gè)基于protobuf協(xié)議的支付接口定義文件,其中定義了支付服務(wù)PayService及其中的doPay支付rpc方法,并定義了其請(qǐng)求和返回參數(shù)對(duì)象,具體的語(yǔ)法遵循“proto3”協(xié)議。

為了能夠正常編譯和生成protobuf文件所定義服務(wù)接口的代碼,需要在項(xiàng)目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通信類庫(kù)(截止目前的最新版本)-->
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-all</artifactId>
            <version>1.36.1</version>
        </dependency>
    </dependencies>

    <build>
        <!--引入gRpc框架proto文件編譯生產(chǎn)插件-->
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.6.2</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

這是單獨(dú)關(guān)于gRPC接口proto文件定義的工程,定義后編譯工程,maven就會(huì)根據(jù)前面定義的paycore.proto文件生成gRPC服務(wù)端/客戶端相關(guān)代碼。

完成后,繼續(xù)構(gòu)建micro-pay微服務(wù)的spring boot工程代碼,并在其pom.xml文件中引入上述gRPC協(xié)議文件定義的依賴,例如:

<!--引入支付服務(wù)gRPC ProtoBuf定義依賴-->
<dependency>
    <groupId>com.wudimanong</groupId>
    <artifactId>micro-pay-client</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>       

在micro-pay-client工程中所引入的gRPC相關(guān)的依賴及插件配置會(huì)自動(dòng)繼承至micro-pay工程!

2、編寫(xiě)gRPC支付服務(wù)代碼

在micro-pay代碼工程中創(chuàng)建一個(gè)PayCoreProvider接口代碼,用于表示支付gRPC服務(wù)的入口(類似于Controller),其代碼如下:

package com.wudimanong.micro.pay.provider;

import com.wudimanong.micro.pay.proto.PayRequest;
import com.wudimanong.micro.pay.proto.PayResponse;
import com.wudimanong.micro.pay.proto.PayServiceGrpc;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class PayCoreProvider extends PayServiceGrpc.PayServiceImplBase {
    /**
     * 實(shí)現(xiàn)ProtoBuf中定義的服務(wù)方法
     *
     * @param request
     * @param responseStreamObserver
     */
    @Override
    public void doPay(PayRequest request, StreamObserver<PayResponse> responseStreamObserver) {
        //邏輯處理(簡(jiǎn)單模擬打印日志)
        log.info("處理gRPC支付處理請(qǐng)求,orderId->{};payAmount{}", request.getOrderId(), request.getAmount());
        //構(gòu)建返回對(duì)象(構(gòu)建處理狀態(tài))
        PayResponse response = PayResponse.newBuilder().setStatus(2).build();
        //設(shè)置數(shù)據(jù)響應(yīng)
        responseStreamObserver.onNext(response);
        responseStreamObserver.onCompleted();
    }

}     

上述代碼所引入的一些依賴代碼如PayServiceGrpc等,就是前面定義paycore.proto文件所生成的樁文件代碼!由于只是簡(jiǎn)單測(cè)試,這里僅僅打印了下日志就返回了,如果涉及復(fù)雜業(yè)務(wù)還是可以按照MVC分層架構(gòu)思想進(jìn)行代碼拆分!

3、編寫(xiě)gRPC與Spring Boot框架集成配置代碼

在Spring Cloud微服務(wù)中集成gRPC可以通過(guò)前面提到的“grpc-client-spring-boot-starter”來(lái)實(shí)現(xiàn),但目前還沒(méi)有現(xiàn)成的支持Service Mesh架構(gòu)下的集成SDK,所以這里通過(guò)手工配置定義的方式實(shí)現(xiàn)集成。先創(chuàng)建一個(gè)配置類,代碼如下:

package com.wudimanong.micro.pay.config;

import com.wudimanong.micro.pay.provider.PayCoreProvider;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class GrpcServerConfiguration {

    @Autowired
    PayCoreProvider service;

    /**
     * 注入配置文件中的端口信息
     */
    @Value("${grpc.server-port}")
    private int port;
    private Server server;

    public void start() throws IOException {
        // 構(gòu)建服務(wù)端
        log.info("Starting gRPC on port {}.", port);
        server = ServerBuilder.forPort(port).addService(service).build().start();
        log.info("gRPC server started, listening on {}.", port);

        // 添加服務(wù)端關(guān)閉的邏輯
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("Shutting down gRPC server.");
            GrpcServerConfiguration.this.stop();
            log.info("gRPC server shut down successfully.");
        }));
    }

    private void stop() {
        if (server != null) {
            // 關(guān)閉服務(wù)端
            server.shutdown();
        }
    }

    public void block() throws InterruptedException {
        if (server != null) {
            // 服務(wù)端啟動(dòng)后直到應(yīng)用關(guān)閉都處于阻塞狀態(tài),方便接收請(qǐng)求
            server.awaitTermination();
        }
    }
}  

如上所示,在該配置代碼中,通過(guò)gRPC-Java依賴所提供的Server對(duì)象構(gòu)建了gRPC服務(wù)端啟動(dòng)、停止、阻塞的方法,并在啟動(dòng)時(shí)將前面定義的服務(wù)端類通過(guò)“.addService()”方法進(jìn)行了加入(可考慮封裝更優(yōu)雅的方式)!

為了讓該配置類與Spring Boot集成,再定義一個(gè)集成類,代碼如下:

package com.wudimanong.micro.pay.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class GrpcCommandLineRunner implements CommandLineRunner {

    @Autowired
    GrpcServerConfiguration configuration;

    @Override
    public void run(String... args) throws Exception {
        configuration.start();
        configuration.block();

    }
}

上述代碼會(huì)在Spring Boot應(yīng)用啟動(dòng)時(shí)自動(dòng)加載,其中的邏輯就是啟動(dòng)gRPC服務(wù),并阻塞等待連接!

接下來(lái)在配置文件中定義服務(wù)所開(kāi)啟的gRPC端口,配置如下:

spring:
  application:
    name: micro-pay
server:
  port: 9092

#定義gRPC服務(wù)開(kāi)放的端口
grpc:
  server-port: 18888

該配置所定義的參數(shù)在前面的服務(wù)配置類中引用,表示gRPC服務(wù)開(kāi)啟的端口,這里定義的是18888!

到這里gRPC服務(wù)端工程代碼就構(gòu)建完成了,從整體上看就是Spring Boot+gRPC的集成與整合,這其中沒(méi)有引入Spring Boot定制的gRPC集成SDK,目的在于避免其中所涉及的客戶端服務(wù)治理邏輯(與前面Http調(diào)用不直接引入Open Feign一樣)。

構(gòu)建gRPC客戶端程序(micro-order)

接下來(lái)我們改造micro-order微服務(wù),使其成為調(diào)用micro-pay微服務(wù)的gRPC客戶端程序!

1、引入gRPC客戶端依賴包

引入前面定義micro-pay gRPC服務(wù)時(shí)構(gòu)建的micro-pay-client protobuf工程依賴,代碼如下:

<!--引入支付服務(wù)gRPC ProtoBuf定義依賴-->
<dependency>
    <groupId>com.wudimanong</groupId>
    <artifactId>micro-pay-client</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

2、業(yè)務(wù)邏輯中實(shí)現(xiàn)gRPC服務(wù)調(diào)用

接下來(lái)在micro-order邏輯中調(diào)用gRPC支付服務(wù),代碼示例如下:

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    /**
     * 引入gRPC客戶端配置依賴
     */
    @Autowired
    GrpcClientConfiguration gRpcClent;

    @Override
    public CreateOrderBO create(CreateOrderDTO createOrderDTO) {
        log.info("現(xiàn)在開(kāi)始處理下單請(qǐng)求.....");
        //生成訂單號(hào)
        String orderId = String.valueOf(new Random(100).nextInt(100000) + System.currentTimeMillis());
        //構(gòu)建支付請(qǐng)求(gRPC調(diào)用)
        PayRequest payRequest = PayRequest.newBuilder().setOrderId(orderId).setAmount(createOrderDTO.getAmount())
                .build();
        //使用stub發(fā)送請(qǐng)求到服務(wù)端
        PayResponse payResponse = gRpcClent.getStub().doPay(payRequest);
        log.info("pay gRpc response->" + payResponse.toString());
        return CreateOrderBO.builder().orderId(orderId).status(payResponse.getStatus()).build();
    }
}

如上所示,該業(yè)務(wù)邏輯在接收micro-api通過(guò)Http調(diào)用的請(qǐng)求后,會(huì)在邏輯實(shí)現(xiàn)過(guò)程中通過(guò)gRPC協(xié)議訪問(wèn)支付服務(wù),其中涉及的接口定義代碼,由protobuf文件所定義!

3、gRPC客戶端配置

上述邏輯是通過(guò)定義“GrpcClientConfiguration”gRPC客戶端配置類來(lái)實(shí)現(xiàn)gRPC服務(wù)調(diào)用的,該配置類代碼如下:

@Slf4j
@Component
public class GrpcClientConfiguration {
    /**
     * 支付gRPC Server的地址
     */
    @Value("${server-host}")
    private String host;
    /**
     * 支付gRPC Server的端口
     */
    @Value("${server-port}")
    private int port;

    private ManagedChannel channel;
    /**
     * 支付服務(wù)stub對(duì)象
     */
    private PayServiceGrpc.PayServiceBlockingStub stub;

    public void start() {
        //開(kāi)啟channel
        channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();

        //通過(guò)channel獲取到服務(wù)端的stub
        stub = PayServiceGrpc.newBlockingStub(channel);
        log.info("gRPC client started, server address: {}:{}", host, port);
    }

    public void shutdown() throws InterruptedException {
        //調(diào)用shutdown方法后等待1秒關(guān)閉channel
        channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
        log.info("gRPC client shut down successfully.");
    }

    public PayServiceGrpc.PayServiceBlockingStub getStub() {
        return this.stub;
    }
}

如上所示配置代碼,通過(guò)依服務(wù)配置文件指定的gRPC服務(wù)端地址+端口,實(shí)現(xiàn)對(duì)gRPC客戶端的配置,其中主要包括啟動(dòng)和停止方法,并在啟動(dòng)的過(guò)程中初始化gRPC服務(wù)客戶端的樁代碼的實(shí)例(可考慮更優(yōu)雅地實(shí)現(xiàn))。

在該配置類中所依賴的gRPC服務(wù)端地址+端口配置,依賴于服務(wù)配置文件的定義,代碼如下:

spring:
  application:
    name: micro-order
server:
  port: 9091

#支付微服務(wù)Grpc服務(wù)地址、端口配置
server-host: ${grpc_server_host}
server-port: ${grpc_server_port}

如果是本地測(cè)試可以直接指定grpc_server_host及端口的值,但在Service Mesh微服務(wù)架構(gòu)中,直接在應(yīng)用的配置文件中指定其他微服務(wù)的地址及端口可能并不是很靈活,這個(gè)配置信息將在發(fā)布Kubernetes集群時(shí),通過(guò)Kubernetes發(fā)布文件注入!

為了讓gRPC客戶端配置與Spring Boot集成,這里也需要定義一個(gè)Spring Boot加載類,代碼如下:

@Component
@Slf4j
public class GrpcClientCommandLineRunner implements CommandLineRunner {
    @Autowired
    GrpcClientConfiguration configuration;

    @Override
    public void run(String... args) throws Exception {
        //開(kāi)啟gRPC客戶端
        configuration.start();

        //添加客戶端關(guān)閉的邏輯
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                configuration.shutdown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));
    }
}

該代碼將在Spring Boot應(yīng)用自動(dòng)時(shí)自動(dòng)加載!到這里micro-order gRPC客戶端配置就完成了!

將部署服務(wù)至Service Mesh架構(gòu)環(huán)境

前面基于“micro-order->micro-pay”微服務(wù)間的gRPC調(diào)用場(chǎng)景,分別將兩個(gè)微服務(wù)改造成了gRPC服務(wù)端/客戶端。但此時(shí)從代碼上是很難看出來(lái)它們二者之間應(yīng)該怎么實(shí)現(xiàn)調(diào)用!而這也恰恰就印證了Service Mesh架構(gòu)的優(yōu)勢(shì),服務(wù)的發(fā)現(xiàn)、及負(fù)載均衡調(diào)用之類的服務(wù)治理邏輯,已經(jīng)完全不用微服務(wù)自己管了!

在Istio中,它們是基于Kubernetes的Service發(fā)現(xiàn)機(jī)制+Istio-proxy(SideCar代理)來(lái)實(shí)現(xiàn)的。而具體的操作就是通過(guò)微服務(wù)Kubernetes服務(wù)發(fā)布文件的定義,接下來(lái)分別定義micro-order及micro-pay的Kubernetes發(fā)布文件。

先看下作為gRPC服務(wù)端的micro-pay的發(fā)布文件(micro-pay.yaml),代碼如下:

apiVersion: v1
kind: Service
metadata:
  name: micro-pay
  labels:
    app: micro-pay
    service: micro-pay
spec:
  type: ClusterIP
  ports:
    - name: http
      #容器暴露端口
      port: 19092
      #目標(biāo)應(yīng)用端口
      targetPort: 9092
    #設(shè)置gRPC端口
    - name: grpc
      port: 18888
      targetPort: 18888
  selector:
    app: micro-pay

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-pay-v1
  labels:
    app: micro-pay
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: micro-pay
      version: v1
  template:
    metadata:
      labels:
        app: micro-pay
        version: v1
    spec:
      containers:
        - name: micro-pay
          image: 10.211.55.2:8080/micro-service/micro-pay:1.0-SNAPSHOT
          imagePullPolicy: Always
          tty: true
          ports:
            - name: http
              protocol: TCP
              containerPort: 19092
            #指定服務(wù)gRPC端口
            - name: grpc
              protocol: TCP
              containerPort: 18888

如上所示k8s發(fā)布文件,主要是定義了Service服務(wù)訪問(wèn)資源及Deployment容器編排資源,這兩種資源都是Kubernetes的資源類型,在容器編排資源和服務(wù)資源中分別定義了gRPC的訪問(wèn)端口,通過(guò)這種設(shè)置,后續(xù)gRPC客戶端通過(guò)Service資源訪問(wèn)服務(wù)時(shí),就能夠進(jìn)行端口映射了!

而其他配置則是基本的Kubernetes發(fā)布部署邏輯,其中涉及的鏡像,需要在發(fā)布之前,通過(guò)構(gòu)建的方式對(duì)項(xiàng)目進(jìn)行Docker鏡像打包并上傳私有鏡像倉(cāng)庫(kù)(如果有疑問(wèn),可以參考本號(hào)之前的文章)。

接下來(lái)繼續(xù)看看作為gRPC客戶端的micro-order微服務(wù)的k8s發(fā)布文件(micro-order.yaml),代碼如下:

apiVersion: v1
kind: Service
metadata:
  name: micro-order
  labels:
    app: micro-order
    service: micro-order
spec:
  type: ClusterIP
  ports:
    - name: http
      #此處設(shè)置80端口的原因在于改造的Mock FeignClient代碼默認(rèn)是基于80端口進(jìn)行服務(wù)調(diào)用
      port: 80
      targetPort: 9091
  selector:
    app: micro-order

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-order-v1
  labels:
    app: micro-order
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: micro-order
      version: v1
  template:
    metadata:
      labels:
        app: micro-order
        version: v1
    spec:
      containers:
        - name: micro-order
          image: 10.211.55.2:8080/micro-service/micro-order:1.0-SNAPSHOT
          imagePullPolicy: Always
          tty: true
          ports:
            - name: http
              protocol: TCP
              containerPort: 19091
          #環(huán)境參數(shù)設(shè)置(設(shè)置微服務(wù)返回gRPC服務(wù)端的地址+端口)
          env:
            - name: GRPC_SERVER_HOST
              value: micro-pay
            - name: GRPC_SERVER_PORT
              value: "18888"

在該發(fā)布文件中,需要說(shuō)明的主要就是通過(guò)容器env環(huán)境參數(shù)的設(shè)置,指定了之前gRPC客戶端服務(wù)配置中所依賴的參數(shù)變量“GRPC_SERVER_HOST及GRPC_SERVER_PORT”,其中服務(wù)地址就是micro-pay微服務(wù)在Kubernetes中Service資源定義的名稱,端口則是gRPC服務(wù)端所開(kāi)啟的端口。

這樣在gRPC客戶端在Kubernetes集群中根據(jù)Service名稱發(fā)起微服務(wù)調(diào)用時(shí),Kubernetes集群自身的服務(wù)發(fā)現(xiàn)邏輯就能自動(dòng)將請(qǐng)求映射到相應(yīng)的Pod資源了!這其實(shí)就是Service Mesh微服務(wù)架構(gòu)服務(wù)發(fā)現(xiàn)的基本邏輯!

接下來(lái)將微服務(wù)進(jìn)行發(fā)布,這里假設(shè)你已經(jīng)部署了一套Kubernetes集群并安裝了基于Istio的Service Mesh微服務(wù)架構(gòu)環(huán)境,最終的部署效果如下所示:

root@kubernetes:/opt/istio/istio-1.8.4# kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
micro-api-6455654996-9lsxr        2/2     Running   2          43m
micro-order-v1-744d469d84-rnqq8   2/2     Running   0          6m28s
micro-order-v1-744d469d84-vsn5m   2/2     Running   0          6m28s
micro-pay-v1-7fd5dd4768-txq9d     2/2     Running   0          43s
micro-pay-v1-7fd5dd4768-wqw6b     2/2     Running   0          43s

如上所示,可以看到案例所涉及的微服務(wù)都被部署了,并且對(duì)應(yīng)的SideCar代理(istio-proxy)也被正常啟動(dòng)了!為了演示負(fù)載均衡效果,這里micro-order及micro-pay都分別被部署了兩個(gè)副本!

微服務(wù)多副本負(fù)載均衡調(diào)用演示

如果環(huán)境都沒(méi)啥問(wèn)題,此時(shí)可以通過(guò)調(diào)用Istio Gateway來(lái)訪問(wèn)micro-api服務(wù),然后micro-api服務(wù)會(huì)通過(guò)Http的方式訪問(wèn)micro-order服務(wù),之后micro-order服務(wù)通過(guò)gRPC協(xié)議調(diào)用micro-pay服務(wù)。

通過(guò)curl命令訪問(wèn)Istio Gateway網(wǎng)關(guān)服務(wù),效果如下:

curl -H "Content-Type:application/json" -H "Data_Type:msg" -X POST --data '{"businessId": "202012102", "amount": 100, "channel": 2}' http://10.211.55.12:30844/api/order/create

如果正常返回響應(yīng)結(jié)果,則說(shuō)明上述調(diào)用鏈路走通了!此時(shí)分別通過(guò)觀察服務(wù)的業(yè)務(wù)日志和istio-proxy代理日志來(lái)加以觀測(cè)!

其中micro-pay兩個(gè)實(shí)例(PodA~PodB)業(yè)務(wù)日志信息:

//支付微服務(wù)接口訪問(wèn)日志(POD-A)
root@kubernetes:~# kubectl logs micro-pay-v1-7fd5dd4768-txq9d micro-pay
 ....

2021-04-01 14:46:15.818  INFO 1 --- [           main] c.w.m.p.config.GrpcServerConfiguration   : Starting gRPC on port 18888.
2021-04-01 14:46:18.859  INFO 1 --- [           main] c.w.m.p.config.GrpcServerConfiguration   : gRPC server started, listening on 18888.
2021-04-01 15:07:36.709  INFO 1 --- [ault-executor-0] c.w.micro.pay.provider.PayCoreProvider   : 處理gRPC支付處理請(qǐng)求,orderId->1617289656289;payAmount100


//支付微服務(wù)接口訪問(wèn)日志(POD-B)
root@kubernetes:~# kubectl logs micro-pay-v1-7fd5dd4768-wqw6b micro-pay
...

2021-04-01 15:34:59.673  INFO 1 --- [           main] c.w.m.p.config.GrpcServerConfiguration   : Starting gRPC on port 18888.
2021-04-01 15:35:06.175  INFO 1 --- [           main] c.w.m.p.config.GrpcServerConfiguration   : gRPC server started, listening on 18888.
2021-04-01 15:40:22.019  INFO 1 --- [ault-executor-0] c.w.micro.pay.provider.PayCoreProvider   : 處理gRPC支付處理請(qǐng)求,orderId->1617291624127;payAmount100
2021-04-01 15:44:31.630  INFO 1 --- [ault-executor-2] c.w.micro.pay.provider.PayCoreProvider   : 處理gRPC支付處理請(qǐng)求,orderId->1617291867537;payAmount100

可以看到,多次訪問(wèn)接口,基于gRPC的微服務(wù)調(diào)用也實(shí)現(xiàn)了負(fù)載均衡調(diào)用!接下來(lái)分別看下這兩個(gè)微服務(wù)的istio-proxy(SideCar代理)的日志,具體如下:

--istio-proxy代理日志(POD-A)
root@kubernetes:~# kubectl logs micro-pay-v1-7fd5dd4768-txq9d istio-proxy
...

2021-04-01T15:34:48.009972Z    info    Envoy proxy is ready
[2021-04-01T15:40:26.240Z] "POST /com.wudimanong.pay.client.PayService/doPay HTTP/2" 200 - "-" 22 7 498 477 "-" "grpc-java-netty/1.36.1" "8eb318e5-ac09-922d-9ca7-603a5c14bdd5" "micro-pay:18888" "127.0.0.1:18888" inbound|18888|| 127.0.0.1:57506 10.32.0.10:18888 10.32.0.12:36844 outbound_.18888_._.micro-pay.default.svc.cluster.local default
2021-04-01T15:45:18.377555Z    info    xdsproxy    disconnected 

...
[2021-04-01T15:45:34.885Z] "POST /com.wudimanong.pay.client.PayService/doPay HTTP/2" 200 - "-" 22 7 1200 171 "-" "grpc-java-netty/1.36.1" "c08d540e-db46-9228-b381-0808ac08377e" "micro-pay:18888" "127.0.0.1:18888" inbound|18888|| 127.0.0.1:33218 10.32.0.10:18888 10.32.0.2:42646 outbound_.18888_._.micro-pay.default.svc.cluster.local default

...
2021-04-01T15:52:49.825955Z    info    xdsproxy    connecting to upstream XDS server: istiod.istio-system.svc:15012

如上所示,可以看到istio-proxy代理日志中顯示了通過(guò)post方式轉(zhuǎn)發(fā)gRPC服務(wù)的情況,而且可以看出gRRPC是采用Http/2實(shí)現(xiàn)的!

后記

本文通過(guò)實(shí)戰(zhàn)案例,演示了在Service Mesh微服務(wù)架構(gòu)下,服務(wù)間通過(guò)gRPC協(xié)議實(shí)現(xiàn)通信調(diào)用的場(chǎng)景!

歡迎大家關(guān)注我的公眾號(hào)【風(fēng)平浪靜如碼】,海量Java相關(guān)文章,學(xué)習(xí)資料都會(huì)在里面更新,整理的資料也會(huì)放在里面。

覺(jué)得寫(xiě)的還不錯(cuò)的就點(diǎn)個(gè)贊,加個(gè)關(guān)注唄!點(diǎn)關(guān)注,不迷路,持續(xù)更新!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容