概述
在进行技术学习过程中,由于大部分读者没有经历过一些中大型系统的实际经验, 导致无法从全局理解一些概念,所以本文以一个 "电子商务" 应用为例,介绍从一百个 到千万级并发情况下服务端的架构的演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知
在正式引入架构演进之前,为避免读者对架构中的概念完全不了解导致低效沟通, 优先对其中一些比较重要的概念做前置介绍开发中的一些重要概念
架构演进
一.单机架构
初期,我们需要利用我们精干的技术团队,快速将业务系统投入市场进行检验, 并且可以迅速响应变化要求。但好在前期用户访问量很少,没有对我们的性能、安全 等提出很高的要求,而且系统架构简单,无需专业的运维团队,所以选择单机架构是合适的。
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址将请求发送给服务器,通过端口号找到电子商务系统。
电子商务系统根据请求去查询本机的数据库,从数据库中获取相关数据,并返回给用户。
简介
应用服务和数据库服务共用一台服务器
出现原因
出现在互联网早期,访问量比较小,单机足以满足需求
架构工作原理
以电子商城为例,可以看到通过应用(划分了多个模块)和数据库在单个服务器上协作完成业务运行
优缺点
优点:部署简单,成本低
缺点:存在严重的性能瓶颈。数据库和应用服务互相竞争资源(应用服务和数据库放到了一台服务器上,在处理用户请求时,两者都会去获取服务器中的资源,如果请求量大就会导致服务器中的资源不足,从而导致响应过慢)
相关技术
Web 服务器软件:Tomcat、Netty、Nginx、Apache 等
数据库软件:MySQL、Oracle、PostgreSQL、SQL Server 等
二.应用数据分离架构
随着系统的上线,市场上出现了一批忠实于我们的用户,使得系统的访问量逐步上升,逐渐逼近了硬件资源的极限,同时团队也在此期 间积累了对业务流程的一批经验。面对当前的性能压力,我们选择了将应用和数据分离的做法,可以最小代价的提升系统的承载能力。
和单机架构的主要区别在于将数据库服务独立部署在其他服务器上, 应用服务和数据库服务之间通过网络来交换数据
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址将请求发送给应用服务器,通过端口号找到电子商务系统。
应用服务根据用户请求去数据库中获取对应数据,与数据库服务间的数据通过网络传输。
简介
应用服务和数据库服务使用不同服务器
出现原因
单机存在严重的资源竞争,导致站点变慢
架构工作原理
以电子商城为例,可以看到应用(划分了多个模块)和数据库在各自的服务器上通过网络协作完成业务运行
优缺点
优点:成本相对可控。性能相比单机有提升。数据库单独隔离,不会因为应用把数据库搞坏,有一定的容灾能力
缺点:硬件成本变高。性能有瓶颈,无法应对海量并发
三.应用服务集群架构
我们的系统受到了用户的欢迎,并且出现了爆款,单台应用服务器已经无法满足需求了。我们的单机应用服务器首先遇到了瓶颈,过多的用户请求涌向一台应用服务器,导致我们的服务器根本处理不过来,本着“一个螺旋丸解决不了的问题就再来一个螺旋丸”的原则,既然一台应用服务器处理不过来,那我们就多加几台应用服务器
通过调整软件架构,增加应用层硬件,将用户流 量分担到不同的应用层服务器上,来提升系统的承载能力。但这需要引入一个新的组件 —— 负载均衡(解决用户流量向哪台应用服务器分发的问题)
同时流量调度算法也有很多种,这里简单介绍几种较为常见的:
• Round-Robin 轮询算法。即非常公平地将请求依次分给不同的应用服务器。
• Weight-Round-Robin 轮询算法。为不同的服务器(比如性能不同)赋予不同的权 重(weight),能者多劳。
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址和端口号将请求发送给负载均衡,负载均衡根据当前多个应用服务器的负载情况来分发请求。
应用服务器收到请求后,根据用户请求去数据库中获取对应数据,与数据库服务间的数据通过网络传输。
简介
引入了负载均衡,应用以集群方式运作
出现原因
单个应用服务器不足以支持海量的并发请求,高并发的时候站点响应变慢
架构工作原理
以电子商城为例,可以看到应用服务器不再是一个,而是变成了多个,通过负载均衡来支持海量的并发
优缺点
优点:应用服务高可用:应用满足高可用,意外应用服务器有多个,所以即使一个服务出问题也不会导致整个站点挂掉
应用服务具备一定高性能:如果不访问数据库,应用相关处理通过扩展可以支持海量请求快速响应
应用服务有一定扩展能力:支持横向扩展
缺点:数据库成为性能瓶颈,无法应对数据库的海量查询。数据库是单点,没有高可用。运维工作增多,扩展后部署运维工作增多,需要开发对应的工具应对快速部署。硬件成本较高
相关技术
负载均衡软件:Nginx、HAProxy、LVS、F5 等
四.读写分离 / 主从分离架构
上一架构提到,我们把用户的请求通过负载均衡分发到不同的应用服务器之后,可以并行处理了,并且可以随着业务的增长,可以动态扩张服务器的数量来缓解压力。 但是现在的架构里,无论扩展多少台服务器,这些请求最终都会从一个数据库中读写数据, 请求多到一定程度之后,会导致数据库对数据进行操作很困难。我们可以像扩展应用服务器一样扩展数据库服务器吗?
答案是否定的,因为数据库服务有其特殊性:如果将数据分散到各台服务器之后,数据的一致性将无法得到保障。所谓数据的一致性,此处是指:针对同一个系统,无论何时何地,我们都应该看到一个始终维持统一的数据。 想象一下,银行管理的账户金额,如果收到一笔转账之后,一份数据库的数据修改了, 但另外的数据库没有修改,则用户得到的存款金额将是错误的。
我们采用的解决办法是这样的,保留一个主要的数据库作为写入数据库,其他的数据库作为从属数据库。从库的所有数据全部来自主库的数据,经过同步后,从库可以维护着与主库一致的数据。然后为了分担数据库的压力,我们可以将写数据请求全部交给主库处理,但读请求分散到各个从库中。由于大部分的系统中,读写请求都是不成比例的,例如 100 次读 1 次写,所以只要将读请求由各个从库分担之后,数据库的压力就没有那么大了
应用中需要对读写请求做分离处理,所以可以利用一些数据库中间件,将请求分离的职责托管出去。
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址和端口号将请求发送给负载均衡,负载均衡根据当前多个应用服务器的负载情况来分发请求。
应用服务器收到请求后,如果请求需要向数据库中写入数据,就将请求发送给主数据库(主数据库中的数据发生改变后,从数据库需要同步改变),如果需要读取数据则将请求发送给从数据库
简介
将数据库读写操作分散到不同的节点上,数据库服务器搭建主从集群,一主一从、一主多从都可以,数据库主机负责写操作,从机只负责读操作
出现原因
数据库成为瓶颈,而互联网应用一般读多写少,数据库承载压力大,主要是由这些读的请求造成的,那么我们可以把读操作和写操作分开
架构工作原理
以电子商城为例,可以看到数据库服务器不再是一个,而是变成了多个,数据库主机负责写操作,从机负责读操作,数据库主机通过复制将数据同步到从机
优缺点
优点:数据库的读取性能提升。读取被其他服务器分担,写的性能间接提升。数据库有从库,数据库的可用性提高了
缺点:热点数据的频繁读取导致数据库负载很高。当同步挂掉,或者同步延迟比较大时,写库和读库的数据不一致。服务器成本需要进一步增加
相关技术
MyCat、TDDL、Amoeba、Cobar 等类似数据库中间件等
五.冷热分离架构
随着访问量继续增加,发现业务中一些数据的读取频率远大于其他数据的读取频 率。我们把这部分数据称为热点数据,与之相对应的是冷数据。针对热数据,为了提升其读取的响应时间,可以增加本地缓存,并在外部增加分布式缓存,缓存热门商品信息或热门商品的 html 页面等。通过缓存能把绝大多数请求在读写数据库前拦截掉, 大大降低数据库压力。其中涉及的技术包括:使用 memcached 作为本地缓存,使用 Redis 作为分布式缓存
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址和端口号将请求发送给负载均衡,负载均衡根据当前多个应用服务器的负载情况来分发请求。
应用服务器收到请求后,如果请求需要向数据库中写入热点数据,先将热点数据写入缓存服务器中,再将数据写入主数据库中,由主数据库同步数据给从数据库
如果请求需要读取热点数据应用服务器会将请求发送给缓存服务器,从缓存服务器中获得热点数据后就直接返回,不用访问数据库,如果请求需要读取冷数据,应用服务器会先将请求发送给缓存服务器,在缓存服务器中没有获取到数据再将请求发送给从数据库服务器,获得到数据并返回。
简介
引入缓存,实行冷热分离,将热点数据放到缓存中快速响应
出现原因
海量的请求导致数据库负载过高,站点响应再度变慢
架构工作原理
以电子商城为例,可以看到多了缓存服务器,对于热点数据全部放到缓存中,不常用数据再去查询我们的数据库
优缺点
优点:大幅降低对数据库的访问请求,性能提升非常明显。
缺点:带来了缓存一致性,缓存击穿,缓存失效,缓存雪崩等问题。服务器成本需要进一步增加。业务体量支持变大后,数据不断增加,数据库单库太大,单个表体量也太大,数据查询会很慢,导致数据库再度成为系统瓶颈
相关技术
Memcached、Redis 等缓存软件
六.垂直分库架构
随着业务的数据量增大,大量的数据存储在同一个库中已经显得有些力不从心了, 所以可以按照业务,将数据分别存储。前面提到的 Mycat 也支持在大表拆分为小表情况下的访问控制。这种做法显著的增加了数据库运维的难度,对 DBA 的要求较高。数据库设计到这种结构时,已 经可以称为分布式数据库。
但是这只是一个逻辑的数据库整体,数据库里不同的组成 部分是由不同的组件单独来实现的,如分库分表的管理和请求分发,由 Mycat 实现, SQL 的解析由单机的数据库实现
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址和端口号将请求发送给负载均衡,负载均衡根据当前多个应用服务器的负载情况来分发请求。
假设此时用户请求获取一个商品的信息,在页面的左上角还要显示商家信息,此时应用服务器会将请求发送给商品数据库和用户数据库,获得商品信息和商家信息(可以通过 Mycat 进行请求分发的管理),应用服务器将得到的数据进行统一,返回给用户
简介
数据库的数据被拆分,数据库数据分布式存储,分布式处理,分布式查询,也可以理解为分布式数据库架构
出现原因
单机的写库会逐渐会达到性能瓶颈,需要拆分数据库,数据表的数据量太大,处理压力太大,需要进行分表,为降低运维难度,业界逐渐研发了分布式数据库,库表天然支持分布式
架构工作原理
以电子商城为例,数据库是由多个主从库或者存储集群构成,支持分布式大规模并行处理
优缺点
优点:数据库吞吐量大幅提升,不再是瓶颈。跨库join、分布式事务等问题,这些需要对应的去进行解决,目前的mpp都有对应的解决方案
缺点:数据库和缓存结合目前能够抗住海量的请求,但是应用的代码整体耦合在一起,修改一行代码需要整体重新发布
相关技术
Greenplum、TiDB、Postgresql XC、HAWQ 等,商用的如南大通用的 GBase、 睿帆科技的雪球 DB、华为的 LibrA 等
七.微服务架构
既然应用服务中的业务代码较多,代码耦合性较高导致不好修改应用服务中的代码,以及不好发布应用服务,我们就可以考虑将庞大的应用服务拆分成一个个的微服务,相互配合完成工作。
随着人员增加,业务发展,我们将业务分给不同的开发团队去维护,每个团队独立实现自己的微服务,然后互相之间对数据的直接访问进行隔离,可以利用 Gateway、 消息总线等技术,实现相互之间的调用关联。甚至可以把一些类似用户管理等业务提成公共服务。
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址和端口号将请求发送给负载均衡,假设此时需要获取一个商品的信息,在页面的左上角还要显示商家信息。
负载均衡根据当前各个微服务的流量情况发送用户请求,用户请求发送给了商品子系统和用户子系统,子系统根据用户请求去对应的数据库中获取用户所需的数据,获取到商品信息和卖家信息以后,将信息返回给负载均衡,由负载均衡返回给用户
简介
微服务是一种架构风格,按照业务板块来划分应用代码,使单个应用的职责更清晰,相互之间可以做到独立升级迭代。
出现原因
持续开发困难:一个很小的代码改动,也需要重新部署整个应用,无法频繁并轻松的发布版本。
不可靠:即使系统的一个功能不起作用,可能导致整个系统无法工作。
不灵活:无法使用不同的技术构建单体应用程序。
代码维护难:所有功能耦合在一起,新人不知道何从下手
架构工作原理
以电子商城为例,一个商城应用拆分成了多个微服务,如用户服务、交易服务和商品服务,相互之间协作支持整个商城的应用
优缺点
优点:
灵活性高:服务独立测试、部署、升级、发布
独立扩展:每个服务可以各自进行扩展
提高容错性:一个服务问题并不会让整个系统瘫痪;
新技术的应用容易:支持多种编程语言
缺点:
运维复杂度高:业务不断发展,应用和服务都会不断变多,应用和服务的部署变得复 杂,同一台服务器上部署多个服务还要解决运行环境冲突的问题,此外,对于如大促这类需 要动态扩缩容的场景,需要水平扩展服务的性能,就需要在新增的服务上准备运行环境,部 署服务等,运维将变得十分困难
资源使用变多:所有这些独立运行的微服务都需要需要占用内存和 CPU
处理故障困难:一个请求跨多个服务调用,需要查看不同服务的日志完成问题定位
容器编排架构
上面的架构的缺点中我们提到,将应用服务分为多个微服务以后,每个微服务的环境配置与发布都需要运维去解决,这就会导致运维的工作量剧增,所以我们要想个办法来减少一些运维兄弟们的工作量。容器化技术的出现给这个问题的解决带来了新的思路。
目前最流行的容器化技术是 Docker,最流行的容器管理服务是 Kubernetes(K8S),应用/服务可以打包为 Docker 镜像,通过 K8S 来动态分发和部署镜像。Docker 镜像可理解为一个能运行你的应用/服务的最小的操作系统,里面放着应用/服务的运行代码,运 行环境根据实际的需要设置好。把整个“操作系统”打包为一个镜像后,就可以分发到需要部署相关服务的机器上,直接启动 Docker 镜像就可以把服务运行起来,使服务的部署和运维变得简单。
流程
用户通过浏览器访问我们的电子商务系统,直接输入域名,DNS(域名解析系统)会将域名对应的 IP 地址返回给浏览器,浏览器通过 IP 地址和端口号将请求发送给负载均衡,假设此时需要获取一个商品的信息,在页面的左上角还要显示商家信息。
负载均衡根据当前各个 Docker 容器中微服务的流量情况发送用户请求,用户请求发送给了商品微服务和用户微服务,子系统根据用户请求去对应的数据库中获取用户所需的数据,获取到商品信息和卖家信息以后,将信息返回给负载均衡,由负载均衡返回给用户
简介
借助容器化技术(如docker)将应用/服务可以打包为镜像,通过容器编排工具(如k8s)来动态分发和部署镜像,服务以容器化方式运行
出现原因
微服务拆分细,服务多部署工作量大,而且配置复杂,容易出错。
微服务数量多扩缩容麻烦,而且容易出错,每次缩容后再扩容又需要重新配置服务对应的环境参数信息
微服务之间运行环境可能冲突,需要更多的资源来进行部署或者通过修改配置来解决冲突
架构工作原理
以电子商城为例,一个商城应用拆分成了多个微服务,如用户服务、交易服务和商品服务,每一个微服务打包到容器之中,相互协作来完成系统功能,通过容器编排工具完成部署运维。
优缺点
优点:部署、运维简单快速:一条命令就可以完成几百个服务的部署或者扩缩容。
隔离性好:容器与容器之间文件系统、网络等互相隔离,不会产生环境冲突
轻松支持滚动更新:版本间切换都可以通过一个命令完成升级或者回滚
缺点:技术栈变多,对研发团队要求变高
相关软件
Docker、 Kubernetes(K8S)
尾声
至此,一个还算合理的高可用、高并发系统的基本雏形已显。注意,以上所说的 架构演变顺序只是针对某个侧面进行单独的改进,在实际场景中,可能同一时间会有 几个问题需要解决,或者可能先达到瓶颈的是另外的方面,这时候就应该按照实际问 题实际解决。