系统设计原则

  在我们的技术生涯中,总是针对新的需求去研发新的系统,然很多系统设计都是想通的,在具有有限资源的情况下,一定是先解决当下最核心的问题,预测并发现未来可能出现的问题,一步步解决最痛点的问题。也就是说,系统设计是一个不断迭代过程,在迭代中不断优化,下面我们来说说系统设计的具体原则,(注:这张只讲大纲和理论,以后说实际场景操作和技术应用)

一, 高并发原则

  1.1 ,无状态

        如果设计的应用是无状态的,那么应用比较容易水平扩展,如有些应用配置不一样 需建立起 配置中心,进行统一配置

        1.2 ,拆分

  在系统设计初期,是做一个大而全的系统还是按功能模块拆,这个要根据自己的需求来觉得,如果这个模块复杂,个人建议还是拆开来,即使由于资源问题,不能拆开也要做成耦合度比较低的。差不多也是微服务的意思

        1.3,服务化

   有的系统访问量太大,导致把整个服务打挂,因此,需要为不同的调用方提供不同的服务分组,隔离访问,后期随着调用量的增加还要服务的限流,白黑名单,还有如 超时时间,重试机制,服务路由(能动态切换不同分组),故障补偿等(C# 中可以用Polly)

   1.4 消息队列

   消息队列是用来解耦一些不需要同步调用的服务或者订阅一些自己系统关心的变化。使用消息队列可以实现服务解耦(一对多消费,多对多消费),异步处理等,如 12306 订单提交 ,如果抢到票了,未付款,半小时订单过期,就删除此订单,座位回到系统中,然没          必要使用轮训

  1.5.缓存

  比如在电商大促销时,系统流量会高于正常流量的几倍甚至几十倍,此时就要进行一些特殊的设计来保证系统平稳度过这段时期;而解决的手段有很多,一般都是牺牲强一致性,而保证最终一致性即可

         比如扣减库存,可以这样设计。

    

  1.6  数据校对

  在使用消息异步机制的场景,可能存在消息的丢失,需要考虑进行数据校对和修正来保证数据的一致性和完整性,可以通过Worker 定期去扫描原始表,通过对业务数据进行校对,有问题的要进行补偿,扫描周期根据实际场景进行定义

  1.7 数据异构(分为冷热数据)

  比如要查一个商品详情,因为数据来源太多,影响查询速度和稳定性的因素有很多,最好的解决办法是把使用到的数据进行异构存储,形成闭环

    如查询用户订单:

    

  1.8 浏览器缓存

  设置请求的过期时间,如对响应头Expires,Cache-control 进行控制,这种机制使用于对实时性不太敏感的数据,如商品详情页框架,商家评分,评价,广告词,但对于价格,库存等实时性要求比较高的数据,就不能做浏览器端缓存

  

  1.9 CDN缓存,应用层缓存,分布式缓存(如redis)

        这些我想你们应该知道  我就不多说了

  

  1.10 并发化

   如 数据A需要10s ,数据B需要15s ,数据C需要10s , 数据D需要 20s ,数据E 需要5秒,,,我们可以使用多线程的方式进行查询,

  线程1  :查询数据A 和 数据 C

       线程2 : 查询数据B 和数据E

       线程3: 查询数据D

       仅需要 20s

  2 高可用

    2.1 降级

  对于一个高可用服务,很重要的一个设计就是降级开关,在设计降级开关时,主要依据如下思路

    a. 开关集中化管理,通过推送机制把开关推送到各个应用

    

    b.可降级的多级读服务:比如服务调用降级为只读本地缓存,只读分布式缓存,只读数据库数据

     

    c.业务降级:当高并发流量来袭,在电商系统大促设计时保证用户能下单,能支付是核心要求,并保障数据最终一致性即可。这样就可以吧一些同步调用改成异步调用,优先处理高优先级数据或特殊的数据,合理分配进入系统流量,以保障系统可用

  2.2 限流

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

  2.3 切流量

    对于一个大型应用,切流量是非常重要的,或者某个机架挂了,或者莫台服务器挂了,都需要切流量

  2.4 可回滚

    版本化的目的是实现可审计可追溯,并且可回滚。当程序或数据出错时,如果有版本化机制,那么久可以通过回滚恢复到最近一个正确的版本,比如事物回滚,代码库回滚,数据版本回滚,静态资源回滚

  3.业务设计原则

  3.1 防重设计

    比如,结算页考虑重复提交,还有如下单扣减库存时需要防止重复扣减库存。解决方案可以考虑防重key,防重表,而有一些场景如重复支付,是因为有的电商网址同时支持微信支付,京东支付,渠道不一样是无法防止重复支付的,但是在系统设计时,需要将支           付  的每笔情况记录下来,

      

  

  3.2 幂等设计

    它要求一次和多次请求某一个资源应该具有同样的副作用。这句话听起来比较晦涩,最简单明了的例子还是支付场景:比如我们在购物网站选好东西后,进入支付页面点击支付,此时支付请求发送给银行后端,然后从数据库中成功扣除了金钱,并将成功扣钱的     消息返回至前端,问题来了,如果在返回途中网络发生异常,消息丢失,那么前端将无任何反应,这体现在用户身上很可能就是再次点击“支付按钮”进行支付!按照正常逻辑,此时支付请求发送给银行后端后是不应该再次扣除金钱的,但由于HTTP协议的无状态性, 它不关心前一次是否扣除了金钱这个条件,只一视同仁地认定这一次是要扣除金钱的,所以最终必然会多扣一次钱!
这个例子就是因为不具备幂等性导致的,对同一订单提交多次支付请求,应该最多只被扣除一次钱,当某次的支付请求成功后,之后对该订单的所有请求都不再应该再生效

       3.3 流程可定义

  如果接触过保险业务,就会发现不同保险的理赔服务是不一样的,我们在系统设计时就设计了一套理赔流程服务,而承保流程和理赔流程是分离的,在需要时进行关联,从而可以复用一些理赔流程,并提供个性化的理赔流程

 

原文地址:https://www.cnblogs.com/xuehaiyiye/p/10199429.html