5.2 分布式缓存架构:常见的缓存实现形式
1. 正向代理缓存
代理用户,部署在用户端。
2.反向代理缓存
代理服务器,部署在服务端(数据中心)。
3.多层反向代理缓存
代理内部服务器,部署在服务端(数据中心)。
4.内容分发网络(CDN)
价值:离用户更近,加快访问速度,降低数据中心服务器负载压力。
5.CDN 同时配置静态文件和动态内容
6.通读缓存(read-through)
1.正向代理缓存,反向代理缓存,CDN 缓存都是通读缓存。
2.通读缓存给客户端返回缓存资源,并在请求未命中缓存时获取实际数据。
3.客户端连接的是通读缓存而不是生成响应的原始服务器。
特点:客户端不直接连接到数据源---客户端不需要知道实际数据源位置
7.旁路缓存(cache-aside)
1.对象缓存是一种旁路缓存,旁路缓存通常是独立的键值对存储(key-value)
2.应用代码通常会询问对象缓存需要的对象是否存在,如果存在,它会获取并使用缓存的对象;
如果不存在或已经过期,应用会连接主数据源组装数据,并将其保存回到对象缓存中,以便将来使用。
特点:客户端直连数据源-----客户端需要知道数据源位置+旁路缓存位置。
浏览器对象缓存--旁路缓存
//在 WebStorage 中缓存对象的 Javascript 代码
var preferences= { /*data object to be stored */};
localStorage.setItem('preferences',JSON.stringify(preferences));
//访问缓存对象的 Javascript 的代码
var cacheData=localStorage.getItem('preferences');
var preferences=JSON.parse(cachedData);
本地对象缓存
1.对象直接缓存在应用程序内存中。
2.对象存储在共享内存,同一台机器的多个进程可以访问他们。
3.缓存服务作为独立应用和应用程序部署在同一台服务器上。
8.本地对象缓存构建分布式集群
1.本地缓存构建分布式集群。
2.每台服务器缓存同样的数据(假设为:key1=value1)。问题:其中一台服务器更新缓存对象 key1(key1=value1.1),其他服务器缓存为就数据 value1,造成读取脏数据。
3.jboss 方案:自己同步更新缓存-----A 服务器缓存更新后,通知集群中其他服务器同步更新。次生问题:如果集群规模较大,比如 10000 台服务器,每台服务器同步更新缓存,产生大量网络流量。
缺点:1.每台服务器缓存数据都是一样的。需要缓存大量数据时,有限的内存缓存的同样数据,浪费内存资源。
2.A 更新缓存时,同步更新集群中其他服务器缓存。占用有限的带宽网络资源。
3.没有足够的数据放到缓存中,降低缓存命中率。
====>互联网早期方案,但是因为这些缺点,很快就被放弃。
9.远程分布式对象缓存
优点:
1.不再争用资源:不再争用前端服务器内部的内存资源。有利于提高前端服务器自身的性能和扩展性。
2.可构建集群:缓存部署在专用的服务器上,可以构建成为集群,有利于自身集群的性能和扩展性。
当集群存储空间不足时,可以添加服务器提供更多的内存,存储更多的数据。
有利于线性伸缩。
==>现代互联网常用的缓存架构设计方案-----分布式缓存:Memcached,Redis
10.Memcached 分布式对象缓存
//PHP 客户端访问 Memcached 集群
$m=new Memcached();
//添加服务器集群
$cache->addServers(array(
array('cache1.example.com',11211),
array('cache2.example.com',11211),
array('cache3.example.com',11211),
));
//写缓存,失效时间 5 分钟
$m->set('userCount',123,600); //根据 Key 计算服务器地址
//读缓存:
$m->get('userCount'); //根据 Key 计算服务器地址
share-nothing 架构:虽然构建了集群, Memcached 服务器之间相互独立,不共享任何信息,不相互通信,不相互感知对方。
有 memcached 客户端来控制 memcached 服务器访问。服务器的增减,有客户端做相应调整。客户端能够感知到集群中的服务器。
11.Memcached 分布式缓存访问模型
假如:路由算法:取模余数法。
当前 Memcached 服务器有三台,路由算法:根据 Key 计算 hash 值,hash 值 %3=【0-2】,有余数计算得到目标服务器地址。
比如:key="beijing";
"beijing".hashCode()=10;
10%3=1;
====>目标服务器地址:Node1(10.0.0.1:9100)。
分布式缓存集群要求可伸缩:增加一台 memcached 服务器至 4 台。仍然使用取模余数法: hashCode%4=【0-3】.
同理分析:key="beijing";
"beijing".hashCode()=10;
10%4=2;====>目标服务器地址:Node2(10.0.0.2:9100)。
问题:路由算法改变,导致相同的 key,不能命中同一台服务器。
延申:大型互联网分布式缓存集群,增加一台服务器后,原本目的:增加内存,缓存更多的数据,提高缓存命中率。
结果:采用取模余数法,缓存不被命中,集群失效,虽然数据仍然在缓存中,但是不能被命中。
大量请求涌向数据库,数据库负载急剧升高,可能超过数据库的最大承受能力,
导致数据库崩溃==>应用崩溃==>整个系统崩溃。
===>没有达到线性伸缩目的:集群扩容。
根本原因:路由算法的改变,路由算法不合适。 ===>达到集群扩容的目的,应该采用什么算法呢?
评论