伸缩性架构

所谓网站的伸缩性是指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力。

京东网( www.360buy.com )在2011年年末的图书促销活动中,由于优惠幅度大引得大量买家访问,结果导致网站服务不可用,大部分用户在提交订单后,页面显示“Serviceis too busy”。当天晚上,京东网老板刘强东在微博发布消息称,已购买多台服务器以增加交易处理能力,第二天继续促销一天。结果第二天,用户在提交订单后,页面继续是“Service is too busy”。显然京东网当时的系统伸缩能力较弱,特别是订单处理子系统几乎没有什么伸缩能力。

与这些缺乏伸缩能力、关键时候掉链子的案例相对应的是淘宝网2012年“双十一”的促销活动,在活动开始的第一分钟,即有1000万独立用户访问网站,当天成功交易的订单总额达191亿,虽然淘宝网及支付宝网站出现了一些问题,但系统总体可用,绝大部分交易顺利完成。

大型网站不是一开始就是大型网站的,而是从小型网站逐步演化而来的,Google诞生的时候也才只有一台服务器。设计一个大型网站或者一个大型软件系统,和将一个小网站逐渐演化成一个大型网站,其技术方案是完全不同的。前者如传统的银行系统,在设计之初就决定了系统的规模,如要服务的用户数、要处理的交易数等,然后采购大型计算机等昂贵的设备,将软件系统部署在上面,即成为一个大型系统,有朝一日这个大型系统也不能满足需求了,就花更多的钱打造一个更大型的系统。而网站一开始不可能规划出自己的规模,也不可能有那么多钱去开发一个大型系统,更不可能到了某个阶段再重新打造一个系统,只能摸着石头过河,从一台廉价的PC服务器开始自己的大型系统演化之路。

在这个渐进式的演化过程中,最重要的技术手段就是使用服务器集群,通过不断地向集群中添加服务器来增强整个集群的处理能力。这就是网站系统的伸缩性架构,只要技术上能做到向集群中加入服务器的数量和集群的处理能力成线性关系,那么网站就可以以此手段不断提升自己的规模,从一个服务几十人的小网站发展成服务几十亿人的大网站,从只能存储几个G图片的小网站发展成存储几百P图片的大网站。

这个演化过程总体来说是渐进式的,而且总是在“伸”,也就是说,网站的规模和服务器的规模总是在不断扩大(通常,一个需要“缩”的网站可能已经无法经营下去了)。但是这个过程也可能因为运营上的需要而出现脉冲,比如前面案例中提到的电商网站的促销活动:在某个短时间内,网站的访问量和交易规模突然爆发式增长,然后又回归正常状态。这时就需要网站的技术架构具有极好的伸缩性——活动期间向服务器集群中加入更多服务器(及向网络服务商租借更多的网络带宽)以满足用户访问,活动结束后又将这些服务器下线以节约成本。

网站架构的伸缩性设计

回顾网站架构发展历程,网站架构发展史就是一部不断向网站添加服务器的历史。只要工程师能向网站的服务器集群中添加新的机器,只要新添加的服务器能线性提高网站的整体服务处理能力,网站就无需为不断增长的用户和访问而焦虑。

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

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

网站发展早期——通过增加服务器提高网站处理能力时,新增服务器总是从现有服务器中分离出部分功能和服务,如图所示。

每次分离都会有更多的服务器加入网站,使用新增的服务器处理某种特定服务。事实上,通过物理上分离不同的网站功能,实现网站仲缩性的于权,个一W1LPA人展早期,而且可以在网站发展的任何阶段使用。具体又可分成如下两种情况。

纵向分离(分层后分离):将业务处理流程上的不同部分分离部署,实现系统伸缩性,如图所示。

横向分离(业务分割后分离):将不同的业务模块分离部署,实现系统伸缩性,如

横向分离的粒度可以非常小,甚至可以一个关键网页部署一个独立服务,比如对于电商网站非常重要的产品详情页面,商铺页面,搜索列表页面,每个页面都可以独立部署,专门维护。

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

将不同功能分离部署可以实现一定程度的伸缩性,但是随着网站访问量的逐步增加,即使分离到最小粒度的独立部署,单一的服务器也不能满足业务规模的要求。因此必须使用服务器集群,即将相同服务部署在多台服务器上构成一个集群整体对外提供服务。

以搜索服务器为例,如果一台服务器可以提供每秒1000次的请求服务,即QPS( Query Per Second )为1000。那么如果网站高峰时每秒搜索访问量为10000,就需要部署10台服务器构成一个集群。若以缓存服务器为例,如果每台服务器可缓存40GB 数据,那么要缓存100GB数据,就需要部署3台服务器构成一个集群。当然这些例子的计算都是简化的,事实上,计算一个服务的集群规模,需要同时考虑其对可用性、性能的影响及关联服务集群的影响。

具体来说,集群伸缩性又可分为应用服务器集群伸缩性和数据服务器集群伸缩性。这两种集群由于对数据状态管理的不同,技术实现也有非常大的区别。而数据服务器集群也可分为缓存数据服务器集群和存储数据服务器集群,这两种集群的伸缩性设计也不大相同。

应用服务器集群的伸缩性设计

应用服务器应该设计成无状态的,即应用服务器不存储请求上下文信息,如果将部署有相同应用的服务器组成一个集群,每次用户请求都可以发送到集群中任意一台服务器上去处理,任何一台服务器的处理结果都是相同的。这样只要能将用户请求按照某种规则分发到集群的不同服务器上,就可以构成一个应用服务器集群,每个用户的每个请求都可能落在不同的服务器上。如图所示。

如果 HTTP请求分发装置可以感知或者可以配置集群的服务器数量,可以及时发现集群中新上线或下线的服务器,开能问新上线的服分备刀反明小,厅Lu/ HIN器分发请求,那么就实现了应用服务器集群的伸缩性。

这里,这个HTTP请求分发装置被称作负载均衡服务器。负载均衡是网站必不可少的基础技术手段,不但可以实现网站的伸缩性,同时还改善网站的可用性,可谓网站的杀手锏之一。具体的技术实现也多种多样,从硬件实现到软件实现,从商业产品到开源软件,应有尽有,但是实现负载均衡的基础技术不外以下几种。

HTTP重定向负载均衡

HTTP重定向服务器是一台普通的应用服务器,其唯一的功能就是根据用户的HTTP请求计算一台真实的Web服务器地址,并将该Web服务器地址写入HTTP重定向响应中(响应状态码302)返回给用户浏览器。在图中,浏览器请求访问域名www.mysite.com,DNS服务器解析得到IP地址是114.100.80.10,即 HTTP重定向服务器的P地址。然后浏览器通过IP地址114.100.80.10访问HTTP重定向负载均衡服务器后,服务器根据某种负载均衡算法计算获得一台实际物理服务器的地址( 114.100.80.3 ),构造一个包含该实际物理服务器地址的重定向响应返回给浏览器,浏览器自动重新请求实际物理服务器的IP地址114.100.80.3,完成访问。这种负载均衡方案的优点是比较简单。缺点是浏览器需要两次请求服务器才能完成一次访问,性能较差;重定向服务器自身的处理能力有可能成为瓶颈,整个集群的伸缩性规模有限;使用HTTP302响应码重定向,有可能使搜索引擎判断为SEO作弊,降低搜索排名。因此实践中使用这种方案进行负载均衡的案例并不多见。

DNS域名解析负载均衡

在DNS 服务器中配置多个A 记录,如: www.mysite.com IN A 114.100.80.1 、www.mysite.com INA 114.100.80.2、www.mysite.com IN A 114.100.80.3。每次域名解析请求都会根据负载均衡算法计算一个不同的IP地址返回,这样A记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。图6.6中的浏览器请求解析域名www.mysite.com,DNS 根据A记录和负载均衡算法计算得到一个IP地址114.100.80.3,并返回给浏览器;浏览器根据该IP地址,访问真实物理服务器114.100.80.3。

DNS域名解析负载均衡的优点是将负载均衡的工作转交给DNS,省掉了网站管理维护负载均衡服务器的麻烦,同时许多DNS还支持基于地理位置的域名解析,即会将域名解析成距离用户地理最近的一个服务器地址,这样可加快用户访问速度,改善性能。但是DNS域名解析负载均衡也有缺点,就是目前的 DNS是多级解析,每一级DNS都可能缓存A记录,当下线某台服务器后,即使修改了DNS的A记录,要使其生效也需要较长时间,这段时间,DNS依然会将域名解析到已经下线的服务器,导致用户访问失败;而且DNS负载均衡的控制权在域名服务商那里,网站无法对其做更多改善和更强大的管理。

事实上,大型网站总是部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,即域名解析得到的一组服务器并不是实际提供 Web服务的物理服务器,而是同样提供负载均衡服务的内部服务器,这组内部负载均衡服务器再进行负载均衡,将请求分发到真实的Web服务器上。

反向代理负载均衡

前面我们提到利用反向代理缓存资源,以改善网站性能。实际上,在部署位置上,反向代理服务器处于Web服务器前面(这样才可能缓存Web响应,加速访问),这个位置也正好是负载均衡服务器的位置,所以大多数反向代理服务器同时提供负载均衡的功能,管理一组Web服务器,将请求根据负载均衡算法转发到不同Web服务器上。Web服务器处理完成的响应也需要通过反向代理服务器返回给用户。田于 web 服方备个且女N外提供访问,因此 Web服务器不需要使用外部IP地址,而反向代理服务器则需要配置双网卡和内部外部两套IP地址。

浏览器访问请求的地址是反向代理服务器的地址114.100.80.10,反向代理服务器收到请求后,根据负载均衡算法计算得到一台真实物理服务器的地址10.0.0.3,并将请求转发给服务器。10.0.0.3处理完请求后将响应返回给反向代理服务器,反向代理服务器再将该响应返回给用户。

由于反向代理服务器转发请求在HTTP协议层面,因此也叫应用层负载均衡。其优点是和反向代理服务器功能集成在一起,部署简单。缺点是反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈。

IP负载均衡

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

这里的关键在于真实物理Web服务器响应数据包如何返回给负载均衡服务器。一种方案是负载均衡服务器在修改目的IP地址的同时修改源地址,将数据包源地址设为自身IP,即源地址转换(SNAT ),这样 Web服务器的响应会再回到负载均衡服务器;另一种方案是将负载均衡服务器同时作为真实物理服务器集群的网关服务器,这样所有响应数据都会到达负载均衡服务器。

IP负载均衡在内核进程完成数据分发,较反向代理负载均衡(在应用程序中分发数据)有更好的处理性能。但是由于所有请求响应都需要经过负载均衡服务器,集群的最大响应数据吞吐量不得不受制于负载均衡服务器网卡带宽。对于提供下载服务或者视频服务等需要传输大量数据的网站而言,难以满足需求。能不能让负载均衡服务器只分发请求,而使响应数据从真实物理服务器直接返回给用户呢?

数据链路层负载均衡

顾名思义,数据链路层负载均衡是指在通信协议的数据链路层修改mac地址进行负载均衡,如图所示。

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

在图6.9中,用户请求到达负载均衡服务器114.100.80.10后,负载均衡服务器将请求数据的目的mac地址修改为00:0c:29:d2,并不修改数目包目标P地址,由于Web服务器集群所有服务器的虚拟IP地址都和负载均服务器的I地址相同,因此数据可以正常传输到达 mac地址00:0c:29:d2对应的服务器,该服务器处理完成后发送响应数据到网站的网关服务器,网关服务器直接将该数据包发送到用户浏览器(通过互联网),响应数据不需要通过负载均衡服务器。使用三角传输模式的链路层负载均衡是目前大型网站使用最广的一种负载均衡手段。在Linux平台上最好的链路层负载均衡开源产品是LVS ( Linux Virtual Server )。

负载均衡算法

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

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

2.将请求数据发送到该地址对应的Web服务器上。

前面描述了如何将请求数据发送到Web 服务器,而具体的负载均衡算法通常有以下几种。

轮询(Round Robin,RR):所有请求被依次分发到每台应用服务器上,即每台服务器需要处理的请求数目都相同,适合于所有服务器硬件都相同的场景。

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

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

最少连接(Least Connections):记录每个应用服务器正在处理的连接数(请求数),将新到的请求分发到最少连接的服务器上,应该说,这是最符合负载均衡定义的算法。同样,最少连接算法也可以实现加权最少连接。

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

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

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

假设NODE1的 Hash 值为 3,594,963,423,NODE2的 Hash值为1,845,328,979,而KEYO的Hash值为2,534,256,785,那么KEYO在环上顺时针查找,找到的最近的节点就是NODE1。

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

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

图6.12中,加入新节点NODE3后,原来的KEY大部分还能继续计算到原来的节点,只有KEY3、KEYO从原来的NODE1重新计算到NODE3。这样就能保证大部分被缓存的数据还可以继续命中。3台服务器扩容至4台服务器,可以继续命中原有缓存数据的概率是75%,远高于余数Hash的25%,而且随着集群规模越大,继续命中原有缓存数据的概率也逐渐增大,100台服务器扩容增加1台服务器,继续命中的概率是99%。虽然仍有小部分数据缓存在服务器中不能被读到,但是这个比例足够小,通过访问数据库获取也不会对数据库造成致命的负载压力。具体应用中,这个长度为23的一致性Hash环通常使用二叉查找树实现,Hash查找过程实际上是在二叉查找树中查找不小于查找数的最小数值。当然这个二叉树的最右边叶子节点和最左边的叶子节点相连接,构成环。

但是,上面描述的算法过程还存在一个小小的问题。

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

解决方案:计算机领域有句话:计算机的任何问题都可以通过增加一个虚拟层来解决。计算机硬件、计算机网络、计算机软件都莫不如此。计算机网络的﹖层协议,每一层都可以看作是下一层的虚拟层;计算机操作系统可以看作是计算机硬件的虚拟层;Java虚拟机可以看作是操作系统的虚拟层;分层的计算机软件架构事实上也是利用虚拟层的概念。

解决上述一致性Hash算法带来的负载不均衡问题,也可以通过使用虚拟层的手段:将每台物理缓存服务器虚拟为一组虚拟缓存服务器,将虚拟服务器的Hash值放置在Hash环上,KEY 在环上先找到虚拟服务器节点,再得到物理服务器的信息。

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

新加入节点 NODE3对应的一组虚拟节点为V30,V31,V32,加入到一致性Hash环上后,影响V01,V12,V22三个虚拟节点,而这三个虚拟节点分别对应NODE0,NODE1,NODE2三个物理节点。最终Memcached集群中加入一个节点,但是同时影响到集群中已存在的三个物理节点,在理想情况下,每个物理节点受影响的数据量(还在缓存中,但是不能被访问到数据)为其节点缓存数据量的1/4(X)(N+X),N为原有物理节点数,X为新加入物理节点数),也就是集群中已经被缓存的数据有75%可以被继续命中,和未使用虚拟节点的一致性Hash算法结果相同。

显然每个物理节点对应的虚拟节点越多,各个物理节点之间的负载越均衡,新加入物理服务器对原有的物理服务器的影响越保持一致(这就是一致性 Hash这个名称的由来)。那么在实践中,一台物理服务器虚拟为多少个虚拟服务器节点合适呢?太多会影响性能,太少又会导致负载不均衡,一般说来,经验值是150,当然根据集群规模和负载均衡的精度需求,这个值应该根据具体情况具体对待。

数据存储服务器集群的伸缩性设计

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

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

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

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

关系数据库凭借其简单强大的 SQL和众多成熟的商业数据库产品,占据了从企业应用到网站系统的大部分业务数据存储服务。市场上主要的关系数据都支持数据复制功能,使用这个功能可以对数据库进行简单伸缩。图为使用数据复制的 MySQL集群伸缩性方案。

在这种架构中,虽然多台服务器部署MySQL实例,但是它们的角色有主从之分,数据写操作都在主服务器上,由主服务器将数据同步到集群中其他从服务器,数据读操作及数据分析等离线操作在从服务器上进行。除了数据库主从读写分离,前面提到的业务分割模式也可以用在数据库,不同业务数据表部署在不同的数据库集群上,即俗称的数据分库。这种方式的制约条件是跨库的表不能进行Join操作。

在大型网站的实际应用中,即使进行了分库和主从复制,对一些单表数据仍然很大的表,比如Facebook 的用户数据库,淘宝的商品数据库,还需要进行分片,将一张表拆开分别存储在多个数据库中。

目前网站在线业务应用中比较成熟的支持数据分片的分布式关系数据库产品主要有开源的Amoeba ( http:lsourceforge.net/projects/amoeba/)和Cobar ( http:I/code.alibabatech.com/wiki/display/cobar/Home )。这两个产品有相似的架构设计,以Cobar为例,部署模型如图6.15所示。

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

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

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

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

Cobar的伸缩有两种:Cobar服务器集群的伸缩和MySQL服务器集群的伸缩。Cobar服务器可以看作是无状态的应用服务器,因此其集群伸缩可以简单使用负载均衡的手段实现。而 MySQL 中存储着数据,要想保证集群扩容后数据一致负载均衡,必须要做数据迁移,将集群中原来机器中的数据迁移到新添加的机器中,如图6.17所示。

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

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

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

在整个分布式关系数据库的访问请求过程中,Cobar服务器处理消耗的时间是很少的,时间花费主要还是在 MySQL 数据库端,因此应用程序通过Cobar访问分布式关系数据库,性能基本和直接访问关系数据库相当,可以满足网站在线业务的实时处理需求。事实上由于Cobar代替应用程序连接数据库,数据库只需要维护更少的连接,减少不必要的资源消耗,改善性能。但由于Cobar路由后只能在单一数据库实例上处理查询请求,因此无法执行跨库的JOIN操作,当然更不能执行跨库的事务处理。

相比关系数据库本身功能上的优雅强大,目前各类分布式关系数据库解决方案都显得非常简陋,限制了关系数据库某些功能的使用。但是当网站业务面临不停增长的海量业务数据存储压力时,又不得不利用分布式关系数据库的集群伸缩能力,这时就必须从业务上回避分布式关系数据库的各种缺点:避免事务或利用事务补偿机制代替数据库事务;分解数据访问逻辑避免JOIN操作等。

除了上面提到的分布式数据库,还有一类分布式数据库可以支持JOIN操作执行复杂的SQL查询,如 GreenPlum。但是这类数据库的访问延迟比较大(可以想象,JOIN操作需要在服务器间传输大量的数据),因此一般使用在数据仓库等非实时业务中。

NoSQL数据库的伸缩性设计

在计算机数据存储领域,一直是关系数据库(Relation Database)的天下,以至传统企业应用领域,许多应用系统设计都是面向数据库设计——先设计数据库然后设计程序,从而导致关系模型绑架对象模型,并由此引申出旷日持久的业务对象贫血模型与充血模型之争。业界为了解决关系数据库的不足,提出了诸多方案,比较有名的是对象数据库,但是这些数据库的出现只是进一步证明关系数据库的优越而已。直到大型网站遇到了关系数据库难以克服的缺陷―-—糟糕的海量数据处理能力及僵硬的设计约束,局面才有所改善。为了解决上述问题,NoSQL这一概念被提了出来,以弥补关系数据库的不足。

NoSQL,主要指非关系的、分布式的数据库设计模式。也有许多专家将NoSQL解读为Not Only SQL,表示NoSQL只是关系数据库的补充,而不是替代方案。一般而言,NoSQL数据库产品都放弃了关系数据库的两大重要基础:以关系代数为基础的结构化查询语言( SQL)和事务一致性保证(ACID)。而强化其他一些大型网站更关注的特性:高可用性和可伸缩性。开源社区有各种NoSQL产品,其支持的数据结构和伸缩特性也各不相同,目前看来,应用最广泛的是Apache HBase。

HBase为可伸缩海量数据储存而设计,实现面向在线业务的实时数据访问延迟。HBase的伸缩性主要依赖其可分裂的 HRegion及可伸缩的分布式文件系统HDFS实现。HBase的整体架构如图6.19所示。HBase 中,数据以HRegion为单位进行管理,也就是说应用程序如果想要访问一个数据,必须先找到HRegion,然后将数据读写操作提交给HRegion,由 HRegion完成存储层面的数据操作。每个HRegion 中存储一段Key值区间[key1,key2)的数据,HRegionServer是物理服务器,每个 HRegionServer 上可以启动多个HRegion 实例。当一个 HRegion中写入的数据太多,达到配置的阈值时,HRegion会分裂成两个HRegion,并将HRegion在整个集群中进行迁移,以使HregionServer的负载均衡。

所有HRegion的信息(存储的Key值区间、所在 HRegionServer地址、访问端口号等)都记录在 HMaser 服务器上,为了保证高可用,HBase启动多个HMaser,并通过Zookeeper(一个支持分布式一致性的数据管理服务)选举出一个主服务器,应用程序通过Zookeeper获得主HMaser的地址,输入Key值获得这个Key所在的HRegionServer地址,然后请求HRegionServer上的 HRegion,获得需要的数据。调用时序如图6.20所示。

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

小结

伸缩性架构设计能力是网站架构师必须具备的能力。伸缩性架构设计是简单的,因为几乎所有稍有规模的网站都必须是可伸缩的,有很多案例可供借鉴,同时又有大量商业的、开源的提供伸缩性能力的软硬件产品可供选用。然而伸缩性设计又是复杂的,没有通用的、完美的解决方案和产品,网站伸缩性往往和可用性、正确性、性能等耦合在一起,改善伸缩性可能会影响一些网站的其他特性,网站架构师必须对网站的商业目标、历史演化、技术路线了然于胸,甚至还需要综合考虑技术团队的知识储备和结构、管理层的战略愿景和规划,才能最终做出对网站伸缩性架构最合适的决策。

一个具有良好伸缩性架构设计的网站,其设计总是走在业务发展的前面,在业务需要处理更多访问和服务之前,就已经做好充足准备,当业务需要时,只需要购买或者租用服务器简单部署实施就可以了,技术团队亦可高枕无忧。反之,设计和技术走在业务的后面,采购来的机器根本就没办法加入集群,勉强加了进去,却发现瓶颈不在这里,系统整体处理能力依然上不去。技术团队每天加班,却总是拖公司发展的后腿。架构师对网站伸缩性的把握,一线之间,天堂和地狱。

系统架构设计——伸缩性架构相关推荐

  1. 架构设计本质-架构思维

    前言: 本篇文章结合多数人在工作中的模块开发,架构设计情况,以及相关权威性文章和书籍,总结下如何在开发过程中,慢慢养成架构思维,共设计以下几个方面: 正文: 简单介绍下架构设计: 软件架构是一个系统的 ...

  2. 架构设计(5)—架构愿景分析

    架构设计学习思维导图: 架构设计系列主要的ADM(架构开发方法)主要基于TOGAF9或者TOGAF9.1来论述.这是个人学习实践和总结笔记,专注并不断积累和更新,努力精进自己.个人拙见,仅供参考. 1 ...

  3. 浅谈系统架构设计-从架构设计原理、架构设计原则、架构设计方法展开

    我们工作中一直强调要做架构设计.系分,最近前端同学在追求前端质量提升的时候,也在进行架构设计.前端系分的推广,那到底什么是架构设计和系分?该怎么做架构设计和系分?本文尝试对架构设计进行全面的介绍和分享 ...

  4. 架构设计:架构设计要平衡兼顾多方需求

    "架构设计要平衡兼顾多方需求" 系统建模 定义接口 划分功能模块 套用模式 优化性能 系统的安全性 易用性(usability) 产品支持 发布管理 部署方式 解决以上问题的技术问 ...

  5. 讲师秀之7:林仕鼎谈架构设计与架构师

    [CSDN综合]林仕鼎自称是个"喜欢厘清概念的人",在他的博客.CSDN举行的TUP活动中以及QCon中一次一次进行了剖析. 林仕鼎在博客中写道,系统架构是一个工程和研究相结合的领 ...

  6. 林仕鼎:架构设计与架构师

    发表于13小时前|340次阅读| 来源CSDN|0 条评论| 作者包研 架构师林仕鼎百度云计算大会第五届云计算大会讲师秀 摘要:他自称"西二旗跨界架构师",又戴上了百度基础体系首席 ...

  7. 林仕鼎谈架构设计与架构师

    摘要:他自称"西二旗跨界架构师",官方身份是百度大数据首席架构师,他喜欢在微博和博客上讨论技术.诗歌和社会热点,他就是林仕鼎.他不断地对架构师这份工作做着总结. [CSDN综合]林 ...

  8. Java性能优化:架构设计-分布式架构设计

    分布式架构设计 一.前言 随着微服务的流行,"分布式架构"作为高频词时常出现在开发者面前,我们是否理解分布式架构?它和微服务有什么区别呢?这一小节我们将讲解微服务和分布式架构那些事 ...

  9. 电商平台-系统报表设计与架构

    说明:任何一个运行的平台都需要一个很清楚的报表来显示,那么作为Java开源生鲜电商平台而言,我们应该如何设计报表呢?或者说我们希望报表来看到什么数据呢?           通过报表我们可以分析出目前 ...

最新文章

  1. 年后准备跳槽可以看看
  2. 操作系统内核(linux)
  3. 多操作系统安装实践小结
  4. dataguard如何实现切换_深度干货 | 如何借助云原生搞定Oracle备份快速恢复?
  5. 攻城掠地端mysql_【图片】攻城掠地单机版本服务端+攻城掠地GM工具【单兆权吧】_百度贴吧...
  6. LeetCode 350. 两个数组的交集 II(哈希)
  7. BTREE与其它索引的优缺点对比
  8. micropython做产品开发_关于MicroPython是否可以真正用在产品开发的讨论
  9. 如果打开MSSQL server 显示无项目的解决方法
  10. 结对编程后传之做汉堡
  11. 15.分布式文档系统-document id的手动指定与自动生成两种方式解析
  12. javascript中引号嵌套
  13. http://visualgo.net/ 数据结构可视化。。。。
  14. 扩展NameValueCollection
  15. C#可视化编程技术总结:制作可视化窗体软件
  16. 求基于图像处理的身份证号码识别的程序
  17. 【转载】CodeWarrior IDE使用tips之prm链接文件详解(自定义存储器分区以及自定义RAM数据初始化与在RAM中运行函数)...
  18. C++:实现量化ODE模型测试实例
  19. 语义分割系列14-DMNet(pytorch)实现
  20. CNN是如何进行图像特征提取的

热门文章

  1. Excel合并单元格如何分组排序?
  2. 离散度计算公式 python_Python分析离散心率信号(中)
  3. AFNetworking为什会请求不到数据
  4. 查看服务器配置以及常用命令
  5. Python开发【第二章】python入门
  6. 浅谈智慧医疗中常见的几种数据标注类型
  7. 浅谈深度学习:LSTM对股票的收益进行预测(Sequential 序贯模型,Keras实现)
  8. 谷歌浏览器87版本 iframe_谷歌Chrome的“混合内容”更新将会影响电商网站,自建站卖家如何应对?...
  9. TLS握手协议分析与理解——某HTTPS请求流量包分析
  10. 基于Cesium的火箭发射演示