Kitex 基礎(chǔ)教程

2022-04-26 13:31 更新

關(guān)于 Kitex

Kitex 是一個(gè) RPC 框架,既然是 RPC,底層就需要兩大功能:

  1. Serialization 序列化
  2. Transport 傳輸

Kitex 框架及命令行工具,默認(rèn)支持 ?thrift ?和 ?proto3 ?兩種 IDL,對應(yīng)的 Kitex 支持 ?thrift ?和 ?protobuf ?兩種序列化協(xié)議。傳輸上 Kitex 使用擴(kuò)展的 ?thrift ?作為底層的傳輸協(xié)議(注:thrift 既是 IDL 格式,同時(shí)也是序列化協(xié)議和傳輸協(xié)議)。IDL 全稱是 Interface Definition Language,接口定義語言。

為什么要使用 IDL

如果我們要進(jìn)行 RPC,就需要知道對方的接口是什么,需要傳什么參數(shù),同時(shí)也需要知道返回值是什么樣的,就好比兩個(gè)人之間交流,需要保證在說的是同一個(gè)語言、同一件事。這時(shí)候,就需要通過 IDL 來約定雙方的協(xié)議,就像在寫代碼的時(shí)候需要調(diào)用某個(gè)函數(shù),我們需要知道函數(shù)簽名一樣。

Thrift IDL 語法可參考:Thrift interface description language

proto3 語法可參考:Language Guide(proto3)

創(chuàng)建項(xiàng)目目錄

在開始后續(xù)的步驟之前,先讓我們創(chuàng)建一個(gè)項(xiàng)目目錄用于后續(xù)的教程。

?$ mkdir example ?

然后讓我們進(jìn)入項(xiàng)目目錄

?$ cd example?

Kitex 命令行工具

Kitex 自帶了一個(gè)同名的命令行工具 ?kitex?,用來幫助大家很方便地生成代碼,新項(xiàng)目的生成以及之后我們會(huì)學(xué)到的 server、client 代碼的生成都是通過 kitex 工具進(jìn)行。

安裝

可以使用以下命令來安裝或者更新 kitex:

?$ go install github.com/cloudwego/kitex/tool/cmd/kitex ?

完成后,可以通過執(zhí)行 kitex 來檢測是否安裝成功。

?$ kitex ?

如果出現(xiàn)如下輸出,則安裝成功。

?$ kitex ?

?No IDL file found. ?

如果出現(xiàn) ?command not found? 錯(cuò)誤,可能是因?yàn)闆]有把 ?$GOPATH/bin? 加入到 ?$PATH? 中。

編寫 IDL

首先我們需要編寫一個(gè) IDL,這里以 thrift IDL 為例。

首先創(chuàng)建一個(gè)名為 ?echo.thrift? 的 thrift IDL 文件。

然后在里面定義我們的服務(wù)

namespace go api

struct Request {
  1: string message
}

struct Response {
  1: string message
}

service Echo {
    Response echo(1: Request req)
}

生成 echo 服務(wù)代碼

有了 IDL 以后我們便可以通過 kitex 工具生成項(xiàng)目代碼了,執(zhí)行如下命令:

?$ kitex -module example -service example echo.thrift ?

上述命令中,?-module? 表示生成的該項(xiàng)目的 go module 名,?-service? 表明我們要生成一個(gè)服務(wù)端項(xiàng)目,后面緊跟的 ?example? 為該服務(wù)的名字。最后一個(gè)參數(shù)則為該服務(wù)的 IDL 文件。

生成后的項(xiàng)目結(jié)構(gòu)如下:

.
|-- build.sh
|-- echo.thrift
|-- handler.go
|-- kitex_gen
|   `-- api
|       |-- echo
|       |   |-- client.go
|       |   |-- echo.go
|       |   |-- invoker.go
|       |   `-- server.go
|       |-- echo.go
|       `-- k-echo.go
|-- main.go
`-- script
    |-- bootstrap.sh
    `-- settings.py

獲取最新的 Kitex 框架

由于 kitex 要求使用 go mod 進(jìn)行依賴管理,所以我們要升級 kitex 框架會(huì)很容易,只需要執(zhí)行以下命令即可:

$ go get github.com/cloudwego/kitex@latest
$ go mod tidy

如果遇到類似如下報(bào)錯(cuò):

github.com/apache/thrift/lib/go/thrift: ambiguous import: found package github.com/apache/thrift/lib/go/thrift in multiple modules

先執(zhí)行一遍下述命令,再繼續(xù)操作:

go mod edit -droprequire=github.com/apache/thrift/lib/go/thrift
go mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.13.0

編寫 echo 服務(wù)邏輯

我們需要編寫的服務(wù)端邏輯都在 ?handler.go? 這個(gè)文件中,現(xiàn)在這個(gè)文件應(yīng)該如下所示:

package main

import (
  "context"
  "example/kitex_gen/api"
)

// EchoImpl implements the last service interface defined in the IDL.
type EchoImpl struct{}

// Echo implements the EchoImpl interface.
func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
  // TODO: Your code here...
  return
}

這里的 ?Echo ?函數(shù)就對應(yīng)了我們之前在 IDL 中定義的 ?echo ?方法。

現(xiàn)在讓我們修改一下服務(wù)端邏輯,讓 ?Echo ?服務(wù)名副其實(shí)。

修改 ?Echo ?函數(shù)為下述代碼:

func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
  return &api.Response{Message: req.Message}, nil
}

編譯運(yùn)行

kitex 工具已經(jīng)幫我們生成好了編譯和運(yùn)行所需的腳本:

  • 編譯:

?$ sh build.sh ?

執(zhí)行上述命令后,會(huì)生成一個(gè) ?output ?目錄,里面含有我們的編譯產(chǎn)物。

  • 運(yùn)行:

?$ sh output/bootstrap.sh ?

執(zhí)行上述命令后,?Echo ?服務(wù)就開始運(yùn)行啦!

編寫客戶端

有了服務(wù)端后,接下來就讓我們編寫一個(gè)客戶端用于調(diào)用剛剛運(yùn)行起來的服務(wù)端。

  • 首先,同樣的,先創(chuàng)建一個(gè)目錄用于存放我們的客戶端代碼:

?$ mkdir client ?

  • 進(jìn)入目錄:

?$ cd client ?

創(chuàng)建一個(gè) main.go 文件,然后就開始編寫客戶端代碼了。

創(chuàng)建 client

首先讓我們創(chuàng)建一個(gè)調(diào)用所需的 ?client?:

import "example/kitex_gen/api/echo"
import "github.com/cloudwego/kitex/client"
...
c, err := echo.NewClient("example", client.WithHostPorts("0.0.0.0:8888"))
if err != nil {
  log.Fatal(err)
}

上述代碼中,?echo.NewClient? 用于創(chuàng)建 ?client?,其第一個(gè)參數(shù)為調(diào)用的 服務(wù)名,第二個(gè)參數(shù)為 options,用于傳入?yún)?shù),此處的 ?client.WithHostPorts? 用于指定服務(wù)端的地址。

發(fā)起調(diào)用

接下來讓我們編寫用于發(fā)起調(diào)用的代碼:

import "example/kitex_gen/api"
...
req := &api.Request{Message: "my request"}
resp, err := c.Echo(context.Background(), req, callopt.WithRPCTimeout(3*time.Second))
if err != nil {
  log.Fatal(err)
}
log.Println(resp)

上述代碼中,我們首先創(chuàng)建了一個(gè)請求 ?req ?, 然后通過 ?c.Echo? 發(fā)起了調(diào)用。

其第一個(gè)參數(shù)為 ?context.Context?,通過通常用其傳遞信息或者控制本次調(diào)用的一些行為,你可以在后續(xù)章節(jié)中找到如何使用它。

其第二個(gè)參數(shù)為本次調(diào)用的請求。

其第三個(gè)參數(shù)為本次調(diào)用的 ?options ?,Kitex 提供了一種 ?callopt ?機(jī)制,顧名思義——調(diào)用參數(shù) ,有別于創(chuàng)建 client 時(shí)傳入的參數(shù),這里傳入的參數(shù)僅對此次生效。 此處的 ?callopt.WithRPCTimeout? 用于指定此次調(diào)用的超時(shí)(通常不需要指定,此處僅作演示之用)同樣的,你可以在 *** 基礎(chǔ)特性*** 一節(jié)中找到更多的參數(shù)。

發(fā)起調(diào)用

在編寫完一個(gè)簡單的客戶端后,我們終于可以發(fā)起調(diào)用了。

你可以通過下述命令來完成這一步驟:

?$ go run main.go ?

如果不出意外,你可以看到類似如下輸出:

?2021/05/20 16:51:35 Response({Message:my request}) ?

恭喜你!至此你成功編寫了一個(gè) Kitex 的服務(wù)端和客戶端,并完成了一次調(diào)用!


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號