【字节青训营-7】:初探 Kitex 字节微服务框架(使用ETCD进行服务注册与发现)

本文目录

  • 一、Kitex概述
  • 二、第一个Kitex应用
  • 三、IDL
  • 四、服务注册与发现

一、Kitex概述

长话短说,就是字节跳动内部的 Golang 微服务 RPC 框架,具有高性能、强可扩展的特点,在字节内部已广泛使用。

如果对微服务性能有要求,又希望定制扩展融入自己的治理体系,Kitex 会是一个不错的选择。

可以看到下面是Kitex的架构设计。

在这里插入图片描述
这个框架有一些特点,比如:

  • 高性能

使用自研的高性能网络库 Netpoll,性能相较 go net 具有显著优势。

  • 扩展性

提供了较多的扩展接口以及默认扩展实现,使用者也可以根据需要自行定制扩展,具体见下面的框架扩展。

  • 多消息协议

RPC 消息协议默认支持 Thrift、Kitex Protobuf、gRPC。Thrift 支持 Buffered 和 Framed 二进制协议,与支持原生 Thrift 协议的多语言框架都能互通; Kitex Protobuf 是 Kitex 自定义的 Protobuf 消息协议,协议格式类似 Thrift;gRPC 是对 gRPC 消息协议的支持,可以与 gRPC 互通。除此之外,使用者也可以扩展自己的消息协议,目前社区也提供了 Dubbo 协议的支持,可以与 Dubbo 互通。

  • 多传输协议

传输协议封装消息协议进行 RPC 互通,传输协议可以额外透传元信息,用于服务治理,Kitex 支持的传输协议有 TTHeader、HTTP2。TTHeader 可以和 Thrift、Kitex Protobuf 结合使用;HTTP2 目前主要是结合 gRPC 协议使用,后续也会支持 Thrift。

  • 多种消息类型

支持 PingPong、Oneway、双向 Streaming。其中 Oneway 目前只对 Thrift 协议支持,双向 Streaming 只对 gRPC 支持,后续会考虑支持 Thrift 的双向 Streaming。

  • 服务治理

支持服务注册/发现、负载均衡、熔断、限流、重试、监控、链路跟踪、日志、诊断等服务治理模块,大部分均已提供默认扩展,使用者可选择集成。

  • 代码生成

Kitex 内置代码生成工具,可支持生成 Thrift、Protobuf 以及脚手架代码。

二、第一个Kitex应用

首先我们创建一个新的Go项目,然后安装对应的插件:kitexthriftgo

然后在终端输入对应的安装命令:

go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
go install github.com/cloudwego/thriftgo@latest

然后等待对应的安装即可。

在项目路径下安装新建thrift文件,然后输入如下代码:

在这里插入图片描述

namespace go api

struct Request{
    1:string message
}

struct Response{
    1:string message
}

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

简单来说,这段代码定义一个简单的服务 Echo,它包含一个方法 echo。这个方法接收一个 Request 类型的对象作为输入,处理后返回一个 Response 类型的对象。Request 和 Response 都包含一个字符串字段 message,分别用于传递请求消息和响应消息。这种定义方式使得 Thrift 可以生成不同语言的代码(例如 Go、Java、Python 等),方便跨语言的服务调用。

然后在命令行输入命令:

kitex -module exampleKitex -service exampleKitex echo.thrift

来生成基本的代码。

在这里插入图片描述
等待一会后,可以看到目录已经更新了。

在这里插入图片描述
在这里插入图片描述
main.go中输入如下代码:

package main

import (
	api "exampleKitex/kitex_gen/api/echo"
	"log"
)
/*
   api.NewServer 是一个函数,用于创建一个新的服务实例。
    new(EchoImpl) 创建了一个 EchoImpl 类型的实例,并将其传递给 api.NewServer。
    调用 svr.Run() 方法启动服务。
*/
func main() {
	svr := api.NewServer(new(EchoImpl))

	err := svr.Run()

	if err != nil {
		log.Println(err.Error())
	}
}

如果有报错,可以输入go mod tidy来补充对应需要的库。

然后在handler.go中来输入逻辑代码。

(s *EchoImpl):这是方法的接收者,表示这个方法属于 EchoImpl 类型的指针 s。
EchoImpl 是一个结构体类型,通常是由 Thrift 生成的接口的具体实现。
echo是方法名称,对应 Thrift 定义中的 echo 方法。
ctx context.Context:这是方法的第一个参数,类型为 context.Context。
context 是 Go 标准库中的一个包,用于在程序中传递上下文信息,例如超时、取消信号等。
req *api.Request:这是方法的第二个参数,类型为 *api.Request,表示这是一个指向 api.Request 类型的指针。
api.Request 是 Thrift 定义的 Request 结构体,通过 Thrift 生成的 Go 代码中的 api 包来访问。

&api.Response{}:创建了一个 api.Response 类型的实例,并取其地址(返回一个指针)。
Message: req.Message:将 req 参数中的 Message 字段值赋给新创建的 Response 实例的 Message 字段。

这是一个简单的回显服务,即客户端发送一个消息,服务端原样返回这个消息。
package main

import (
	"context"
	api "exampleKitex/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 &api.Response{Message: req.Message}, nil
}

然后我们来启动main.go和handler.go. 启动之后会默认在监听端口进行对应的监听。

在这里插入图片描述

然后我们新建一个客户端,并且写入对应的客户端代码。

package main

import (
	"context"
	"github.com/cloudwego/kitex/client/callopt"
	"log"
	"exampleKitex/kitex_gen/api"
	"exampleKitex/kitex_gen/api/echo"
	"time"
)

import "github.com/cloudwego/kitex/client"

func main() {
	//下面的destService对应服务名称是我们在启动kitex代码生成工具命令中的service名称
	// kitex -moudle exampleKitex -service exampleKitex(服务名称) echo.thrift
	c, err := echo.NewClient("exampleKitex", client.WithHostPorts("0.0.0.0:8888"))
	if err != nil {
		log.Fatal(err)
	}

	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)
}

然后运行客户端,新开一个终端,输入命令go run .\client.go即可。

然后可以看到返回的Response如下:

在这里插入图片描述

所以总结一下,就是,先在echo.thrift中编写接口,定义发送什么样的请求,请求里边有什么样的一个信息,然后就是继续定义一个响应,以及服务的逻辑。

在这里插入图片描述

三、IDL

IDL(Interface Definition Language,接口定义语言)是一种用于定义软件组件之间交互接口的规范语言。它允许开发者以一种语言无关的方式描述服务接口、数据结构和通信协议,从而实现不同编程语言之间的互操作性。IDL 的核心目的是提供一种标准化的方式来定义服务的接口和数据结构,使得这些接口和数据结构可以在多种编程语言中被实现和使用。

IDL就是我们刚刚定义的这个thrift文件。

如果进行PRC,那么就需要知道对方的接口是什么,需要传什么参数,也需要知道返回值是什么样子的。这个时候就需要通过IDL来约定双方的协议。就像调用某个函数,需要知道函数签名一样。

定义好thrift文件之后,就可以使用命令生成代码了。
kitex -module example -service example echo.thrift生成代码。

在这里插入图片描述

服务是默认监听8888端口的。

四、服务注册与发现

目前Kitex的服务注册与发现已经对接了主流的服务注册与发现中心,如ETCD、Nacos、zookeeper、Eureka等。

接下来我们进行一个简单的实战。

首先我们下载etcd:https://github.com/etcd-io/etcd/releases,找到对应的电脑的版本。

在这里插入图片描述

下载好之后找个文件夹进行解压缩,然后打开,双击打开即可。

在这里插入图片描述

运行起来之后可以看到对应的2380和2379两个端口。

在这里插入图片描述
到这一步,服务器已经启用成功了。

接下来我们需要把服务注册到etcd注册中心去。修改handler.go的相关代码。

简单说明下作用:实现一个 Kitex 服务端程序,通过 ETCD 注册中心将自身注册为一个可发现的服务,并提供了一个简单的 Echo 方法。程序的主要功能包括:

package main

import (
	"context"
	api "exampleKitex/kitex_gen/api"

	"exampleKitex/kitex_gen/api/echo"
	"github.com/cloudwego/kitex/pkg/rpcinfo"
	"github.com/cloudwego/kitex/server"
	etcd "github.com/kitex-contrib/registry-etcd"
	"log"
)

// EchoImpl implements the last service interface defined in the IDL.EchoImpl:定义了一个结构体,用于实现服务接口。
type EchoImpl struct{}

// Echo implements the EchoImpl interface.
// ctx context.Context:上下文对象,用于传递超时和取消信号。
// req *api.Request:请求对象,包含客户端发送的数据。
func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
	// TODO: Your code here...
	return &api.Response{Message: req.Message}, nil

}

func main() {

	//etcd.NewEtcdRegistry:创建一个 ETCD 注册中心实例。
	//参数 []string{"127.0.0.1:2379"} 指定了 ETCD 服务的地址。
	r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"})
	if err != nil {
		log.Fatal(err)
	}

	//echo.NewServer:创建一个服务实例。
	//new(EchoImpl):创建一个 EchoImpl 实例,作为服务的具体实现。
	//server.WithRegistry(r):指定使用 ETCD 注册中心实例 r,将服务注册到 ETCD 中。
	//server.WithServerBasicInfo:设置服务的基本信息,例如服务名称。ServiceName: "Hello":将服务名称设置为 "Hello",客户端可以通过这个名称找到服务。
	server := echo.NewServer(new(EchoImpl), server.WithRegistry(r), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{
		ServiceName: "Hello",
	}))
	err = server.Run()
	if err != nil {
		log.Fatal(err)
	}

}

同时我们修改client.go的代码如下:

一句话概括下作用,就是:使用 Kitex 框架的客户端程序,通过 ETCD 注册中心动态发现服务,并调用名为 Hello 的服务的 Echo 方法。代码的主要功能是定期发送请求到服务端,并打印响应结果。

package main

import (
	"context"
	"exampleKitex/kitex_gen/api"
	"exampleKitex/kitex_gen/api/echo"
	"github.com/cloudwego/kitex/client"
	etcd "github.com/kitex-contrib/registry-etcd"
	"log"
	"time"
)

func main() {
	//etcd.NewEtcdResolver:创建一个 ETCD 解析器实例,用于从 ETCD 服务注册中心获取服务实例的地址。
	//参数 []string{"127.0.0.1:2379"} 指定了 ETCD 服务的地址。
	r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"})
	if err != nil {
		log.Fatal(err)
	}
	
	//echo.MustNewClient:创建一个服务客户端实例。
	//"Hello" 是服务名称,与服务端在 ETCD 中注册的名称一致。
	//client.WithResolver(r):指定使用 ETCD 解析器 r 来动态发现服务实例。这意味着客户端会从 ETCD 中获取服务实例的地址,而不是直接指定服务地址。
	client := echo.MustNewClient("Hello", client.WithResolver(r))

	//创建一个带有超时时间的上下文,超时时间为 3 秒。
	for {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)

		//调用服务端的 Echo 方法,传递一个请求对象,其中 Message 字段为 "hello"。
		resp, err := client.Echo(ctx, &api.Request{Message: "hello"})
		cancel() //调用 cancel() 释放上下文资源。
		if err != nil {
			log.Fatal(err)
		}
		log.Println(resp)
		time.Sleep(time.Second)
	}
}

来捋顺一下步骤:

实现一个 Kitex 客户端程序,通过 ETCD 注册中心动态发现服务,并调用名为 Hello 的服务的 Echo 方法:

创建 ETCD 解析器实例,用于从 ETCD 注册中心获取服务实例的地址。然后创建服务客户端实例,指定使用 ETCD 解析器。并且在一个无限循环中,每隔 1 秒调用一次服务的 Echo 方法。打印服务端返回的响应。

这种设计适用于微服务架构,其中服务实例可能动态变化,通过 ETCD 注册中心可以实现服务发现和负载均衡。

通过命令 go run .\handler.go来启动服务端,会将我们的服务注册到etcd里面去。

在这里插入图片描述
然后运行client,会看到如下的消息。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/964237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

51单片机入门_05_LED闪烁(常用的延时方法:软件延时、定时器延时;while循环;unsigned char 可以表示的数字是0~255)

本篇介绍编程实现LED灯闪烁,需要学到一些新的C语言知识。由于单片机执行的速度是非常快的,如果不进行延时的话,人眼是无法识别(停留时间要大于20ms)出LED灯是否在闪烁所以需要学习如何实现软件延时。另外IO口与一个字节位的数据对应关系。 文…

JVM的GC详解

获取GC日志方式大抵有两种 第一种就是设定JVM参数在程序启动时查看,具体的命令参数为: -XX:PrintGCDetails # 打印GC日志 -XX:PrintGCTimeStamps # 打印每一次触发GC时发生的时间第二种则是在服务器上监控:使用jstat查看,如下所示,命令格式为jstat -gc…

基于python去除知乎图片水印

基于python去除知乎图片水印 背景:看到知乎技术文章里面的图片非常好,但是下载下来都是带有水印的,并不是不尊重别人的版权和劳动成果,纯粹的是洁癖,总感觉水印打上去很难受~~~ 实在想去掉水印,但是又不会P…

Android学习20 -- 手搓App2(Gradle)

1 前言 昨天写了一个完全手搓的:Android学习19 -- 手搓App-CSDN博客 后面谷歌说不要用aapt,d8这些来搞。其实不想弄Gradle的,不过想着既然开始了,就多看一些。之前写过一篇Gradle,不过是最简单的编译,不涉…

【愚公系列】《循序渐进Vue.js 3.x前端开发实践》051-案例:教务系统学生列表页面

标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主&…

毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统

目录 前言 课题背景和意义 实现技术思路 一、算法理论基础 1.1 卷积神经网络 1.2 目标检测算法 1.3 注意力机制 二、 数据集 2.1 数据采集 2.2 数据标注 三、实验及结果分析 3.1 实验环境搭建 3.2 模型训练 3.2 结果分析 最后 前言 📅大四是整个大学…

2025.2.1——八、Web_php_wrong_nginx_config

题目来源:攻防世界 Web_php_wrong_nginx_config 目录 一、打开靶机,整理信息 二、解题思路 step 1:找找解题入口 step 2:抓包修改信息,得到配置文件 step 3:找到突破口,进行文件遍历 st…

Netty中用了哪些设计模式?

大家好,我是锋哥。今天分享关于【Netty中用了哪些设计模式?】面试题。希望对大家有帮助; Netty中用了哪些设计模式? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Netty 是一个基于 Java 的高性能网络应用框架&#…

【办公类-99-01】20250201学具PDF打印会缩小一圈——解决办法:换一个PDF阅读器

背景需求: 2024年1月13日,快要放寒假了,组长拿着我们班的打印好的一叠教案来调整。 “前面周计划下面的家园共育有调整,你自己看批注。” “还有你这个教案部分的模版有问题,太小(窄)了。考虑…

【BUUCTF杂项题】FLAG

一.FLAG 一张图片扔进随波逐流 发现RGB似乎隐藏压缩包 优先考虑RBG中的LSB隐写,用Stegsolve打开文件 1.查看每个颜色通道下的图片,未发现异常 2.LSB最低位提取,用Stegsolve的Data Extrace功能,确实存在一个压缩包,sa…

ros 创建Node

1、使用catkin_create_pkg创建一个软件包 catkin_create_pkg ssr_pkg roscpp rospy std_msgs 2、在软件包的src文件夹下创建一个节点的cpp源码文件 3、在CMakeLists.txt中设置节点源码的编译规则 4.编译运行 编译:shiftctrlB 运行: rosrun ssr_pkg …

给AI用工具的能力——Agent

ReAct框架: Reason Action,推理与行动结合 可以借助思维链,用小样本提示展示给模型一个ReAct框架 推理:针对问题或上一步观察的思考 行动:基于推理,与外部环境的一些交互(调用外部工具&…

实验十 Servlet(一)

实验十 Servlet(一) 【实验目的】 1.了解Servlet运行原理 2.掌握Servlet实现方式 【实验内容】 1、参考课堂例子,客户端通过login.jsp发出登录请求,请求提交到loginServlet处理。如果用户名和密码相同则视为登录成功&#xff0c…

PAT甲级1052、Linked LIst Sorting

题目 A linked list consists of a series of structures, which are not necessarily adjacent in memory. We assume that each structure contains an integer key and a Next pointer to the next structure. Now given a linked list, you are supposed to sort the stru…

【BUUCTF杂项题】荷兰宽带数据泄露、九连环

一.荷兰宽带数据泄露 打开发现是一个.bin为后缀的二进制文件,因为提示宽带数据泄露,考虑是宽带路由器方向的隐写 补充:大多数现代路由器都可以让您备份一个文件路由器的配置文件,软件RouterPassView可以读取这个路由配置文件。 用…

【Game】Powerful——The Dragon Hiding in Deep Waters(3)

文章目录 1、规则2、条件——宠物2.1、宠物装备2.1、宠物突破2.2、洗练石 3、条件——符石4、条件——化龙鼎5、附录——星穹 1、规则 寒渊城,神秘老兵处可查看 霜风携雨掠寒江,孤城独影人心凉 贤才此件难相遇,忠骨何日还故乡 宠物、符石、…

差分数组的学习

文章目录 1.差分数组的应用场景2.如何构造一个差分数组2.1 原数组转换为差分数组2.2 差分数组还原为原数组 3.差分数组的特性 1.差分数组的应用场景 需要频繁对某个区间的数组进行增减操作 2.如何构造一个差分数组 2.1 原数组转换为差分数组 # 存在一个数组Nums,求出他的差分…

AES 与 SM4 加密算法:深度解析与对比

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…

【C++】线程池实现

目录 一、线程池简介线程池的核心组件实现步骤 二、C11实现线程池源码 三、线程池源码解析1. 成员变量2. 构造函数2.1 线程初始化2.2 工作线程逻辑 3. 任务提交(enqueue方法)3.1 方法签名3.2 任务封装3.3 任务入队 4. 析构函数4.1 停机控制 5. 关键技术点解析5.1 完美转发实现5…

[EAI-023] FAST,机器人动作专用的Tokenizer,提高VLA模型的能力和训练效率

Paper Card 论文标题:FAST: Efficient Action Tokenization for Vision-Language-Action Models 论文作者:Karl Pertsch, Kyle Stachowicz, Brian Ichter, Danny Driess, Suraj Nair, Quan Vuong, Oier Mees, Chelsea Finn, Sergey Levine 论文链接&…