共计 5419 个字符,预计需要花费 14 分钟才能阅读完成。
所谓零碎的伸缩性是指不须要扭转零碎的软硬件设计,仅仅通过扭转部署的服务器数量就能够扩充或者放大零碎的服务解决能力。
根底设计
在利用零碎渐进式的演化过程中,最重要的技术手段就是应用服务器集群,通过一直地向集群中增加服务器来加强整个集群的解决能力。
一般说来,零碎的伸缩性设计可分成两类,一类是依据性能进行物理拆散实现伸缩,一类是繁多性能通过集群实现伸缩。前者是不同的服务器部署不同的服务,提供不同的性能;后者是集群内的多台服务器部署雷同的服务,提供雷同的性能。
在利用零碎倒退的晚期,通过减少服务器进步解决能力时,新增服务器总是从现有服务器中拆散出局部性能和服务。具体又能够分成纵向拆散和横向拆散两种状况,纵向拆散也即业务分层,横向拆散则是业务拆分。
将不同性能拆散部署能够实现肯定水平的伸缩性,然而随着访问量的逐渐减少,即便拆散到最小粒度,繁多的服务器也不能满足业务规模的要求。因而必须应用服务器集群,行将雷同服务部署在多台服务器上形成一个集群整体对外提供服务。
应用层设计
应用服务器应该设计成无状态的,如果将部署有雷同利用的服务器组成一个集群,每次用户申请都能够发送到集群中任意一台服务器下来解决。这样只有能将用户申请依照某种规定散发到集群的不同服务器上,就能够形成一个应用服务器集群。
这个申请散发安装就是所谓的负载均衡器。负载平衡是网站必不可少的根底技术手段,岂但能够改善网站的可用性,同时还能够实现网站的伸缩性。具体的技术实现也多种多样,根底技术不外以下几种。
HTTP 重定向
HTTP 重定向服务器是一台一般的应用服务器,其惟一的性能就是 依据用户的 HTTP 申请计算一台实在的 Web 服务器地址,并将该 Web 服务器地址写入 HTTP 重定向响应中(响应状态码 302)返回给用户浏览器。
这种负载平衡计划的长处是比较简单。毛病是浏览器须要两次申请服务器能力实现一次拜访,性能较差;重定向服务器本身的解决能力有可能成为瓶颈,整个集群的伸缩性规模无限;应用 302 响应码重定向,有可能使搜索引擎判断为 SEO 舞弊,升高搜寻排名。因而这种计划很少见。
DNS 解析
咱们能够在 DNS 服务器中为利用网址注册多条 A 记录,这样的话,每次域名解析申请都会依据负载平衡算法计算一个不同的 IP 地址返回,A 记录中配置的多个服务器就形成一个集群,实现了负载平衡。
DNS 域名解析负载平衡的长处是将负载平衡的工作转交给 DNS,省掉了网站治理保护负载平衡服务器的麻烦,同时许多 DNS 还反对基于地理位置的域名解析,即会将域名解析成间隔用户天文最近的一个服务器地址,这样可放慢用户访问速度。
然而 DNS 域名解析负载平衡也有毛病,DNS 是多级解析,每一级 DNS 都可能缓存 A 记录,当下线某台服务器后,即便批改了 DNS 的 A 记录,要使其失效也须要较长时间,这段时间,DNS 仍然会将域名解析到曾经下线的服务器,导致用户拜访失败;而且 DNS 负载平衡的控制权在域名服务商那里,网站无奈对其做更多改善和更弱小的治理。
大型网站总是局部应用 DNS 域名解析,利用域名解析作为第一级负载平衡伎俩。域名解析失去的一组服务器并不是理论提供 Web 服务的物理服务器,而是同样提供负载平衡服务的外部服务器,这组外部负载平衡服务器再进行负载平衡,将申请散发到实在的 Web 服务器上。
反向代理
之前咱们提到能够利用反向代理缓存资源,以改善网站性能。同时大多数反向代理服务器还提供负载平衡的性能,治理一组 Web 服务器,将申请依据负载平衡算法转发到不同 Web 服务器上,Web 服务器解决实现的响应也须要通过反向代理服务器返回给用户。
因为反向代理服务器转发申请在 HTTP 协定层面,因而也叫应用层负载平衡。其长处是和反向代理服务器性能集成在一起,部署简略。毛病是反向代理服务器是所有申请和响应的中转站,其性能可能会成为瓶颈。
IP 负载平衡
在网络层,能够通过批改申请指标地址进行负载平衡。用户申请数据包达到负载平衡服务器后,负载平衡服务器依据负载平衡算法计算失去一台实在 Web 服务器地址,而后将数据包的目标 IP 地址批改为该地址。实在 Web 应用服务器解决实现后,响应数据包回到负载平衡服务器,负载平衡服务器再将数据包源地址批改为本身的 IP 地址发送给用户浏览器。
这里的关键在于实在物理 Web 服务器响应数据包如何返回给负载平衡服务器。一种计划是负载平衡服务器在批改目标 IP 地址的同时批改源地址,将数据包源地址设为本身 IP,即源地址转换(SNAT),这样 Web 服务器的响应会再回到负载平衡服务器;另一种计划是将负载平衡服务器同时作为实在物理服务器集群的网关服务器,这样所有响应数据都会达到负载平衡服务器。
IP 负载平衡在内核过程实现数据散发,较反向代理负载平衡(在应用程序中散发数据)有更好的解决性能。然而因为所有申请响应都须要通过负载平衡服务器,集群的最大响应数据吞吐量不得不受制于负载平衡服务器网卡带宽。
那么,能不能让负载平衡服务器只散发申请,而使响应数据从实在物理服务器间接返回给用户呢?
数据链路层负载平衡
顾名思义,数据链路层负载平衡是指在通信协议的数据链路层批改 mac 地址进行负载平衡。负载平衡数据散发过程中不批改 IP 地址,只批改目标 mac 地址,通过配置实在物理服务器集群所有机器虚构 IP 和负载平衡服务器 IP 地址统一,从而达到不批改数据包的源 IP 地址和目标 IP 地址就能够进行数据散发的目标。
因为理论解决申请的实在物理服务器 IP 和数据申请目标 IP 统一,不须要通过负载平衡服务器进行地址转换,可将响应数据包间接返回给用户浏览器,防止负载平衡服务器网卡带宽成为瓶颈。这种负载平衡形式又称作间接路由形式(DR)。
如图所示,用户申请达到负载平衡服务器 114.100.80.10 后,负载平衡服务器将申请数据的目标 mac 地址批改为 00:0c:29:d2,因为 Web 服务器集群所有服务器的虚构 IP 地址都和负载均服务器的 IP 地址雷同,因而数据能够失常传输达到 mac 地址 00:0c:29:d2 对应的服务器,该服务器解决实现后发送响应数据到网站的网关服务器,网关服务器间接将该数据包发送到用户浏览器,响应数据不须要通过负载平衡服务器。
数据链路层负载平衡是目前应用较广的一种负载平衡伎俩。在 Linux 平台上最好的链路层负载平衡开源产品是 LVS(Linux Virtual Server)。
负载平衡算法
后面形容了如何将申请数据发送到 Web 服务器,而具体的负载平衡算法通常有以下几种:
- 轮询(Round Robin,RR):所有申请被顺次散发到每台应用服务器上,适宜于所有服务器硬件都雷同的场景。
- 加权轮询(Weighted Round Robin,WRR):依据应用服务器硬件性能的状况,在轮询的根底上,依照配置的权重将申请散发到每个服务器。
- 随机(Random):申请被随机调配到各个应用服务器,在许多场合下,这种计划都很简略实用。即便应用服务器硬件配置不同,也能够应用加权随机算法。
- 起码连贯(Least Connections):记录每个应用服务器正在解决的连接数(申请数),将新到的申请散发到起码连贯的服务器上。同样,也能够实现加权起码连贯。
- 源地址散列(Source Hashing):依据申请起源的 IP 地址进行 Hash 计算,失去应用服务器,这样来自同一个 IP 地址的申请总在同一个服务器上解决。
缓存设计
和所有服务器都部署雷同利用的应用服务器集群不同,分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存拜访申请不能够在缓存服务器集群中的任意一台解决,必须先找到缓存有须要数据的服务器,而后能力拜访。这个特点会重大制约分布式缓存集群的伸缩性设计,因为新上线的缓存服务器没有缓存任何数据,而已下线的缓存服务器还缓存着网站的许多热点数据。
必须让新上线的缓存服务器对整个分布式缓存集群影响最小,也就是说新退出缓存服务器后应使整个缓存服务器集群中曾经缓存的数据尽可能还被拜访到,这是分布式缓存集群伸缩性设计的最次要指标。
路由算法
在分布式缓存服务器集群中,对于服务器集群的治理,路由算法至关重要,和负载平衡算法一样,决定着到底该拜访集群中的哪台服务器。
余数 Hash 算法
余数 Hash 是最简略的一种路由算法:用服务器数目除以缓存数据 KEY 的 Hash 值,余数为服务器列表下标编号。因为 HashCode 具备随机性,因而应用余数 Hash 路由算法可保障缓存数据在整个服务器集群中比拟平衡地散布。
对余数 Hash 路由算法稍加改良,就能够实现和负载平衡算法中加权负载平衡一样的加权路由。事实上,如果不须要思考缓存服务器集群伸缩性,余数 Hash 简直能够满足绝大多数的缓存路由需要。
然而,当分布式缓存集群须要扩容的时候,会呈现重大的问题。很容易就能够计算出,如果由 3 台服务器扩容至 4 台服务器,大概有 75%(3/4)被缓存了的数据不能正确命中,随着服务器集群规模的增大,这个比例线性回升。当 100 台服务器的集群中退出一台新服务器,不能命中的概率是 99%(N/(N+1))。
一种解决办法是在网站访问量起码的时候扩容缓存服务器集群,这时候对数据库的负载冲击最小。而后通过模仿申请的办法逐步预热缓存,使缓存服务器中的数据从新散布。然而这种计划对业务场景有要求,还须要抉择特定的时段,要求较为严苛。
一致性 Hash 算法
一致性 Hash 算法通过一个叫作一致性 Hash 环的数据结构实现 KEY 到缓存服务器的 Hash 映射,如图所示。
具体算法过程为:先结构一个长度为 0~2³²的整数环(这个环被称作一致性 Hash 环),依据节点名称的 Hash 值(其散布范畴同样为 0~2³²)将缓存服务器节点搁置在这个 Hash 环上。而后依据须要缓存的数据的 KEY 值计算失去其 Hash 值(其散布范畴也同样为 0~2³²),而后在 Hash 环上顺时针查找间隔这个 KEY 的 Hash 值最近的缓存服务器节点,实现 KEY 到服务器的 Hash 映射查找。
当缓存服务器集群须要扩容的时候,只须要将新退出的节点名称(NODE3)的 Hash 值放入一致性 Hash 环中,因为 KEY 是顺时针查找间隔其最近的节点,因而新退出的节点只影响整个环中的一小段,如图 6 中深色一段。
退出新节点 NODE3 后,原来的 KEY 大部分还能持续计算到原来的节点,只有 KEY3、KEY0 从原来的 NODE1 从新计算到 NODE3。这样就能保障大部分被缓存的数据还能够持续命中。
具体利用中,这个长度为 2³²的一致性 Hash 环通常应用二叉查找树实现,Hash 查找过程实际上是在二叉查找树中查找不小于查找数的最小数值。当然这个二叉树的最左边叶子节点和最右边的叶子节点相连接,形成环。
然而,上述算法还存在一个小小的问题。假如本来 3 台服务器的负载大抵相等,新退出的节点 NODE3 只分担了节点 NODE1 的局部负载,这就意味着 NODE0 和 NODE2 缓存数据量和负载压力比 NODE1 与 NODE3 的大,从概率上来说大概是 2 倍。这种后果显然不是咱们想要的。
解决办法也很简略,计算机的任何问题都能够通过减少一个虚构层来解决。解决上述一致性 Hash 算法带来的负载不平衡问题,也能够通过应用虚构层的伎俩:将每台物理缓存服务器虚构为一组虚构缓存服务器,将虚构服务器的 Hash 值搁置在 Hash 环上,KEY 在环上先找到虚构服务器节点,再失去物理服务器的信息。
这样新退出物理服务器节点时,是将一组虚构节点退出环中,如果虚构节点的数目足够多,这组虚构节点将会影响同样少数目标曾经在环上存在的虚构节点,这些曾经存在的虚构节点又对应不同的物理节点。最终的后果是:新退出一台缓存服务器,将会较为平均地影响原来集群中曾经存在的所有服务器。如图所示。
显然每个物理节点对应的虚构节点越多,各个物理节点之间的负载越平衡,新退出物理服务器对原有的物理服务器的影响越保持一致,然而太多又会影响性能。那么在实践中,一台物理服务器虚构为多少个虚构服务器节点适合呢?一般说来,经验值是 150,当然依据集群规模和负载平衡的精度需要,这个值应该依据具体情况具体看待。
数据存储层设计
数据存储服务器集群的伸缩性对数据的持久性和可用性提出了更高的要求,因为数据存储服务器在任何状况下都必须保证数据的可用性和正确性。
关系数据库集群的伸缩性设计
目前,市面上次要的关系数据都反对数据复制性能,应用这个性能能够对数据库进行简略伸缩。下图为应用数据复制的 MySQL 集群伸缩性计划。
在这种架构中,多台 MySQL 实例有主从之分,数据写操作都在主服务器上,由主服务器将数据同步到集群中其余从服务器,数据读操作及数据分析等离线操作在从服务器上进行。
除了数据库主从读写拆散,后面提到的业务宰割模式也能够用在数据库,不同业务数据表部署在不同的数据库集群上,即俗称的数据分库。
在大型零碎中,即便进行了分库和主从复制,对一些单表数据依然很大的表,还须要进行分片,将一张表拆开别离存储在多个数据库中。目前市场上罕用的分库分表的中间件是 Mycat。
相比关系数据库自身性能的弱小,目前各类分库分表中间件的性能都显得十分简陋,限度了关系数据库某些性能的应用。然而当网站业务面临不停增长的海量业务数据存储压力时,又不得不利用分布式关系数据库的集群伸缩能力,这时就必须从业务上回避分布式关系数据库的各种毛病:防止事务或利用事务弥补机制代替数据库事务;合成数据拜访逻辑防止 JOIN 操作等。
延长浏览:
【分布式—要点】数据复制
【分布式—要点】数据分区