8张图带你了解⼤型应⽤架构演进历程
前⾔
先点赞再观看,要有好习惯
⼏乎所有的⼤型应⽤都是从⼀个⼩应⽤开始的,好的互联⽹产品是慢慢运营出来的,不是⼀开始就开发好的,所以本篇我们来聊聊应⽤架构的演进历程。
如何打造⼀个⾼可⽤,⾼性能,易扩展的应⽤?⾸先我们了解⼀下⼤型应⽤的特点:
⾼可⽤:系统需要不间断的提供服务,不能出现单点故障
⾼并发:在⼤流量的冲击下,系统依然稳定提供服务
⼤数据:应⽤每天都会产⽣⼤量的数据,需要存储和管理好这些数据
最简单的架构
刚开始应⽤没有太多访问量,所以只需要⼀台服务器,这时候的架构如下图:
应⽤程序、⽂件、数据库往往都部署在⼀台服务器上。应⽤程序可以采⽤Java开发,部署在Tomcat服务器上,数据库可以使⽤开源的MySQL
应⽤与数据服务分隔
随着应⽤的业务越来越复杂,应⽤访问量越来越⼤,导致性能越来越差,存储空间严重不⾜,这时候我们考虑把服务增加到三台(能通过加机器解决的问题都不是问题);分离出应⽤服务器、数据库服务器、⽂件服务器。
应⽤服务器需要处理⼤量的访问,所以需要性能更好的CPU
数据库服务器需要存储⼤量的数据以及快速的检索,所以需磁盘的检索速度较快以及存储空间⼤
⽂件服务器需要存储上传的⽂件,需要更⼤的磁盘;现在通常情况下会选择第三⽅的存储服务
根据每个服务器对应的场景,配置服务器后应⽤的性能能够⼤⼤提⾼,更好的⽀持业务的发展。但是随之业务的发展,访问量的增⼤,这种架构⼜将再次⾯临挑战,应⽤服务器处理能⼒下降,存储空间不⾜
应⽤服务器集
在⾼并发,⼤流量的情况下,⼀台服务器是肯定处理不过来的,这个时候增加服务器,部署集提供服务,来分担每台服务器的压⼒。部署集的另⼀个好处是可伸缩⾏,⽐如当遇到了双11⼤流量的场景下,可以增加服务器分摊流量,等双11过后,减少服务器节约成本。架构如下:
如果应⽤服务器是Tomcat,那么可以部署⼀个Tomcat的集,外部在部署⼀个负载均衡器,可以采⽤随机、轮询或者⼀致性哈希算法达将⽤户的请求分发到不同应⽤服务集;通常选择的免费的负载均衡是nginx。在这种架构下,应⽤服务器的负载将不会是整个应⽤的瓶颈点;
虽然应⽤程序的处理速度在这种架构下提升了许多,但是⼜会暴露⼀个问题,数据库的压⼒⼤⼤增⼤,导致访问响应延迟,影响整个应⽤的性能。
这种架构还有个问题,通常应⽤是有状态的,需要记录⽤户的登录信息,如果每次⽤户的请求都是随机路由到后端的应⽤服务器,那么⽤户的会话将会丢失;解决这个问题两个⽅案:
采⽤⼀致性hash把⽤户的请求路由到同⼀个Tomcat,如果有⼀台服务器跪了,那么这台服务器上⾯的⽤户信息将会丢失
Tomcat集之间通过配置session复制,达到共享,此⽅案效率较低
两个⽅案都不是很好,那么还有其他的⽅案吗?请继续往下看
根据⼆⼋原则,80%的的业务都是集中访问20%的数据,这20%的数据通常称为热点数据,但是这20%的数据占⽤的内存也不会⼩,如果每个应⽤服务器都存放⼀份,有些浪费存储空间,所以这时候需要考虑加⼊分布式缓存服务器(常⽤的是Redis);当引⼊了分布式缓存服务器,再来看上⾯那个⽅案的问题,就可以解决了,把⽤户的会话存放到缓存服务器,不仅可以防⽌⽤户数据丢失,效率也不低;架构图如下:
由于分布式缓存服务器毕竟存放在远程,需要经过⽹络,所以取数据还是要花⼀点时间;本地缓存访问速度更快,但是内存空间有限,并且还会出现和应⽤程序争抢资源;所以这种架构搭配了分布式缓存和本地缓存,本地缓存存放少量常⽤热点数据,当本地缓存中没有命中时在去集中式缓存取
在引进缓存之后,数据库的访问压⼒可以的⼀定的缓解
数据库读写分离
虽然在加⼊了缓存之后,部分数据可以直接⾛缓存,不需要访问数据库,但是任然会有⼀些请求,会访问数据库,⽐如:缓存失效,缓存未命中;当流量⼤的时候,数据库的访问量也不⼩。这时候我们需要考虑搭建数据库集,读写分离
当应⽤服务器有写操作时,访问主库,当应⽤程序有读操作时,访问从库;⼤多数的应⽤都是读的操作远远⼤于写的操作,所以可以配置数据库⼀主多从来分担数据库的压⼒;为了让应⽤程序对应主库
和从库⽆感知,通常需要引⼊⼀些读写分离的框架做⼀个统⼀的数据访问模
这种架构通常需要警惕的⼀个问题是主从延迟,当在⾼并发的场景下,主库刚写成功,数据库还未成功同步完从库,这时候另⼀个请求进⼊读取数据发现不存在;解放⽅案是在应⽤程序中⾼并发的场景下设置强制⾛主库查询
兄弟们,请不要⽩嫖哦,⽂章看⼀半,请先点个赞
反向代理和CDN
假如随着业务的不断扩⼤,全国各地都会使⽤到我们的应⽤,由于各地区的⽹络情况不同,所以有的⼈请求响应速度快,有的⼈请求响应速度慢,这会严重的影响到⽤户的体验。为了提⾼响应速度需要引⼊反向代理和CDN;CDN和反向代理都是采⽤的缓存,⽬的:
尽可能快的把数据呈现给⽤户
减轻后端服务器的压⼒
架构图如下:
CDN: 部署在⽹络提供商的机房,当⽤户来访问的时候,从距离⽤户最近的服务器返回数据,尽快呈现给⽤户;通常情况下在CDN中缓存的是静态资源(html,js,css),达到动静分离;但是有时候遇到了某些数据访问量特别⼤的时候,后端会⽣成静态资源放⼊到CDN,⽐如:商城的⾸页,每个⽤户进⼊都需要访问的页⾯,如果每次请求都进⼊到后端,那么服务器的压⼒肯定不⼩,这种情况下会把⾸页⽣成静态的⽂件缓存到cdn和反向代理服务器
反向代理:部署在应⽤的中⼼机房,通常也是缓存的静态资源,当⽤户通过CDN未请求到需要的数据
时,先进⼊反向代理服务器,如果有缓存⽤户访问的数据,那么直接返回给⽤户;这⾥也有特殊情况,对于有些场景下的热点数据,在这⾥根据⽤户的请求去分布式缓存服务器中获取,能拿到就直接返回。
这种架构已经把缓存做到了4级
第⼀级:CDN 缓存静态资源
redis是nosql数据库吗第⼆级:反向代理缓存静态资源以及部分热点数据
第三级:应⽤服务器的本地缓存
第四级:分布式缓存服务器
通常情况下经过了这4级缓存,能够进⼊到数据库的请求也不多了,很好的释放了数据库的压⼒
搜索引擎和NoSQL
随着业务的不断扩⼤,对于数据的存储和查询的需求也越来越复杂,通常情况我们需要引⼊⾮关系型数据库,⽐如搜索引擎和NoSQL数据库
有时候我们的查询场景很复杂,需要查询很多数据表,经过⼀系列的计算才能完成,这时候可以考虑通过数据同步⼯具(⽐如canal)拉去数据到⼤数据平台,使⽤批处理框架离线计算,把输出的结果存放到搜索引擎或者NoSQL数据库中,应⽤程序直接查询计算的结果返回给⽤户。也有可能我们需要汇总多个表的数据做⼀张宽表,⽅便应⽤程序查询
由于引⼊的数据存储⽅式增多,为了减轻应⽤程序的管理多个数据源的⿇烦,需要封装统⼀数据访问模块,如果使⽤的时Java,可以考虑spring-data
业务纵向拆分
互联⽹公司通常的宗旨是⼩步迭代试错快跑,当业务发展到⾜够⼤,对于单体应⽤想要达到这个宗旨是有难度的,随着业务的发展,应⽤程序越来越⼤,研发、维护、发布的成本也越来越⼤,这时候就需要考虑根据业务把单体应⽤拆分为多个服务,服务之间可以通过RPC远程调⽤和消息队列来⼀起完成⽤户的请求。
由于业务的拆分,通常情况下也会相应的对数据库进⾏拆分,达到⼀个服务对应⼀个数据库的理想状态
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论