《亿级流量网站架构核心技术》读书笔记 —— 交易型系统设计的一些原则

设计一个系统,不仅需要考虑实现业务功能,还要保证系统高并发、高可用、高可靠等,在系统容量规划(流量、容量)、SLA指定(吞吐量、响应时间、可用性、降级方案等)、压测方案(线上、线下等)、监控报警(机器负载、响应时间、可用率等)、应急预案(容灾、降级、限流、隔离、切流量、可回滚)等方面

1. 高并发原则

1.1 无状态

应用无状态易于扩展.实际中应用无状态,配置文件有状态。

1.2 拆分

是否拆分取决于系统规模与可利用资源. 如果确实需要拆分,一般来说有以下几种情况:

  • 系统维度:按照系统功能和系统业务拆分,如商品系统、购物车系统、结算系统、订单系统等
  • 功能维度:对一个系统进行功能再拆分,比如优惠券系统可以拆分为后台券创建系统、领券系统、用券系统等;
  • 读写维度:根据读写比例特征进行拆分,比如商品系统的读远大于写,可拆分为商品写服务和商品读服务;读的时候可用缓存优化;写的时候可分库分表;
  • AOP维度:根据访问特征,按照AOP进行拆分,比如商品详情页可以分为CDN、页面渲染系统;
  • 模块维度:按照基础或者代码维护特征拆分,比如基础模块分库分表,数据库池连接等;

1.3 服务化

服务注册与发现,服务分组、隔离、路由,服务治理:限流、黑白名单等.

题外话: 之前有被问到一个问题:能不能用nginx代替微幅服务API网关? 这个问题还是需要根据系统规模来看;如果说你只有两三个微服务,每个微服务的部署节点也只有两三个,那不嫌麻烦的话可以手工配置nginx;但如果你微服务数量较多、部署节点较多时,那手动配置nginx就会成为一个灾难;这个时候服务注册于发现以及统一API网关就会起到非常巨大的作用,让你不在进行繁琐的nginx路由配置,不用担心服务扩容与缩容修改路由配置.

1.4 消息队列

消息队列一般用来解耦一些不需要同步调用的服务或者订阅一个自己系统关心的变化。使用消息队列可以实现服务解耦、异步处理、流量削峰/缓冲等.

1.4.1 大流量缓冲

针对较大流量涌入,系统需要进行一些特殊的设计平稳过度,一般来说可以系统强一致性,保证最终一致性.

1.4.2 数据校对

使用了消息异步机制的场景下,可能会出现消息丢失,因此需要考虑进行数据校对和修正来保证数据的一致性和完整性(消息补偿)

1.5 数据异构

异构的目的是实现数据的自我控制,当其他系统出问题或者自己的系统出问题不会互相影响,一般通过消息队列实现数据分发.

1.5.1 数据异构

若订单表按照订单ID进行分库分表,那么查询用户所有订单就会导致全表扫描;异构一套用户订单表,按用户ID进行分库.

1.5.2 数据闭环

如果请求的数据来源较多,则会增加请求的响应时间和影响服务的稳定,此时可以将用到的数据进行异构存储,形成数据闭环:

  • 数据异构:通过消息机制接收数据变更,然后原子化存储到合适的存储引擎
  • 数据聚合:将异构的数据进行聚合,一次请求就可以获取到完整的数据
  • 前端展示:前端通过一次或少量次数就可以拿到所有数据

1.6 缓存

缓存对于读服务可以说是一枚抗流量的银弹.

1.6.1 浏览器缓存

设置请求的过期时间,如针对响应头ExpiresCache-control进行控制,适用于对实时性不太敏感的数据;

1.6.2 APP客户端缓存

预先下发访问素材,APP离线缓存

1.6.3 CDN缓存

可以考虑将一些公共的或者不频繁改的资源推送到离用户最近的CDN节点,如公共JS、图片等

1.6.4 接入层缓存

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

  • URL重写:将URL按照指定的顺序或者格式重写
  • 一致性hash:按照查询参数做一致性hash
  • proxy_cache:使用内存级或者SSD级代理缓存来缓存内容
  • proxy_cache_lock: 使用lock机制,将多个回源合并为一个,以减少回源量
  • shared_dict:考虑使用lua shared_dict, 最大的好处是reload缓存不会丢失

1.6.5 应用层缓存

如使用tomcat时,可采用堆内缓存和堆外缓存;堆内缓存重启时丢失,堆外缓存如local redis cache,就是使用本机redis缓存,降低网络消耗. 适用于数据量不大的结构.

1.6.6 分布式缓存

数据量较大单机不能处理,可采用分布式缓存

1.7 并发化

针对一次请求多份数据,根据其先后顺序以及依存关系,进行并发处理请求,以减少耗时.

2. 高可用原则

2.1 降级

对于高可用服务,很重要的设计是降级开关,主要有以下思路:

  • 开关集中化管理:通过推送机制把降级开关推送到各个应用
  • 可降级的多级读服务:比如服务调用降级为只读本地缓存、只读分布式缓存、只读默认降级数据(如订单始终有货)
  • 开关前置化:将降级开关前置,如前置到nginx,不让请求回源到后端tomcat
  • 业务降级:当高并发流量来袭时,为保证核心业务正常进行,并满足最终一致性,可把一些同步调用改为异步调用,优先处理优先级数据或者特殊特征的数据

2.2 限流

限流的目的是防止恶意请求流量,恶意攻击,或者防止流量超出系统峰值;原则是限制流量穿透的后端薄弱的应用层. 主要有以下思路:

  • 恶意请求流量只访问到cache
  • 对于穿透到后端应用的流量可以考虑使用nginx的limit模块处理
  • 对于恶意IP可使用nginx-deny进行屏蔽

2.3 切流量

如果某个机架或者机房出现故障,可使用以下方式切流量:

  • DNS:切换入口
  • HttpDNS: 主要用于APP场景下,在客户端分配好流量入口,绕过运营商的localDNS
  • LVS/HaProxy: 切换故障的nginx层
  • Nginx: 切换故障的应用层

2.4 可回滚

版本化的目的是实现可审计可追溯,可回滚;如果有版本化机制,当出现故障或错误时,可进行回滚,如事务回滚代码库回滚部署版本回滚数据版本回滚静态资源版本回滚.

3. 业务设计原则

3.1 防重设计

如重复支付、重复扣减等

3.2 幂等设计

业务系统在进行消息消费时需要进行幂等处理,包括使用第三方支付异步回调时的幂等处理

3.3 流程可定义

不同的流程进行分离,必要时进行关联;

3.4 状态与状态机

  • 在设计交易系统时,会存在正向状态(待付款、待发货、已发货、完成)和逆向状态(取消、退款)等,根据系统特征来决定需不需要分离存储正向状态和逆向状态.
  • 状态设计时应有状态轨迹,方便用户跟踪当前订单的轨迹并记录相关的日志;
  • 对于状态的变迁,考虑要不要使用状态机来驱动状态的变更和后续流程的操作;
  • 并发状态修改问题,状态变更的有序性,比如需要考虑支付成功消息和用户取消消息的时间差。

3.5 后台系统操作可反馈

在后台系统的设计中,需要考虑操作结果的可预览、可反馈.

3.6 后台系统审批化

对于重要的功能,要设计审批流,比如调整价格,对操作日志记录,从而保证操作可追溯可审计

3.7 文档和注释

建立文档库,包括设计架构、设计思想、数据字典、业务流程、现有问题,此外业务代码特殊需求需要由注释

3.8 备份

包括代码和人员的备份,代码入版本库; 人员的话一个系统至少两个全面了解的人(小公司压力大)


京东:《亿级流量网站架构核心技术》张开涛

你可能感兴趣的:(读书笔记)