[亿级流量架构读后记录一] 交易性系统设计原则
2018-02-28 18:25
651 查看
交易性系统设计原则
高并发原则
1. 无状态
应用无状态, 配置文件有状态, 方便水平扩展2. 拆分
系统维度— 商品, 购物车, 结算, 订单);功能维度— 优惠券系统可以拆分为后台券创建系统, 领券系统, 用券系统等;
读写维度— 读服务架构缓存; 写服务分库分表; 聚合读取的数据,如商品详情页, 考虑将分散的数据聚合一处存储;
AOP维度— 根据访问特征, 比如, 商品详情页可以分为CDN, 页面渲染系统; CDN就是一个AOP系统;
模块维度— 比如按照基础或者代码维护特征进行拆分, 如基础模块分库分表, 数据库连接池等基础服务; 代码结构一般按照三层架构 web, service, dao进行拆分;
3. 服务化
除了服务的自动注册和发现, 还要考虑服务的分组/隔离,比如,有的系统访问过大,导致把整个服务打挂,因此,需要为不同的调用方提供不同的服务分组,隔离访问(其实就是进行隔离). 后期随着调用量增加还要考虑服务的限流/黑白名单等. 其中掺杂细节: 超时时间/重试机制/服务路由(能动态切换不同的分组)/故障补偿等.4. 消息队列
消息队列的重要性不言而喻, 功能: 服务解耦(一对多消费)、异步消费、流量削峰/缓冲等。比如,订单数据, 有非常多的系统关心并订阅,比如,订单生产系统、定期送系统、订单风控系统等。如果订阅者太多,那么订阅单个消息队列就会成为瓶颈,此时需要考虑对消息队列进行多个镜像复制。 当然还有生产消息失败,消息重复接受时的场景。指定重试次数内进行生产重试(或者记录,报警)。对于消息重复问题,需要做防重处理。
案例:
扣减库存,redis扣减库存 > 记录扣减日志 (后台同步 worker 将其 同步到 DB);
交易订单系统 , 从购物车确认结算时, 将订单存储到订单redis和订单队列表(可按需水平拓展多个表), 然后通过同步worker同步到订单中心表; 假设用户支付订单, 订单状态机会驱动状态变更,此时,可能订单队列表的订单还没有同步到订单中心表(不存在或者数据不对),状态机要根据实际情况进行重试。
如果用户查看单个订单详情, 那么可以直接从订单redis中查到。但如果查询订单列表,则考虑订单redis和列表的合并。
同步worker在设计时, 需要考虑并发处理和重复处理的问题。比如,使用单机串行扫描处理(每台worker扫描其中的一部分表)还是集群处理(Map-Reduce)。另外,需要考虑是否需要对订单队列表添加相关字段: 处理人(哪个应用正在处理)和处理状态(正在处理、已处理、处理失败)、最后处理时间(应对超时)、失败次数等。
数据校对: 在消息异步机制场景下,可能存在消息丢失,需要考虑进行数据校对和修正来保证数据的一致性和完整性.可通过worker定期去扫描原始表, 通过对业务数据进行比对, 有问题进行补偿, 扫描周期按需定义.
5. 数据异构
数据异构: 订单分库分表按照订单Id进行分,如果要查询某个用户的订单列表,则需要聚合多个表的数据后才能返回,这样会导致订单表读性能很低.此时需要对订单表进行异构。异构一套用户订单表,按照用户id进行分库分表。另外,还需要考虑对历史订单数据进行归档处理,以提升服务的性能和稳定性。而有些数据异构的意义不大,如库存价格,可以考虑异步加载,或者合并并发请求。数据闭环: 数据闭环如商品详情页,因为数据来源太多,影响服务稳定性因素太多。因此,最好的办法是把使用到的数据进行异构存储,形成数据闭环,基本步骤如下:
数据异构:通过如MQ机制进行接收数据变更,然后原子化存储到合适的存储引擎,如redis或持久化KV存储。
数据聚合:这步是可选的,数据异构目的是把数据从多个数据源拿过来,数据聚合的目的是把这些数据做个聚合,这样前端一次调用即可,一般存储到KV中。
前端展示:前端通过一次或者少量几次调用拿到所需要的数据。
这种方式的好处就是数据的闭环,任何依赖系统出问题了,还是能正常工作,只是更新会有积压,但是不影响前端展示。
另外,如果一次需要多个数据,可以考虑使用Hash Tag机制将相关数据聚合到一个实例,如在展示商品详情页时需要商品基本信息”p:productId:和商品规格参数”d:productId:”,使用冒号中间的productId作为数据分片key,这样相同productId的商品相关数据就在一个实例。
数据闭环和数据异构其实是一个概念,目的都是事先数据的自我控制,当其他系统出问题时不影响自己的系统,或者自己出问题时不影响其他系统。一般通过消息队列来实现数据分发。
6. 缓存银弹
浏览器端缓存app客户端缓存
CDN缓存 (需要注意url中不能有随机数,否则穿透CDN回源到源服务器。对于爬虫,可以返回过期数据不回源)
接入层缓存,对于没有CDN缓存的应用来说,考虑使用nginx搭建一层接入层,该接入层考虑如下机制:
url重写:将url按照指定的顺序或格式重写,去除随机数。
一致性哈希
proxy_cache: 使用内存级/SSD级代理缓存来缓存内容。
proxy_cache_lock: 使用lock机制,将多个回源合并为一个,以减少回源量,并设置相应的lock超时时间。 当多个客户端同时请求同一份内容时,如果开启proxy_cache_lock(默认off)则只有一个请求被发送至后端;其他请求将等待该内容返回;当第一个请求返回时,其他请求将从缓存中获取内容返回;当第一个请求超过了proxy_cache_lock_timeout超时时间(默认5s),则其他请求将同时请求到后端来获取响应,且响应不会被缓存;启用proxy_cache_lock可以应对雪崩效应。
shared_dict: 如果架构使用了nginx + lua实现,则可以考虑使用 lua shared_dict进行cache,最大的好处就是reload缓存不会丢失。
此处注意,对于托底(或兜底,指降级后显示的)数据或异常数据,不应该让其缓存,否则用户会很长一段时间看到这些数据。
应用层缓存,tomcat 或者 local redis cache,或者接入层使用shared_dict来讲缓存前置,以减少风暴。
分布式缓存,如果数量不大,使用local redis是最优的。但是数据量太大,单服务器存储不了,可以使用分片机制将流量分散到多台,或者直接用分布式缓存。
架构缓存例子:
首先接入层(nginx + lua)读取本地proxy cache / local cache
如果不命中, 则接入层会接着读取分布式redis缓存
如果还不命中, 则会回源到Tomcat, 然后读取Tomcat应用堆内cache
如果都没有命中, 则调用依赖业务来获取数据, 然后异步化写到redis集群等
此种架构, 因为使用nginx + lua, 第二三步可使用lua-resty-lock非阻塞锁减少峰值时需要的回源量; 如果你的服务是用户维度的,那么这种非阻塞锁大部分情况下不会有太大的作用
7. 并发化 所谓 fork/join
高可用原则
1. 降级
对于一个高可用服务,很重要的一个设计就是降级开关,在设计降级开关时,主要依据如下思路.开关集中化管理: 通过推送机制把开关推送到各个应用.
可降级的多级读服务: 比如服务调用降级为只读本地缓存、只读分布式缓存、只读默认降级数据(如库存状态默认有货, 即默认值).
开关前置化: 如架构是nginx->tomcat, 可以将开关前置到nginx接入层,在nginx层做开关,请求流量回源后端应用或者只是一部分流量回源.
业务降级: 即高峰时, 保证核心业务,保障数据最终一致性即可. 这样可以把一些同步调用改成异步滴啊用, 优先处理高优先级数据或特殊特征的数据, 合理分配进入系统的流量, 以保障系统可用.
2. 限流
限流的目的是防止恶意请求流量, 恶意攻击, 或防止流量超出系统峰值. 可考虑一下思路:恶意请求流量只访问到cache.
对于穿透到后端应用的流量可以考虑使用nginx的limit的模块处理.
对于恶意ip可以使用nginx deny进行屏蔽.
原则是限制流量传统到后端薄弱的应用层.
3. 切流量
DNS、HttpDns、lVS/HaProxy、nginx 做切换4. 可回滚
事务回滚、代码回滚、部署版本回滚、数据版本回滚、静态资源回滚就业务涉及原则
1. 防重设计
比如, 购物侧结算页需要考虑重复提交下单扣库存时需要防止重复扣减库存, 解决方案可考虑防重key, 防重表.
重复支付, 渠道不一样是无法防止重复支付的. 但是, 在系统设计的时候, 需要将支付的每笔情况记录下来.
2. 幂等设计
比如消息重复, 第三方异步回调等3. 流程可定义
保险, 承保流程和理赔流程是分离的, 在需要时进行关联, 从而复用, 并能提供个性化理赔.4. 状态与状态机
一般会存在正向状态(待退款, 待发货, 已发货, 完成)和逆向状态(取消, 退款)等. 正向状态和逆向状态应该根据系统的特征来决定要不要分离存储. 状态设计时应有状态轨迹, 方便用户跟踪当前订单的轨迹并记录相关日志, 万一出问题时可回溯问题. 如果状态很多时,可以考虑使用状态机驱动状态的变更和后续流程节点操作, 能更好控制状态迁移; 还要考虑并发状态修改问题, 如一个订单同时只能有一个修改; 状态变更的有序问题, 以及状态变更消息的先到后到问题, 如支付成功消息和用户取消消息的时间差.
5. 后台系统操作可反馈
6. 后台系统审批化
7. 文档和注释
8. 备份 (包括代码和人员)
相关文章推荐
- 亿级流量网站架构读后记录三、HTTP缓存篇
- [亿级流量网站架构读后记录二、缓存篇]
- 亿级流量电商详情页系统的大型高并发与高可用缓存架构
- 【转】大访问量系统的设计(二)——高并发高流量网站架构
- 系统架构(1)---单机至亿级流量大型网站系统架构演进
- Microsoft NLayerApp案例理论与实践 - 多层架构与应用系统设计原则
- 系统架构师-基础到企业应用架构-系统设计规范与原则[下篇]
- 架构学习之路——高可用高并发系统设计原则 (转)
- 高性能、高流量互联网应用系统架构设计上所遵循的基本原则
- 系统架构师-基础到企业应用架构-系统设计规范与原则[上篇]
- 系统架构设计理论与原则
- 系统架构设计模块拆分维度和原则
- 系统架构设计理论与原则、负载均衡及高可用系统设计速记
- Microsoft NLayerApp案例理论与实践 - 多层架构与应用系统设计原则
- 阿里P9架构师讲解从单机至亿级流量大型网站系统架构的演进过程
- 系统架构设计理论与原则、负载均衡及高可用系统设计速记
- 一起谈.NET技术,Microsoft NLayerApp案例理论与实践 - 多层架构与应用系统设计原则
- 架构高可用高并发系统的设计原则
- 系统架构师谈企业应用架构之系统设计规范与原则1
- 从单机至亿级流量大型网站系统架构的演进过程