Go 框架三件套详解 | 青训营

94 阅读4分钟

介绍

Gorm 是一个已经迭代了 10年+的功能强大的 ORM 框架,在字节内部被广泛 使用并且拥有非常丰富的 开源扩展。

Kitex 是字节内部的 Golang 微服务 RPC 框架 具有高性能、强可扩展的 主要特点,支持多协议并 且拥有丰富的开源扩展。

Hertz 是字节内部的 HTTP 框架,参考了其他开源框 架的优势(比如fasthttp),结合字节跳动 内部的需求,具有高易用 性、高性能、高扩展性特 点。

使用

Gorm的基础使用

文档:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

Gorm定义结构体

image.png

GORM 定义一个 gorm.Model 结构体,其包括字段 IDCreatedAtUpdatedAtDeletedAt

image.png

您可以将它嵌入到您的结构体中,以包含这几个字段,比如:

image.png

连接数据库 image.png

创建记录

image.png

批量插入

image.png

Upsert 及冲突

image.png

查询

image.png

更新

image.png

删除

image.png

Kitex的基础使用

官方文档:概览 | CloudWeGo

KiteX 是字节跳动(Bytedance)开源的高性能 RPC 框架,它具有高吞吐、高负载和高性能等特性。KiteX 提供了多种传输协议和消息协议的支持,其中包括 Thrift 和 Protobuf。下面是对 Thrift 和 Protobuf 的简要介绍:

Thrift:

  • Thrift 是一种软件框架,用于构建可扩展且跨语言的服务。
  • 它结合了功能强大的软件堆栈和代码生成引擎,使得在 C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk 和 OCaml 等编程语言之间构建高效的服务成为可能。
  • Thrift 还作为接口定义语言(IDL)允许您在一个简单的定义文件中定义数据类型和服务接口。编译器可以根据这个定义文件生成用于方便地在 RPC 客户端和服务器之间进行无缝跨编程语言通信的代码。

Protobuf:

  • Protobuf(Google Protocol Buffer)是一种高效轻巧的结构化数据存储方式,用于数据的通信协议和数据存储等。
  • 相对于 XML,Protobuf 具有以下特点:
    • 语言无关,平台无关。
    • 高效。
    • 具有更强的扩展性和兼容性。

在 KiteX 中,基于接口定义语言(IDL)的实践是非常重要的。服务端与客户端之间的远程通信需要通过一套协议(如消息、通信、传输等)来规范。客户端只需要定义好通信方式,而无需关心底层的技术实现。

KiteX 提供了一个命令行工具叫做 "kitex",它支持使用 Thrift、Protobuf 等接口定义语言(IDL)生成对应协议的代码。同时,它还支持生成服务端项目的骨架,帮助您快速搭建服务端应用。

编写 IDL

首先我们需要编写一个 IDL,这里以 thrift IDL 为例。 首先创建一个名为 echo.thrift 的 thrift IDL 文件。 然后在里面定义我们的服务

namespace go api

struct Request {
  1: string message
}

struct Response {
  1: string message
}

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

生成 echo 服务代码

$ kitex -module example -service example echo.thrift

上述命令中,-module 表示生成的该项目的 go module 名,-service 表明我们要生成一个服务端项目,后面紧跟的 example 为该服务的名字。最后一个参数则为该服务的 IDL 文件。

eg kitex -module kitex-ex -service api echo.thrift

编写 echo 服务端

我们需要编写的服务端逻辑都在 handler.go 这个文件中,现在这个文件应该如下所示:

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 函数就对应了我们之前在 IDL 中定义的 echo 方法。

现在让我们修改一下服务端逻辑,让 Echo 服务名副其实。

修改 Echo 函数为下述代码:

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

服务端的编译运行

kitex 工具已经帮我们生成好了编译和运行所需的脚本:

编译:

$ sh build.sh

执行上述命令后,会生成一个 output 目录,里面含有我们的编译产物。

运行:

$ sh output/bootstrap.sh

执行上述命令后,Echo 服务就开始运行啦!


编写客户端

有了服务端后,接下来就让我们编写一个客户端用于调用刚刚运行起来的服务端。

首先,同样的,先创建一个目录用于存放我们的客户端代码:$ mkdir client

进入目录:$ cd client

创建一个 main.go 文件,然后就开始编写客户端代码了。

首先让我们创建一个调用所需的 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)
}

发起调用

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)

在客户端的文件夹下执行

$ go run main.go

Hertz的基础使用

Hertz是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 fasthttp、gin、echo 的优势, 并结合字节跳动内部的需求,使其具有高易用性、高性能、高扩展性等特点。
官方文档:Hertz概览 | CloudWeGo

image.png

使用 Hertz 实现,服务监听 8080 端口并注册了一个 GET 方法的路由函数。

package main

import (
    "context"

    "github.com/cloudwego/hertz/pkg/app"
    "github.com/cloudwego/hertz/pkg/app/server"
    "github.com/cloudwego/hertz/pkg/common/utils"
    "github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main() {
    h := server.Default()

    h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
            ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
    })

    h.Spin()
}

运行代码,运行成功,接下来,我们可以对接口进行测试:

curl http://127.0.0.1:8888/ping

如果不出意外,我们可以看到类似如下输出:

{"message":"pong"}

Hertz提供了路由组的功能,用于支持路由分组

	// Simple group: v1
	v1 := h.Group("/v1")
	{
		//LoginEndpoint is a handler func
		V1.POST("/login", oginEndpoint)
		v1.POST("/submit", submitEndpoint)
		v1.POST("/streaming_read", readEndpoint)
	}
	// Simple group: v2
	v2 := h.Group(" /v2")
	{
		v2.POST("/login", loginEndpoint)
		v2.POST("/submit", submitEndpoint)
		v2.POST("/streaming_read", readEndpoint)
	}

Hertz 提供了代码生成工具 Hz,通过定义 DL(inteface description language ) 文件即可生成对应的基础服务代码。

gorm+kitex+hertz的官方demo:
kitex-examples/bizdemo/easy_note at main · cloudwego/kitex-examples (github.com)