看似复杂的互联网抗量架构原理及其演进过程

514 阅读6分钟

摘要:互联网的基因是快速根据用户需求迭代,大型互联网架构都是复杂的集群架构,这种复杂性其实是伴随流量增长一点点进化的,每一个复杂的引入都是为了解决具体的问题。

1. 看似复杂的互联网架构

互联网抗量整体架构.png 如上图,是一个常见的互联网架构,第一眼看上去很复杂,其实只是一些简单原理的综合使用而已,这些基本原理有:

  • 快的保护慢的:比如使用guava保护redis,使用redis保护mysql。
  • 人多力量大(集群):一个Mysql不行,就分库分表;一个redis不行,就redis集群;主不行,从可以帮忙扛读流量;
  • 尽可能懒:能一会做,就别现在做,能异步就别同步;比如读集群通过异步推送数据,能接受一定时延,就不同步。

真实的互联网架构总是从简单开始,不断面临不同痛点,引入复杂来不断解决痛点,最终演变到复杂的架构,本文中,我们从最简单的系统,看它如何一步步发展为复杂的架构,每步演进又解决了什么问题。

2. 从单点到集群

先来看下这个过程的进化图:

1单体-应用集群-DB主从.png

  • 单服务器: 最初我们使用一个服务器,比如服务器上安装tomcat+mysql,就可以完成一个java-web应用的部署,支撑起一些小规模要求不高的业务。
  • 分离数据库服务器: 数据库可以单独出来安装在独立的服务器上,分离开应用服务器和库的部署,形成如下的架构,形成应用服务器和数据库服务器分离的架构。
  • 应用集群配合单库: 流量越来越大,单个应用服务器很难承受,可以把应用服务器升级为集群提供服务,这样应用服务器是可以水平扩展的,并且不同应用服务器可以通过负载均衡容灾。
  • 应用集群+数据库主从: 伴随访问量的增多,数据库成为性能瓶颈点,可以考虑一部分读流量使用从库,采用读写分离的思想,读写分别设计,读写主库,一部分读流量读从库。

3. 使用分库分表数据库集群

伴随访问量的增多,单库性能成为性能瓶颈点,我们考虑加入分库分表,通过分库分表引入数据库集群来增强多数据读写的并发性。写流量使用主库,从库资源可以抗一些读流量,形成如下架构。

读写分离与分库分表.png

后文使用集群图例说明:伴随着集群的引入,示例图中总画出集群中的机器图形过于复杂,后面图例使用「数据库集群」代表分库分表数据库构成的集群,「Redis集群」表示分片Redis构成的集群;「应用服务器集」群表示多台应用服务器构成的集群。

4. 引入集中缓存来解决大并发读

读写分离设计,针对读写流量分别设计,面对一些读流量很大的场景,数据库因为使用磁盘,不能支持高并发请流量,读流量开始采用基于内存抗量的Redis缓存集群;写流量为了数据一致性继续使用库,引入集中缓存的架构示例的如下:

读写分离-水平扩展抗读.png

注:canal是阿里的开源框架,原理是自己伪装为mysql的从,可以得到所有主数据库变更binlog数据,可用于增量数据同步。

如上图是基于数据分发形成了可水平扩展的读缓存集群,缓存的使用有下面几个常用权衡点:

  • 全量缓存或热点缓存: 全量缓存缓存全部数据,读请求只查缓存,缓存没有就是没有,永远不会回源数据库;热点缓存只缓存热点数据,数据有失效时间,缓存查询不到,需要回源数据库;推荐比较经济的方案热点缓存+回源数据库,回源数据库需要使用Redis加锁,防止大规模回源造成数据库性能抖动。
  • 缓存数据更新方式: 主动更新,源数据变更后,主动更新缓存数据,可以通过订阅数据库变更日志或数据变更业务消息。被动更新,待缓存失效后,靠下次读流量触发更新。一般是两者结合使用。
  • 利用缓存的从集群: 伴随着流量加大,可以考虑吧Redis从利用起来,把不同的流量导向不同的Redis从集群。

5. 热点数据本地缓存与防刷限流

不管是分库分表还是Redis集群,当遇到热点都会打向统一片Redis或同一个库表,如果超出了单片承载极限,就会影响到路由到单片的正常流量。可以综合使用下面手段治理:

  • Jvm本地缓存: 采用被动到过期时间失效,一般设置失效时间很短,几秒钟之内。
  • 本地限流降级: 通过本地guava对热点数据进行计数,达到一定次数进行访问限制,限流响应很快,不如远端限流精准。
  • 远端限流降级: 通过远端Redis集中对热点数据进行计数,达到一定次数进行访问限制,比本地更精准,限流响应更慢。

6. 大并发抗写架构

抗写架构不同于抗读,抗读的原理是异构数据可以接受一定时间的延迟。而抗写必须保证数据的同步持久化,有下面几个思路:

  • 最简单的持久化方式是使用数据库来做,一致性可以通过数据库事务
  • 可以通过分库分表来扩展整个并发能力
  • 对于热点数据可以使用先落地任务再处理的原理来分解热点。 业务库使用业务数据标识分库分表,任务库使用业务单据来分库分表。先落地可以消除热点。
  • 对于扣减类写,比如库存的扣减,可以分离防超卖和数据持久化 使用缓存比如Redis的incrby命令来做防超卖,负责秒杀订单的庞大并发写流量。通过任务库消除热点的思路来做数据持久化,消除数据热点。
  • 防刷限流 防刷限流读写皆可使用。

抗写架构比抗读架构难度更高一些,此处给出了基本原理,需要了解细节的可以进一步阅读

电商库存系统的防超卖和高并发扣减方案