你的单体服务架构是否遇到一些问题, 不能满足业务需求? 那么微服务会是好的解决方案.
Cinch是一套轻量级微服务脚手架, 基于Kratos, 节省基础服务搭建时间, 快速投入业务开发.
我们参考了Go的许多微服务架构, 结合实际需求, 最终选择简洁的Kratos作为基石(B站架构), 从架构的设计思路以及代码的书写格式和我们非常匹配.
cinch意为简单的事, 小菜. 希望把复杂的事变得简单, 提升开发效率.
若你想深入学习微服务每个组件, 建议直接看Kratos官方文档. 本项目整合一些业务常用组件, 开箱即用, 并不会把每个组件都介绍那么详细.
Go- 当前Go版本直接上v1.20Proto- proto协议同时开启gRPC & HTTP支持, 只需开发一次接口, 不用写两套Jwt- 认证, 用户登入登出一键搞定Action- 权限, 基于行为的权限校验Redis- 缓存, 内置防缓存穿透/缓存击穿/缓存雪崩示例Gorm- 数据库ORM管理框架, 可自行扩展多种数据库类型, 目前使用MySQL, 其他自行扩展Gorm Gen- Gorm实体自动生成, 无需再写数据库实体映射Tenant- 基于Gorm的schema层面的多租户(一个租户一个数据库schema)SqlMigrate- 数据库迁移工具, 每次更新平滑迁移Asynq- 分布式定时任务(异步任务)Log- 日志, 在Kratos基础上增加一层包装, 无需每个方法传入Embed- go 1.16文件嵌入属性, 轻松将静态文件打包到编译后的二进制应用中Opentelemetry- 链路追踪, 跨服务调用可快速追踪完整链路Idempotent- 接口幂等性(解决重复点击或提交)Pprof- 内置性能分析开关, 对并发/性能测试友好Wire- 依赖注入, 编译时完成依赖注入Swagger- Api文档一键生成, 无需在代码里写注解I18n- 国际化支持, 简单切换多语言
使用cinch工具快速创建Game服务
go install github.com/go-cinch/cinch/cmd/cinch@latest
cinch new game├── api                  // 各个微服务的proto/go文件, proto文件通过submodule管理包含proto后缀
│   ├── auth             // auth服务所需的go文件(通过命令生成)
│   ├── auth-proto       // auth服务proto文件
│   ├── reason
│   ├── reason-proto     // 公共reason(错误码建议统一管理, 不要不同服务搞不同的)
│   ├── xxx              // xxx服务所需的go文件(通过命令生成)
│   ├── xxx-proto        // xxx服务proto文件
│   └── ...
├── cmd                  
│   └── game             // 项目名
│       ├── main.go      // 程序主入口
│       ├── wire.go      // wire依赖注入
│       └── wire_gen.go
├── configs              // 配置文件目录
│   ├── config.yml       // 主配置文件
│   ├── client.yml       // 配置grpc服务client, 如auth
│   ├── gen.yml          // gen gorm或migrate会用到的配置文件
│   └── ...              // 其他自定义配置文件以yml/yaml结尾均可
├── internal             // 内部逻辑代码
│   ├── biz              // 业务逻辑的组装层, 类似 DDD 的 domain 层, data 类似 DDD 的 repo, 而 repo 接口在这里定义, 使用依赖倒置的原则. 
│   │   ├── biz.go
│   │   ├── reason.go    // 定义错误描述
│   │   ├── game.go      // game业务
│   │   └── xxx.go       // 其他业务
│   ├── conf
│   │   ├── conf.pb.go
│   │   └── conf.proto   // 内部使用的config的结构定义, 使用proto格式生成
│   ├── data             // 业务数据访问, 包含 cache、db 等封装, 实现了 biz 的 repo 接口. 我们可能会把 data 与 dao 混淆在一起, data 偏重业务的含义, 它所要做的是将领域对象重新拿出来, 我们去掉了 DDD 的 infra层. 
│   │   ├── model        // gorm gen生成model目录
│   │   ├── query        // gorm gen生成query目录
│   │   ├── cache.go     // cache层, 防缓存击穿/缓存穿透/缓存雪崩
│   │   ├── client.go    // 各个微服务client初始化
│   │   ├── ctx.go
│   │   ├── data.go      // 数据初始化, 如DB/Redis
│   │   ├── game.go
│   │   └── tracer.go    // 链路追踪tracer初始化
│   ├── db
│   │   ├── migrations   // sql迁移文件目录, 每一次数据库变更都放在这里, 参考https://github.com/rubenv/sql-migrate
│   │   │   ├── xxx.sql  // sql文件
│   │   │   └── ...
│   │   └── migrate.go   // embed sql文件
│   ├── pkg              // 自定义扩展包
│   │   ├── idempotent   // 接口幂等性
│   │   ├── task         // 异步任务, 内部调用asynq
│   │   └── xxx          // 其他扩展
│   ├── server           // http和grpc实例的创建和配置
│   │   ├── middleware   // 自定义中间件
│   │   │   ├── locales  // i18n多语言map配置文件
│   │   │   └── xxx.go   // 一些中间件
│   │   ├── grpc.go
│   │   ├── http.go
│   │   └── server.go
│   └── service          // 实现了 api 定义的服务层, 类似 DDD 的 application 层, 处理 DTO 到 biz 领域实体的转换(DTO -> DO), 同时协同各类 biz 交互, 但是不应处理复杂逻辑
│       ├── service.go
│       ├── game.go      // game接口入口
│       └── xxx.go       // 其他接口入口
├── third_party          // api依赖的第三方proto, 编译proto文件需要用到
│   ├── cinch            // cinch公共依赖
│   ├── errors
│   ├── google
│   ├── openapi
│   │── validate
│   └── ...              //  其他自定义依赖
├─ .gitignore
├─ .gitmodules           // submodule配置文件
├─ .golangci.yml         // golangci-lint
├─ Dockerfile
├─ go.mod
├─ go.sum
├─ LICENSE
├─ Makefile
└─ README.md
启动项目前, 我默认你已准备好(部分软件按建议方式安装即可):
- go1.18+(建议使用g)
# sudo apt update # sudo apt install -y curl curl -sSL https://raw.githubusercontent.com/voidint/g/master/install.sh | bash source "$HOME/.g/env" # g --version # g version 1.5.0 g install 1.20 # go version # go version go1.20 linux/amd64 echo "export GOPATH=/home/ubuntu/go" >> ~/.bashrc # 设置go/bin目录到PATH, 若不设置, go安装的一些文件无法识别 echo "export PATH=$PATH:/home/ubuntu/.g/go/bin:/home/ubuntu/go/bin" >> ~/.bashrc source ~/.bashrc
 - 开启go modules
 - mysql(本地测试建议使用docker-compose搭建)
 - redis(本地测试建议使用docker-compose搭建)
# 安装docker sudo apt-get update curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo apt-key fingerprint 0EBFCD88 sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo apt-get update sudo apt-get install -y docker-ce # sudo docker -v # Docker version 23.0.1, build a5ee5b1 # 国内加速安装 sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" sudo apt-get update sudo apt-get install -y docker-ce # sudo docker -v # Docker version 23.0.1, build a5ee5b1 # 去除docker sudo sudo groupadd docker sudo gpasswd -a ${USER} docker sudo systemctl restart docker sudo chmod a+rw /var/run/docker.sock # docker -v # Docker version 23.0.1, build a5ee5b1 # docker-compose sudo curl -L https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose # docker-compose -v # Docker Compose version v2.10.2 # 简单启动一个单机版mysql和redis git clone https://github.com/go-cinch/compose cd compose/single # 修改默认密码 source myenv docker-compose -f docker-compose.db.yml up -d redis mysql # docker ps # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 918328d0aae1 mysql:8.0.19 "docker-entrypoint.s…" About an hour ago Up 59 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql # 918b2cfcd72e redis:7.0 "docker-entrypoint.s…" About an hour ago Up 59 minutes 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
 - protoc
curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.20.3/protoc-3.20.3-`uname -s`-`uname -m`.zip # apt install -y unzip sudo unzip protoc-3.20.3-`uname -s`-`uname -m`.zip -d /usr # protoc --version # libprotoc 3.20.3
 - protoc-gen-go
go install google.golang.org/protobuf/cmd/[email protected] # protoc-gen-go --version # protoc-gen-go v1.30.0
 - git
sudo apt update sudo apt install -y git
 - cinch cli工具
go install github.com/go-cinch/cinch/cmd/cinch@latest # cinch -v cinch version v1.0.0 
权限认证服务无需再开发, 下载开箱即用
git clone https://github.com/go-cinch/auth
# 可以指定tag
# git clone -b v1.0.3 https://github.com/go-cinch/auth# 1.通过模板创建项目
cinch new game
# -r 指定仓库 -b 指定分支
# cinch new game -r https://github.com/go-cinch/layout.git -b dev
# 2. 进入项目
cd game
# 创建个人开发分支
git init -b mark/dev
# 如果你的git版本较低
# git init
# git checkout -b mark/dev
# 3. 初始化submodule(不想使用可忽略此步骤)
# -b指定分支 --name指定submodule名称
git submodule add -b master --name api/auth-proto https://github.com/go-cinch/auth-proto.git ./api/auth-proto
# -b指定分支 --name指定submodule名称
git submodule add -b master --name api/reason-proto https://github.com/go-cinch/reason-proto.git ./api/reason-proto
# 这里用game作为示例, 按需修改
# -b指定分支 --name指定submodule名称
git submodule add -b master --name api/game-proto https://github.com/go-cinch/game-proto.git ./api/game-proto
# 删除一个已经存在的submodule
# git submodule deinit api/game-proto
# git rm --cached api/game-proto
# rm -rf .git/modules/api/game-proto
# rm -rf api/game-proto
# 4. 初始化依赖项(需确保已经安装make)
# sudo apt install -y make
make init
# 5. 编译项目
make all# 修改auth项目配置
cd auth
# 将mysql/redis的配置修改成你本地配置
vim configs/config.yml
# 修改game项目配置
cd game
# 将mysql/redis的配置修改成你本地配置
vim game/configs/config.yml
# 将auth服务host和端口修改成你本地配置
vim game/configs/client.yml
# 启动auth
cd auth
cinch run
# 启动game
cd game
cinch run# 启动auth
# 如果你用的是compose/single
export AUTH_DATA_DATABASE_DSN='root:mysqlrootpwd@tcp(127.0.0.1:3306)/auth?parseTime=True'
export AUTH_DATA_REDIS_DSN='redis://:[email protected]:6379/0'
# 其他按需修改
export AUTH_DATA_DATABASE_DSN='root:root@tcp(127.0.0.1:3306)/auth?parseTime=True'
export AUTH_DATA_REDIS_DSN='redis://127.0.0.1:6379/0'
cd auth
cinch run
# 启动game
# 如果你用的是compose/single
export GAME_DATA_DATABASE_DSN='root:mysqlrootpwd@tcp(127.0.0.1:3306)/game?parseTime=True'
export GAME_DATA_REDIS_DSN='redis://:[email protected]:6379/0'
# 其他按需修改
export GAME_DATA_DATABASE_DSN='root:root@tcp(127.0.0.1:3306)/game?parseTime=True'
export GAME_DATA_REDIS_DSN='redis://127.0.0.1:6379/0'
# 设置auth服务
export GAME_CLIENT_AUTH='127.0.0.1:6160'
cd game
cinch runTip: 环境变量前缀可在cmd/xxx/main.go中修改, 参见环境变量前缀
auth服务:
curl http://127.0.0.1:6060/idempotent
# 输出如下说明服务通了只是没有权限, 出现其他说明配置有误
# {"code":401, "reason":"UNAUTHORIZED", "message":"token is missing", "metadata":{}}game服务:
curl http://127.0.0.1:8080/hello/world
# 输出如下说明服务通了只是没有权限, 出现其他说明配置有误
# {"code":401, "reason":"UNAUTHORIZED", "message":"token is missing", "metadata":{}}至此, 微服务已启动完毕, auth以及game, 接下来可以自定义你的game啦~
以下几个较为常用, 当然你也可以按顺序查看Docs