交易型系统设计的一些原则

交易型系统设计的一些原则

一。高并发原则

1。无状态

    如果设计的应用是无状态的,那么应用比较容易进行水平扩展。实际生产环境可能是这样的:应用无状态,配置文件有状态。

    如:不同的机房需要读取不同的数据源,此时,就需要通过配置文件或配置中心指定。

2。拆分

   拆分情况:

   【1】。系统维度

             按照系统功能/业务拆分。

             如:商品系统,购物车,结算,订单系统等。

   【2】。功能维度

             对一个系统进行功能再拆分。

     如:优惠券系统可拆分为:后台券创建系统,领券系统,用券系统。

   【3】。读写维度

           根据读写比例特征进行拆分。

      如:商品系统,交易的各个系统均会读取数据,读的量 大于 写的量。因此可拆分成“商品写服务”与“商品读服务”

              “商品读服务”:可考虑用缓存提升性能

              “商品写服务”:写的量太大,要考虑分库,分表

              有些聚合读取的场景,如商品详情页,可考虑数据异构拆分系统,将分散在多处的数据聚合到一处存储,以提升系统的性能和可靠性。

   【4】。AOP维度

              根据访问特征,按照AOP进行拆分。

              如:商品详情页可分为“CDN” 与 “页面渲染系统”,而“CDN”就是一个AOP系统。

   【5】。模块维度

             如:按照基础或代码维护特征进行拆分

      基础模块分库分表,数据库连接池等。

      代码结构一般按三层架构(web , service , dao)进行划分。

3。服务化

    首先:判断是不是只需要简单的单点远程服务调用,单点/单机不行,集群是不是可以解决。

             在客户端注册多台机器并使用Nginx负载均衡是不是可以解决。

             随着调用方越来越多,应考虑使用服务自动注册和发现(如:Dubbo使用ZooKeeper

    其次:考虑服务的分组/隔离。

                     如:有的系统访问量太大,导致把整个服务打挂,因此需要为不同的调用方法提供不同的服务分组,隔离访问。

        后期,随着调用量的增加还要考虑服务限流,黑白名单等。

还有一些细节需要注意:如超时时间,重试机制,服务路由(能动态切换不同的分组),故障补偿等。以上均会影响服务质量。

总结:进程内服务-》单机远程服务-》集群手动注册服务-》自动注册和发现服务-》服务的分组/隔离/路由-》服务治理如限流/黑白名单

4。消息队列

     消息队列可以实现服务解耦(一对多消费),异步处理,流量削峰/缓冲等。

如:电商系统中的交易订单数据(该数据有非常多的系统关心并订阅,如:订单生产系统,定期送系统,订单风控系统等)

      若订阅者太多,则订阅单个消息队列就会出现瓶颈,需要考虑对消息队列进行镜像复制。

消息队列使用说明:

      注意处理生产消息失败,以及消息重复接收时的场景。

      有些消息队列产品会提供生产重试功能,在达到指定重试次数还未生产成功时,会对外通知生产失败。此时,对于不能容忍生产失败的业务场景,一定要做好后绪的数据处理工作。如持久化数据要同时增加日志,报警等。

     对于消息重复问题,特别是一些分布式消息队列,出于对性能和开销的考虑,在一些场景下会发生消息重复接收,需要在业务层面进行防重处理。

【1】大流量缓冲

     在电商大促时,系统流量会高于正常流量(几倍/几十倍)。需要进行一些特殊设计保证系统度过这段时期。解决手段:牺牲强一致性而保证最终一致性。

如:扣减库存,可考虑如下设计:

如:交易订单系统,可考虑如下设计:

【2】数据校对

在使用了消息异步机制场景下,可能存在消息的丢失,需要考虑进行数据校对和修正来保证数据的一致性和完整性。

可通过worker定期去扫描原始表,通过对数据业务进行校对,有问题的要进行补偿,扫描周期根据实际场景定义。

5。数据异构

【1】。数据异构

订单分库分表一般按订单ID进行划分。若查询某用户的订单列表,需聚合多个表的数据后才能返回,这样会导致订单表的读性能很低。

此时,需要对订单表进行异构,异构一套用户订单表,按用户ID分库分表。

另:还需要考虑对历史订单数据归档处理,以提升服务的性能和稳定性。

注:有些数据异构的意义不大,如:库存价格。可考虑异步加载或合并并发请求。

【2】。数据闭环

如商品详情页,数据来源太多,影响服务稳定性。最好办法是将使用到的数据进行异构存储,形成数据闭环。

(1)。数据异构:

      通过如MQ机制接收数据变更,原子化存储到合适的存储引擎。

(2)。数据聚合:

     可选。

     数据异构目的:把数据从多个数据源拿过来

     数据聚合目的:将从多个数据源拿过来的数据做个聚合,前端可通过一次调用拿到所有数据。此步骤一般存储到KV存储中。

(3)。前端展示:

     前端通过一次或少量几次调用拿到所需要的数据。

此种方式好处:数据的闭环,任何依赖系统出问题,还能正常工作,只是更新会有积压,但不影响前端展示。

6。缓存银弹

【1】浏览器端缓存

设置请求的过期时间,如对响应头Expires,Cache-control进行控制。

此种机制适用于对实时性不太敏感的数据。如商品详情页框架,商家评分,评价,广告词等。

但对于价格,库存等实时要求比较高的数据,不能做浏览器缓存。

【2】APP客户端缓存

在大促时为防止瞬间流量冲击,一般会在大促之前把APP需要访问的一些素材(如js/css/image等)提前下发到客户端进行缓存,在大促时即不用拉取这些素材。

还有如首屏数据也可缓存起来,在网络异常情况下,有托底数据给用户展示。还有如APP地图一般也会做地图的离线缓存。

【3】CDN缓存

有些页面,活动页,图片等服务可考虑将页面/活动页/图片推送到离用户最近的CDN节点。让用户能在离他最近的节点找到想要的数据。

一般2种机制:

(1)。推送机制

      当内容变更后主动推送到CDN边缘节点

(2)。拉取机制

     先访问边缘节点,当没有内容时,回源到源服务器拿到内容并存储到节点上。

使用CDN时要考虑URL 设计:URL中不能有随机数,否则每次都穿透CDN回源到源服务器,相当于CDN没有任何效果。

对于爬虫,可以返回过期数据而选择不回源。

【4】接入层缓存

对于没有CDN缓存的应用来说,可考虑使用如Nginx搭建一层接入层,该接入层可考虑使用如下机制实现:

(1)。URL重写

      将URL按指定的顺序或者格式重写,去除随机数。

(2)。一致性哈希

     按照指定的参数(如分类/商品编号)做一致性HASH,从而保证相同数据落到一台服务器上。

(3)。proxy_cache

    使用内存级/SSD级代理缓存来缓存内容

(4)。proxy_cache_lock

    使用lock机制,将多个回源合并为一个,以减少回源量,并设置相应的lock超时时间。

(5)。shared_dict

    若架构使用了nginx+lua实现,可考虑用lua shared_dict进行cache,最大好处是reload缓存不会丢失

注:对于托底(或兜底,指降级后显示的)数据或异常数据,不应该让其缓存,否则用户会在很长一段时间里看到这些数据。

【5】应用导缓存

使用Tomcat时,可使用堆内缓存/堆外缓存

    堆内缓存最大问题:重启tomcat时,缓存会丢失。当流量风暴来临,可能冲垮应用。

可考虑使用load redis cache来代替堆外内存,load redis cache通过在应用所在服务器上部署一组redis,应用直接读本机redis获取数据,多机之间使用主从机制同步数据。这种方式没有网络消耗,性能最优。

或在接入层使用shared_dict来将缓存前置,以减少风暴。

【6】分布式缓存

有一种机制是要废弃分布式缓存,改成应用load redis cache。(适宜数据量不大)

若数据量太大,单服务器存储不了,可使用分片机制将流量分散到多台,或直接用分布式缓存实现。

常见分片规则:一致性哈希



7。并发化

串行获取数据时间共计:60ms

若C依赖于A&B,D独立,数据E依赖于C。则

数据A/B/D并行,只需30秒。(获取A,B时间15ms,再获取C时间10ms,再获取E时间5ms共计30ms.此时D已并行执行完)

二。高可用原则

1。降级

【1】开关集中化管理

通过推送机制,把开关推送到各个应用。

【2】可降级的多级读服务

如:服务调用降级为只读本地缓存,只读分布式缓存,只读默认降级数据(如库存状态默认有货)

【3】开关前置化

若架构是Nginx-》tomcat,可将开关前置到Nginx接入层。

 

【4】业务降级

当高并发流量来袭,为保障用户能下单,能支付是核心要求,并保障数据最终一致。

此时可将一些同步调用改为异步调用,优先处理高优先级数据或特殊特征数据,合理分配进入系统的流量,保障系统可用。

2。限流

限流目的:防止恶意请求流量,恶意攻击,或防止流量超出系统峰值,

思路:

【1】。恶意请求流量只访问到cache

【2】。对于穿透到后端应用的流量可考虑使用Nginx的limit模块处理

【3】。对于恶意IP可使用nginx deny进行屏蔽

原则是限制流量穿透到后端薄弱的应用层。

3。切流量

【1】DNS:切换机房入口

【2】HttpDNS:主要APP场景下,在客户端分配好流量入口,绕过运营商LocalDNS并实现更精准流量调度

【3】LVS/Haproxy:切换故障的Nginx接入层

【4】Nginx:切换故障的应用层

4。可回滚

版本化目的:实现可审计可追溯,且可回滚。

如:事务,代码库,部署版本,数据版本,表态资源版本回滚。

三。业务设计原则

1。防重设计

2。幂等设计

3。流程可定义

4。状态与状态机

5。后台系统操作可反馈

6。后台系统审批化

7。文档和注释

8。备份

总结:

 

posted @ 2018-05-20 18:00  kaixinyufeng  阅读(630)  评论(0编辑  收藏  举报