10月3日线上交流问题汇总
- go-zero适用场景
- 希望说说应用场景,各个场景下的优势
- 高并发的微服务系统
- 支撑千万级日活,百万级QPS
- 完整的微服务治理能力
- 支持自定义中间件
- 很好的管理了数据库和缓存
- 有效隔离故障
- 低并发的单体系统
- 这种系统直接使用api层即可,无需rpc服务
- 高并发的微服务系统
- 各个功能的使用场景以及使用案例
- 限流
- 熔断
- 降载
- 超时
- 可观测性
- 希望说说应用场景,各个场景下的优势
- go-zero的实际体验
- 服务很稳
- 前后端接口一致性,一个api文件即可生成前后端代码
- 规范、代码量少,意味着bug少
- 免除api文档,极大降低沟通成本
- 代码结构完全一致,便于维护和接手
- 微服务的项目结构, monorepo的 CICD 处理
bookstore
├── api
│ ├── etc
│ └── internal
│ ├── config
│ ├── handler
│ ├── logic
│ ├── svc
│ └── types
└── rpc
├── add
│ ├── adder
│ ├── etc
│ ├── internal
│ │ ├── config
│ │ ├── logic
│ │ ├── server
│ │ └── svc
│ └── pb
├── check
│ ├── checker
│ ├── etc
│ ├── internal
│ │ ├── config
│ │ ├── logic
│ │ ├── server
│ │ └── svc
│ └── pb
└── model
mono repo的CI我们是通过gitlab做的,CD使用jenkins CI尽可能更严格的模式,比如-race,使用sonar等工具 CD有开发、测试、预发、灰度和正式集群 晚6点上灰度、无故障的话第二天10点自动同步到正式集群 正式集群分为多个k8s集群,有效的防止单集群故障,直接摘除即可,集群升级更有好
- 如何部署,如何监控?
- 全量K8S,通过jenkins自动打包成docker镜像,按照时间打包tag,这样可以一眼看出哪一天的镜像
- 上面已经讲了,预发->灰度->正式
- Prometheus+自建dashboard服务
- 基于日志检测服务和请求异常
- 如果打算换go-zero框架重构业务,如何做好线上业务稳定安全用户无感切换?另外咨询下如何进行服务划分?
- 逐步替换,从外到内,加个proxy来校对,校对一周后可以切换
- 如有数据库重构,则需要做好新老同步
- 服务划分按照业务来,遵循从粗到细的原则,避免一个api一个微服务
- 数据拆分对于微服务来讲尤为重要,上层好拆,数据难拆,尽可能保证按照业务拆分数据
- 服务发现
- 服务发现 etcd 的 key 的设计
- 服务key+时间戳,服务进程数存在时间戳冲突的概率极低,忽略
- etcd服务发现与治理, 异常捕获与处理异常
- 为啥k8s还使用etcd做服务发现,因为dns的刷新有延迟,导致滚动更新会有大量失败,而etcd可以做到完全无损更新
- etcd集群直接部署在k8s集群内,因为多个正式集群,集群单点和注册避免混乱
- 针对etcd异常或者leader切换,自动侦测并刷新,当etcd有异常不能恢复时,不会刷新服务列表,保障服务依然可用
- 服务发现 etcd 的 key 的设计
- 缓存的设计与使用案例
- 分布式多redis集群,线上最大几十个集群为同一个服务提供缓存服务
- 无缝扩缩容
- 不存在没有过期时间的缓存,避免大量不常使用的数据占用资源,默认一周
- 缓存穿透,没有的数据会短暂缓存一分钟,避免刷接口或大量不存在的数据请求带垮系统
- 缓存击穿,一个进程只会刷新一次同一个数据,避免热点数据被大量同时加载
- 缓存雪崩,对缓存过期时间自动做了jitter,5%的标准变差,使得一周的过期时间分布在16小时内,有效防止了雪崩
- 我们线上数据库都有缓存,否则无法支撑海量并发
- 自动缓存管理已经内置于go-zero,并可以通过goctl自动生成代码
能否讲解下, 中间件,拦截器的设计思想
- 洋葱模型
- 本中间件处理,比如限流,熔断等,然后决定是否调用next
- next调用
- 对next调用返回结果做处理
- 微服务的事务处理怎么实现好,gozero分布式事务设计和实现,有什么好中间件推荐
- 2PC,两阶段提交
- TCC,Try-Confirm-Cancel
- 消息队列,最大尝试
- 人工补偿
- 多级 goroutine 的异常捕获 ,怎么设计比较好
- 微服务系统请求异常应该隔离,不能让单个异常请求带崩整个进程
- go-zero自带了RunSafe/GoSafe,用来防止单个异常请求导致进程崩溃
- 监控需要跟上,防止异常过量而不自知
- fail fast和故障隔离的矛盾点
- k8s配置的生成与使用(gateway, service, slb)
- 内部自动生成k8s的yaml文件,过于依赖配置而未开源
- 打算在bookstore的示例里加上k8s配置样板
- slb->nginx->nodeport->api gateway->rpc service
- gateway限流、熔断和降载
- 限流分为两种:并发控制和分布式限流
- 并发控制用来防止瞬间过量请求,保护系统不被打垮
- 分布式限流用来给不同服务配置不同的quota
- 熔断是为了对依赖的服务进行保护,当一个服务出现大量异常的时候,调用者应该给予保护,使其有机会恢复正常,同时也达到fail fast的效果
- 降载是为了保护当前进程资源耗尽而陷入彻底不可用,确保尽可能服务好能承载的最大请求量
- 降载配合k8s,可以有效保护k8s扩容,k8s扩容分钟级,go-zero降载秒级
- 介绍core中好用的组件,如timingwheel等,讲讲设计思路
- 布隆过滤器
- 进程内cache
- RollingWindow
- TimingWheel
- 各种executors
- fx包,map/reduce/filter/sort/group/distinct/head/tail…
- 一致性hash实现
- 分布式限流实现
- mapreduce,带cancel能力
- syncx包里有大量的并发工具
- 如何快速增加一种rpc协议支持,將跨机发现改为调本机节点,并关闭复杂filter和负载均衡功能
- go-zero跟grpc关系还是比较紧密的,设计之初没有考虑支持grpc以外的协议
- 如果要增加的话,那就只能fork出来魔改了
- 调本机直接用direct的scheme即可
- 为啥要去掉filter和负载均衡?如果要去的话,fork了改,但没必要
- 日志和监控和链路追踪的设计和实现思路,最好有大概图解
- 日志和监控我们使用prometheus, 自定义dashboard服务,捆绑提交数据(每分钟)
- 链路追踪可以看出调用关系,自动记录trace日志
- go-zero框架有用到什么池化技术吗?如果有,在哪些core代码里面可以参考
- 一般不需要提前优化,过度优化是大忌
- core/syncx/pool.go里面定义了带过期时间的通用池化技术
- go-zero用到了那些性能测试方法框架,有代码参考吗?可以说说思路和经验
- go benchmark
- 压测可以通过现有业务日志样本,来按照预估等比放大
- 压测一定要压到系统扛不住,看第一个瓶颈在哪里,改完再压,循环
- 说一下代码的抽象经验和心得
- Don’t repeat yourself
- 你未必需要它,之前经常有业务开发人员问我可不可以增加这个功能或那个功能,我一般都会仔细询问深层次目的,很多时候会发现其实这个功能是多余的,不需要才是最佳实践
- Martin Fowler提出出现三次再抽象的原则,有时有些同事会找我往框架里增加一个功能,我思考后经常会回答这个你先在业务层写,其它地方也有需要了你再告诉我,三次出现我会考虑集成到框架里
- 一个文件应该尽量只做一件事,每个文件尽可能控制在200行以内,一个函数尽可能控制在50行以内,这样不需要滚动就可以看到整个函数
- 需要抽象和提炼的能力,多去思考,经常回头思考之前的架构或实现
- 你会就go-zero 框架从设计到实践出书吗?框架以后的发展规划是什么?
- 暂无出书计划,做好框架是最重要的
- 继续着眼于工程效率
- 提升服务治理能力
- 帮助业务开发尽可能快速落地