伸缩性是指仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力。

在发展为大型网站的渐进式的演化过程中,最重要的手段就是使用服务器集群,这就是网站系统的伸缩性架构。

网站架构的伸缩性设计

  • 根据功能进行物理分离实现伸缩,不同服务器部署不同服务
  • 单一功能通过集群实现伸缩,集群多台服务器部署相同的任务

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

新增服务器从现有服务器中分离出功能和服务

  • 纵向分离:将业务处理流程上的不同部分分离部署
  • 横向分离:将不同业务模块分离部署

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

相同服务部署在多台服务器上构成一个集群整体对外进行服务

当一头牛拉不动车的时候,不要去寻找一头更强壮的牛,而是用两头牛来拉车

集群伸缩性可以分为:

  • 应用服务器集群伸缩性
  • 数据服务器集群的伸缩性
    • 缓存数据服务器集群
    • 存储数据服务器集群

不同原因是因为对数据状态管理的不同

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

HTTP请求分发装置来感知或者配置集群的服务器数量,可以及时发现集群中新上线或者下线的服务器,就可以实现应用服务器集群的伸缩性。这个HTTP请求分发装置就是负载均衡服务器。

负载均衡,不仅实现网站伸缩性,同时改善了网站可用性。硬件到软件实现都有。

HTTP重定向负载均衡

根据用户HTTP请求计算一台真实的Web服务器地址,将web服务器地址写入HTTP重定向响应302返回给用户浏览器。

DNS域名解析负载均衡

缺点在于下线某台服务器之后,就算改掉DNS的A记录,也需要较长的生效时间。

大型网站会部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,也就是返回的是提供负载均衡服务的内部服务器。

反向代理负载均衡

反向代理服务器需要配置双网卡和内部外部两套IP地址,反向代理服务器转发请求在HTTP协议层面,因此叫做应用层负载均衡。另外使用反向代理缓存资源,改善网站性能。

缺点在于反向代理服务器是所有请求和响应的中转站,性能可能成为瓶颈。

IP负载均衡

在网络层修改请求目标地址进行负载均衡。

在操作系统内核进程获取网络数据包,根据负载均衡算法计算到一台真实web服务器地址,将数据包IP地址修改为该地址。响应的源地址也需要修改。

这里关键是真实web服务器的数据包如何返回负载均衡服务器

  • 负载均衡服务器修改目的IP地址同时修改源地址,将源地址设为自身IP,即源地址转换SNAT
  • 将负载服务器同时做为真实物理服务器集群的网关服务器,这样所有数据都会到达负载均衡服务器。

所以集群的最大数据吞吐量受制于负载均衡服务器网卡带宽。反向代理进行了请求转发,而且是HTTP协议,应用层的。这里是IP,网络层的。

数据链路层负载均衡

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

负载均衡数据分发只修改mac地址,通过配置真实物理服务器集群所有机器虚拟IP和负载均衡服务器IP地址一样,就可以进行分发。所以不需要修改IP地址,真实物理服务器就会自己返回客户端响应。

处理完成后发送响应数据到网站的网关服务器,网关服务器直接将数据发送到用户浏览器,不需要通过负载均衡服务器。

数据链路层负载均衡是使用最广的负载均衡手段,Linux上是LVS(Linux Virtual Server)

负载均衡算法

  • 根据负载均衡算法和web服务器列表得到集群中web服务器地址
  • 将请求数据发送到改地址对应的web服务器上

负载均衡算法:

  • 轮询
  • 加权轮询
  • 随机
  • 加权随机算法
  • 最少连接
  • 加权最少链接
  • 源地址散列:根据请求来源的IP地址进行hash计算,来自同一个IP地址的请求总会在同一个服务器上处理,但是这样不符合高可用要求。

分布式缓存集群的伸缩性设计

分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存访问请求不可以在缓存服务器集群中的任意一台处理,必须先找到缓存有需要数据的服务器,然后才能访问。

分布式缓存集群伸缩性设计主要目标是,让新上线的缓存服务器对整个分布式缓存集群影响最小。

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

应用程序通过Memcached客户端访问Memcached服务器集群,Memcached客户端主要由一组API,Memcached服务器集群路由算法,Memcached服务器集群列表和通信模块组成。

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

伸缩性挑战

hash路由算法,在扩容的时候就有问题。

一种方法是在网站访问量最小的时候扩容缓存服务器集群,这样对数据库负载冲击最小。

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

一致性hash环实现了key到缓存服务器的hash映射

  • 先构造长度为0~2^32的整数环,一致性hash环
  • 根据节点名称的hash值将缓存服务器节点放置在这个hash环上
  • 缓存数据key计算hash值
  • 在hash环上顺时针查找距离离key的hash最近的缓存服务器节点

这样加入新节点,就只会影响整个环中的一小段

长度为2^32的一致性hash环通常用二叉查找树实现,hash查找过程是在二叉查找树中查找不小于查找树的最小数值。

但是目前这种情况会导致,新加入节点之后,各个节点负载不均衡。

计算机的任何问题都可以通过增加一个虚拟层来解决

将每台物理缓存服务器虚拟为一组虚拟缓存服务器,将虚拟服务器的hash值放在hash环上,key在环上先找到虚拟服务器节点,再得到物理服务器的信息。

这样,新加入一台缓存服务器,将会比较均匀的影响原来集群中已经存在的所有服务器。同时集群中每个物理节点受影响的数据为其节点缓存数据量的(x/(N+x)), N为原来物理节点数,x为新加入的物理节点数,与未使用虚拟节点的一致性hash算法结果相同。

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

数据的持久性和可用性,关系数据库集群的伸缩性和NoSQL数据库的伸缩性

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

  • 数据库主从读写分离:主从复制,数据写操作在主服务器上,由主服务器将数据同步到集群中其他从服务器,数据读操作和数据分析等离线操作在从服务器上进行。
  • 数据分库:不同业务数据表部署在不同的数据库集群上
  • 数据分片:将一张表拆开分别存储在多个数据库中,Amoeba,Cobar

Cobar是一个分布式关系数据库访问代理,介于应用服务器和数据库服务器之间,应用程序访问Cobar集群,Cobar服务器根据SQL和分库规则分解SQL,分发到MySQL集群不同数据库实例上执行,MySQL实例为主从结构

Cobar服务器是无状态的,所以可以使用负载均衡手段实现。

MySQL服务器集群伸缩需要做数据迁移,将集群中原来机器的数据迁移到新添加的机器中。

Cobar路由模块可以使用一致性hash算法进行路由,这样可以使得要迁移的数据最少。但是需要遍历数据库并且进行路由计算查看其是否需要迁移。

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

所以虽然关系数据库本身功能比较强大,但是各类分布式关系数据库解决方案都比较简陋。

NoSQL数据库的伸缩性设计

NoSQL,非关系的,分布式的数据库设计模式。放弃了关系代数为基础的结构化查询语言SQL和事务一致性保证ACID,强化了高可用和伸缩性。

HBase伸缩性依赖于可分裂的HRegion和可伸缩的分布式文件系统HDFS的实现。

救世主定律:遇到问题,分析问题,最后总能解决问题

银弹:为具有极端有效性的解决方法,作为杀手锏、最强杀招、王牌等的代称。