golang 基于 gRPC 的服務(wù)間通信示例

基于 gRPC 的服務(wù)間通信示例

示例說(shuō)明,存在兩個(gè)服務(wù),訂單服務(wù)和產(chǎn)品服務(wù)。其中:

  • 訂單服務(wù)提供 HTTP 接口,用于完成訂單查詢。訂單中包含產(chǎn)品信息,要利用 grpc 從產(chǎn)品服務(wù)獲取產(chǎn)品信息
  • 產(chǎn)品服務(wù)提供 grpc 接口,用于響應(yīng)微服務(wù)內(nèi)部產(chǎn)品信息查詢

本例中,對(duì)于 grpc 來(lái)說(shuō),產(chǎn)品服務(wù)為服務(wù)端、訂單服務(wù)為客戶端。

同時(shí)不考慮其他業(yè)務(wù)邏輯,例如產(chǎn)品服務(wù)也需要對(duì)外提供 http 接口等,僅在乎 grpc 的通信示例。同時(shí)不考慮服務(wù)發(fā)現(xiàn)和網(wǎng)關(guān)等。

image.png

編碼實(shí)現(xiàn):

一:基于之前定義的 .proto 文件生成 pb.go 文件

注意,客戶端和服務(wù)端,都需要使用生成的 pb.go 文件

二:實(shí)現(xiàn)訂單服務(wù)

orderService/httpService.go

package main

import (
    "context"
    "encoding/json"
    "flag"
    "fmt"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "log"
    "net/http"
    "orderService/protos/codes"
    "time"
)

var (
    // 目標(biāo) grpc 服務(wù)器地址
    gRPCAddr = flag.String("grpc", "localhost:50051", "the address to connect to")
    // http 命令行參數(shù)
    addr = flag.String("addr", "127.0.0.1", "The Address for listen. Default is 127.0.0.1")
    port = flag.Int("port", 8080, "The Port for listen. Default is 8080.")
)

func main() {
    flag.Parse()
    // 連接 grpc 服務(wù)器
    conn, err := grpc.Dial(*gRPCAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    // 實(shí)例化 grpc 客戶端
    c := codes.NewProductClient(conn)

    // 定義業(yè)務(wù)邏輯服務(wù),假設(shè)為產(chǎn)品服務(wù)
    service := http.NewServeMux()
    service.HandleFunc("/orders", func(writer http.ResponseWriter, request *http.Request) {
        // 調(diào)用 grpc 方法,完成對(duì)服務(wù)器資源請(qǐng)求
        ctx, cancel := context.WithTimeout(context.Background(), time.Second)
        defer cancel()
        r, err := c.ProductInfo(ctx, &codes.ProductInfoRequest{
            Int64: 42,
        })
        if err != nil {
            log.Fatalln(err)
        }

        resp := struct {
            ID       int                          `json:"id"`
            Quantity int                          `json:"quantity"`
            Products []*codes.ProductInfoResponse `json:"products"`
        }{
            9527, 1,
            []*codes.ProductInfoResponse{
                r,
            },
        }
        respJson, err := json.Marshal(resp)
        if err != nil {
            log.Fatalln(err)
        }
        writer.Header().Set("Content-Type", "application/json")
        _, err = fmt.Fprintf(writer, "%s", string(respJson))
        if err != nil {
            log.Fatalln(err)
        }
    })

    // 啟動(dòng)監(jiān)聽(tīng)
    address := fmt.Sprintf("%s:%d", *addr, *port)
    fmt.Printf("Order service is listening on %s.\n", address)
    log.Fatalln(http.ListenAndServe(address, service))
}

三,實(shí)現(xiàn)產(chǎn)品服務(wù)

productService/grpcService.go

package main

import (
    "context"
    "flag"
    "fmt"
    "google.golang.org/grpc"
    "log"
    "net"
    "productService/protos/compiles"
)

//grpc 監(jiān)聽(tīng)端口
var port = flag.Int("port", 50051, "The server port")

// ProductServer 實(shí)現(xiàn) UnimplementedProductServer
type ProductServer struct {
    compiles.UnimplementedProductServer
}

func (ProductServer) ProductInfo(ctx context.Context, pr *compiles.ProductInfoRequest) (*compiles.ProductInfoResponse, error) {
    return &compiles.ProductInfoResponse{
        Name:   "馬士兵 Go 云原生",
        Int64:  42,
        IsSale: true,
    }, nil
}

func main() {
    flag.Parse()
    //設(shè)置 tcp 監(jiān)聽(tīng)器
    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    // 新建 grpc Server
    s := grpc.NewServer()
    // 將 ProductServer 注冊(cè)到 grpc Server 中
    compiles.RegisterProductServer(s, ProductServer{})
    log.Printf("server listening at %v", lis.Addr())
    // 啟動(dòng)監(jiān)聽(tīng)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

測(cè)試,訪問(wèn) order 的 http 接口。獲取訂單信息中,包含產(chǎn)品信息。

gRPC 核心概念

服務(wù)定義

與許多 RPC 系統(tǒng)一樣,gRPC 基于定義服務(wù)的思想,指定可以遠(yuǎn)程調(diào)用的方法及其參數(shù)和返回類(lèi)型。默認(rèn)情況下,gRPC 使用 Protocol Buffer 作為接口定義語(yǔ)言 (IDL) 來(lái)描述服務(wù)接口和有效負(fù)載消息的結(jié)構(gòu)。

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}

gRPC 支持定義四種服務(wù)方法:

  • 一元 RPC,其中客戶端向服務(wù)器發(fā)送單個(gè)請(qǐng)求并獲得單個(gè)響應(yīng),就像正常的函數(shù)調(diào)用一樣。
rpc SayHello(HelloRequest) returns (HelloResponse);
  • 服務(wù)器流式 RPC,其中客戶端向服務(wù)器發(fā)送請(qǐng)求并獲取流以讀回一系列消息??蛻舳藦姆祷氐牧髦凶x取,直到?jīng)]有更多消息為止。 gRPC 保證單個(gè) RPC 調(diào)用中的消息順序。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
  • 客戶端流式 RPC,其中客戶端寫(xiě)入一系列消息并將它們發(fā)送到服務(wù)器,再次使用提供的流。一旦客戶端完成了消息的寫(xiě)入,它就會(huì)等待服務(wù)器讀取它們并返回它的響應(yīng)。 gRPC 再次保證了單個(gè) RPC 調(diào)用中的消息順序。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
  • 雙向流式 RPC,雙方使用讀寫(xiě)流發(fā)送一系列消息。這兩個(gè)流獨(dú)立運(yùn)行,因此客戶端和服務(wù)器可以按照他們喜歡的任何順序讀取和寫(xiě)入:例如,服務(wù)器可以在寫(xiě)入響應(yīng)之前等待接收所有客戶端消息,或者它可以交替讀取消息然后寫(xiě)入消息,或其他一些讀取和寫(xiě)入的組合。保留每個(gè)流中消息的順序。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
使用 API

.proto 文件中的服務(wù)定義開(kāi)始,gRPC 提供了生成客戶端和服務(wù)器端代碼的 Protocol Buffer 編譯器插件。 gRPC 用戶通常在客戶端調(diào)用這些 API,并在服務(wù)器端實(shí)現(xiàn)相應(yīng)的 API。

  • 在服務(wù)端,服務(wù)端實(shí)現(xiàn)服務(wù)聲明的方法,并運(yùn)行一個(gè) gRPC 服務(wù)器來(lái)處理客戶端調(diào)用。 gRPC 基礎(chǔ)架構(gòu)解碼傳入請(qǐng)求、執(zhí)行服務(wù)方法并編碼服務(wù)響應(yīng)。
  • 在客戶端,客戶端有一個(gè)稱(chēng)為存根的本地對(duì)象(對(duì)于某些語(yǔ)言,首選術(shù)語(yǔ)是客戶端),它實(shí)現(xiàn)與服務(wù)相同的方法。然后客戶端可以在本地對(duì)象上調(diào)用這些方法,將調(diào)用的參數(shù)包裝在適當(dāng)?shù)膮f(xié)議緩沖區(qū)消息類(lèi)型中——gRPC 負(fù)責(zé)將請(qǐng)求發(fā)送到服務(wù)器并返回服務(wù)器的協(xié)議緩沖區(qū)響應(yīng)。
同步與異步

在接收到服務(wù)端響應(yīng)之前阻塞的同步 RPC 調(diào)用最接近 RPC 所希望的過(guò)程調(diào)用的抽象。另一方面,網(wǎng)絡(luò)本質(zhì)上是異步的,在許多情況下,能夠在不阻塞當(dāng)前線程的情況下啟動(dòng) RPC 是很有用的。

大多數(shù)語(yǔ)言中的 gRPC 編程 API 有同步和異步兩種風(fēng)格。

gRPC 生命周期

生命周期指的是 gRPC 客戶端調(diào)用 gRPC 服務(wù)端方法的過(guò)程。區(qū)別于不同的4種服務(wù)定義,過(guò)程如下:

一元 RPC

首先考慮最簡(jiǎn)單的 RPC 類(lèi)型,其中客戶端發(fā)送單個(gè)請(qǐng)求并返回單個(gè)響應(yīng)。

  1. 一旦客戶端調(diào)用了一個(gè)存根方法,服務(wù)器就會(huì)被通知該 RPC 已被調(diào)用,其中包含該調(diào)用的客戶端元數(shù)據(jù)、方法名稱(chēng)和指定的截止日期(如果適用)。
  2. 然后,服務(wù)器可以立即發(fā)回自己的初始元數(shù)據(jù)(必須在任何響應(yīng)之前發(fā)送),或者等待客戶端的請(qǐng)求消息。首先發(fā)生的是特定于應(yīng)用程序的。
  3. 一旦服務(wù)器收到客戶端的請(qǐng)求消息,它就會(huì)執(zhí)行任何必要的工作來(lái)創(chuàng)建和填充響應(yīng)。然后將響應(yīng)連同狀態(tài)詳細(xì)信息(狀態(tài)代碼和可選狀態(tài)消息)和可選尾隨元數(shù)據(jù)一起返回(如果成功)給客戶端。
  4. 如果響應(yīng)狀態(tài)為 OK,則客戶端得到響應(yīng),從而完成客戶端的調(diào)用。
服務(wù)器流式 RPC

服務(wù)器流式 RPC 類(lèi)似于一元 RPC,除了服務(wù)器返回消息流以響應(yīng)客戶端的請(qǐng)求。發(fā)送所有消息后,服務(wù)器的狀態(tài)詳細(xì)信息(狀態(tài)代碼和可選狀態(tài)消息)和可選的尾隨元數(shù)據(jù)將發(fā)送到客戶端。這樣就完成了服務(wù)器端的處理。客戶端在擁有所有服務(wù)器消息后完成。

客戶端流式 RPC

客戶端流式 RPC 類(lèi)似于一元 RPC,不同之處在于客戶端向服務(wù)器發(fā)送消息流而不是單個(gè)消息。服務(wù)器響應(yīng)一條消息(連同其狀態(tài)詳細(xì)信息和可選的尾隨元數(shù)據(jù)),通常但不一定是在它收到所有客戶端的消息之后。

雙向流式 RPC

在雙向流式 RPC 中,調(diào)用由調(diào)用方法的客戶端和接收客戶端元數(shù)據(jù)、方法名稱(chēng)和截止日期的服務(wù)器發(fā)起。服務(wù)器可以選擇發(fā)回其初始元數(shù)據(jù)或等待客戶端開(kāi)始流式傳輸消息。

客戶端和服務(wù)器端流處理是特定于應(yīng)用程序的。由于這兩個(gè)流是獨(dú)立的,客戶端和服務(wù)器可以以任意順序讀寫(xiě)消息。例如,服務(wù)器可以等到它收到客戶端的所有消息后再寫(xiě)入它的消息,或者服務(wù)器和客戶端可以玩 “ping-pong”——服務(wù)器收到請(qǐng)求,然后發(fā)回響應(yīng),然后客戶端發(fā)送基于響應(yīng)的另一個(gè)請(qǐng)求,依此類(lèi)推。

截止日期/超時(shí)

gRPC 允許客戶端指定在 RPC 因 DEADLINE_EXCEEDED 錯(cuò)誤而終止之前,他們?cè)敢獾却?RPC 完成多長(zhǎng)時(shí)間。在服務(wù)器端,服務(wù)器可以查詢特定的 RPC 是否已超時(shí),或者還剩多少時(shí)間來(lái)完成 RPC。

指定期限或超時(shí)是特定于語(yǔ)言的:一些語(yǔ)言 API 根據(jù)超時(shí)(持續(xù)時(shí)間)工作,而一些語(yǔ)言 API 根據(jù)期限(固定時(shí)間點(diǎn))工作,可能有也可能沒(méi)有默認(rèn)期限。

RPC 終止

在 gRPC 中,客戶端和服務(wù)器都對(duì)調(diào)用是否成功做出獨(dú)立的本地判斷,并且它們的結(jié)論可能不匹配。這意味著,例如,您可能有一個(gè) RPC 在服務(wù)器端成功完成(“我已經(jīng)發(fā)送了所有響應(yīng)!”)但在客戶端失敗(“響應(yīng)在我的截止日期之后到達(dá)!”)。服務(wù)器也可以在客戶端發(fā)送所有請(qǐng)求之前決定完成。

取消 RPC

客戶端或服務(wù)器都可以隨時(shí)取消 RPC。取消會(huì)立即終止 RPC,以便不再進(jìn)行任何工作。

Protocol buffer 語(yǔ)法參考

消息類(lèi)型定義

以一個(gè)簡(jiǎn)單的請(qǐng)求消息為例:

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

首先指定版本 proto3,否則編譯器默認(rèn)為 proto2。版本指定為文件的第一非空白、非注釋行。

message 關(guān)鍵字用于定義消息,需要指定消息類(lèi)型的名稱(chēng)。

消息由多個(gè)名稱(chēng)/值對(duì)組成,稱(chēng)為字段,每個(gè)字段要指定名字和類(lèi)型。string、int32 是典型的標(biāo)量類(lèi)型,除了標(biāo)量類(lèi)型 protobuf 還支持構(gòu)造類(lèi)型,例如枚舉或其他消息類(lèi)型。

應(yīng)該為每個(gè)字段分配唯一的字段序號(hào),用于在二進(jìn)制編碼中標(biāo)識(shí)該字段。序號(hào)范圍1-15會(huì)消耗1個(gè)字節(jié)的存儲(chǔ),16-2047 會(huì)消耗2個(gè)字節(jié)。因此應(yīng)該將常用的字段分配1-15字段序號(hào)。編號(hào)全部的范圍是1到2^29-1,其中19000到19999是 proto編譯器保留序號(hào),不要使用。

消息的字段分為單一和重復(fù)兩種規(guī)則:

  • 單一 Singular,proto3 中字段的默認(rèn)規(guī)則。一個(gè)消息中僅可以包含0或1個(gè)該字段,就是字段不能重復(fù)。
  • 重復(fù)的 repeated,該規(guī)則說(shuō)明此字段可以重復(fù)多次(包含0次)。重復(fù)值的順序是保留的。
message SearchRequest {
  // 同上略
  repeated string keywords = 4
}

.proto 文件支持 C/C++ 風(fēng)格的注釋 ///* ... */

標(biāo)量類(lèi)型

標(biāo)量消息字段可以具有以下類(lèi)型之一。該表顯示了 .proto 文件中指定的類(lèi)型,以及自動(dòng)生成的類(lèi)中的相應(yīng)類(lèi)型:

.proto Type 說(shuō)明 Go Type
double float64
float float32
int32 變長(zhǎng)編碼,對(duì)負(fù)數(shù)進(jìn)行編碼效率低下。若字段可能有負(fù)值,請(qǐng)改用 sint32 int32
int64 變長(zhǎng)編碼,對(duì)負(fù)數(shù)進(jìn)行編碼效率低下。若字段可能有負(fù)值,請(qǐng)改用 sint64 int64
uint32 變長(zhǎng)編碼 uint32
uint64 變長(zhǎng)編碼 uint64
sint32 變長(zhǎng)編碼,帶符號(hào)的 int 值。這些比常規(guī) int32 更有效地編碼負(fù)數(shù) int32
sint64 變長(zhǎng)編碼,帶符號(hào)的 int 值。這些比常規(guī) int64 更有效地編碼負(fù)數(shù) int64
fixed32 固定4個(gè)字節(jié),如果值通常大于 2^28,則比 uint32 更有效 uint32
fixed64 固定8個(gè)字節(jié),如果值通常大于 2^56,則比 uint64 更有效 uint64
sfixed32 固定4個(gè)字節(jié) int32
sfixed64 固定8個(gè)字節(jié) int64
bool bool
string 始終包含 UTF-8 編碼或 7 位 ASCII 文本,并且長(zhǎng)度不能超過(guò) 2^32 string
bytes 可以包含不超過(guò) 2^32 的任意字節(jié)序列 []byte

解析消息時(shí),如果編碼的消息不包含特定元素,則解析對(duì)象中的相應(yīng)字段將設(shè)置為該字段的默認(rèn)值。這些默認(rèn)值是基于類(lèi)型的:

  • 對(duì)于字符串,默認(rèn)值為空字符串。
  • 對(duì)于字節(jié),默認(rèn)值為空字節(jié)。
  • 對(duì)于布爾值,默認(rèn)值為 false。
  • 對(duì)于數(shù)字類(lèi)型,默認(rèn)值為零。
  • 對(duì)于枚舉,默認(rèn)值是第一個(gè)定義的枚舉值,必須為 0。
  • 對(duì)于消息字段,未設(shè)置該字段。它的確切值取決于語(yǔ)言。有關(guān)詳細(xì)信息,請(qǐng)參閱生成的代碼指南。
  • 重復(fù)字段的默認(rèn)值為空(通常是相應(yīng)語(yǔ)言的空列表)。

枚舉值

在定義消息類(lèi)型時(shí),您可能希望其字段之一僅具有預(yù)定義的值列表之一。例如,假設(shè)您要為每個(gè) SearchRequest 添加一個(gè) corpus 字段,其中值可以是 UNIVERSAL、WEB、IMAGES、LOCAL、NEWS、PRODUCTS 或 VIDEO。您可以通過(guò)在消息定義中添加一個(gè)枚舉來(lái)非常簡(jiǎn)單地做到這一點(diǎn),每個(gè)可能的值都有一個(gè)常量。

message SearchRequest {
  // 同上略
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 4;
}

枚舉值列表的第一常量值必須為0,這樣可以更好的處理默認(rèn)值。(也為了向下兼容)

也可以為同一個(gè)枚舉值分配不同的常量,稱(chēng)為別名。需要使用選項(xiàng) option allow_alias = true 來(lái)啟用別名設(shè)置:

message MyMessage1 {
  enum EnumAllowingAlias {
    option allow_alias = true;
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 1;
  }
}

保留值

當(dāng)某些字段不再使用時(shí),例如更新消息類(lèi)型時(shí)移除了某些字段,為了防止其他人重新使用了之前的字段名或字段序號(hào)而導(dǎo)致邏輯混亂的問(wèn)題,可以把這些不用的字段設(shè)置為保留字段,關(guān)鍵字 reserved 用來(lái)設(shè)置:

enum Foo {
  reserved 2, 15, 9 to 11, 40 to max;
  reserved "FOO", "BAR";
}

這樣,以上的序號(hào)和字段名就不能后續(xù)使用了,避免了邏輯混亂。

使用其他消息類(lèi)型

可以使用其他消息類(lèi)型作為字段類(lèi)型。例如:

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

可以將不同類(lèi)型的消息定義在不同的 .proto 文件中,需要時(shí)導(dǎo)入進(jìn)來(lái):

import "myproject/other_protos.proto";

未知字段

未知字段是格式良好的 Protocol Buffer 序列化數(shù)據(jù),表示解析器無(wú)法識(shí)別的字段。例如,當(dāng)舊二進(jìn)制文件用新字段解析新二進(jìn)制文件發(fā)送的數(shù)據(jù)時(shí),這些新字段將成為舊二進(jìn)制文件中的未知字段。

最初,proto3 消息在解析過(guò)程中總是丟棄未知字段,但在 3.5 版本中,我們重新引入了保留未知字段以匹配 proto2 行為。在 3.5 及更高版本中,未知字段在解析期間保留并包含在序列化輸出中。

Any

Any 消息類(lèi)型允許您將消息用作嵌入類(lèi)型,而無(wú)需定義它們的 .proto。 Any 包含作為 Bytes 的任意序列化消息,以及充當(dāng)全局唯一標(biāo)識(shí)符并解析為該消息類(lèi)型的 URL。要使用 Any 類(lèi)型,您需要導(dǎo)入 google/protobuf/any.proto。

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  repeated google.protobuf.Any details = 2;
}

Oneof

如果您有一條包含多個(gè)字段的消息,并且最多同時(shí)設(shè)置一個(gè)字段,您可以強(qiáng)制執(zhí)行此行為并使用 oneof 功能節(jié)省內(nèi)存。

message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}

Map

如果您想創(chuàng)建關(guān)聯(lián)映射作為數(shù)據(jù)定義的一部分,protocol buffers 提供了一種方便的快捷語(yǔ)法:

map<key_type, value_type> map_field = N;

例如:

map<string, Project> projects = 3;

Packages

您可以將可選的 package 說(shuō)明符添加到 .proto 文件中,以防止協(xié)議消息類(lèi)型之間的名稱(chēng)沖突。

package foo.bar;
message Open { ... }

在 GO 中,該軟件包被用作 GO 軟件包名稱(chēng),除非您在 .proto 文件中明確提供 option go_package

服務(wù)定義

如果您想在 RPC(遠(yuǎn)程過(guò)程調(diào)用)系統(tǒng)中使用您的消息類(lèi)型,您可以在 .proto 文件中定義一個(gè) RPC 服務(wù)接口,并且協(xié)議緩沖區(qū)編譯器將以您選擇的語(yǔ)言生成服務(wù)接口代碼和存根。因此,例如,如果您想使用獲取 SearchRequest 并返回 SearchResponse 的方法定義 RPC 服務(wù),您可以在 .proto 文件中定義它,如下所示:

service SearchService {
  rpc Search(SearchRequest) returns (SearchResponse);
}

與 Proto Buffers 一起使用的最直接的 RPC 系統(tǒng)是 gRPC:由 Google 開(kāi)發(fā)的一種語(yǔ)言和平臺(tái)中立的開(kāi)源 RPC 系統(tǒng)。 gRPC 特別適用于協(xié)議緩沖區(qū),并允許您使用特殊的協(xié)議緩沖區(qū)編譯器插件直接從 .proto 文件生成相關(guān)的 RPC 代碼。

選項(xiàng)

.proto 文件中支持定義選項(xiàng)。全部的選項(xiàng)定義在 google/protobuf/descriptor.proto 中。

例如我們使用 option go_package 選項(xiàng)來(lái)控制生成的 go 代碼所在的 package。

Protocol buffer 語(yǔ)法指導(dǎo)

消息隊(duì)列

事件驅(qū)動(dòng)

API 網(wǎng)關(guān)

API 網(wǎng)關(guān)介紹

image.png

API 網(wǎng)關(guān)是客戶端訪問(wèn)服務(wù)的統(tǒng)一入口,API 網(wǎng)關(guān)封裝了后端服務(wù)。核心功能是轉(zhuǎn)發(fā)請(qǐng)求,基于客戶端請(qǐng)求的 Host、Method、Path 將請(qǐng)求轉(zhuǎn)發(fā)到目標(biāo)服務(wù)上??梢越鉀Q客戶端直接訪問(wèn)后端服務(wù)的入口不統(tǒng)一的問(wèn)題,尤其是在微服務(wù)時(shí)代,網(wǎng)關(guān)尤其重要,否則如下圖所示:

image.png

現(xiàn)代的 API 網(wǎng)關(guān),除了具備基本的轉(zhuǎn)發(fā)功能外,通常還具有:

  • 多協(xié)議支持:tcp,http、https、websock、gRPC
  • 負(fù)載均衡
  • 身份驗(yàn)證
  • 監(jiān)控、日志
  • 緩存
  • 熔斷、限流

等核心功能。目前市場(chǎng)上比較知名的 API 網(wǎng)關(guān)有:

  • Netflix Zuul,spring cloud 的一個(gè)推薦組件,java 系首選
  • Kong 是基于Nginx+Lua 進(jìn)行二次開(kāi)發(fā)的實(shí)現(xiàn),社區(qū)比較活躍
  • Tyk Go編寫(xiě),社區(qū)版相對(duì)薄弱
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容