拥抱云原生——Hertz与Kitex的初探与实践
随着微服务和云原生技术的日益成熟,企业和开发者都在寻找能够提供高性能、高可用性和高扩展性的解决方案。字节跳动,作为全球领先的技术公司,推出了两个开源项目——Hertz和Kitex,为开发者提供了构建云原生应用的强大工具。本文将深入探讨这两个项目的特点、优势和实践应用。
框架初探
Hertz:高性能的HTTP框架
概述
Hertz是一个为Go设计的高性能、高可用性、可扩展的HTTP框架。它结合了fasthttp、gin和echo等开源框架的优点,并融入了字节跳动的独特挑战,使其在多年的生产环境中得到了验证。
核心特点
- 高可用性:Hertz旨在提供最佳的用户体验,帮助开发者快速、准确地完成工作。
- 高性能:默认使用Netpoll,一个从零开始构建的高性能网络库,与go.net相比,Hertz在某些场景中表现更佳。
- 高扩展性:其分层设计使得框架非常易于扩展,同时保持核心功能的稳定性。
Kitex:RPC框架的新选择
概述
Kitex是一个高性能、高扩展性的Golang RPC框架,专为微服务设计。它不仅集成了高性能的网络库Netpoll,还提供了多种RPC消息和传输协议的支持。
核心特点
- 高性能:与go net相比,Kitex提供了显著的性能优势。
- 可扩展性:Kitex提供了许多带有默认实现的接口供用户自定义,满足不同的业务需求。
- 多协议支持:Kitex支持多种RPC消息协议,如Thrift、Kitex Protobuf和gRPC。
- 服务治理:Kitex集成了服务治理模块,如服务注册、服务发现、负载均衡等。
微服务架构
微服务架构是软件工程中的一种变体,属于面向服务的架构风格。它是一种架构模式,将应用程序组织为一系列松散耦合的、细粒度的服务,这些服务通过轻量级协议进行通信。其主要目标之一是使团队能够独立地开发和部署他们的服务。这是通过减少代码库中的多个依赖关系来实现的,从而允许开发者在用户的有限限制下发展他们的服务,并隐藏额外的复杂性。
微服务的核心特点
- 服务组织:微服务通常是通过网络进行通信的进程,使用技术无关的协议(如HTTP)来实现特定的目标。
- 业务驱动:服务围绕业务能力进行组织。
- 多样性:服务可以使用不同的编程语言、数据库、硬件和软件环境来实现,取决于最适合的选择。
- 小而美:服务小巧、支持消息传递、由上下文界定、可以独立开发和部署。
微服务不是单一应用中的一个层(例如,Web控制器或后端的前端)。相反,它是一个具有清晰接口的业务功能单元,并且可能通过其内部组件实现分层架构。从战略角度看,微服务架构基本上遵循Unix哲学的“做一件事,做得好”。
微服务的优势
- 模块化:这使得应用程序更容易理解、开发、测试,并变得更能抵御架构退化。
- 可伸缩性:由于微服务是独立于其他服务实现和部署的,它们可以独立地进行监控和伸缩。
- 集成异构和遗留系统:微服务被认为是现代化现有单体软件应用的有效手段。
- 分布式开发:它通过使小型自主团队能够独立地开发、部署和扩展其各自的服务来并行化开发。
微服务的挑战
- 服务形成信息障碍。
- 网络延迟和消息处理时间
- 与单体服务进程内的调用相比,网络上的服务间调用成本更高。
- 测试和部署更为复杂。
- 服务间的责任转移更为困难。
总的来说,微服务架构为构建灵活、独立部署的软件系统提供了一种方法。这种方法是面向服务架构的第一个实现,随着云原生应用、无服务器计算和使用轻量级容器部署的应用的普及,它变得越来越受欢迎。
微服务架构中的Hertz与Kitex:构建一个示例
微服务架构的核心在于将大型应用程序分解为小型、独立的服务单元,这些单元可以独立地开发、部署和扩展。字节跳动的Hertz和Kitex为开发者提供了构建微服务应用的强大工具。在本章节中,我们将探讨如何使用Hertz和Kitex构建一个简单的微服务示例。
项目架构
首先,我们来看一下项目的文件结构:
├─api
│ ├─biz
│ │ ├─client
│ │ ├─handler
│ │ ├─model
│ │ └─router
│ └─script
├─idl
│ └─rpc
└─service
└─pong
└─script
在这个结构中,api目录负责处理HTTP请求,idl目录定义了RPC的接口,而service目录则包含了微服务的具体实现。
Hertz:API网关
Hertz在这个示例中扮演了API网关的角色,它负责接收和处理来自客户端的HTTP请求。我们使用/ping端点作为演示。
// api/biz/handler/ping.go
func Ping(ctx context.Context, c *app.RequestContext) {
c.JSON(consts.StatusOK, utils.H{
"message": "pong",
"data": client.PingClient(),
})
}
在这段代码中,PingClient函数负责向Kitex的PingService发送RPC请求。
Kitex:RPC服务
在微服务架构中,服务之间的通信通常不是通过可读的格式,而是通过远程过程调用(RPC)进行的。RPC调用的数据是二进制格式,需要在发送端和接收端之间进行编码和解码。为了定义这种数据交互的格式,我们使用接口定义语言(IDL)。
// idl/rpc/pong.thrift
namespace go pong
struct PingReq {
1: required string ping_time,
}
struct PongResp {
1: required string pong_time,
}
service PongService {
PongResp Pong(1: required PingReq req),
}
在这个IDL定义中,我们定义了一个PongService,它接受一个字符串作为请求,并返回一个字符串作为响应。
为了快速构建服务,我们可以使用Kitex的代码生成工具。这个工具可以根据IDL定义生成服务的脚手架代码。
// service/pong/main.go
func main() {
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8889")
if err != nil {
log.Println(err.Error())
return
}
svr := pong.NewServer(new(PongServiceImpl), server.WithServiceAddr(addr))
err = svr.Run()
if err != nil {
log.Println(err.Error())
}
}
在这段代码中,我们启动了一个监听在8889端口的微服务。这个服务的具体逻辑在PongServiceImpl中实现。
// service/pong/handler.go
func (s *PongServiceImpl) Pong(ctx context.Context, req *pong.PingReq) (resp *pong.PongResp, err error) {
// TODO: Your code here...
resp = &pong.PongResp{
PongTime: req.PingTime + " " + time.Now().String(),
}
return resp, nil
}
在这个实现中,服务接收一个请求,然后返回一个响应。
结论
通过上述示例,我们可以看到Hertz和Kitex如何协同工作,为开发者提供了一个简单、高效的方式来构建微服务应用。这种架构模式不仅提供了高性能和可扩展性,还简化了服务之间的通信和数据交互。