
电 话:17792598618
网址:huaquantongstone.com
邮 箱:65852235@qq.com
前言
我们以(yi)Java Web为例,型网型网来搭建一个简单的站大站架电商系统,看看(kan)这个系统可以如(ru)何一步步演变。构演

该系统具备的大阶段功能:

正(zheng)文

阶段一、单机构建(jian)网站
网站的型网型(xing)网初期(qi),我们经常会在单机上跑我们所有的站大站架程序和(he)软件。此时我们使用一个容(rong)器,构演如Tomcat、大阶段Jetty、型网型(xing)网Jboss,站大站架然后直接使用JSP/Servlet技术,构演或(huo)者使用一些开源的大(da)阶段框架如Maven + Spring + Struts + Hibernate、Maven + Spring + Spring MVC + Mybatis。型网型网最后(hou)再选择一个(ge)数据(ju)库管理系统来存储数据,站大站架如MySQL、构演SqlServer、Oracle,然后通过(guo)JDBC进行数据库的连接和操作。
把以(yi)上的所有软件(jian)包括数(shu)据库、应用(yong)程序都装载同一台机器上,应用跑起来了,也算(suan)是一个小(xiao)系统了。此时系统结果如下:
阶段二、应用服务器(qi)与数据库分离
随着网站的(de)上线,访问量逐步上(shang)升,服务器的负载慢慢提高,在服务(wu)器还没有(you)超载的(de)时候,我们应该就要做好准备,提升网站的负载能力。假如我们代码层面已难以优化,在不提高单台机器的性(xing)能的情况下,采用增(zeng)加机器是一个不(bu)错的方式,不仅可以有效地提高系统的负载(zai)能力,而且性价比高。
增(zeng)加的机器用来做什么呢?此时我们可以把(ba)数(shu)据库服务器和Web服务器(qi)拆分开(kai)来,这样不仅提高了单台机器的负载能力,也提高了容灾能力。
阶段三、应用服务器集群
随着访问量继续增加,单台应用服务器已经无法满足需求了。在假设数据库服务器没有压力的情(qing)况下,我(wo)们可(ke)以(yi)把应用服务器从一台变成了两台甚至多台,把用户的请求分散到不同的(de)服务器中,从而提高负载能(neng)力。而多台应用服务器之间没有直接的交互,他们都是(shi)依赖数据库各自对外提供服务。著名的做故障切换的软件有KeepAlived,KeepAlived是一个类似于Layer3、4、7交换机制的软件,他不是某个(ge)具体软件故障切换的专属品,而是可(ke)以适用于(yu)各种软件的一款产品。KeepAlived配合上ipvsadm又可以做负载均衡,可谓是神器。
系统演变到这里,将会(hui)出现下面(mian)四(si)个问题:
用户的(de)请求由谁来转发到到具体的应用服务器?有那些转发的算法和策(ce)略可以(yi)使用?应用服务器如何返回用户的请求?用户如果每次访问到的服务(wu)器不一样,那么如何维护session的一致性(xing)?针对以(yi)上问题,常用的解决方(fang)案如(ru)下:
1、负载(zai)均衡的问题
一般以下有5种解决方案:
1、HTTP重定向
HTTP重定向就是应用层的请求转发。用户的请求其实已经到了HTTP重定向(xiang)负载均衡服务器,服务器根据算法要(yao)求用户重定向,用户收到重定向请求后,再次请求真正的集群
优点:简单易用(yong);缺点:性能较差。2、DNS域名解析负载均衡
DNS域名解析负载均衡就是在用户请求DNS服务器,获取域名对应(ying)的IP地址时(shi),DNS服务器直接给出负载均衡后的服务(wu)器(qi)IP。
优点:交给DNS,不用我们去维护负载均衡服务器;缺点:当一个应(ying)用服务器挂了,不能(neng)及时通知DNS,而且DNS负载(zai)均衡的控制(zhi)权在域名服务商那里,网站无法做更多的改(gai)善和(he)更强大的管理。3、反向代理服务器(qi)
在用户的请求到达反向代理(li)服务器(qi)时(已经到达网站机房),由反向代(dai)理(li)服务器(qi)根(gen)据算法转发到具体的服务器。常(chang)用(yong)的Apache,Nginx都可以充当反向代理服务器(qi)。
优点:部署简单;缺点:代理服务器可能成为性能的瓶颈,特别是(shi)一次上传大文件。4、IP层负载均衡
在请求到达负载均衡器后(hou),负载均衡器通过修改请求的目的IP地址,从而实现请求的(de)转发,做到负载均衡。
优点:性能更好(hao);缺点:负载均衡器(qi)的宽带成为瓶颈。5、数据链路层负载均衡
在请求到达负载均衡器后,负载均衡器通过修改请求的MAC地址,从而做到负载均衡,与IP负载均衡不(bu)一样(yang)的(de)是,当请求访问完(wan)服务器之后,直接返回(hui)客户。而(er)无需再经过负载均衡器。
2、集(ji)群调度转发算法
1、rr轮询调度算法
顾名思义,轮询分发请求。
优点:实现简单缺点:不考虑每台服务器(qi)的处理能力2、wrr加(jia)权调度算法
我们给(gei)每个服务器设置权值Weight,负载均衡调度器根据权值调(diao)度服务器,服务器被调用的次(ci)数跟权值成正比。
优点:考虑了服务器处(chu)理能力的不同3、sh原地址散列算法
提取用户IP,根据散列(lie)函数得出(chu)一个key,再根据静态映射表,查处对应(ying)的value,即目标服务器IP。过目标机器超负荷,则返回空。
优点:实(shi)现同一个用户访问同一个(ge)服务器。4、dh目标地址散列算法
原理同上,只是现在提取的是目标地址的IP来做哈希。
优点:实现同一个用户访问同一个服务器(qi)。5、lc最少连接算法
优先把请求转发给连接数少的(de)服务器。
优点:使得集群中各个服务器的负载更加均匀。在lc的(de)基础上,为每台服务器加(jia)上权值。算法为:(活动连接数(shu) * 256 + 非活动连接数(shu)) ÷ 权重,计(ji)算出来的值小的服务器优先被选择。
优点:可以根据(ju)服务器的能力分配请求。其实sed跟wlc类似,区(qu)别是不考虑非活(huo)动连(lian)接数。算法为(wei):(活动连接数 +1 ) * 256 ÷ 权重,同样计算(suan)出来的值小的服务器优先(xian)被选择。
8、nq永不(bu)排队算法
改进(jin)的sed算法(fa)。我们想一下什么情况下才能“永不排队”,那(na)就是(shi)服务(wu)器的连接数为0的时候(hou),那么(me)假如有服务器(qi)连接数为0,均衡器直接把请求转发给它,无需经过sed的(de)计算(suan)。
9、LBLC基于局部性最少连接算(suan)法
负载均衡器(qi)根据请求的目的IP地址,找出该IP地址最近被使用的(de)服务器,把请求转发(fa)之。若该服务器超载,最采用(yong)最少连接(jie)数算法。
10、LBLCR带复制(zhi)的基于局部性最少连(lian)接算法
负载均衡器根据请求的目的IP地址,找出该IP地址最近使用的“服务器组(zu)”,注意,并不是具体某个服务器,然后(hou)采用最少连接数从该组中挑出具体的某台服务器出来,把请求转发之。若该服务器超载,那么根据最少连接数算法,在集群(qun)的(de)非本服务器组的服务器中,找出一台服务(wu)器出来,加入本服务器组,然后把请求转发。
3、集群请求返回模式问题
1、NAT
负载均衡器接收用户的请求,转发给具体服务器,服务器处(chu)理完请求返回给均衡器,均衡器再重新返回给用户。
2、DR
负载均衡器接(jie)收用户的请求,转发给具体服务器,服务(wu)器(qi)出来玩请求后直接返回给用户。需要系(xi)统支持IP Tunneling协议,难以跨平台。
3、TUN
同上,但无需IP Tunneling协议,跨平台性好,大部分系统(tong)都可以支持。
4、集群(qun)Session一致性问(wen)题
1、Session Sticky
Session sticky就是把同一个用(yong)户在某一个会话中(zhong)的请求,都分配到固定的某一台服务器中,这样我(wo)们就不(bu)需要解决跨服务器的session问题了,常见的算(suan)法有(you)ip_hash算法,即上面提到的两种散列算法(fa)。
优点:实现(xian)简单;缺点:应用服务器重启则session消(xiao)失。2、Session Replication
Session replication就是在集群中复制(zhi)session,使得每个服务器都保存有全部用户的session数据。
优点:减轻负载均衡服务(wu)器的(de)压(ya)力,不需要要实现ip_hasp算(suan)法来转发请求;缺点:复(fu)制时网络带宽开销大,访问量大的话Session占用内存大且浪费。3、Session数(shu)据集中存储
Session数据集中存储就是利(li)用数据库来存储session数据,实现了session和应(ying)用服务器的解耦。
优点:相比Session replication的方案,集群间对(dui)于宽带和内存的压(ya)力大幅减少;缺点:需要维护存储Session的数据库。4、Cookie Base
Cookie base就是把Session存在Cookie中,由浏览器来告诉应用服务器(qi)我的session是什么,同样(yang)实(shi)现了(le)session和应用服务器的解耦。
优点(dian):实现简单,基本免维护。缺点:cookie长度限制,安全性低,带宽消耗。值得一提的是:
Nginx目前支持(chi)的负载均衡算(suan)法有wrr、sh(支持一致性哈希)、fair(lc)。但(dan)Nginx作为均衡器的话,还可(ke)以一同作为静态资源服务器。Keepalived + ipvsadm比较强大,目前支持的算法有:rr、wrr、lc、wlc、lblc、sh、dhKeepalived支持集群模式有:NAT、DR、TUNNginx本身并没有提供session同步的解决(jue)方案,而Apache则提(ti)供了(le)session共享的(de)支持。阶段四、数据库读写分离(li)化
上面我们总是假设数据库负载正常,但随着访问量的的提(ti)高,数据库的负载也(ye)在慢慢增大。那么可能有人马上就想到跟应用服务器一样,把数(shu)据库一份为二再负载均衡即可。
但对于数据库来说,并没有那(na)么简单。假如我们简单的把(ba)数据库一分为(wei)二,然后对于(yu)数据库的请求,分别负载(zai)到A机器和B机器,那么显而易见会造成两台数据库数据不统一的问题。那么对(dui)于这种(zhong)情况,我们可以先考虑使用读写分离和主从复制的方式。
这个结构变化后(hou)也会带来两个问题(ti):
主从数据(ju)库之(zhi)间数据(ju)同步问题。应用对于数据源的选择问(wen)题。解决方(fang)案:
使用MySQL自带的(de)Master + Slave的方式(shi)实现(xian)主从复制。采用第三方数据库中间件,例如MyCat。MyCat是(shi)从Cobar发展(zhan)而来的,而Cobar是阿里开源的数据库中间件,后来停止开发。MyCat是国(guo)内比较好的(de)MySql开源数(shu)据库分库分表中间件。阶段五、用搜索引擎缓解(jie)读库的压力
数(shu)据库做读库的话,常常对(dui)模糊查找力不从(cong)心,即使(shi)做了读写分离,这(zhe)个问题还未能解决。以我们所举的交易网站为例,发布的商品存储在数据库中,用(yong)户最常使(shi)用的(de)功能就是查找商品,尤其是根据商品的标(biao)题来查找对应的商品。对(dui)于这种需(xu)求,一般我们都是通过like功能来实现的,但是这种方式的代价非常大,而且结果非常不(bu)准确。此时我们可以使用(yong)搜索引擎的倒排索引来完成。
搜索引擎具有的优点:它(ta)能够大大提高查询速度和搜索准(zhun)确性。
引入搜索引擎的开销
带来大(da)量的维护工作,我们需要自己实现索引的(de)构建过程,设计全量/增加的构建方式来应(ying)对非实时与(yu)实时的查询需(xu)求。需要维护搜索引擎集(ji)群(qun)搜索引擎并不能替代数(shu)据库,它解决了某些场景下的精准、快速、高效的“读”操作,是否引入搜索引擎,需要综合考虑整个系统的需求。
阶段六、用缓存缓解读库的压力
常用的缓存机制包括页面级缓存、应用数据(ju)缓存和数据库缓存。
应用层和数据库层的缓存
随着访问量(liang)的增加,逐渐出现了许多用户访问同一部分热门内容的情况,对于(yu)这些比较热门的内容(rong),没必(bi)要每次都从数(shu)据库读取。我们可以使用缓存技术,例如可以使用Google的开源缓存技术Guava或者使用Memecahed作(zuo)为应用层的缓存,也可以使用Redis作为数据库层的缓存。
另外,在某些场景下(xia),关(guan)系型数据库并不是很适合,例如(ru)我(wo)想做(zuo)一个“每日输入密码错误次数限制”的功能,思(si)路大概是(shi)在用户登录时,如果登录错误,则(ze)记录下该用户的IP和错误次数,那(na)么这个(ge)数据要放在哪里呢?假如放在内存中,那么显然会占用太大的内容;假如放在关系型数(shu)据库中,那么既要建(jian)立数据库表,还要简历对应的Java bean,还要写SQL等等。而分析一下我们要存(cun)储的数据,无非就(jiu)是类似{ ip:errorNumber}这样的key:value数据。对于这种数据,我们可以用NOSQL数据库来代替传统的关系型数据库。
页面(mian)缓存
除了数据缓存,还有(you)页面缓存。比如使用HTML5的localstroage或者Cookie。除了页面缓存带来的性能提升外,对于并发(fa)访问(wen)且页面(mian)置换频率小的页面,应尽量使用页面静态化技术。
优点:减轻数据库的压(ya)力, 大幅度提高访问速度;缺点:需要维护缓存服务器,提高了编码的复杂性。值得一提的(de)是:
阶段七、数据库水平拆分与垂直拆分
我们的网站演进到现在,交易、商品、用户的数(shu)据(ju)都还在同一个数据库中。尽管采取了增加缓存和读写分离的方式,但随着数据库的压力(li)继续增加,数据库数据量的瓶颈越来越突出(chu),此时,我们可以有数据垂直拆分和水平拆分两种选择。
数据垂直(zhi)拆分(fen)
垂直拆分的意(yi)思是把(ba)数据库中不同的业务数据拆分到不同的数(shu)据库中,结合现在的例子,就是把交易、商品、用户的数(shu)据(ju)分开。
优点:
解决了(le)原来把所有业务放在一个数据库中(zhong)的压力问(wen)题;可以根据业务的(de)特点进行更多(duo)的优化。缺点:
需要维护多个数据库的状态一致性和数(shu)据同步。问题:
需要考虑原来跨业(ye)务(wu)的事务;跨数据库的Join。解决问题方案:
应该在(zai)应用层尽量避免跨数据库的(de)分布(bu)式事务,如果非要跨数据(ju)库,尽量在(zai)代码中控制(zhi)。通过第三方中间件来解决,如上面提到的MyCat,MyCat提供了丰富的跨库Join方案,详情可参考MyCat官方文档。数据水平(ping)拆分就是把同一个表中的数据拆分到两个甚至多个数(shu)据库中。产生数据(ju)水(shui)平拆分的原因是某个业务的数(shu)据量或者更新量到达了单个数据库的瓶颈,这(zhe)时就可以把(ba)这个表拆分到两个(ge)或更多个数据库中。
优点:
如果能克服以上(shang)问题,那么我们将能够很好地对数据量及写入量增(zeng)长的情况。问题:
访问用户信息的应用系(xi)统需(xu)要解决SQL路由的问题,因为现在(zai)用户信息分在了两个数据库中,需要在进行数据操作时了解需要操作的数据在哪里。主键(jian)的(de)处理也(ye)变得不同,例如原来自增字段,现在不能简单地继续使用。如果需要分页查询,那就更加麻烦。解决问题方案:
我们还是可以通过可以解决第三方中间件(jian),如MyCat。MyCat可以通过(guo)SQL解析模块对我(wo)们的SQL进行解析,再根据我(wo)们的配置,把请求转发到具体的某个(ge)数据库。我们可以通(tong)过UUID保证唯一或自定义ID方案来解决(jue)。MyCat也提供了丰富的分页查询方案,比如先从每个数据库做分页查询,再合并数据做一次(ci)分页查询等等阶段八、应用的拆分
按微服务(wu)拆分应用
随着业务的发展,业务(wu)越来越(yue)多,应用越来越大。我们需要考虑如何避免让应用越来越臃肿。这就需要把应用拆开,从(cong)一个(ge)应用变为俩个(ge)甚至更多。还是以(yi)我(wo)们上面的例子,我们可以把用户、商品、交易拆分开。变成“用户、商品”和“用户,交易”两个子系统。
问题:
这样拆分(fen)后,可能会有一些相同的代码,如用户相关的代码,商品和交易都需要用户信息,所以(yi)在两个系统中都保留差不多的操作用户信息的代码。如何保证这些(xie)代码可以复用是(shi)一个需要解决的(de)问题。
解决(jue)问题:
通过走服务化SOA的路线来解决频繁公共的服务。
走SOA服务化治(zhi)理道路
为(wei)了解决上面拆分(fen)应用后所出现(xian)的问(wen)题,我们把公共的服务拆分出来,形成一种(zhong)服务化的模式,简称SOA
优点(dian):
相同的代码不会(hui)散落在不同的应用(yong)中了,这些实现放在了各个服务中心,使代码得到更好的维护。我们把对数据库的交互业务放在了各个服务中心(xin),让前(qian)端的Web应用更注重与浏览器(qi)交(jiao)互的工作。问题:
如何进行远程的服务调用?
解决方法:
阶段九、引入消息中间件
随着网站的继续发展,的系统中可能出现不同语言开发的子模块和部署在不同平台的子系统。此(ci)时我们需(xu)要一个平台来传递可靠的,与平台和语言无关的数据(ju),并且能(neng)够把负载均衡透明化(hua),能(neng)在调(diao)用过程中收集并分析调用数据,推测出网站的访问增长率等(deng)等一系列需求,对于网站应该如何成长做出预测。开源消息中间件有阿里的Dubbo,可以搭配Google开源的分布式程序协调服务Zookeeper实现服务器的注册与发现。
总结
以上的(de)演变过程只(zhi)是一个例子,并不适合所有的网站,实际中网站演进过程与自身业(ye)务和不同遇到的(de)问题有密切的关(guan)系(xi),没有固定的模式。只有认真的分析和(he)不断地探究,才能发现适合自己网站的架构。