简介
Gorm是一个已经迭代了十年加的orm框架并在字节内部广泛使用且拥有非常丰富的开源拓展。
Kitex是字节内部GOlang微服务RPC框架,有高性能,强可拓展性的特点,拥有多协议并有丰富的开源拓展。
Hertz是字节内部的HTTP框架,参考了其他开源框架优势,结合了字节内部需求,具有高易用性,高性能,高拓展性特点。
Gorm
基本操作 要使用Gorm,第一步要定义modle,可以如下:
type User struct {
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time
MemberNumber sql.NullString
ActivedAt sql.NullTime
CreatedAt time.Time
UpdatedAt time.Time
}
要注意的是,GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,也可以通过func来实现表名的定义。
下一步是连接到数据库,我们可以通过不同的驱动去调用不同的数据库,可以通过
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
来调用官方数据库类型MySQL, PostgreSQL, SQlite, SQL Server。
GORM 允许通过 DriverName 选项自定义 MySQL 驱动,例如:
import (
_ "example.com/my_mysql_driver"
"gorm.io/gorm"
)
db, err := gorm.Open(mysql.New(mysql.Config{
DriverName: "my_mysql_driver",
DSN: "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local", // Data Source Name,参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name
}), &gorm.Config{})
这个过程许需要传递一个DSN,这样我们就创建了一个Gorm对象,接下来我们可以进行一些基本操作
我们可以使用db.creat来创建一条记录或多条组成的切片或数组,也可以在此基础上使用select和omit来筛选记录
db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")
db.Omit("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")
也可以使用db.first来查询单条记录,注意要输入指针在这里,db.find可查询多条记录,但find命令若查不到数据则不回返回错误,当使用结构作为条件查询时,只会查询非0值,更新也类似,使用select可以规避0值。以下查询方式较为常见:
// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');
使用update可以更新列数据,注意在使用结构体字段时仅会更改非0字段,更新0值可以使用map,附加.model和.table可以在指定的表中查询记录。
使用upsert处理冲突
// 不处理冲突
DB.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)
// `id` 冲突时,将字段值更新为默认值
DB.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.Assignments(map[string]interface{}{"role": "user"}),
删除分为软件删除和物理删除,平常的开发中多用软删除
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;
//物理删除
// user 的 ID 是 `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
//软删除
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;
//查找软删除的内容
下面是一些事务相关的操作,注意忘写rollback或commit可能导致泄露
事务相关的操作
// 开始事务
tx := db.Begin()
// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)
// 遇到错误时回滚事务
tx.Rollback()
// 否则,提交事务
tx.Commit()
当然,也可使用tansaction自动提交来防止漏泄。
Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数。下面是示例
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
u.UUID = uuid.New()
if !u.IsValid() {
err = errors.New("can't save invalid data")
}
return
}
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
if u.ID == 1 {
tx.Model(u).Update("role", "admin")
}
return
}
为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,可以在初始化时禁用它,这将获得大约 30%+ 性能提升。
// 全局禁用
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{ SkipDefaultTransaction: true, })
// 持续会话模式
tx := db.Session(&Session{SkipDefaultTransaction: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)
或者preparedstmt缓存预编译语句也可提高调用速度。
Gorm还有许多扩展生态,如gorm-gen代码生成工具,分片库,手动索引等。
Kitex
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 支持
服务治理:支持服务注册/发现、负载均衡、熔断、限流、重试、监控、链路跟踪、日志、诊断等服务治理模块,大部分均已提供默认扩展,使用者可选择集成。
代码生成:Kitex 内置代码生成工具,可支持生成 Thrift、Protobuf 以及脚手架代码。
对于windows的支持还不完全,建议在虚拟机上进行操作。
需要安装代码生成工具,可以通过执行以下命令来实现:
go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
和go install github.com/cloudewego/thriftgo@latest来实现,当显示版本后,则代表安装成功
安装完成后,第一步是定义IDL,如果我们要进行RPC,就需要知道对方的接口是什么,需要什么参数,也要知道返回值是什么,通过IDL来约定双方的协议,描述接口
namespace go api
struct Request{
1:string message
}
struct Respone{
1:string message
}
使用 kitex-module example-service examlpe echo.thrift 命令可用于生成代码,需要指定module名service名和api就可用于生成代码,建议直接使用该官方工具生成代码,会自带官方优化。
启动后我们可以使用cd kitex-examples/hello来进入hello目录,用go run ./server来运行服务器,go run ./client另起一个终端。
以下展示定义一个新的请求和响应
namespace go api
struct Request
{ 1: string message }
struct Response
{ 1: string message }
struct AddRequest
{ 1: i64 first 2: i64 second }
struct AddResponse
{ 1: i64 sum }
service Hello
{ Response echo(1: Request req)
AddResponse add(1: AddRequest req) }
使用Kitex Client发起请求,系统默认的监听接口是8888,保证协议一致,这样我们就可以去调度其他语言的服务,使用newclient来创建新的client,再使用c.Echo如(context.Background(),req,callopt.WithRPCTimeout (3*time.second)) 设置超时.
目前Kitex的服务已经与主流服务器注册与发现中心对接,如ETCD,Macos,时间效率高,服务的注册和发现依旧要使用Etcd的扩展,只要传递地址和对象,接下来用newclient传递服务名,将服务的对象传递进来就行了。
多环境治理等可以使用XDS扩展工具,poentelemetry扩展也可以在RPC广泛应用