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.mzph.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 注册/登录/…

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;经历了…

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…

string【基础篇】

1.1string字符串类 注意&#xff1a;这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列&#xff0c;这个 类的所有成员(如长度或大小)以及它的迭代器&#xff0c;将仍然按照字节(而不是实际编码的字符)来操作。 总结&#xff1a; string是表…

设计模式系列文章-7个创建型模式更新已完结

其实从2019年开始就有些一套关于设计模式的系列文章&#xff0c;但是因为种种原因一直搁置到现在。直到2024年才又恢复更新。 24年1月份上旬一直在弄博客站&#xff1a;https://jaune162.blog 的搭建 24年1月份下旬弄专题站&#xff1a;https://books.jaune162.blog 的搭建。…

Qt应用软件【测试篇】vargrid内存检查工具

文章目录 vargrid介绍vargrid官网vargrid安装常用命令Valgrind的主要命令vargrid介绍 Valgrind是一个用于构建动态分析工具的框架,能自动检测许多内存管理和线程错误,并详细分析程序性能。Valgrind发行版包括七个成熟工具:内存错误检测器、两个线程错误检测器、缓存和分支预…

Java8 - LocalDateTime时间日期类使用详解

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

redis+定时 模拟滑动窗口实现熔断降级

业务背景 公司业务现用的通道为 A、B&#xff0c;为了降本&#xff0c;引入新的支付通道 Y&#xff0c;但 Y 通道的稳定性要低于 A、B&#xff0c;系统要能在 Y 通道故障时自动切回到 A、B&#xff0c;等 Y 恢复正常后&#xff0c;再切换到 Y。 乍一看很简单&#xff0c;不就是…

使用链表和数组输出A~Z的ASCII码

输出结果 26个字母以及其对应的ASCII码 一、使用链表创建&#xff0c;注意&#xff1a; 节点需要有next指针初始化时head需要new一下 cur指针代表当前指针&#xff0c;每次不断的New新的节点&#xff0c;pre指针代表当前指针的前一个指针&#xff0c;每次pre的next指针指向cur…