缓存与一致性哈希

Posted gouchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缓存与一致性哈希相关的知识,希望对你有一定的参考价值。

 

 

 

1.系统演化

 

 

Step 1.应用程序、数据库、文件等所有资源都在一台服务器上

图1

技术分享图片

 

网站最开始没有太多人访问,只需要一台服务器绰绰有余,如图1,这时应用程序、数据库、文件等所有的资源都在一台服务器上。通常是Linux+Apache+mysql+php架构。

 

Step 2.应用服务和数据服务分离

图2:

技术分享图片

随着网站业务的发展,一台服务器逐渐不能满足需求:越来越多的用户访问导致性能越来越差,越来越多的数据导致存储空间不足。这是就需要将应用和数据分离。应用和数据分离后整个网站使用三台服务器:应用服务器、文件服务器和数据库服务器,如图2所示。 

应用和数据分离后,不同特性的服务器承担不同的服务角色,网站的并发处理能力和数据存储空间得到了很大改善,支持网站的业务进一步发展。但是随着用户逐渐增多,网站又一次面临挑战:数据库压力太大导致访问延迟,进而影响整个网站的性能,用户体验收到影响,需要进一步优化。

 

Step 3.使用缓存改善网站性能

图3:

 

技术分享图片

 

 网站使用缓存分为两种:缓存在应用服务器上的本地缓存和缓存在专门的分布式缓存服务器上的远程缓存。本地缓存的访问速度更快一些,但是受应用服务器内存限制,其缓存数据量有限,而且会出现和应用程序争用内存的情况。远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以在理论上做到不受内存容量限制的缓存服务,如图3所示。 
使用缓存后,数据访问压力得到有效缓解,但是单一应用服务器能够处理的请求连接数有限,在网站访问高峰期,应用服务器成为整个网站的瓶颈。

可以根据业务需要选择使用,或将本地和远程配合分别作为一二级使用。

 

 

Step 4.使用应用服务器集群改善网站的并发处理能力

图4:

技术分享图片

 

使用集群是完整解决高并发、海量数据问题的常用手段。当一台服务器的处理能力,存储空间不足时,通过增加一台服务器分担原有的服务器的访问及存储压力。对网站结构而言,只要能通过增加一台服务器的方式改善负载压力,就可以同样的方式持续增加服务器不断改善系统性能,从而实现系统的可伸缩性。 
通过负载均衡调度服务器,可将来自用户浏览器的访问请求分发到应用服务器的集群中的任何一台服务器上,如果有更多的用户,就在集群中假如更多的应用服务器,使应用服务器的负载压力不再成为整个网站的瓶颈。 

 

 

Step 5.数据库读写分离

 图5:

技术分享图片

 

 

网站在使用缓存后,使绝大部分的数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(缓存访问不命中、缓存过期)和全部的写操作需要访问数据库,在网站的用户达到一定的规模后,数据库因为负载压力过高而成为网站的瓶颈。 
目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库服务器的数据库更新同步到另一台服务器上。网站利用数据库的这一功能实现数据库读写分离,从而改善数据库负载压力,如图5所示。 
应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据更新同步到从数据库,这样当应用服务读数据的时候,就可以通过从数据库获得数据。为了便于应用程序访问读写分离后的数据库,通常在应用服务器端使用专门的数据访问模块,是数据库读写分离对应用透明。 

 

 

Step 6.使用反向代理和CDN加速网站响应 

图6:

 

技术分享图片

 

 

随着网站业务不断发展,用户规模越来越大,由于中国复杂的网络环境,不同地区的用户访问网站时,速度差别也极大。有研究表明,网站访问延迟和用户流失率正相关,网站访问越慢,用户越容易失去耐心而离开。未来提供更好的用户体验,留住用户,网站需要加速网站访问速度。主要手段有使用CDN和反向代理,如图6所示。 
CDN和反向代理的基本原理都是缓存,区别在于CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据;而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户。 
使用CDN和反向代理的目的都是尽早返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的负载压力。 

 

Step 7.使用分布式文件系统和分布式数据库系统 

图7:

 

技术分享图片

任何强大的单一服务器都满足不了大型网站持续增长的业务需求。数据库经过读写分离后,从一台服务器拆分成两台服务器,但是随着网站业务的发展依然不能满足需求,这是需要使用分布式数据库。文件系统也一样,需要使用分布式文件 系统,如图7所示。 
分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同的业务的数据库部署在不同的物力服务器上。

 

Step 8. 使用NoSQL和搜索引擎 

 图8:

技术分享图片

 

 

 随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非关系数据库技术如NoSQL和非数据库查询技术如搜索引擎,如图8所示。 
NoSQL和搜索引擎都是源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器则通过一个统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。 

 

Step 9.业务拆分 

  图 9:

技术分享图片

 大型网站为了应对日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分成不同的产品线,如大型购物交易网站就会将首页、商铺、订单、买家、卖家等拆分成不同的产品线,分归不同的业务团队负责。 
具体到技术上,也会根据产品线划分,将一个网站拆分成许多不同的应用,每个应用独立部署维护。应用之间可以通过超链接建立关系,也可以通过消息队列进行数据分发,当然最多的还是通过访问同一个数据存储系统来构成一个关联的完整系统,如图9所示。

 

Step 10. 分布式服务 

图 10:

技术分享图片

 

随着业务拆分越来越小,存储系统越来越庞大,应用系统的整体复杂度呈指数级增长,部署维护越来越困难。由于所有应用要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致数据库连接资源不足,拒绝服务。 
既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理等,那么可以将这些公用的业务提取出来,独立部署。由这些可复用的业务连接数据库,提供公共业务服务,而应用系统只需要管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作,如图10所示。 
大型网站的架构演化到这里,基本上大多数的技术问题都得以解决,诸如跨数据中心的实时数据同步和具体网站业务相关的问题也都可以通过组合改进现有的技术架构来解决。

 

以上转自:《大型网站技术架构—核心原理与案例分析》 李智慧著 电子工业出版社

 

 

 

2.缓存简介

 技术分享图片

 一图胜千言

 

3.伸缩性

考虑到分布式系统每个节点都有可能失效,并且新的节点很可能动态的增加进来,如何保证当系统的节点数目发生变化时仍然能够对外提供良好的服务,这是值得考虑的,尤其实在设计分布式缓存系统时,如果某台服务器失效,对于整个系统来说如果不采用合适的算法来保证一致性,那么缓存于系统中的所有数据都可能会失效(即由于系统节点数目变少,客户端在请求某一对象时需要重新计算其hash值(通常与系统中的节点数目有关),由于hash值已经改变,所以很可能找不到保存该对象的服务器节点)。

如下图所示是余数哈希算法

 

 

技术分享图片

 

 技术分享图片

 

现在我们假设有n台redis服务器,一份数据a进来的时候,以散列公式hash(a)%n,计算所存放的服务器,假设hash(a)%n = i,那么数据被散列到标号为 1 的服务器,

然后这个时候服务器新增了一台,然后散列公式为hash(a)%(n+1),这个时候请求访问数据a的时候,被分配至 2 号服务器,但是其实这个时候数据是在 1 号服务器的。

如上图所示

这个时候会有大量数据丢失(访问不到了)

所以这个时候,我们假设是新增了服务器,如果是持久化存储的,我们可以让服务器集群对数据进行重新散列,进行数据迁移,然后重新预热恢复数据。

但是这样意味着每次增减服务器的时候,集群就需要大量的通信和数据迁移,这个开销是非常大的。

而且当如果大量缓存失效时,请求会直接落到数据库上,造成突然的数据库压力大增,甚至造成宕机引起不可预测的后果。

因此关键在于,服务器数量变动的时候,要能够保证命中丢失率足够低。

 

 

现在业界流行的解决方案是一致性哈希算法

  一致性哈希算法(Consistent Hashing)最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。简单来说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形,若哈希算法的值超过2^32  ,就除以2^32 取余数),整个哈希空间环如下:

 

 

  整个空间按顺时针方向组织。0和232-1在零点中方向重合。

  下一步将各个服务器使用Hash进行一个哈希,具体可以选择服务器的ip或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置,这里假设将ABC三台服务器使用ip地址哈希后在环空间。

接下来使用如下算法定位数据访问到相应服务器:将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,对应的访问服务器位置就是顺时针的遇到的第一台服务器。

假设我们有K1~K7 7个数据,哈希后映射的位置如下:

技术分享图片

根据一致性哈希算法,数据K1~K3会被定为到Node B上,K4~K5被定为到Node C上,K6~K7被定为到Node A上。 

 

下面分析伸缩性问题:

蓝线为宕机或者扩展前的数据-节点映射路线,绿线为宕机或者扩展后的映射路线,红线为原来的蓝线在宕机或扩展后的失效路线。

技术分享图片

 为了解决上述方案存在的问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。

具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况,可以为每台服务器计算三个虚拟节点,例如将节点A映射为 “VA1”、“VA2”、“VA3”三个虚拟节点,此处ABC三台机子映射为9个虚拟节点(实际运用中虚拟节点数量会远大于这个数,具体可以自己测试最优数量。一般经验值为150左右)。

 技术分享图片

 

 

 

参考资料:
《大型网站技术架构—核心原理与案例分析》 李智慧著 电子工业出版社
《深入分布式缓存—从原理到实践》 于君泽,曹洪伟,邱硕等著 机械工业出版社














以上是关于缓存与一致性哈希的主要内容,如果未能解决你的问题,请参考以下文章

缓存与一致性哈希

分布式数据缓存中的一致性哈希算法

面试常问:分布式缓存如何实现一致性哈希?

一致性哈希与java实现

一致性哈希算法与Java实现

一致性哈希原理与应用