# 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有异常不能恢复时，不会刷新服务列表，保障服务依然可用
- 缓存的设计与使用案例
   - 分布式多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日志

![](https://lh5.googleusercontent.com/PBRdYmRs22xEH1gjNkQnoHuB5WFBva10oKCm61A6G23xvi28u95Bwq-qTc_WVV-PihzAHyLpAKkBtbtzK8v9Kjtrp3YBZqGiTSXhHJHwf7CAv5K9AqBSc1CZuV0u3URCDVP8r1RD0PY#align=left&display=inline&height=658&margin=%5Bobject%20Object%5D&originHeight=658&originWidth=1294&status=done&style=none&width=1294)

- go-zero框架有用到什么池化技术吗？如果有，在哪些core代码里面可以参考
   - 一般不需要提前优化，过度优化是大忌
   - core/syncx/pool.go里面定义了带过期时间的通用池化技术
- go-zero用到了那些性能测试方法框架，有代码参考吗？可以说说思路和经验
   - go benchmark
   - 压测可以通过现有业务日志样本，来按照预估等比放大
   - 压测一定要压到系统扛不住，看第一个瓶颈在哪里，改完再压，循环
- 说一下代码的抽象经验和心得
   - Don’t repeat yourself
   - 你未必需要它，之前经常有业务开发人员问我可不可以增加这个功能或那个功能，我一般都会仔细询问深层次目的，很多时候会发现其实这个功能是多余的，不需要才是最佳实践
   - Martin Fowler提出出现三次再抽象的原则，有时有些同事会找我往框架里增加一个功能，我思考后经常会回答这个你先在业务层写，其它地方也有需要了你再告诉我，三次出现我会考虑集成到框架里
   - 一个文件应该尽量只做一件事，每个文件尽可能控制在200行以内，一个函数尽可能控制在50行以内，这样不需要滚动就可以看到整个函数
   - 需要抽象和提炼的能力，多去思考，经常回头思考之前的架构或实现
- 你会就go-zero 框架从设计到实践出书吗？框架以后的发展规划是什么？
   - 暂无出书计划，做好框架是最重要的
   - 继续着眼于工程效率
   - 提升服务治理能力
   - 帮助业务开发尽可能快速落地

<Vssue title="103" />
