kitex 入門和基于grpc的使用

在這里插入圖片描述

📕作者簡介: 過去日記,致力于Java、GoLang,Rust等多種編程語言,熱愛技術,喜歡游戲的博主。
📗本文收錄于kitex系列,大家有興趣的可以看一看
📘相關專欄Rust初階教程、go語言基礎系列、spring教程等,大家有興趣的可以看一看
📙Java并發編程系列,設計模式系列、go web開發框架 系列正在發展中,喜歡Java,GoLang,Rust,的朋友們可以關注一下哦!


文章目錄

  • 概述
    • 架構設計
    • 框架特點
  • 環境
    • 代碼生成工具
      • IDL 編譯器
        • 安裝IDL編譯器
        • kitex tool
  • 基礎教程
    • 代碼生成
    • 拉取依賴
    • 編寫商品服務邏輯
      • 運行商品服務
    • 創建 client
    • 暴露 HTTP 接口
      • 測試接口

概述

Kitex字節跳動內部的 Golang 微服務 RPC 框架,具有高性能、強可擴展的特點,在字節內部已廣泛使用。如果對微服務性能有要求,又希望定制擴展融入自己的治理體系,Kitex 會是一個不錯的選擇。

架構設計

在這里插入圖片描述

框架特點

  • 高性能
    使用自研的高性能網絡庫 Netpoll,性能相較 go net 具有顯著優勢。
  • 擴展性
    提供了較多的擴展接口以及默認擴展實現,使用者也可以根據需要自行定制擴展,具體見下面的框架擴展。
  • 多消息協議
    RPC 消息協議默認支持 Thrift、Kitex Protobuf、gRPC。Thrift 支持 Buffered 和 Framed 二進制協議;Kitex Protobuf 是 Kitex 自定義的 Protobuf 消息協議,協議格式類似 Thrift;gRPC 是對 gRPC 消息協議的支持,可以與 gRPC 互通。除此之外,使用者也可以擴展自己的消息協議。
  • 多傳輸協議
    傳輸協議封裝消息協議進行 RPC 互通,傳輸協議可以額外透傳元信息,用于服務治理,Kitex 支持的傳輸協議有 TTHeader、HTTP2。TTHeader 可以和 Thrift、Kitex Protobuf 結合使用;HTTP2 目前主要是結合 gRPC 協議使用,后續也會支持 Thrift。
  • 多種消息類型
    支持 PingPong、Oneway、雙向 Streaming。其中 Oneway 目前只對 Thrift 協議支持,雙向 Streaming 只對 gRPC 支持,后續會考慮支持 Thrift 的雙向 Streaming。
  • 服務治理
    支持服務注冊/發現、負載均衡、熔斷、限流、重試、監控、鏈路跟蹤、日志、診斷等服務治理模塊,大部分均已提供默認擴展,使用者可選擇集成。
  • 代碼生成
    Kitex 內置代碼生成工具,可支持生成 Thrift、Protobuf 以及腳手架代碼。

環境

代碼生成工具

確保已經安裝GoLang環境。

Kitex 中使用到的代碼生成工具包括 IDL 編譯器, protobuf 編譯器,kitex tool。

IDL 編譯器

IDL 編譯器能夠解析 IDL 并生成對應的序列化和反序列化代碼,Kitex 支持 Thrift 和 protobuf 這兩種 IDL,這兩種 IDL 的解析分別依賴于 thriftgo 與 protoc。

安裝IDL編譯器

安裝 thriftgo,執行以下命令即可:

go install github.com/cloudwego/thriftgo@latest

安裝成功后,執行 thriftgo --version 可以看到具體版本號的輸出:

thriftgo --version

thriftgo 0.3.6

protobuf 執行以下命令即可:

go install github.com/golang/protobuf/proto

安裝成功后,執行 protoc --version 可以看到具體版本號的輸出:

protoc --version

libprotoc 23.0

kitex tool

kitex 是 Kitex 框架提供的用于生成代碼的一個命令行工具。目前,kitex 支持 thrift 和 protobuf 的 IDL,并支持生成一個服務端項目的骨架。kitex 的使用需要依賴于 IDL 編譯器確保你已經完成 IDL 編譯器的安裝。

執行以下命令:

go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
安裝成功后,執行 kitex --version 可以看到具體版本號的輸出:

kitex --version

v0.8.0

基礎教程

首先我們我們創建一個名叫mykitex的文件,然后在命令行運行以下命令初始化模塊。

go mod init mykitex

然后在根目錄創建idl文件夾。
然后創建以下文件添加以下內容。

一般不同的服務都會使用不同的 IDL,所以我們這里創建 item.thrift 與 stock.thrift 分別定義商品服務與庫存服務的接口,同時創建 base.thrift 定義公共數據結構。

base.proto

syntax = "proto3";
// 設置生成類的包路徑
package base;// 輸出路徑;
option go_package = "example/shop/base";// 設置基礎結構體
message BaseResp{string code=1;string msg=2;
}

item.proto

syntax = "proto3";
package item;
// 第一個分割參數,輸出路徑;第二個設置生成類的包路徑option go_package = "example/shop/item";
// 引入公共文件
import "idl/base.proto";
// 所有字段默認必填,message Item {
int64 id=1;
string title=2;
string description=3;
int64 stock=4;
}message GetItemReq {int64 id=1;
}message GetItemResp {Item item=1;
base.BaseResp baseResp=255;
}service ItemService{rpc GetItem(GetItemReq) returns (GetItemResp);
}

stock.proto

syntax = "proto3";
package item;
// 第一個分割參數,輸出路徑;第二個設置生成類的包路徑
option go_package = "example/shop/stock";
// 引入公共文件
import "idl/base.proto";// 設置服務名稱
message GetItemStockReq {int64 item_id = 1;
}message GetItemStockResp {int64 stock = 1;base.BaseResp base_resp = 255; // 在 protobuf 中,字段名應遵循小寫字母和下劃線的命名規范
}service StockService {rpc GetItemStock(GetItemStockReq) returns (GetItemStockResp);
}

代碼生成

有了 IDL 以后我們便可以通過 kitex 工具生成項目代碼了,我們在先回到項目的根目錄即 example_shop。因為我們有兩個 IDL 定義了服務,所以執行兩次 kitex 命令:

kitex -module mykitex idl/item.protokitex -module mykitex idl/stock.proto

生成的代碼分兩部分,一部分是結構體的編解碼序列化代碼,由 IDL 編譯器生成;另一部分由 kitex 工具在前者產物上疊加,生成用于創建和發起 RPC 調用的樁代碼。它們默認都在 kitex_gen 目錄下。

上面生成的代碼并不能直接運行,需要自己完成 NewClient 和 NewServer 的構建。kitex 命令行工具提供了 -service 參數能直接生成帶有腳手架的代碼,接下來讓我們為商品服務和庫存服務分別生成腳手架。

首先為兩個 RPC 服務分別單獨創建目錄。

mkdir -p rpc/item rpc/stock

再分別進入各自的目錄中,執行如下命令生成代碼:

// item 目錄下執行
kitex -module mykitex -service example.shop.item -use mykitex/kitex_gen -I ../../  ../../idl/item.proto  // stock 目錄下執行
kitex -module mykitex -service example.shop.item -use mykitex/kitex_gen -I ../../  ../../idl/stock.proto

kitex 默認會將代碼生成到執行命令的目錄下,kitex 的命令中:

  • -module 參數表明生成代碼的 go mod 中的 module name,在本例中為 example_shop
  • -service 參數表明我們要生成腳手架代碼,后面緊跟的 example.shop.item 或 example.shop.stock 為該服務的名字。
  • -use 參數表示讓 kitex 不生成 kitex_gen 目錄,而使用該選項給出的 import path。在本例中因為第一次已經生成 kitex_gen 目錄了,后面都可以復用。
  • 最后一個參數則為該服務的 IDL 文件
│  go.mod // go module 文件
│  go.sum
│
├─.idea
│      .gitignore
│      modules.xml
│      mykitex.iml
│      workspace.xml
│
├─idl        // 示例 idl 存放的目錄
│      base.proto
│      item.proto
│      stock.proto
│
├─kitex_gen
│  └─example
│      └─shop
│          ├─base  // 根據 IDL 生成的編解碼文件,由 IDL 編譯器生成
│          │      base.pb.fast.go
│          │      base.pb.go
│          │
│          ├─item
│          │  │  item.pb.fast.go
│          │  │  item.pb.go
│          │  │
│          │  └─itemservice
│          │          client.go
│          │          invoker.go
│          │          itemservice.go
│          │          server.go
│          │
│          └─stock
│              │  stock.pb.fast.go
│              │  stock.pb.go
│              │
│              └─stockservice
│                      client.go
│                      invoker.go
│                      server.go
│                      stockservice.go
│
└─rpc├─item│  │  build.sh    // 用來編譯的腳本,一般情況下不需要更改│  │  handler.go   // 服務端的業務邏輯都放在這里,這也是我們需要更改和編寫的文件│  │  kitex_info.yaml│  │  main.go  // 服務啟動函數,一般在這里做一些資源初始化的工作,可以更改│  ││  └─script│          bootstrap.sh│└─stock│  build.sh│  handler.go│  kitex_info.yaml│  main.go│└─scriptbootstrap.sh

拉取依賴

完成代碼生成后,我們回到項目根目錄。 使用 go mod tidy 命令拉取項目依賴

編寫商品服務邏輯

我們需要編寫的服務端邏輯都在 handler.go 這個文件中,目前我們有兩個服務,對應了兩個 handler.go,他們的結構都是類似的,我們先看看商品服務的服務端邏輯 rpc/item/handler.go

package mainimport ("context"item "example_shop/kitex_gen/example/shop/item"
)// ItemServiceImpl implements the last service interface defined in the IDL.
type ItemServiceImpl struct{}// GetItem implements the ItemServiceImpl interface.
func (s *ItemServiceImpl) GetItem(ctx context.Context, req *item.GetItemReq) (resp *item.GetItemResp, err error) {// TODO: Your code here...return
}

這里的 GetItem 函數就對應了我們之前在 item.thrift IDL 中定義的 GetItem 方法。

現在讓我們修改一下服務端邏輯,本項目僅僅演示使用方法,重點不在于業務邏輯,故簡單處理后返回。

package mainimport ("context"item "mykitex/kitex_gen/example/shop/item"
)// ItemServiceImpl implements the last service interface defined in the IDL.
type ItemServiceImpl struct{}// GetItem implements the ItemServiceImpl interface.
func (s *ItemServiceImpl) GetItem(ctx context.Context, req *item.GetItemReq) (resp *item.GetItemResp, err error) {resp = &item.GetItemResp{}resp.Item = &item.Item{}resp.Item.Id = req.GetId()resp.Item.Title = "Kitex"resp.Item.Description = "Kitex is an excellent framework!"return
}

除了 handler.go 外,我們還需關心 main.go 文件,我可以看看 main.go 中做了什么事情:

rpc/item/main.go

package mainimport ("log"item "mykitex/kitex_gen/example/shop/item/itemservice"
)func main() {svr := item.NewServer(new(ItemServiceImpl))err := svr.Run()if err != nil {log.Println(err.Error())}
}

運行商品服務

2024/03/01 19:36:03.685752 server.go:83: [Info] KITEX: server listen at addr=[::]:8888

在上面的日志輸出中,addr=[::]:8888 代表我們的服務運行在本地的 8888 端口,此參數可以在創建 server 時傳入 option 配置來修改,更多服務端配置見 Server Option。

創建 client

在生成的代碼中,kitex_gen 目錄下,Kitex 已經為我們封裝了創建客戶端的代碼,我們只需要使用即可.

client/client.go

package mainimport ("context""github.com/cloudwego/kitex/client""log""mykitex/kitex_gen/example/shop/item""mykitex/kitex_gen/example/shop/item/itemservice""time"
)func main() {client, err := itemservice.NewClient("hello", client.WithHostPorts("0.0.0.0:8888"))if err != nil {log.Fatal(err)}for {req := &item.GetItemReq{Id: 1}resp, err := client.GetItem(context.Background(), req)if err != nil {log.Fatal(err)}log.Println(resp)time.Sleep(time.Second)}
}

我們上述代碼直接調用我們kitex工具自動生成的代碼,

暴露 HTTP 接口

你可以使用 net/http 或其他框架來對外提供 HTTP 接口,此處使用 Hertz 做一個簡單演示,有關 Hertz 用法參見 Hertz 文檔

完整代碼如下:

main.go

package mainimport ("context""mykitex/kitex_gen/example/shop/item""github.com/cloudwego/hertz/pkg/app""github.com/cloudwego/hertz/pkg/app/server""github.com/cloudwego/kitex/client""github.com/cloudwego/kitex/client/callopt""log""mykitex/kitex_gen/example/shop/item/itemservice""time"
)var (cli itemservice.Client
)func main() {c, err := itemservice.NewClient("example.shop.item", client.WithHostPorts("0.0.0.0:8888"))if err != nil {log.Fatal(err)}cli = chz := server.New(server.WithHostPorts("localhost:8889"))hz.GET("/api/item", Handler)if err := hz.Run(); err != nil {log.Fatal(err)}
}func Handler(ctx context.Context, c *app.RequestContext) {req := &item.GetItemReq{Id: 1}req.Id = 1024resp, err := cli.GetItem(context.Background(), req, callopt.WithRPCTimeout(3*time.Second))if err != nil {log.Fatal(err)}c.String(200, resp.String())
}

接下來另啟一個終端,執行 go run . 命令即可啟動 API 服務,監聽 8889 端口,請求 localhost:8889/api/item 即可發起 RPC 調用商品服務提供的 GetItem 接口,并獲取到響應結果。

測試接口

打開游覽器訪問 localhost:8889/api/item,看到如下信息,代表請求成功。

item:{id:1024 title:“Kitex” description:“Kitex is an excellent framework!”}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/712347.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/712347.shtml
英文地址,請注明出處:http://en.pswp.cn/news/712347.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Web】青少年CTF擂臺挑戰賽 2024 #Round 1 wp

好家伙,比賽結束了還有一道0解web題是吧( 隨緣寫點wp(簡單過頭,看個樂就好) 目錄 EasyMD5 PHP的后門 PHP的XXE Easy_SQLi 雛形系統 EasyMD5 進來是個文件上傳界面 說是只能上傳pdf,那就改Content-Type為application/pdf,改…

11.盛最多水的容器

題目:給定一個長度為 n 的整數數組 height 。有 n 條垂線,第 i 條線的兩個端點是 (i, 0) 和 (i, height[i]) 。 找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。 返回容器可以儲存的最大水量。 解題思路:可以…

判斷閏年(1000-2000)

判斷規則&#xff1a;1.能被4整除&#xff0c;不能被100整除是閏年,2.能被400整除是閏年 #include <stdio.h>int is_leap_year(int n){if((n % 400 0)||((n % 4 0)&&(n % 100 ! 0)))return 1;elsereturn 0; } int main() {int i 0;int count 0;for(i 1000;…

基于PHP的在線英語學習平臺

有需要請加文章底部Q哦 可遠程調試 基于PHP的在線英語學習平臺 一 介紹 此在線英語學習平臺基于原生PHP開發&#xff0c;數據庫mysql。系統角色分為學生&#xff0c;教師和管理員。(附帶參考設計文檔) 技術棧&#xff1a;phpmysqlphpstudyvscode 二 功能 學生 1 注冊/登錄/…

C++/Python簡單練手題

前言 最近需要開始使用python&#xff0c;但是對python了解的并不多&#xff0c;于是先從很早之前剛學C時寫過的一些練手題開始&#xff0c;使用python來實現相同的功能&#xff0c;在溫習python基礎語法的同時&#xff0c;也一起來感受感受python的魅力 99乘法表 c&#xf…

kettle開發-Day43-加密環境下運行作業

前言&#xff1a; 金三銀四&#xff0c;開年第一篇我們來介紹下&#xff0c;怎么在加密情況下運行我們的kettle作業及任務。無疑現在所有企業都認識到加密的重要性&#xff0c;加密后的文件在對外傳輸的時候不能被訪問&#xff0c;訪問時出現一堆亂碼&#xff0c;同時正常的應用…

1分鐘學會Python字符串前后綴與編解碼

1.前綴和后綴 前綴和后綴指的是&#xff1a;字符串是否以指定字符開頭和結尾 2.startswith() 判斷字符串是否以指定字符開頭&#xff0c;若是返回True&#xff0c;若不是返回False str1 "HelloPython"print(str1.startswith("Hello")) # Trueprint…

Navicat Premium 16:打破數據庫界限,實現高效管理mac/win版

Navicat Premium 16是一款功能強大的數據庫管理工具&#xff0c;旨在幫助用戶更輕松地連接、管理和保護各種數據庫。該軟件支持多種數據庫系統&#xff0c;如MySQL、Oracle、SQL Server、PostgreSQL等&#xff0c;并提供了直觀的圖形界面&#xff0c;使用戶能夠輕松地完成各種數…

【力扣白嫖日記】585.2016年的投資

前言 練習sql語句&#xff0c;所有題目來自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免費數據庫練習題。 今日題目&#xff1a; 585.2016年的投資 表&#xff1a;Person 列名類型pidinttiv_2015floattiv_2016floatlatfloatlonfloat pid …

AI也來打摜蛋,難道人工智能也能當領導?

在人工智能&#xff08;AI&#xff09;的研究領域中&#xff0c;游戲被視為現實世界的簡化模型&#xff0c;常常是研究的首選平臺。這些研究主要關注游戲代理的決策過程。例如&#xff0c;中國的傳統卡牌游戲“摜蛋”&#xff08;字面意思是“扔雞蛋”&#xff09;就是一個挑戰…

Unity(第十七部)Unity自帶的角色控制器

組件Character Controller 中文角色控制器 using System.Collections; using System.Collections.Generic; using UnityEngine;public class player : MonoBehaviour {private CharacterController player;void Start(){player GetComponent<CharacterController>();}v…

對于爬蟲的學習

本地爬取 package MyApi.a08regexdemo;import java.util.regex.Matcher; import java.util.regex.Pattern;public class RegexDemo03 {public static void main(String[] args) {//要求&#xff1a;找出里面所有javaxxString str"Java自從95年問世以來&#xff0c;經歷了…

騰訊日常實習-數據科學-初試涼經

個人背景&#xff1a;雙985 騰訊會議面了一個小時左右&#xff0c;過程如下&#xff1a; 1.面試官首先介紹了一下部門&#xff08;騰訊云&#xff09;的情況和業務方向。 2.讓我介紹一下自己&#xff08;目前情況&#xff0c;科研經歷&#xff0c;項目經歷&#xff09;。 3.就我…

HarmonyOS—編譯構建概述

編譯構建是將應用/服務的源代碼、資源、第三方庫等&#xff0c;通過編譯工具轉換為可直接在硬件設備上運行的二進制機器碼&#xff0c;然后再將二進制機器碼封裝為HAP/APP軟件包&#xff0c;并為HAP/APP包進行簽名的過程。其中&#xff0c;HAP是可以直接運行在模擬器或真機設備…

牛皮癬發作和復發的觸發因素

谷禾健康 銀屑病&#xff0c;又叫牛皮癬&#xff0c;會導致出現皮疹伴發癢的鱗狀斑塊&#xff0c;最常見于膝蓋、肘部、軀干和頭皮。通常呈周期性發展&#xff0c;發作數周或數月&#xff0c;然后消退一段時間&#xff0c;長期的發作和復發會給患者帶來很大的痛苦和困擾&#x…

Qt5.9.9交叉編譯(帶sqlite3、OpenSSL)

1、交叉編譯工具鏈 這里ARM平臺是ARM CortexA9的&#xff0c;一般交叉編譯工具鏈demo板廠商都會提供&#xff0c;若未提供或想更換新版本的交叉編譯工具鏈可參考以下方式獲取。 1.1 下載適用于ARM CortexA9的交叉編譯工具鏈 Linaro Releases下載gcc4的最新版xxxx-i686_arm-li…

洛谷P1009階乘之和

題目描述 用高精度計算出S1!2!3!?n!&#xff08;n≤50&#xff09;。 其中 ! 表示階乘&#xff0c;定義為 n!n(n?1)(n?2)?1。例如&#xff0c;5!543211205!54321120。 輸入格式 一個正整數 n。 輸出格式 一個正整數 S&#xff0c;表示計算結果。 輸入輸出樣例 輸入…

2024/3/1 貪心

跳跳 跳跳&#xff01; - 洛谷 思路&#xff1a;從一個數組里面依次取出最大值和最小值&#xff0c;然后進行運算 完整代碼&#xff1a; #include <bits/stdc.h> #define int long long #define PII std::pair<int,int> signed main() {int n;std::cin >>…

接口文檔-示例

接口文檔-示例 1 根據ID查詢員工 1.1 基本信息 請求路徑&#xff1a;/emp 請求方式&#xff1a;GET 接口描述&#xff1a;該接口用于根據ID查詢員工信息 1.2 請求參數 參數說明&#xff1a; 參數名類型是否必須備注idnumber必須員工ID 請求樣例&#xff1a; GET http://l…

string【基礎篇】

1.1string字符串類 注意&#xff1a;這個類獨立于所使用的編碼來處理字節:如果用來處理多字節或變長字符(如UTF-8)的序列&#xff0c;這個 類的所有成員(如長度或大小)以及它的迭代器&#xff0c;將仍然按照字節(而不是實際編碼的字符)來操作。 總結&#xff1a; string是表…