Grpc-GO API设计实践
grpc-go API设计实践,参考 https://www.youtube.com/watch?v=Z_yD7YPL2oE
- API接口幂等性
- 服务接口应该是幂等的,可以让客户端在请求失败的情况下安全重试
- 性能
- repeated字段
- 请求:可能包含无限制请求,需要设置限制
- 回复:应该支持分页
- 避免长时间运行操作
- 运行时间越长,重试可能性就越大
- 后台执行(可靠性),异步发送回复(回调,邮件,pubsub),或者提供可跟踪token
- repeated字段
- 默认值
- 定义合理的默认行为
- 枚举zero value为Unset,使用UNKOWN/UNSPECIFIED/UNSET作为默认值(防止误用)
- 向前兼容
- 服务的和客户端是无法同步更新的
- 添加字段时,默认行为应该是之前的行为
- 加入新特性时可回滚
- 定义合理的默认行为
- 错误信息
- Errors
- grpc内置First-class
- 不要在response payload中包含错误信息(大多数情况下)
- 避免批量处理多个无关操作
- 例如更新数据库的多条记录
- 错误处理会变得更复杂(因为存在部分成功的场景)
- 使用stream形式的接口,或者调用多次接口
- Errors
- 错误处理-避免Panic,尽可能优雅的处理错误
- 只有内部状态无法恢复时,Panic才是合适做法
- 内存错误
- OOM
- 数据错误
- 错误都返回给调用方(避免隐藏错误)
- 避免nil指针异常(使用proto结构的getter方法,可以正确处理nil指针)
- 只有内部状态无法恢复时,Panic才是合适做法
- 错误处理-适当传播错误,
- 避免直接返回从依赖库或服务产生的错误,调用方可能无法理解错误信息,难以调试
- Deadline
- 客户端应该总是使用deadline来调用接口
- 服务端在必要的情况下检查deadline设置(避免过短或过长的Deadline)
- 过短的Deadline会导致操作无法在指定时间内完成,接口几乎总是失败
- 过长的Deadline可能会占用其他用户的资源(特定任务类型的情况下)
- 传播Deadline-服务继续调用其他服务或接口
- 直接重用客户端的context
- 优点:简单有效
- 缺点:依赖接口可能需要不同的deadline设置
- 为每个接口指定适当的deadline
- 优点:可以更早的取消调用(cancellation)
- 缺点:代码较多,可能过早取消
- 直接重用客户端的context
- 限速-服务在需要的情况下应该限制接口调用速率
- golang.org/x/time/rate
- 客户端也应该对接口调用限速(限制调用次数和速率,特别是在重试的情况下)
- 内存管理
- 限制并发goroutine(grpc-Go默认无限制)
- 设置listener限制和并发stream限制 golang.org/x/net/netutil
- 当太多的rpc请求在执行中时,使用Tap handler处理错误
- 健康报告和负载均衡
- 限制请求和回复payload大小
- 设置最大request payload size:grpc.MaxRecvMsgSize
- 防止产生过大回复请求
- 例如数据库查询(select * from …)
- API设计-使用stream返回,或者使用分页返回限制单次最大返回
- 限制并发goroutine(grpc-Go默认无限制)
- 日志
- 在错误时发生时详细记录错误上下文,便于调试
- 开发阶段使用Trace或Debug级别记录日志
- 使用日志分析工具进行统计和告警
- 监控
- 导出各种监控指标(响应时间,请求数,失败数,etc…),总和,平均,峰值,按接口分类
- 配置合适的告警策略