任何复杂技术的架构几乎都是随着需求的变化以及业务的增长逐渐演化出来的,并不是一开始就是复杂的庞然大物,互联网后端的技术架构几乎莫不是如此。
数据库篇
以 MySQL 为例说明支持事务的持久化数据库的架构演变。
单实例 single-instance
在数据量很小,业务规模也很小的时候一般使用一台数据库实例即可,比如业务还处于探索阶段,用户量很少的情况。
优势
简单,开发调试方便,维护成本低廉
缺点
缺乏可靠性,单机实例一旦故障,既不可写,又不可读。
主从结构 master-slave
伴随着业务的增长,单机性能会遇到瓶颈,比如单机连接数、单机处理并发的能力都是有限的,这就需要数据库可以做到横向扩展,主从结构 master-slave 就是满足这一需求的架构,有的地方又称之为 master-replication 架构。
优势
可靠性得到提升,主节点故障,从节点会自动提升为主节点,突破了单机性能瓶颈,可以做到横向扩展。
缺点
主从节点同步有延迟,主从节点数据一致性需要一定的时间,对数据实时性要求较高的场景需要开发者自己处理同步延迟的问题,比如读写都在 master 节点上执行。
双主多从
为了保证主库的高可用,可以设置多个主库,多个主库之间进行双向同步,使用 keepalive 监测双主的可用性随时进行切换。
优势
解决写单点的问题。
缺点
主库之间同步一致性复杂。
分片 sharding
随着数据量的不断增大,单机存储所有数据会导致数据库实例的性能开始下降,于是会考虑根据业务需求,把数据拆分成几部分存储,称之为切片分库,每一数据库实例存储整体数据中的一部分,这样单机存储的容量会降低,能够继续充分发挥单机的性能。
优势
数据分散存储,能够通过横向扩展,满足业务发展需求。
缺点
复杂度高,横向扩展虽然能够降低单机数据的存储量,但是实时复杂,比如对于一般采用的 hash 方法实时的分库,新增节点,意味着原有的数据需要重新 hash。
分片加主从
数据分片解决的是数据量过大的问题,但是单节点的可靠性并没有得到保证,因而可以在分片的同时,对每一个分片继续实施主从架构以保证单个片的数据可靠性。
优势
数据分散存储,数据可靠性有保证,支持横向扩展,满足业务需求。
自动分片和自动扩容
这是数据库架构最理想的状态,相当于支持无限扩展,只要新增节点,在保证数据可靠性的同时(多副本存储),集群会自动对数据进行动态平衡(重新 hash)。
缓存篇
缓存是互联网架构中必不可少的一个组件,以 redis 为例说明缓存架构的演变。
单点 single-instance
缓存的重要作用就是缓解持久化 DB 的压力,业务发展的初期用户量少,单点足以应付
优势
配合单点 APP 使用,和 APP 部署在同一主机,部署方便,维护方便,开发方便
主从结构 master-slave
随着用户量增大,请求规模的增长,单点无法满足请求压力,可以使用主从结构来分摊请求压力,缓存的场景以写少读多最常见,主从结构能够有效缓解单点的带来的问题。
优势
解决单点性能瓶颈
一致性 hash 切片 sharding
随着单点的写压力以及数据量逐步增大,可以使用一致性 hash 的方式将数据进行切片分散存储,解决单点容量的问题,一致性 hash 的方式能够有效缓解,增减节点带来的缓存失效问题。
优势
解决单点容量不足的问题和压力过大的问题
劣势
运维复杂
一致性 hash 高可用
切片之后的数据存在单点的问题,也就是数据只在一个节点读和写,如果节点挂掉,缓存就失效了。如果业务需要保证缓存也要高可用,每个节点可以使用主从结构,多副本的方式存储,配合以 sentinel 进行主从切换。
优势
解决切片之后数据单点的问题
一致性 hash 自动伸缩
采用一致性 hash 最大的问题是缩容和扩容带来的数据一致性难题,每增加和删除节点都需要重新对数据进行动态调整,要做到能够自动伸缩一般会配以 monitor 组件对每个节点的容量进行监控,在达到阈值之后,新增节点进行扩容,然后通知 router 等组件,一致性 hash 的 slot 发生了变化,对受影响的 key 进行特殊处理,保证数据的可用性,迁移完成之后,通知 router 开始正常处理请求。
APP 篇
同数据库和缓存,后端应用服务的架构也是随业务的发展逐步调整,不断演化
单点
压力很小的验证业务时候采用的架构模式,cache、session、nginx、DB 可能都是同一主机,配合以 crontab 完成异步任务。
集群
采用集群一方面是为了解决单点压力的问题,一方面是为了解决单点可靠性的问题,当 crontab 的任务数量成规模之后,需要采用异步任务队列来代替实现,维护成本更低,开发更高效。
更大规模的单体应用
随着业务的复杂度的提升,在未采用微服务之前,APP 会按照功能和服务不断进行拆分,各个 APP 之间通过 MQ 进行通信,异步任务队列也可以采用 MQ 来取代,缓存使用分布式缓存,可以按照自己的需要采用 master-slave 或者一致性 hash,数据库按照业务需要可以是 master-slave,也可以是切片分库,外网通过 DNS 轮询的方式进行负载均衡,静态文件采用 CDN 进行分发。
微服务
随着单体规模的不断变大,单体应用的业务边界会越来越模糊,会有很多重复的功能出现在单体应用中,这些重复功能会导致每个单体应用都会消耗一定的基础设置资源,比如缓存、DB 资源等等,为了减少重复功能的开发和维护,合理利用基础设置资源,单体应用逐步演化成微服务架构。
在微服务架构中,每个服务维护着自己的数据库,也就是说数据库的连接资源等都是每个服务自己持有,各个服务之间通过 MQ 进行数据通信,随着架构的复杂度提升,配套的需要有配置中心、服务注册与发现、日志、监控、调用链接追踪等基础设施来支持整个微服务的运行。