网站架构的伸缩性

一般来说,网站的伸缩性设计可分为两类:一类是根据功能进行物理分离实现伸缩,一类是单一功能通过集群实现伸缩。前者是不同的服务器部署不同的服务,提供不同的功能,后者是集群内的多台服务器部署相同的服务,提供相同的功能。

1、不同功能进行物理分离实现伸缩


2、单一功能通过集群规模实现伸缩

具体来说,集群伸缩性又分为应用服务器集群伸缩性和数据服务器集群伸缩性

(1)应用服务器集群的伸缩性

应用服务器应该设计成无状态的,即应用服务器不存储请求上下文信息,如果将部署有相同应用的服务器组成一个集群,每次用户请求都可以发送到任意一台服务器上去处理,任何一台服务器的处理结果都是相同的。


如果HTTP请求分发装置可以感知或者可以配置集群的服务器数量,可以及时发现集群中新上线或下线的服务器,并能向新上线的服务器分发请求,停止向已下线的服务器发送请求,那么就实现了应用服务器集群的伸缩性。

这里这个HTTP请求分发装置被称作负载均衡服务器。

那么实现负载均衡与哪些基础技术呢?


a、HTTP重定向负载均衡

利用HTTP重定向协议实现负载均衡。


这种负载均衡方案优点是比较简单,缺点是浏览器需要两次请求服务器才能完成一次访问,性能较差,这种方案使用并不多。

b、DNS域名解析负载均衡


在DNS服务器中配置多个A记录,每次域名解析请求都会根据负载均衡算法计算一个不同的IP地址返回,这样A记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。

c、反向代理负载均衡


浏览器访问请求的地址是反向代理服务器的地址114.100.80.10,反向代理服务器收到请求后,根据负载均衡算法计算得到一台真实服务器的地址10.0.0.3,并将请求转发给服务器,10.0.0.3处理完请求后将响应返回给反向代理服务器,反向代理服务器再将该响应返回给用户。缺点是反向代理服务器是所有请求和响应的中转站,其性能可能成为瓶颈。

d

d、IP负载均衡


用户请求数据包到达负载均衡服务器114.100.80.10后,负载均衡服务器在操作系统内核进程获取网络数据包,根据负载均衡算法得到一台真实的web服务器10.0.0.1,然后将数据目的ip地址修改为10.0.0.1,不需要通过用户进程处理,真实web应用服务器处理完成后,响应数据包回到负载均衡服务器,负载均衡服务器再将数据包源地址修改为自身ip地址(114.100.80.10)发送给用户浏览器。

e、数据链路层负载均衡

数据链路层负载均衡是指在通信协议的数据链路层修改mac地址进行负载均衡。


这种方式又叫做三角传输模式,负载均衡数据分发过程中不修改Ip地址,只修改目的mac地址,通过配置真实物理服务器集群所有机器虚拟ip和负载均衡服务器ip地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的,由于实际处理情求的真实物理服务器ip和数据情求目的ip一致,不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽称为瓶颈。这种负载均衡方式又称作直接路由方式。


负载均衡算法

负载服务器的实现可以分成两个部分:

1、根据负载均衡算法和web服务器列表计算得到集群中一台web服务器的地址。

2、将请求数据发送到该地址对应的web服务器上。前面描述了如何将请求数据发送到web服务器,而具体的均衡算法通常有以下几种。

轮询(Round Robin)

所有请求都被一次分发到每台应用服务器上,即每台服务器需要处理的请求数目都相同,适合于所有服务器硬件都相同的场景。

加权轮询(Weighted Round Robin)

根据应用服务器硬件性能的情况,在轮询基础上,按照配置的权重将请求分发到每个服务器,高性能的服务器能分配更多的请求。

随机

请求被随机分配到各个应用服务器,在很多场合下,这种方案都很简单实用,因为好的随机数本身就很均衡,即使应用服务器硬件配置不同,也可以使用加权随机算法。

最少连接

记录每个应用服务器正在处理的连接数(请求数),将新到的请求分发到最少连接的服务器上,应该说,这最符合负载均衡定义的算法。

源地址散列:

根据请求来源的ip地址进行Hash计算,得到应用服务器,这样来自同一个ip地址的请求总在同一个服务器上处理,该请求的上下文信息可以存储在这台服务器上,在一个会话周期内重复使用,从而会实现会话粘滞。

(3)分布式缓存集群的伸缩性

和所有服务器部署相同的应用服务器集群不同,分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存访问请求不可以在缓存服务器集群中的任意一台处理,必须先找到缓存有需要数据的服务器,然后才能访问。这个特点会严重制约分布式缓存集群的伸缩性设计,因为新上线的缓存服务器没有缓存任何数据,而已下线的缓存服务器还缓存着网站的许多热点数据。

必须让新上线的缓存服务器对整个分布式缓存集群影响最小,也就是说新加入缓存服务器后应使整个缓存服务器集群中已经缓存的数据尽可能还被访问到,这是分布式缓存集群伸缩性设计的最基本主要目标。

a、Memcached分布式缓存集群的访问模型



路由算法负责根据应用程序输入的缓存数据Key计算得到应该将数据写入到Memcached的哪台服务器(写缓存)或者应该从哪台服务器读数据(读缓存)。

一个典型缓存写操作如图所示,应用程序输入需要写缓存的数据<‘BEIJING’,DATA>,API将key(“BEIJING”)输入路由算法模块,路由算法根据key和Memcached集群服务器列表计算得到一台服务编号(NODE1),进而得到该机器的IP和地址端口(10.0.0.0:91000)。API调用通信模块和编号为NODE1的服务器通信,将数据<'BEIJING',DATA>写入该服务器,完成一个分布式缓存的写操作。

读缓存的过程和写缓存一样,使用同样的路由算法和服务器列表。

b、Memcached分布式缓存集群的伸缩性挑战、

由上可知,路由算法至关重要,和负载均衡算法一样,决定着究竟该访问集群中的哪台服务器。

简单的路由算法可是使用余数Hash:用服务器数目除以缓存数据Key的Hash值,余数为服务器列表下标编号, 假设“BEIJING”的Hash值是490806430(java中HashCode()的返回值),用服务器数目3除以该值,得到余数1,对应节点NODE1,由于HashCode具有随机性,因此使用余数Hash路由算法可以保证缓存数据在整个Memcached服务器集群中比较均衡分布。

由于业务发展,网站需要将3台缓存服务器扩容至4台,更改服务器列表,仍旧使用余数Hash, 用4除以“BEIJING”的Hash值49080643,余数为2,对应服务器NODE2,由于数据<"BEIJING",DATA>缓存在NODE1,对NODE2的读缓存操作失败,缓存没有命中,很容易计算出,3台服务器扩容至4台服务器,大约有75%(3/4)被缓存的数据不能正确命中,随着服务器集群规模的增大,这个比例线性上升。

通过改进路由算法,使得新加入的服务器不影响大部分缓存数据的正确命中呢?目前比较流行的算法是一致性Hash算法。

(3)分布式缓存一致性的Hash算法

一致性Hash算法通过一个叫做一致性Hash环的数据结构实现Key到缓存服务器的Hash映射。



具体算法过程:先构造一个长度为0-2的32次方的整数环(这个环被称作一致性Hash环),根据节点名称的Hash值(其分布范围同样为0-2的32次方)将缓存服务器节点放置在这个Hash环上,然后根据需要缓存的数据的Key值计算得到其Hash值(其分布范围同样也为0-2的32次方),然后在Hash环上顺时针查找距离这个key的Hash值最忌的缓存服务器节点,完成key到服务器的Hash映射查找。

当缓存服务器集群中需要扩容的时候,只需要将新加入的节点名称(NODE3)的Hash值放入一致性Hash环中,由于Key是顺时针查找距离其最近的节点,因此新加入的节点只影响整个环中的一小段。



假设NODE3的Hash值是2,790,324,235,那么加入NODE3后,KEY0(Hash值2,534,256,785)顺时针找到的节点就是NODE3。

加入新节点NODE3后,原来的KEy大部分还能继续计算到原来的节点,只有Key3、key0从原来NODE1重新计算到NODE3,这样就能保证大部分被缓存的数据还可以继续命中,3台服务器扩容至4台,可以继续命中原有缓存数据的概率是75%,远高于余数Hash的25%。

上述算法还存在一个小问题?

新加入的节点NODE3只影响了原来的节点NODE1,也就是说一部分原来需要方位NODE1的缓存现在需要访问NODE3,但是原来的节点NODE0和NODE2不受影响,这就意味着NODE0和NODE2缓存数据量和负载压力是NODE1与NODE3的两倍,如果4台机器的性能是一样的,这种结果显然不是我们需要的。

计算机领域有句话:计算机中的任何问题都可以通过增加一个虚拟层来解决。解决上述一致性Hash算法带来的负载不均衡问题,也可以通过使用虚拟层的手段:将每台物理缓存服务器虚拟为一组虚拟缓存服务器,将虚拟机服务器的Hash值放置在Hash环上,Key在换上先找到虚拟服务器节点,在得到物理服务器的信息。

这样新加入物理服务器节点时,是将一组虚拟节点加入环中,如果虚拟节点的数据足够多,这种虚拟节点将会影响同样多数目的已经在环上存在的虚拟节点,这些已经存在的虚拟节点又对应不同的物理节点,最终结果:新加入一台缓存服务器,将会较为均匀的影响原来集群中已经存在的所有服务器,也就是说分摊原有缓存服务器集群中所有服务器的一小部分负载。

(4)数据存储服务器集群的伸缩性

和缓存服务器集群的伸缩性设计不同,数据存储服务器集群的伸缩性对数据的持久性和可用性提出了更高的要求。

缓存的目的是加速数据读取的速度并减轻数据存储服务器的负载压力,因此部分缓存数据的丢失不影响业务的正常处理,因为还可以从数据库等存储服务器上获取。

而数据存储服务器必须保证数据的可靠存储,任何情况下都必须保证数据的可用性和正确性。因此缓存服务器集群的伸缩性架构方法不能直接适用于数据库等存储服务器,存储服务器集群的伸缩性设计相对更复杂一些,具体来说,又可分为关系数据库集群的伸缩性设计和NoSQL数据库的伸缩性设计。

1、关系数据库集群的伸缩性设计


这种架构中,虽然多台服务器器部署MySql实例,但是角色有主从之分,数据写操作都在主服务器上,由主服务器将数据同步到集群中其他服务器,数据读操作及数据分析等离线操作从服务器上进行。

除了数据库主从读写分离,不同业务数据表部署在不同的数据库集群上,即俗称的数据分库,这种方式的制约条件是跨库的表不能进行join操作。

在大型网站的实际应用中,即使进行了分库和主从复制,对一些单表数据仍然很大的表,还需要进行分片,将一张表拆开分别存储在多个数据库中。Cobar是比较成熟的支持数据分片的分布式关系数据库产品。


Cobar是一个分布式关系数据库访问代理,介于应用服务器和数据库服务器之间,应用程序通过JDBC驱动访问Corbar集群,Corbar服务器根据SQL和分库规则SQL,分发到MySQl集群不同的数据库实例上执行(每个MySQL实例部署都为主/从结构,保证数据高可用)

Corbar系统组件模型:


前端通信模块负责和应用程序通信,接收到SQL请求(select * from users where userid in(12,22,23))后转交给SQL解析模块,SQl解析模块解析获得SQL中的路由规则查询条件(userid in(12,22,23))再转交给SQL路由模块,SQL路由模块根据路由规则配置(userid 为偶数路由至数据库A,userid为奇数路由至数据库B)将应用程序提交的SQL分解成两条SQL(select * from user where userid in(12,22);select * from users where userid in(23);)转交给SQL执行代理模块,发送至数据库A和数据库B分别执行。

数据库A和数据库B的执行结果返回至SQL执行模块,通过结果合并模块将两个返回结果集合合并成一个结果集,最终返回给应用程序,完成在分布式数据库中的一次访问请求。

那么Cobar如何做集群的伸缩呢?

Corbar的伸缩有两种:Cobar服务器集群的伸缩和MySql服务器集群的伸缩。

Corbar服务器可以看做是无状态的应用服务器,因此其集群伸缩可以简单使用负载均衡的手段实现,而MySql中存储着数据,要保证集群扩容后数据一致性负载均衡,必须要做数据迁移,将集群中原来机器中的数据迁移到新添加的机器中。


具体迁移哪些数据可以利用一致性Hash算法(即路由模块使用一致性Hash算法进行路由),尽量使需要迁移的数据最少,但是迁移数据需要遍历数据库中的每条记录(的索引),重新进行路由计算确定其是否需要迁移,这会对数据库造成一定压力,并且需要解决迁移过程中数据的一致性、可访问性、迁移过程中服务器宕机时的可用性等诸多问题。

实践中,Cobar利用了MySql的数据同步功能进行数据迁移,数据迁移不是以数据为单位,而是以Schema为单位,在Corbar集群初始化时,在每个MySql实例创建多个Schema(根据业务远景规划未来集群规模,如集群最大规模为1000台数据库服务器,那么总的初始Schema数>=1000).进群扩容的时候,从每个服务器中迁移部分Schema到新机器中,由于迁移以Schema为单位,迁移过程中可以使用MySql的同步机制。


同步完成时,即新机器中Schema数据和原机器中Schema数据一致的时候,修改Cobar服务器的路由配置,将这些schema的Ip修改为新机器的Ip。然后删除原机器中的相关Schema,完成MySql集群扩容。

由于Cobar路由只能在单一数据库实例上处理查询请求,因此无法执行跨库的JOIN操作,当然更不能执行跨库的事务处理。

(2)NoSQL数据库的伸缩性设计

一直以来是关系数据库的天下,直到大型网站遇到了关系数据库难以克服的缺陷---糟糕的海量数据处理能力记忆僵硬的设计约束,为了解决这一问题,NoSQl这一概念被提了出来,以弥补关系数据库的不足。

NoSQl主要指非关系的、分布式的数据库设计模式,NoSql表示not only sql,表示NoSql只是关系数据库的补充,而不是替代方案,一般而言,NoSql数据库产品都放弃了关系数据库的两大重要基础:以关系代数为基础的结构化查询语言(SQL)和事务一致性保证(ACID),而强化其他一些大型网站更关注的特性:高可用性和可伸缩性。

目前来看,最广泛的NoSql是Apache HBase,HBase为可伸缩海量数据存储而设计,实现面向在线业务的实时数据访问延迟。HBase的伸缩性主要依赖其可分裂的HRegion及可伸缩的分布式文件系统HDFS实现。

HBase整体架构如图:


HBase中,数据以HRegion为单位进行管理,也就是说应用程序如果想要访问一个数据,必须先找到HRegion,然后将数据读写操作提交给HRegion,由HRegion完成存储层面的数据操作,每个HRegion中存储一段key值区间[key1,key2)的数据,HRegionServer是物理服务器,每个HRegionServer上可以启动多个HRegion实例,当一个HRegion中写入的数据太多,达到配置的阈值时,HRegion会分裂成两个HRegion,并将HRegion在整个集群中进行迁移,以使HRegionServer的负载均衡。

所有HRegion的信息(存储的key值区间、所在HRegionServer地址、访问端口号等)都记录在HMaster服务器上,为了保证高可用,HBase启动多个Master,并通过Zookeeper获得主HMaster的地址,输入key值获得这个key所在的HRegionServer地址,然后请求HRegionServer上的HRegion,获得需要的数据,调用时序图:


数据写入过程也是一样的,需要先得到HRegion才能继续操作,HRegion会把数据存储在若干个叫做HFile格式的文件中,这些文件使用HDFS分布式文件系统存储,在整个集群内分布并高可用,当一个HRegion中数据量太多时,HRegion(连同HFile)会分裂成两个HRegion,并根据集群中服务器负载进行迁移,如果集群中有新加入的服务器,也就是有了新的HRegionServer,由于其负载较低,也会把HRegion迁移过去并记录到HMaster,从而实现HBase的线性伸缩。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值