ColinOrg 2020-03-21
1. 交易型系统的一些设计原则
无状态:有利于水平扩容
数据异构:比如订单系统,既需要根据userId维度查询所有订单,又需要根据订单id查询,这时候需要数据异构存储
防重设计:跟客户端(比如clientSeqId)配合,或者服务端控制,组合key,进行防重限制
幂等设计:服务或接口考虑支持幂等,提高可用性
2. 高可用
负载均衡:动态upstream更新(Consul+OpenResty), 可以结合nginx,进行动态upstream更新,其实nginx有插件支持health check机制(或者直接使用淘宝开源的Tengine),可以自动摘除问题机器的; 还有一点 upstream的若使用域名解析通常比较费时,所以upstream会配置内网ip
3. 隔离
集群隔离保证不同子业务互相无影响,机房维度隔离可以保证有问题切机房,对于web端来说动静隔离也很重要,比如静态资源都走CDN
4. 限流
guava提供了令牌桶算法的实现,RateLimiter,有阻塞和非阻塞限流方式,阻塞限流适用于异步场景比如kafka消费或离线跑任务;非阻塞限流适用于同步场景快速失败返回
RateLimiter允许一定程度的突发
分布式场景下,通常预估好总QPS,然后均摊到每个服务,然后配置单进程的RateLimiter
优点:没有中心依赖,单进程控制;
缺点:集群扩容和缩容,单进程限流值得人工修改。
但是实际情况是我们会按照预估流量的一定倍数,提前做压测,压测通过后通常不再扩容,所以单进程扛的并发量是相对固定的值,只需要RateLimiter封装下,支持动态修改qps生效即可(比如每次acquire时检查qps配置更新)
还可以基于单进程的并发度控制,这个会更加灵活和动态,这个限制的是并发度,下游变快 qps能力就能提升,下游变慢qps就变慢,实际是通过atomic变量控制(进入方法判断是否达到threshold,达到则拒绝,未达到则increase && 执行结束 decrease)
5. 降级
限流通常伴随着降级,通常限流封装的类提供传入限流后的降级返回方法;
还有一些场景配置降级开关,普通情况可以配置降级开关,提供给人工干预修改;
但是对于大型活动,应该配置成时间在某个范围自动降级,因为活动中人工处理风险高
6. 超时与重试
通常有些业务需要错误重试,重试次数依赖于配置,可以动态调整;
对于一些业务,通常有失败异步重试补偿的方式,比如支付场景某一笔订单通知业务失败,可以实时重试(次数有限并且有可能重试后还是失败)+定时任务扫表重试(定时任务比如1分钟(时间可动态调整)执行一次,扫描过去10分钟(时间可动态调整)的失败订单并重试,并添加监控报警)
7. 回滚
需要部署工具支持,灰度上线有问题可以及时回滚
8. 压测与预案
压测:线下压测可以压单进程性能,但是因为与线上环境数据差距较大,压测数据可靠性不大;线上压测,通常需要低峰期压测(比如凌晨),并且线上压测切忌不能产生影响正常用户的数据
预案:大型活动需要提供预案文档,写好各种情况的处理流程(一切问题都通过设计来避免,但是有些情况确实需要线上调整,比如kafka消费速度配置可能需要当时情况动态调整),一旦执行,需要2人以上review