随着访问量继续增加,单台应用服务器已经无法满足需求了。在假设数据库服务器没有压力的情况下,我们可以把应用服务器从一台变成了两台甚至多台,把用户的请求分散到不同的服务器中,从而提高负载能力。
多台应用服务器之间没有直接的交互,他们都是依赖数据库各自对外提供服务。
在多台服务器上分别部署Tomcat,使用反向代理软件(Nginx)把请求均匀分发到每个Tomcat中。此处假设Tomcat最多支持100个并发,Nginx最多支持50000个并发,那么理论上Nginx把请求分发到500个Tomcat上,就能抗住50000个并发。其中涉及的技术包括:Nginx、HAProxy,两者都是工作在网络第七层(最高层、应用层)的反向代理软件,主要支持HTTP协议,还会涉及Session共享,文件上传、下载的问题。
系统演变到这里,有可能会出现下面四个问题:
-
用户的请求由谁来转发到到具体的应用服务器
-
有什么转发的算法
-
应用服务器如何返回用户的请求
-
用户如果每次访问到的服务器不一样,那么如何维护session的一致性
解决方案:
-
第一个问题即是负载均衡的问题,一般有5种解决方案:
-
http重定向。HTTP重定向就是应用层的请求转发。用户的请求其实已经到了HTTP重定向负载均衡服务器,服务器根据算法要求用户重定向,用户收到重定向请求后,再次请求真正的集群
优点:简单。
缺点:性能较差。
- DNS域名解析负载均衡。DNS域名解析负载均衡就是在用户请求DNS服务器,获取域名对应的IP地址时,DNS服务器直接给出负载均衡后的服务器IP。
优点:交给DNS,不用我们去维护负载均衡服务器。
缺点:当一个应用服务器挂了,不能及时通知DNS,而且DNS负载均衡的控制权在域名服务商那里,网站无法做更多的改善和更强大的管理。
- 反向代理服务器。在用户的请求到达反向代理服务器时(已经到达网站机房),由反向代理服务器根据算法转发到具体的服务器。常用的apache,nginx都可以充当反向代理服务器。
优点:部署简单。
缺点:代理服务器可能成为性能的瓶颈,特别是一次上传非常大的文件。
- IP层负载均衡。在请求到达负载均衡器后,负载均衡器通过修改请求的目的IP地址,从而实现请求的转发,做到负载均衡。
优点:性能更好。
缺点:负载均衡器的宽带成为瓶颈。
-
数据链路层负载均衡。在请求到达负载均衡器后,负载均衡器通过修改请求的mac地址,从而做到负载均衡。与IP负载均衡不一样的是,当请求访问完服务器之后,直接返回客户。而无需再经过负载均衡器。
-
第二个问题即是集群调度算法问题,常见的调度算法有以下10种:
-
rr 轮询调度算法。顾名思义,轮询分发请求。
优点:实现简单
缺点:不考虑每台服务器的处理能力
- wrr 加权调度算法。我们给每个服务器设置权值weight,负载均衡调度器根据权值调度服务器,服务器被调用的次数跟权值成正比。
优点:考虑了服务器处理能力的不同
-
sh 原地址散列:提取用户IP,根据散列函数得出一个key,再根据静态映射表,查出对应的value,即目标服务器IP。如果目标机器超负荷,则返回空。
-
dh 目标地址散列:同上,只是现在用提取的是目标地址的IP来做哈希。
优点:以上两种算法都能实现同一个用户访问同一个服务器。
- lc 最少连接。优先把请求转发给连接数少的服务器。
优点:使得集群中各个服务器的负载更加均匀。
- wlc 加权最少连接。在lc的基础上,为每台服务器加上权值。算法为:(活动连接数*256+非活动连接数)÷权重 ,计算出来的值小的服务器优先被选择。
优点:可以根据服务器的能力分配请求。
-
sed 最短期望延迟。其实sed跟wlc类似,区别是不考虑非活动连接数。算法为:(活动连接数+1)*256÷权重,同样计算出来的值小的服务器优先被选择。
-
nq 永不排队。改进的sed算法。我们想一下什么情况下才能“永不排队”,那就是服务器的连接数为0的时候,那么假如有服务器连接数为0,均衡器直接把请求转发给它,无需经过sed的计算。
-
LBLC 基于局部性的最少连接。均衡器根据请求的目的IP地址,找出该IP地址最近被使用的服务器,把请求转发之;若该服务器超载,最采用最少连接数算法。
-
LBLCR 带复制的基于局部性的最少连接。均衡器根据请求的目的IP地址,找出该IP地址最近使用的“服务器组”。注意,并不是具体某个服务器,然后采用最少连接数从该组中挑出具体的某台服务器出来,把请求转发之。若该服务器超载,那么根据最少连接数算法,在集群的非本服务器组的服务器中,找出一台服务器出来,加入本服务器组,然后把请求转发之。
-
第三个问题是集群模式问题,一般3种解决方案:
-
NAT:负载均衡器接收用户的请求,转发给具体服务器,服务器处理完请求返回给均衡器,均衡器再重新返回给用户。
-
DR:负载均衡器接收用户的请求,转发给具体服务器,服务器处理完请求后直接返回给用户。需要系统支持IP Tunneling协议,难以跨平台。
-
TUN:同上,但无需IP Tunneling协议,跨平台性好,大部分系统都可以支持。
-
第四个问题是session问题,一般有以下4种解决方案:
-
Session Sticky。session sticky就是把同一个用户在某一个会话中的请求,都分配到固定的某一台服务器中,这样我们就不需要解决跨服务器的session问题了,常见的算法有ip_hash法,即上面提到的两种散列算法。
优点:实现简单。
缺点:应用服务器重启则session消失。
- Session Replication。session replication就是在集群中复制session,使得每个服务器都保存有全部用户的session数据。
优点:减轻负载均衡服务器的压力,不需要实现ip_hasp算法来转发请求。
缺点:复制时宽带开销大,访问量大的话session占用内存大且浪费。
- Session数据集中存储:session数据集中存储就是利用数据库来存储session数据,实现了session和应用服务器的解耦。
优点:相比session replication的方案,集群间对于宽带和内存的压力减少了很多。
缺点:需要维护存储session的数据库。
- Cookie Base:cookie base就是把session存在cookie中,有浏览器来告诉应用服务器我的session是什么,同样实现了session和应用服务器的解耦。
优点:实现简单,基本免维护。
缺点:cookie长度限制,安全性低,宽带消耗。
值得一提的是:
-
nginx目前支持的负载均衡算法有wrr、sh(支持一致性哈希)、fair(本人觉得可以归结为lc)。但nginx作为均衡器的话,还可以一同作为静态资源服务器。
-
keepalived+ipvsadm比较强大,目前支持的算法有:rr、wrr、lc、wlc、lblc、sh、dh
-
keepalived支持集群模式有:NAT、DR、TUN
-
nginx本身并没有提供session同步的解决方案,而apache则提供了session共享的支持。
虽然反向代理使应用服务器可以支持的并发量大大增加,但是并发量的增加也意味着更多请求穿透到数据库,单机的数据库最终会称为性能瓶颈。
上面我们总是假设数据库负载正常,但随着访问量的的提高,数据库的负载也在慢慢增大。那么可能有人马上就想到跟应用服务器一样,把数据库一份为二再负载均衡即可。
但对于数据库来说,并没有那么简单。假如我们简单的把数据库一分为二,然后对于数据库的请求,分别负载到A机器和B机器,那么显而易见会造成两台数据库数据不统一的问题。那么对于这种情况,我们可以先考虑使用读写分离的方式。
把数据库划分为读库和写库,读库可以有多个,通过同步机制把写库的数据同步到读库,对于需要查询最新写入数据的场景,可以在缓存中多写一份,通过缓存获得最新数据。其中涉及的技术包括Mycat,它是数据库中间件,可通过它来组织数据库的读写分离和分库分表,客户端通过它来访问下层数据库,还会涉及数据同步,数据一致性的问题。
这个结构变化后也会带来两个问题:
-
主从数据库之间数据同步问题
-
应用对于数据源的选择问题
解决问题方案:
-
我们可以使用MYSQL自带的master+slave的方式实现主从复制。
-
采用第三方数据库中间件,例如mycat。mycat是从cobar发展而来的,而cobar是阿里开源的数据库中间件,后来停止开发。mycat是国内比较好的mysql开源数据库分库分表中间件。
随着业务逐渐变多,不同业务之间的访问量差距较大,不同业务直接竞争数据库资源,相互影响性能。
我们的网站演进到现在,交易、商品、用户的数据都还在同一个数据库中。尽管采取了增加缓存,读写分离的方式,但随着数据库的压力继续增加,数据库的瓶颈越来越突出,此时,我们可以有数据垂直拆分和水平拆分两种选择。
数据库垂直拆分(按业务分库)
垂直拆分的意思是把数据库中不同的业务数据拆分道不同的数据库中,比如把电商项目中的交易、商品、用户的数据分开。
把不同业务的数据保存到不同的数据库中,使业务之间的资源竞争降低。对于访问量大的业务,可以部署更多的服务器来支撑。
-
优点:
-
解决了原来把所有业务放在一个数据库中的压力问题。
-
可以根据业务的特点进行更多的优化
-
缺点:
需要维护多个数据库
-
问题:
-
需要考虑原来跨业务的事务
-
跨数据库的join
-
解决问题方案:
-
应该在应用层尽量避免跨数据库的事物,如果非要跨数据库,尽量在代码中控制。
-
可以通过第三方应用来解决,如上面提到的mycat,mycat提供了丰富的跨库join方案,详情可参考mycat官方文档。
随着用户数量的增长,单机的写库会逐渐达到性能瓶颈。
水平拆分(把大表拆分为小表(分表))
数据水平拆分就是把同一个表中的数据拆分到两个甚至多个数据库中。产生数据水平拆分的原因是某个业务的数据量或者更新量到达了单个数据库的瓶颈,这时就可以把这个表拆分到两个或更多个数据库中。
比如针对评论数据,可以按照商品的ID进行Hash,路由到对应的表中存储;针对支付记录,可以按照支付的小时创建表,每个小时表继续拆分为小表,使用用户ID或记录编号来路由数据。只要实时操作的表数据量足够小,请求能够足够均匀地分发到多台服务器上的小表,那数据库就能通过水平扩展的方式来提升性能。其中前面提到的Mycat也支持在大表拆分为小表的情况下进行访问控制。
这种做法显著地增加了数据库运维的难度,对DBA的要求较高。当数据库设计到这种结构时,已经可以称为分布式数据库,但是这只是一个逻辑的数据库整体,数据库里不同的组成部分是由不同的组件单独来实现的,比如分库分表的管理和请求分发由Mycat实现,SQL的解析由单机的数据库实现,读写分离可能由网关和消息队列来实现,查询结果的汇总可能由数据库接口层来实现等,这种架构其实是MPP
(大规模并行处理)架构的一类实现。
目前开源和商用都已经有不少MPP数据库,开源中比较流行的有Greenplum、TiDB、Postgresql XC、HAWQ等,商用的如南大通用的GBase、睿帆科技的雪球DB、华为的LibraA等,不同的MPP数据库的侧重点也不一样,比如TiDB侧重于分布式OLTP场景,Greenplum侧重于分布式OLAP场景,这些MPP数据库基本都提供了类似Postgresql、Oracle、MySQL那样的SQL标准支持能力,能把一个查询解析为分布式的执行计划分发到每台机器上并行执行,最终由数据库本身汇总数据进行返回,也提供了注入权限管理、分库分表、事务、数据副本等能力,并且大多能够支持100个节点以上的集群,大大降低了数据
库运维的成本,并且使数据库也能够水平扩展。
- 优点:
如果我们能克服以上问题,那么我们将能够很好地应对数据量及写入量增长的情况。
-
问题:
-
访问用户信息(假设用户表进行了水平拆分)的应用系统需要解决SQL路由的问题,因为现在用户信息分在了两个数据库中,需要在进行数据操作时了解需要操作的数据在哪里。
-
主键的处理也变得不同,例如原来自增字段,现在不能简单地继续使用了。
-
如果需要分页,就麻烦了。
-
解决问题方案:
-
可以通过可以解决第三方中间件,如mycat。mycat可以通过SQL解析模块对我们的SQL进行解析,再根据我们的配置,把请求转发到具体的某个数据库。
-
可以通过UUID保证唯一或自定义ID方案来解决。
-
mycat也提供了丰富的分页查询方案,比如先从每个数据库做分页查询,再合并数据做一次分页查询等等。
虽然数据库和Tomcat都能够水平扩展,可以支撑的并发量大幅提升,但是随着用户量的增长,最终单机的Nginx会成为性能上的瓶颈。
由于性能瓶颈在Nginx,因此无法通过两层的Nginx来实现多个Nginx的负载均衡。LVS和F5是工作在网络第四层的负载均衡解决方案,其中:
-
LVS是软件,运行在操作系统内核态,可对TCP请求或更高层级的网络协议进行转发,因此支持的协议更丰富,并且性能也远高于Nginx,可假设单机的LVS可支持几十万个并发的请求转发;
-
F5是一种负载均衡硬件,与LVS提供的能力类似,性能比LVS更高,但价格昂贵。
由于LVS是单机版的软件,若LVS所在服务器宕机则会导致整个后端系统都无法访问,因此需要有备用节点。可使用keepalived软件模拟出虚拟IP,然后把虚拟IP绑定到多台LVS服务器上,浏览器访问虚拟IP时,会被路由器重定向到真实的LVS服务器,当主LVS服务器宕机时,keepalived软件会自动更新路由器中的路由表,把虚拟IP重定向到另外一台正常的LVS服务器,从而达到LVS服务器高可用的效果。
此处需要注意的是,上图中从Nginx层到Tomcat层这样画并不代表全部Nginx都转发请求到全部的Tomcat,在实际使用时,可能会是几个Nginx下面接一部分的Tomcat,这些Nginx之间通过keepalived实现高可用,其他的Nginx接另外的Tomcat,这样接入的Tomcat数量就能成倍的增加。
由于LVS也是单机的,随着并发数量增长到几十万时,LVS服务器最终会达到性能瓶颈,此时用户数量达到千万甚至上亿级别,用户分布在不同的地区,与服务器机房距离不同,导致了访问的延迟会明显不同。
在DNS服务器中可配置一个域名对应多个IP地址,每个IP地址对应到不同的机房里的虚拟IP。当用户访问www.taobao.com时,DNS服务器会使用轮询策略或其他策略,来选择某个IP供用户访问。此方式能实现机房间的负载均衡。至此,系统可做到机房级别的水平扩展,千万级到亿级的并发量都可通过增加机房来解决,系统入口处的请求并发量不再是问
题。
随着数据的丰富程度和业务的发展,检索、分析等需求越来越丰富,单单依靠数据库无法解决如此丰富的需求。
当数据库中的数据多到一定规模的时候,数据库就不适用于复杂查询了,往往只能满足普通查询的场景。对于统计报表的场景,在数据量大时不一定能跑出结果,而且在跑复杂查询时会导致其他查询变慢,对于全文检索、可变数据结构等场景,数据库天生不适用。因此需要针对特定的场景,引入合适的解决方案。
如对于海量文件的存储,可以通过分布式文件系统HDFS解决;对于KEY-VALUE类型的数据,可以通过HBase和Redis等方案解决;对于全文检索场景,可以通过搜索引擎,比如ElasticSearch解决;对于多维分析场景,可以通过Kylin或Druid等方案解决。
当然,引入更多的组件同时会提高系统的复杂度,不同的组件保存的数据需要同步,需要考虑数据一致性的问题,需要有更多的运维手段来管理这些组件等。
搜索引擎最大的优点是它能够大大提高查询速度。 引入搜索引擎后也会带来以下的开销:
-
带来大量的维护工作,我们需要自己实现索引的构建过程,设计全量/增加的构建方式来应对非实时与实时的查询需求。
-
发需要维护搜索引擎集群
搜索引擎并不能替代数据库,他解决了某些场景下的“读”的问题,是否引入搜索引擎,需要综合考虑整个系统的需求。
引入更多组件解决了丰富的需求,业务维度能够极大扩充,但是随之而来的是一个应用中包含了太多的业务代码,业务的升
级迭代变得困难。
随着业务的发展,业务越来越多,应用越来越大。我们需要考虑如何避免让应用越来越臃肿。这就需要把应用拆开,从一个应用变为俩个甚至更多。比如,我们可以把用户、商品、交易拆分开。变成“用户、商品”和“用户,交易”两个子系统。
按照业务板块来划分应用代码,使单个应用的职责更清晰,相互之间可以做到独立升级迭代。这时候应用之间可能会涉及到一些公共配置,可以通过分布式配置中心Zookeeper来解决。
- 问题:
这样拆分后,可能会有一些相同的代码,如用户相关的代码,商品和交易都需要用户信息,所以在两个系统中都保留差不多的操作用户信息的代码。如何保证这些代码可以复用是一个需要解决的问题。
- 解决问题:
通过走服务化(微服务)的路线来解决
但是不同的应用之间可能存在共用的模块,由应用单独管理会导致相同的代码存在多份,导致公共功能在升级时全部应用代码都要跟着升级。
如用户管理、订单、支付、鉴权等功能在多个应用中都存在,那么可以把这些功能的代码单独抽取出来形成一个单独的服务来管理,这样的服务就是所谓的微服务。应用和服务之间通过HTTP、TCP或RPC请求等多种方式来访问公共服务,每个单独的服务都可以由单独的团队来管理。此外,可以通过Dubbo、SpringCloud等框架实现服务治理、限流、熔断、降级等功能,提高服务的稳定性和可用性。
-
优点:
-
相同的代码不会散落在不同的应用中了,这些实现放在了各个服务中心,使代码得到更好的维护。
-
我们把对数据库的交互放在了各个服务中心,让”前端“的web应用更注重与浏览器交互的工作。
-
问题:
如何进行远程的服务调用
- 解决方法:
我们可以通过下面的引入消息中间件来解决。开源消息中间件有阿里的dubbo,可以搭配Google开源的分布式程序协调服务zookeeper实现服务器的注册与发现。
但是由于不同服务的接口访问方式不同,应用代码需要适配多种访问方式才能使用服务。此外,应用访问服务,服务之间也可能相互访问,调用链将会变得非常复杂,逻辑变得混乱。
通过ESB统一进行访问协议转换,应用统一通过ESB来访问后端服务,服务与服务之间也通过ESB来相互调用,以此降低系统的耦合程度。这种单个应用拆分为多个应用,公共服务单独抽取出来来管理,并使用企业消息总线来解除服务之间耦合问题的架构,就是所谓的SOA
(面向服务)架构。
SAO架构与微服务架构容易混淆,因为表现形式十分相似。个人理解,微服务架构更多是指把系统里的公共服务抽取出来单独运维管理的;而SOA架构则是指一种拆分服务并使服务接口访问变得统一的架构思想,SOA架构中包含了微服务的思想。
随着业务不断发展,应用和服务都会不断变多,应用和服务的部署变得复杂,同一台服务器上部署多个服务还要解决运行环境冲突的问题。此外,对于如大促这类需要动态扩缩容的场景,需要水平扩展服务的场景,就需要在新增的服务器上准备运行环境,部署服务等,运维将变得十分困难。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

更多面试题
**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等
伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**
[外链图片转存中…(img-K9C1POFx-1712562794008)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

更多面试题
**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等
[外链图片转存中…(img-hLW4aMrh-1712562794008)]