Nginx+Memcache+一致性hash算法 实现页面分布式缓存(转)

网站响应速度优化包括集群架构中很多方面的瓶颈因素,这里所说的将页面静态化、实现分布式高速缓存就是其中的一个很好的解决方案...

1)先来看看Nginx负载均衡

Nginx负载均衡依赖自带的 ngx_http_upstream_module 、 ngx_http_memcached_module两大功能模块,其中一致性hash算法Nginx本身是不支持的,可以借助第三方模块: ngx_http_upstream_consistent_hash

或者直接使用淘宝的Tengine:

http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html

模块的添加

unzip ngx_http_consistent_hash-master.zip
cd nginx-1.6.3 #进入nginx安装原始文件夹
./configure --user=www --group=www --add-module=../ngx_http_consistent_hash-master --with-http_ssl_module --with-http_stub_status_module --prefix=/application/nginx-1.6.3/ #添加模块
make #如果是生产环境添加模块,切记不要make install,否则会覆盖文件
cp objs/nginx /application/nginx/sbin/nginx #停掉nginx进程,覆盖二进制文件
[[email protected] sbin]# ./nginx -V #查看模块是否添加成功
nginx version: nginx/1.6.3
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
TLS SNI support enabled
configure arguments: --user=www --group=www --add-module=../ngx_http_consistent_hash-master --with-http_ssl_module --with-http_stub_status_module --prefix=/application/nginx-1.6.3/

2)调度算法选择

如上图,在我们确定要将数据采用分布式memcache服务器缓存起来后,就面临一个问题:采用一种什么方式去缓存和调度数据?很显然,最简单的策略就是将每一次Memcache请求都随机发送到一台Memcache服务器,但这种策略可能又会带来两个问题:一是同一份数据可能被存在不同机器上而造成数据冗余,二是可能某数据已经被缓存但是没法命中。因此,随机策略无论是时间效率还是空间效率都利用的不是很好。

url_hash算法

url_hash算法是Nginx负载均衡动态调度算法中的一种,是将一个完整的URL经过哈希运算key=HASH($URL)%3(3是memcache节点台数)得到一个key值,具有相同key值得URL也就是Memcache请求将会发往同一台缓存服务器,比如,H=0发往Memcache_server01、H=1发往Memcache_server02、H=2发往Memcache_server03,避免了数据冗余和命中率低的两个问题;

普通url_hash的缺点就是,计算公式key=HASH($URL)%N中,一旦缓存节点N数量发生变化,那么所有数据都要重新按照公式key=HASH($URL)%(N-1)计算,之前计算得到的key值结果就会全部发生变化,意味着缓存节点下缓存的数据全部失效!要重新缓存全部节点数据。如果是高并发大数据量的话,对后端节点服务器的冲击是致命的,很有可能会导致系统的全面瘫痪。这也是为什么在使用大量的分布式缓存系统在遭遇系统重启时,要对缓存预热及严格遵守集群服务启动顺序的原因。

一致性HASH算法

一致性HASH算法的出现有效的解决了上面普通url_hash调度算法在节点变动后面临全部缓存失效的问题

简单地说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某空间哈希函数H的值空间是0-2^32-1(即哈希值是一个32位无符号整形),整个哈希空间如下:

下一步将各个服务器使用H进行一个哈希计算,具体可以使用服务器的IP地址或者主机名作为关键字,这样每台机器能确定其在上面的哈希环上的位置了,并且是按照顺时针排列,这里我们假设三台节点memcache经计算后位置如下

接下来使用相同算法计算出数据的哈希值h,并由此确定数据在此哈希环上的位置

假如我们有数据A、B、C、D、4个对象,经过哈希计算后位置如下:

根据一致性哈希算法,数据A就被绑定到了server01上,D被绑定到了server02上,B、C在server03上,是按照顺时针找最近服务节点方法

这样得到的哈希环调度方法,有很高的容错性和可扩展性:

假设server03宕机

可以看到此时A、C、B不会受到影响,只是将B、C节点被重定位到Server 1。一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即顺着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。

考虑另外一种情况,如果我们在系统中增加一台服务器Memcached Server 04:

此时A、D、C不受影响,只有B需要重定位到新的Server 4。一般的,在一致性哈希算法中,如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即顺着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。

综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

一致性哈希的缺点:在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。我们可以采用增加虚拟节点的方式解决。

为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希【具体可以这么做:根据服务器的名字或者是ip计算节点hash的时候,可以加上编号,然后再计算哈希值】,在每个计算的结果位置都放置一个服务节点,称为虚拟节点。这样,数据再被存储的时候,就不会因为服务器在环上的间距太大而导致“数据倾斜”了。

同时数据定位算法不变,只是多了一步虚拟节点 到实际节点的映射,例如定位到“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”三个虚拟节点的数据均定位到Server 1上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分 布,避免出现雪崩的情况

3)Nginx配置

upstream memcached {
    consistent_hash $request_uri; #采用一致性哈希计算请求字段request_rui值
    server 172.16.2.11:11211; #节点服务器
    server 172.16.2.12:11212;
    server 172.16.2.13:11213;
}

server {
    listen       80;
    server_name  lichengbing.cn;

    location ^~ /cache/ { #匹配带cache目录时将请求转发给计算好的哈希节点服务器
        set                     $enhanced_memcached_key $request_uri;
        enhanced_memcached_pass memcached;
    }

    error_page     404 502 504 = @fallback;
}
location @fallback {
    proxy_pass     http://backend;
}

4)修改示例PHP页面

$htmlContent = file_get_contents(‘http://lichengbing.cn‘);

// 页面过期时间
$expiresTime = 60 * 5;

// Last-Modified头设置的时间
$lastModified = gmdate(‘D, d M Y H:i:s \G\M\T‘, time());

// Expires头设置的时间
$expires = gmdate(‘D, d M Y H:i:s \G\M\T‘, time() + $expiresTime);

// 最终缓存的内容
$cacheContent = "EXTRACT_HEADERS
Content-Type: text/html
Cache-Control:max-age=$expiresTime
Expires:$expires
Last-Modified:$lastModified

$htmlContent";

// 获取memcache实例
$memcached = new Memcache();
$memcached->addServer(‘172.16.2.11‘, 11211);
$memcached->addServer(‘172.16.2.12‘, 11212);
$memcached->addServer(‘172.16.2.13‘, 11213);

// 写入缓存
$memcached->set(‘/cache/index.html‘, $cacheContent, $expiresTime);

至此,我们已经简单的完成了使用Nginx和Memcached对缓存页面的访问,但这只是后端的简单实现,在前端还需要实现对页面缓存的管理等等的工作。

原文地址(http://www.tuicool.com/articles/BZBVfaM)

时间: 2024-08-06 07:50:26

Nginx+Memcache+一致性hash算法 实现页面分布式缓存(转)的相关文章

一致性Hash算法在Redis分布式中的使用

由于redis是单点,但是项目中不可避免的会使用多台Redis缓存服务器,那么怎么把缓存的Key均匀的映射到多台Redis服务器上,且随着缓存服务器的增加或减少时做到最小化的减少缓存Key的命中率呢?这样就需要我们自己实现分布式. Memcached对大家应该不陌生,通过把Key映射到Memcached Server上,实现快速读取.我们可以动态对其节点增加,并未影响之前已经映射到内存的Key与memcached Server之间的关系,这就是因为使用了一致性哈希.因为Memcached的哈希策

用大白话讲一致性Hash算法在Redis分布式中的使用

在了解一致性哈希算法之前,最好先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那么,我们先来描述一下这个经典的分布式缓存的应用场景. 1 .场景描述 假设,我们有三台缓存服务器,用于缓存图片,我们为这三台缓存服务器编号为0号.1号.2号,现在,有3万张图片需要缓存,我们希望这些图片被均匀的缓存到这3台服务器上,以便它们能够分摊缓存的压力.也就是说,我们希望每台服务器能够缓存1万张左右的图片,那么,我们应该怎样做呢?如果

分布式memcached学习(四)—— 一致性hash算法原理

    分布式一致性hash算法简介 当你看到"分布式一致性hash算法"这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前,我们先来了解一下这几个概念. 分布式 分布式(distributed)是指在多台不同的服务器中部署不同的服务模块,通过远程调用协同工作,对外提供服务. 以一个航班订票系统为例,这个航班订票系统有航班预定.网上值机.旅客信息管理.订单管理.运价计算等服务模块.现在要以集中式(集群,cluster)和分布

分布式缓存技术memcached学习系列(四)—— 一致性hash算法原理

文章主目录 分布式一致性hash算法简介 分布式一致性hash算法使用背景 环形hash空间 映射key到环形hash空间 映射server节点到hash空间 映射key到server节点 添加server节点 删除server节点 虚拟节点的引入 节点变化数据分流的问题 一致性hash算法与取模算法的比较 参考文档 回到顶部 分布式一致性hash算法简介 当你看到“分布式一致性hash算法”这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法

一致性Hash算法原理白话

1.技术背景 1.1.技术举例:Memcache 1.2.技术瓶颈 memcached服务器端本身不提供分布式cache的一致性,由客户端实现提供.以余数分布式算法为例. 余数分布式算法是根据添加进入缓存时key的hash值通过特定的算法得出余数,然后根据余数映射到关联的缓存服务器,将该key-value数据保存到该服务器 1.2.1.假设有3台缓存服务器以及它们对应的余数值 Node A:0,3,6,9 Node B:1,4,7 Node C:2,5,8 1.2.2.此时添加一台服务器Node

memcache的一致性hash算法使用

一.概述 1.我们的memcache客户端(这里我看的spymemcache的源码),使用了一致性hash算法ketama进行数据存储节点的选择.与常规的hash算法思路不同,只是对我们要存储数据的key进行hash计算,分配到不同节点存储.一致性hash算法是对我们要存储数据的服务器进行hash计算,进而确认每个key的存储位置.  2.常规hash算法的应用以及其弊端 最常规的方式莫过于hash取模的方式.比如集群中可用机器适量为N,那么key值为K的的数据请求很简单的应该路由到hash(K

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

基本场景 比如你有 N 个 cache 服务器(后面简称 cache ),那么如何将一个对象 object 映射到 N 个 cache 上呢,你很可能会采用类似下面的通用方法计算 object 的 hash 值,然后均匀的映射到到 N 个 cache : 常规取余的hash算法 hash(key) % N 对于N台缓存服务器构成的集群缓存,依次编号为0 - (N-1)先对要存储的key进行hash取值,然后用hash值对N取余,得到一个在缓存服务器编号区间的一个数字,则将当前key存到这台服务器

分布式缓存一致性hash算法理解

今天阅读了一下大型网络技术架构这本苏中的分布式缓存一致性hash算法这一节,针对大型分布式系统来说,缓存在该系统中必不可少,分布式集群环境中,会出现添加缓存节点的需求,这样需要保障缓存服务器中对缓存的命中率,就有很大的要求了: 采用普通方法,将key值进行取hash后对分布式缓存机器数目进行取余,以集群3台分布式缓存为例子: 对于数据进行取hash值然后对3其进行取余,余数为0则进入node 0,余数位1则进入node1,余数位2则进入node2. 如果增加一个节点则对4进行取余,则会将node

7.redis 集群模式的工作原理能说一下么?在集群模式下,redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?

作者:中华石杉 面试题 redis 集群模式的工作原理能说一下么?在集群模式下,redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗? 面试官心理分析 在前几年,redis 如果要搞几个节点,每个节点存储一部分的数据,得借助一些中间件来实现,比如说有 codis,或者 twemproxy,都有.有一些 redis 中间件,你读写 redis 中间件,redis 中间件负责将你的数据分布式存储在多台机器上的 redis 实例中. 这两年,redis 不断在发展