【涨知识】_咖谈memcached的几大特点

【引言】
我们在做数据架构时,除了需要详细了解各类数据库的特性和架构优劣势(商业库Oracle,DB2,SQL Server、开源库PG,MySQL,MongoDB外,NewSQL SQL Azure、MySQL NDB cluster,以及最近的国产数据库GaussDB,TiDB,SequoiaDB,OceanBase;列存储数据库HBase),还需要站在更高一层的角度去思考如何更好地支持各种各样的业务需求。

数据架构的设计当然也有包含Active MQ,Rocket Mq、kafka、RabbitMQ等消息队列的应用解耦,异步消息,流量削锋等作用,实现高性能,高可用,可伸缩和最终一致性架构。

鉴于现在互联网用户数量大、高并发访问的特性,数据缓存的提出就是一个很自然的事情,业界有句话叫:“性能不够,缓存来凑”;今天我们主要来聊下数据缓存。

最近在系统的学习数据缓存这块的知识,比较有代表性的就是redis、memcached。今天就主要聊一下memcached。

以下主要内容来自如下参考https://blog.csdn.net/qq_33314107/article/details/80543590。根据自身理解,做了适当调整。

memcached的几大特点

1. memcached最大的优势是什么?
Memcached最大的好处就是它带来了极佳的水平可扩展性,特别是在一个巨大的系统中。由于客户端自己做了一次哈希,那么很容易增加大量memcached到集群中。memcached之间没有相互通信,因此不会增加 memcached的负载;没有多播协议,不会网络通信量爆炸(implode)。memcached的集群很好用。内存不够了?增加几台 memcached;CPU不够用了?再增加几台;有多余的内存?在增加几台。

2. memcached和MySQL的querycache相比,有什么优缺点?
MySQL有个使用方便的query cache,可以自动地缓存SQL查询结果,被缓存的SQL查询可以被反复地快速执行。MySQL的query cache是集中式的,连接到该query cache的MySQL服务器都会受益。

当用户修改表时,MySQL的query cache会立刻被刷新(flush)。存储一个memcached item只需要很少的时间,但是当写操作很频繁时,MySQL的query cache会经常让所有缓存数据都失效。

在多核CPU上,MySQL的query cache会遇到扩展问题(scalability issues)。在多核CPU上,query cache会增加一个全局锁(global lock), 由于需要刷新更多缓存数据,速度会变得更慢。

在 MySQL的query cache中,是不能存储任意的数据的(只能是SQL查询结果)。而利用memcached,可以搭建出各种高效的缓存。如,可以执行多个独立的查询,构建出一个用户对象(user object),然后将用户对象缓存到memcached中。而query cache是SQL语句级别的,不可能做到这一点。在并发量小的业务需求,query cache会有所帮助,但随着网站规模的增加,query cache的弊将大于利。

query cache能够利用的内存容量受到MySQL服务器实际空闲内存空间的限制。给数据库服务器增加更多的内存来缓存数据,固然是很好的。但是,有了memcached,只要您有空闲的内存,都可用来增加memcached集群规模,可以缓存更多的数据。

3. memcached和localcache(PHP APC、mmap),有什么优缺点?
首先,local cache有许多与如上(query cache)相同的问题。local cache能够利用的内存容量受到(单台)服务器空闲内存空间的限制。不过,local cache有一点比memcached和query cache都要好,是它不但可以存储任意的数据,而且没有网络存取的延迟。

local cache的数据查询更快,考虑把highly common的数据放在local cache中;如每个页面都需要加载一些数量较少的数据,考虑放在local cached。

local cache缺少集体失效(group invalidation)的特性。在memcached集群中,删除或更新一个key会让所有的观察者觉察到,可以使用此特性做防会话失效的机制。但在local cache中, 只能通知所有的服务器刷新cache(很慢,不具扩展性),或者仅仅依赖缓存超时失效机制。

此外,local cache面临着严重的服务器物理实际内存限制,只能纵向扩展。

4. memcached的cache机制
Memcached主要的cache机制是LRU(最近最少用)算法+超时失效。

当客户存数据到memcached中,可以指定该数据在缓存中可以呆多久。如果memcached的内存不够,过期的slabs会优先被替换,接着就轮到最老的未被使用的slabs。

5. memcached如何实现冗余机制?
不实现!
Memcached应该是应用的缓存层。它的设计本身就不带有任何冗余机制。如果一个memcached节点失去了所有数据,可从数据源(比如数据库)再次获取到数据。此场景下,缓存从数据库重新搂数,对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。

注意,因为Memcached没有做数据持久化处理,数据失效引起的数据重新加载,会导致缓存雪崩现象。为了防止此现象,通常处理途径为:
1.加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。
2.简单方案为将缓存失效时间分散开;
3.给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存

6. memcached如何处理容错
不处理!
在memcached节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,使用如下几种方案:

1.忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响;
2.把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到(与原来)不同的节点上。
3.启动热备节点,接管失效节点所占用的IP。这样可以防止哈希噪音(hashing chaos)。
4. 如添加和移除节点,为不影响原先的哈希结果,可使用一致性哈希算法(consistent hashing)。

注意:
两次哈希(reshing)。当客户端存取数据时,如发现一个节点宕了,就再做一次哈希(哈希算法与前一次不同),重新选择另一个节点(需要注意的时,客户端并没有把down的节点从节点列表中移除,下次还是有可能先哈希到它)。如果某个节点时好时坏,两次哈希的方法就有风险了,好的节点和坏的节点上都可能存在脏数据(stale data)。

7. memcached是如何做身份验证
没有身份认证机制!
memcached是运行在应用下层的软件,身份验证应是应用上层的职责。

memcached的客户端和服务器端之所以是轻量级的,部分原因就是完全没有实现身份验证机制。这样,memcached可以很快地创建新连接,服务器端也无需任何配置。

如希望限制访问,可使用防火墙,或者让memcached监听unix domain socket。

8.如何使用memcached的多线程
线程就是定律(threads rule)!
在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本支持多线程模式。多线程模式允许memcached能够充分利用多个CPU,并在CPU之间共享所有的缓存数据。
注意:这里指的是在多CPU的情况下,才开启多线程模式;熟悉redis的亲可以想到redis的单线程处理,本人个人公众号将在后续对redis进行专题解说。

memcached使用一种简单的锁机制来保证数据更新操作的互斥。相比在同一个物理机器上运行多个memcached实例,这种方式能够更有效地处理multi gets。

如业务系统负载不高,不需启用多线程工作模式。如运行一个拥有大规模硬件的、庞大的网站,可使用多线程模式。

9. memcached能接受的key的最大长度是多少?
key的最大长度是250个字符。
250是memcached服务器端内部的限制,如果您使用的客户端支持”key的前缀”或类似特性,那么key(前缀+原始key)的最大长度是可以超过250个字符。推荐使用使用较短的key,因为可以节省内存和带宽。

注意
对比redis,Memcached的简单限制就是键(key)和Value的限制。最大键长为250个字符。可以接受的储存数据不能超过1MB(可修改配置文件变大),因为这是典型slab 的最大值,不适合虚拟机使用。而Redis的Key长度支持到512k。

10 .memcached对item的过期时间有何限制
过期时间最大可30天。
memcached把传入的过期时间(时间段)解释成时间点后,一旦到了这个时间点,memcached就把item置为失效状态。这是一个简单但obscure的机制。

11. memcached最大能存储多大的单个item?
Memcached的内存存储引擎使用slabs来管理。内存被分成大小不等的slabs chunks(先分成大小相等的slabs,然后每个slab被分成大小相等chunks,不同slab的chunk大小是不相等的)。chunk的大小依次从一个最小数开始,按某个因子增长,直到达到最大的可能值。

如果最小值为400B,最大值是1MB,因子是1.20,各个slab的chunk的大小依次是:slab1 – 400B slab2 – 480B slab3 – 576B …

slab中chunk越大,它和前面的slab之间的间隙就越大。因此,最大值越大,内存利用率越低。Memcached必须为每个slab预先分配内存,因此如果设置了较小的因子和较大的最大值,会需要更多的内存。

不要尝试把巨大的网页放到mencached中,把大的数据结构load和unpack到内存中需要花费很长的时间,从而导致业务性能恰得其反。

12. Memcached可在各个服务器上配置大小不等的缓存空间吗?
Memcache客户端仅根据哈希算法来决定将某个key存储在哪个节点上,不考虑节点的内存大小。因此,可在不同的节点上使用大小不等的缓存。

13. memcached是如何分配内存的?
memcached的内存分配器是如何工作的?为什么不适用malloc/free!?为何要使用slabs? 
实际上,这是一个编译时选项。默认会使用内部的slab分配器。确实应该使用内建的slab分配器。最早的时候,memcached只使用 malloc/free来管理内存。然而,这种方式不能与OS的内存管理很好融洽。反复的malloc/free会造成内存碎片,OS最终花费大量的时间去查找连续的内存块来满足malloc的请求,而不是运行memcached进程。

slab分配器就是为了解决此问题而生。内存被分配并划分成chunks,一直被重复使用。因为内存被划分成大小不等的slabs,如果item 的大小与被选择存放它的slab不合适,就会浪费一些内存。Steven Grimm正在这方面已经做出了有效的改进。

14. memcached能保证数据存储的原子性吗?
所有的被发送到memcached的单个命令是完全原子的。如针对同一份数据同时发送了一个set命令和一个get命令,它们不会影响对方,将被串行化、先后执行。即使在多线程模式,所有的命令都是原子的。

命令序列不是原子的。如果您通过get命令获取了一个item,修改了它,然后想把它set回memcached,不保证这个item没有被其他进程(process,未必是操作系统中的进程)操作过。在并发的情况下,也可能覆写了一个被其他进程set的item。

memcached 1.2.5以及更高版本,提供了gets和cas命令,可解决上面的问题。如使用gets命令查询某个key的item,memcached会返回该item当前值的唯一标识。如覆写了这个item并想把它写回到memcached中,可通过cas命令把那个唯一标识一起发送给 memcached。如该item存放在memcached中的唯一标识与您提供的一致,写操作将会成功。如果另一个进程在这期间也修改了这个 item,那么该item存放在memcached中的唯一标识将会改变,写操作会失败。

通常,基于memcached中item的值来修改item,是一件棘手的事情。除非很清楚自己在做什么,否则请不要做这样的事情。

15.memecache将 $expire 设置为100天,发现设置的key总是获取不到值?
memcache默认过期时间是30天,过期时间用秒为单位或时间戳为单位,前一种情况秒数不能超过60×60×24×30(30天时间的秒数);如果失效的值大于这个值,服务端会将其作为一个真实的Unix时间戳来处理而不是自当前时间的偏移。如果过期时间设定为0,表示永不过期,但也不是相对的,有可能因为服务端为了给其他新的元素分配空间而被LRU算法删除。

文章至此结束。
以下为个人公众号“一森咖记”,欢迎关注。
image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值