主頁 > 後端開發 > 快速了解Service Mesh微服務架構實作服務間gRPC通信

快速了解Service Mesh微服務架構實作服務間gRPC通信

2021-04-08 07:24:57 後端開發

在前面的文章之中我們介紹了基于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.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>

這是單獨關于gRPC介面proto檔案定義的工程,定義后編譯工程,maven就會根據前面定義的paycore.proto檔案生成gRPC服務端/客戶端相關代碼,

完成后,繼續構建micro-pay微服務的spring boot工程代碼,并在其pom.xml檔案中引入上述gRPC協議檔案定義的依賴,例如:

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

在micro-pay-client工程中所引入的gRPC相關的依賴及插件配置會自動繼承至micro-pay工程!

2、撰寫gRPC支付服務代碼

在micro-pay代碼工程中創建一個PayCoreProvider介面代碼,用于表示支付gRPC服務的入口(類似于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 {
    /**
     * 實作ProtoBuf中定義的服務方法
     *
     * @param request
     * @param responseStreamObserver
     */
    @Override
    public void doPay(PayRequest request, StreamObserver<PayResponse> responseStreamObserver) {
        //邏輯處理(簡單模擬列印日志)
        log.info("處理gRPC支付處理請求,orderId->{};payAmount{}", request.getOrderId(), request.getAmount());
        //構建回傳物件(構建處理狀態)
        PayResponse response = PayResponse.newBuilder().setStatus(2).build();
        //設定資料回應
        responseStreamObserver.onNext(response);
        responseStreamObserver.onCompleted();
    }

}     

上述代碼所引入的一些依賴代碼如PayServiceGrpc等,就是前面定義paycore.proto檔案所生成的樁檔案代碼!由于只是簡單測驗,這里僅僅列印了下日志就回傳了,如果涉及復雜業務還是可以按照MVC分層架構思想進行代碼拆分!

3、撰寫gRPC與Spring Boot框架集成配置代碼

在Spring Cloud微服務中集成gRPC可以通過前面提到的“grpc-client-spring-boot-starter”來實作,但目前還沒有現成的支持Service Mesh架構下的集成SDK,所以這里通過手工配置定義的方式實作集成,先創建一個配置類,代碼如下:

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 {
        // 構建服務端
        log.info("Starting gRPC on port {}.", port);
        server = ServerBuilder.forPort(port).addService(service).build().start();
        log.info("gRPC server started, listening on {}.", port);

        // 添加服務端關閉的邏輯
        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) {
            // 關閉服務端
            server.shutdown();
        }
    }

    public void block() throws InterruptedException {
        if (server != null) {
            // 服務端啟動后直到應用關閉都處于阻塞狀態,方便接收請求
            server.awaitTermination();
        }
    }
}  

如上所示,在該配置代碼中,通過gRPC-Java依賴所提供的Server物件構建了gRPC服務端啟動、停止、阻塞的方法,并在啟動時將前面定義的服務端類通過“.addService()”方法進行了加入(可考慮封裝更優雅的方式)!

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

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();

    }
}

上述代碼會在Spring Boot應用啟動時自動加載,其中的邏輯就是啟動gRPC服務,并阻塞等待連接!

接下來在組態檔中定義服務所開啟的gRPC埠,配置如下:

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

#定義gRPC服務開放的埠
grpc:
  server-port: 18888

該配置所定義的引數在前面的服務配置類中參考,表示gRPC服務開啟的埠,這里定義的是18888!

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

構建gRPC客戶端程式(micro-order)

接下來我們改造micro-order微服務,使其成為呼叫micro-pay微服務的gRPC客戶端程式!

1、引入gRPC客戶端依賴包

引入前面定義micro-pay gRPC服務時構建的micro-pay-client protobuf工程依賴,代碼如下:

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

2、業務邏輯中實作gRPC服務呼叫

接下來在micro-order邏輯中呼叫gRPC支付服務,代碼示例如下:

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

    @Override
    public CreateOrderBO create(CreateOrderDTO createOrderDTO) {
        log.info("現在開始處理下單請求.....");
        //生成訂單號
        String orderId = String.valueOf(new Random(100).nextInt(100000) + System.currentTimeMillis());
        //構建支付請求(gRPC呼叫)
        PayRequest payRequest = PayRequest.newBuilder().setOrderId(orderId).setAmount(createOrderDTO.getAmount())
                .build();
        //使用stub發送請求到服務端
        PayResponse payResponse = gRpcClent.getStub().doPay(payRequest);
        log.info("pay gRpc response->" + payResponse.toString());
        return CreateOrderBO.builder().orderId(orderId).status(payResponse.getStatus()).build();
    }
}

如上所示,該業務邏輯在接收micro-api通過Http呼叫的請求后,會在邏輯實作程序中通過gRPC協議訪問支付服務,其中涉及的介面定義代碼,由protobuf檔案所定義!

3、gRPC客戶端配置

上述邏輯是通過定義“GrpcClientConfiguration”gRPC客戶端配置類來實作gRPC服務呼叫的,該配置類代碼如下:

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

    private ManagedChannel channel;
    /**
     * 支付服務stub物件
     */
    private PayServiceGrpc.PayServiceBlockingStub stub;

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

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

    public void shutdown() throws InterruptedException {
        //呼叫shutdown方法后等待1秒關閉channel
        channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
        log.info("gRPC client shut down successfully.");
    }

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

如上所示配置代碼,通過依服務組態檔指定的gRPC服務端地址+埠,實作對gRPC客戶端的配置,其中主要包括啟動和停止方法,并在啟動的程序中初始化gRPC服務客戶端的樁代碼的實體(可考慮更優雅地實作),

在該配置類中所依賴的gRPC服務端地址+埠配置,依賴于服務組態檔的定義,代碼如下:

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

#支付微服務Grpc服務地址、埠配置
server-host: ${grpc_server_host}
server-port: ${grpc_server_port}

如果是本地測驗可以直接指定grpc_server_host及埠的值,但在Service Mesh微服務架構中,直接在應用的組態檔中指定其他微服務的地址及埠可能并不是很靈活,這個配置資訊將在發布Kubernetes集群時,通過Kubernetes發布檔案注入!

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

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

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

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

該代碼將在Spring Boot應用自動時自動加載!到這里micro-order gRPC客戶端配置就完成了!

將部署服務至Service Mesh架構環境

前面基于“micro-order->micro-pay”微服務間的gRPC呼叫場景,分別將兩個微服務改造成了gRPC服務端/客戶端,但此時從代碼上是很難看出來它們二者之間應該怎么實作呼叫!而這也恰恰就印證了Service Mesh架構的優勢,服務的發現、及負載均衡呼叫之類的服務治理邏輯,已經完全不用微服務自己管了!

在Istio中,它們是基于Kubernetes的Service發現機制+Istio-proxy(SideCar代理)來實作的,而具體的操作就是通過微服務Kubernetes服務發布檔案的定義,接下來分別定義micro-order及micro-pay的Kubernetes發布檔案,

先看下作為gRPC服務端的micro-pay的發布檔案(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
      #目標應用埠
      targetPort: 9092
    #設定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
            #指定服務gRPC埠
            - name: grpc
              protocol: TCP
              containerPort: 18888

如上所示k8s發布檔案,主要是定義了Service服務訪問資源及Deployment容器編排資源,這兩種資源都是Kubernetes的資源型別,在容器編排資源和服務資源中分別定義了gRPC的訪問埠,通過這種設定,后續gRPC客戶端通過Service資源訪問服務時,就能夠進行埠映射了!

而其他配置則是基本的Kubernetes發布部署邏輯,其中涉及的鏡像,需要在發布之前,通過構建的方式對專案進行Docker鏡像打包并上傳私有鏡像倉庫(如果有疑問,可以參考本號之前的文章),

接下來繼續看看作為gRPC客戶端的micro-order微服務的k8s發布檔案(micro-order.yaml),代碼如下:

apiVersion: v1
kind: Service
metadata:
  name: micro-order
  labels:
    app: micro-order
    service: micro-order
spec:
  type: ClusterIP
  ports:
    - name: http
      #此處設定80埠的原因在于改造的Mock FeignClient代碼默認是基于80埠進行服務呼叫
      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
          #環境引數設定(設定微服務回傳gRPC服務端的地址+埠)
          env:
            - name: GRPC_SERVER_HOST
              value: micro-pay
            - name: GRPC_SERVER_PORT
              value: "18888"

在該發布檔案中,需要說明的主要就是通過容器env環境引數的設定,指定了之前gRPC客戶端服務配置中所依賴的引數變數“GRPC_SERVER_HOST及GRPC_SERVER_PORT”,其中服務地址就是micro-pay微服務在Kubernetes中Service資源定義的名稱,埠則是gRPC服務端所開啟的埠,

這樣在gRPC客戶端在Kubernetes集群中根據Service名稱發起微服務呼叫時,Kubernetes集群自身的服務發現邏輯就能自動將請求映射到相應的Pod資源了!這其實就是Service Mesh微服務架構服務發現的基本邏輯!

接下來將微服務進行發布,這里假設你已經部署了一套Kubernetes集群并安裝了基于Istio的Service Mesh微服務架構環境,最終的部署效果如下所示:

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

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

微服務多副本負載均衡呼叫演示

如果環境都沒啥問題,此時可以通過呼叫Istio Gateway來訪問micro-api服務,然后micro-api服務會通過Http的方式訪問micro-order服務,之后micro-order服務通過gRPC協議呼叫micro-pay服務,

通過curl命令訪問Istio Gateway網關服務,效果如下:

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

如果正常回傳回應結果,則說明上述呼叫鏈路走通了!此時分別通過觀察服務的業務日志和istio-proxy代理日志來加以觀測!

其中micro-pay兩個實體(PodA~PodB)業務日志資訊:

//支付微服務介面訪問日志(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支付處理請求,orderId->1617289656289;payAmount100


//支付微服務介面訪問日志(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支付處理請求,orderId->1617291624127;payAmount100
2021-04-01 15:44:31.630  INFO 1 --- [ault-executor-2] c.w.micro.pay.provider.PayCoreProvider   : 處理gRPC支付處理請求,orderId->1617291867537;payAmount100

可以看到,多次訪問介面,基于gRPC的微服務呼叫也實作了負載均衡呼叫!接下來分別看下這兩個微服務的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代理日志中顯示了通過post方式轉發gRPC服務的情況,而且可以看出gRRPC是采用Http/2實作的!

后記

本文通過實戰案例,演示了在Service Mesh微服務架構下,服務間通過gRPC協議實作通信呼叫的場景!

歡迎大家關注我的公眾號【風平浪靜如碼】,海量Java相關文章,學習資料都會在里面更新,整理的資料也會放在里面,

覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/273517.html

標籤:其他

上一篇:[SpringCloud教程]3. Eureka服務注冊中心集成

下一篇:python你TM太皮了——區區30行代碼就能記錄鍵盤的一舉一動

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more