• 高并发原则
  • 高可用原则
  • 业务设计原则

高并发原则

1. 无状态
   若应用无状态、方便水平扩展、则要保证配置服务有状态
   eg. 不同的机房需要读取不同的数据源、此时可以通过配置中心指定

2. 拆分
   拆分不是必须的、可以根据系统流量和人员状况来进行
   1) 系统维度
      eg. 订单、购物车、结算等可以拆分成不同的服务
   2) 功能维度
      eg. 优惠券可以分为优惠券创建、优惠券领取和优惠券使用系统
   3) 读写维度
      eg. 读的量明显大于写、可以拆分为商品读服务和商品写服务
          读服务可以考虑使用缓存提升性能、写服务可以考虑分库分表
          聚合读的场景、如商品详情页、可以考虑数据异构拆分系统、
          将分散在多处的数据聚合存储、来提升系统的性能和可靠性
    4) AOP维度
       根据访问特征、按照aop维度拆分、eg. 商品详情页可以分为CDN、页面渲染系统
    5) 模块维度
       eg. 按照基础或者代码维度特征进行拆分
           基础模块分库分表、代码结构一般按照三层架构web、service、dao进行划分

3. 服务化
   随调用增多、单机集群无法满足的时候、可以考虑服务自动注册和发现 eg. dubbo 和 ZooKeeper
   其次要考虑 服务的分组和隔离、防止一个服务出问题、压垮整个系统的现象出现
   最后还要考虑、服务限流、黑白名单
   注意:超时时间、重试机制及补偿机制
   即:进程内服务->进程外服务-> 集群收到注册服务->自动注册和发现服务->服务的分组隔离/服务治理(eg. 限流 和 黑白名单)

4. 消息队列
   用来解耦一些不需要同步调用的服务或者订阅一些自己系统关心的变化
   可以实现:服务解耦(一对多消费)、异步处理、流量削峰等
   (流量削峰:上下游处理效率不一致时、可以使用MQ作为中间缓冲)
   当很多个系统订阅单个消息队列、成为瓶颈时、可以考虑消息队列镜像复制
   注意可靠性:
   a. 消息丢失(可先进行持久化、保证数据最终投递成功)
   b. 消息重复投递(可通过版本号等解决)
   c. 顺序投递(允许丢失)
   要注意数据核对的问题、定期去源库扫描、有必要时进行数据补偿

5. 数据异构
   eg. 通过MQ接收数据变更、然后原子化存储到合适的存储引擎、eg. Redis或者KV存储
   数据聚合:将数据通过多个数据源拿到、然后聚合到一起、
   前端展示:数据聚合后、前端可以通过一次或者少量几次调用来拿到所有的数据、保证数据闭环

   这样、任意一个依赖系统出了问题、依然可以正常工作、只是更新会有积压、单不影响展示

6. 数据缓存
   1. 浏览器端缓存
      expire、cache-control
   2. APP端缓存
      eg. 大促前可以将前端 js/img/css 等、缓存到客户端、在大促时、就不用再拉取、还可以直接将首屏缓存、在数据异常时、依然可以拿到数据、进行托底
   3. CDN缓存
      一般可以考虑将页面、活动页、图片推送到用户最近的cdn节点、
      一般是推送(内容变更、主动推送到cdn节点) / 拉取机制(先到最近的cdn节点读取、无内容则回源访问)
      注意:url中最好不要有随机数、否则、每次cdn回源到源服务器、相当于cdn无效果
      对于爬虫、可以返回过期数据、而不回源
   4. 接入层缓存
      没有cdn缓存的应用、可以考虑nginx搭建接入层
      1) url重写:将url按照指定格式重写、去除随机数
      2) 一致性hash:按照指定的参数(eg. 分类/商品编号)做一致性hash、保证相同数据落到一台服务器上
      3) proxy_cache:使用内存级/SSD级代理缓存来缓存内容
      4) proxy_cache_lock: 使用lock机制、将多个回源合并为一个、减少回源、并设置lock超时时间
      5) shared_dict:若使用nginx+lua架构、可以考虑lua shared_dict进行cache、最大的好处是 reload不丢失

   5. 应用层缓存
      使用tomcat时、可以考虑堆内缓存/堆外缓存、堆内缓存最大的问题是重启时、内存中的缓存会丢失、若此时出现流量风暴、可能冲垮应用
      可以使用local cache代替堆外缓存、或者在接入层使用shared_dict来将缓存前置、减少风暴

  6. 分布式缓存
     有一种机制是放弃分布式缓存、改成应用local redis cache、如果数据量不大、这种架构是最优的、但是如果数据量大的话、单服务器存储不了、就可以使用分片机制、将流量分散到多台、或者直接使用分布式缓存来实现、常见的分片规则是一致性hash

     接入层(nginx+lua)读取本地proxy_cache/ local cache
     -> 接入层读取分布式Redis集群、
     -> 如果依然无法命中、会接着读取Tomcat的应用堆内cache
     -> 都未命中、则调用依赖业务方来获取数据、然后异步缓存到Redis集群中
  7. 并发化处理
     无相互依赖关系的数据可并行请求

高可用原则

1. 降级
   1) 开关集中化管理、通过推送机制推送到各个服务
   2) 可降级的多级读服务 eg. 默认服务调用降级为只读本地缓存、只读分布式缓存、只读默认降级数据(如库存状态默认有货)
   3) 开关前置化 eg. 架构是nginx+tomcat、可以将开关前置到nginx接入层、在nginx层做开关、请求流量不回源到后端tomcat应用层或者只是一小部分流量回源
   4) 业务降级:当高流量来袭、只要保障核心功能可用、其它功能保障最终数据一致性即可
2. 限流
   限流的目的是防止恶心请求流量、恶意攻击或者防止流量超出系统峰值
   1) 恶意流量只访问到cache
   2) 对于穿透到后端应用的流量、可以考虑使用nginx的limit模块、
   3) 对于恶意ip可以使用nginx deny进行屏蔽
   原则是、限制流量穿透到后端薄弱的应用层
3. 切流量
  对于一个大型应用、切流量是很重要的、eg. 多机房情况下、某一个机房挂了、或者某个server挂了、都需要切流量
  1) DNS切机房入口
  2) HttpDNS:主要APP场景下、在客户端分配好流量入口、绕过运营商LocalDNS并实现精准流量调度
  3) LVS/HaProxy: 切换故障的nginx切入层
  4) Nginx: 切换故障的应用层
4. 可回滚
   版本化的目的是实现可审计、可追溯、可回滚、当程序或者数据出错时、若有版本化机制、可迅速回滚到最近的一个正确版本、eg. 事务回滚、代码库回滚、数据版本回滚、静态资源版本回滚等

业务设计原则

1. 防重设计
2. 幂等设计
   经常会有消息队列的参与、现有消息中间件基本无法保证不发生重复消息的消费、因此、需要业务系统在重复消息消费时进行幂等处理、在使用第三方支付时、第三方支付会进行异步回调、此时也要注意回调的幂等处理
3. 流程可定义
4. 状态与状态机
   要注意并发修改状态的问题、保证统一时间、只有一个修改、
5. 后台系统操作可反馈
6. 后台系统审批化
7. 文档和注释
   要有完整的文档库、设计库、特殊设计标注原因、不能以人传人的方式进行
8. 备份
   任何操作都必须有至少2人知道其中的逻辑
10-03 20:35