0. 为什么说做好微服务很难?
要想做好微服务,我们需要理解和掌握的知识点非常多,从几个维度上来说:
•基本功能层面1.并发控制&限流,避免服务被突发流量击垮2.服务注册与服务发现,确保能够动态侦测增减的节点3.负载均衡,需要根据节点承受能力分发流量4.超时控制,避免对已超时请求做无用功5.熔断设计,快速失败,保障故障节点的恢复能力•高阶功能层面1. 请求认证,确保每个用户只能访问自己的数据2.链路追踪,用于理解整个系统和快速定位特定请求的问题3.日志,用于数据收集和问题定位4.可观测性,没有度量就没有优化
对于其中每一点,我们都需要用很长的篇幅来讲述其原理和实现,那么对我们后端开发者来说,要想把这些知识点都掌握并落实到业务系统里,难度是非常大的,不过我们可以依赖已经被大流量验证过的框架体系。go-zero 微服务框架[1]就是为此而生。
另外,我们始终秉承工具大于约定和文档的理念。我们希望尽可能减少开发人员的心智负担,把精力都投入到产生业务价值的代码上,减少重复代码的编写,所以我们开发了 工具。
下面我通过书店服务来演示通过 go-zero[1]快速的创建微服务的流程,走完一遍,你就会发现:原来编写微服务如此简单!
1. 书店服务示例简介
为了教程简单,我们用书店服务做示例,并且只实现其中的增加书目和检查价格功能。
写此书店服务是为了从整体上演示 go-zero 构建完整微服务的过程,实现细节尽可能简化了。
2. 书店微服务架构图
3. goctl 各层代码生成一览
所有绿色背景的功能模块是自动生成的,按需激活,红色模块是需要自己写的,也就是增加下依赖,编写业务特有逻辑,各层示意图分别如下:
•API Gateway
•RPC
•model
下面我们来一起完整走一遍快速构建微服务的流程,Let’s !
4. 准备工作
•安装 etcd, mysql, redis•安装 goctl 工具
•创建工作目录 •在 目录下执行 初始化5. 编写 API Gateway 代码•在 目录下通过 goctl 生成 :
编辑 ,为了简洁,去除了文件开头的 ,代码如下:
type 用法和 go 一致,service 用来定义 get/post/head/delete 等 api 请求,解释如下:
• 这一行定义了 service 名字•部分用来定义 server 端用到的属性•定义了服务端 handler 名字•定义了 get 方法的路由、请求参数、返回参数等•使用 goctl 生成 API Gateway 代码
生成的文件结构如下:
•启动 API Gateway 服务,默认侦听在 8888 端口
•测试 API Gateway 服务
返回如下:
可以看到我们 API Gateway 其实啥也没干,就返回了个空值,接下来我们会在 rpc 服务里实现业务逻辑
•可以修改 来传递服务依赖(如果需要)•实现逻辑可以修改 下的对应文件•可以通过 生成各种客户端语言的 api 调用代码•到这里,你已经可以通过 goctl 生成客户端代码给客户端同学并行开发了,支持多种语言,详见文档。6. 编写 add rpc 服务•在 目录下编写 文件
可以通过命令生成 proto 文件模板
修改后文件内容如下:
•用 生成 rpc 代码,在 目录下执行命令
文件结构如下:
直接可以运行,如下:
文件里可以修改侦听端口等配置
7. 编写 check rpc 服务
•在 目录下编写 文件
可以通过命令生成 proto 文件模板
修改后文件内容如下:
•用 生成 rpc 代码,在 目录下执行命令
文件结构如下:
文件里可以修改侦听端口等配置
需要修改 的端口为 ,因为 已经被 服务使用了,直接可以运行,如下:
8. 修改 API Gateway 代码调用 add/check rpc 服务
•修改配置文件 ,增加如下内容
通过 etcd 自动去发现可用的 add/check 服务
•修改 如下,增加 add/check 服务依赖
•修改 ,如下:
通过 ServiceContext 在不同业务逻辑之间传递依赖
•修改 里的 方法,如下:
通过调用 的 方法实现添加图书到 bookstore 系统
•修改 里的 方法,如下:
通过调用 的 方法实现从 bookstore 系统中查询图书的价格。
9. 定义数据库表结构,并生成 CRUD+cache 代码
•bookstore 下创建 目录:•在 rpc/model 目录下编写创建 book 表的 sql 文件,如下:
•创建 DB 和 table
•在 目录下执行如下命令生成 CRUD+cache 代码, 表示使用
也可以用 命令代替 来指定数据库链接直接从 schema 生成
生成后的文件结构如下:
10. 修改 add/check rpc 代码调用 CRUD+cache 代码
•修改 和 ,增加如下内容:
可以使用多个 redis 作为 cache,支持 redis 单点或者 redis 集群
•修改 和 ,如下:
增加了 MySQL 和 redis cache 配置
•修改 和 ,如下:
•修改 ,如下:
•修改 ,如下:
至此代码修改完成,凡事手动修改的代码我加了标注。
11. 完整调用演示
•add api 调用
返回如下:
•check api 调用
返回如下:
12. Benchmark
因为写入依赖于 MySQL 的写入速度,就相当于压 MySQL 了,所以压测只测试了 check 接口,相当于从 MySQL 里读取并利用缓存,为了方便,直接压这一本书,因为有缓存,多本书也是一样的,对压测结果没有影响。
压测之前,让我们先把打开文件句柄数调大:
并日志的等级改为 ,防止过多的 info 影响压测结果,在每个 yaml 配置文件里加上如下:
可以看出在我的 MacBook Pro 上能达到 3万+ 的 QPS。
13. 总结
我们一直强调工具大于约定和文档。
go-zero 不只是一个框架,更是一个建立在框架+工具基础上的,简化和规范了整个微服务构建的技术体系。
我们在保持简单的同时也尽可能把微服务治理的复杂度封装到了框架内部,极大的降低了开发人员的心智负担,使得业务开发得以快速推进。
通过 go-zero+goctl 生成的代码,包含了微服务治理的各种组件,包括:并发控制、自适应熔断、自适应降载、自动缓存控制等,可以轻松部署以承载巨大访问量。
有任何好的提升工程效率的想法,随时欢迎交流!
14. 项目地址
https://github.com/tal-tech/go-zero
References
go-zero 微服务框架:https://github.com/tal-tech/go-zero
最后再附上万俊峰 Kevin 在 Go 夜读第 101 期《晓黑板 go-zero 微服务框架实践》的视频回看。
领取专属 10元无门槛券
私享最新 技术干货