memcached面试专题及答案【一】

96 阅读7分钟

memcached 是怎么工作的?

Memcached 的神奇来自两阶段哈希(two-stage hash)。Memcached 就像一个巨大的、存储了很多<key,value>对的哈希表。通过 key,可以存储或查询任意的数据。客户端可以把数据存储在多台 memcached 上。当查询数据时,客户端首先参考节点列表计算出 key 的哈希值(阶段一哈希),进而选中一个节点;客户端将请求发送给选中的节点,然后 memcached 节点通过一个内部的哈希算法(阶段二哈希),查找真正的数据(item)。

举个列子,假设有 3 个客户端 1, 2, 3,3 台 memcached A, B, C:

Client 1 想把数据”barbaz”以 key “foo”存储。Client 1 首先参考节点列表(A, B, C),计算 key“foo”的哈希值,假设 memcached B 被选中。接着,Client 1 直接 connect 到 memcached B,通过 key “foo”把数据”barbaz”存储进去。 Client 2 使用与 Client 1 相同的客户端库(意味着阶段一的哈希算法相同),也拥有同样的 memcached 列表(A, B, C)。

于是,经过相同的哈希计算(阶段一),Client 2 计算出 key “foo”在 memcached B 上,然后它直接请求 memcached B,得到数据”barbaz”。各种客户端在 memcached 中数据的存储形式是不同的(perl Storable, php serialize, javahibernate, JSON 等)。一些客户端实现的哈希算法也不一样。但是,memcached 服务器端的行为总是一致的。

最后,从实现的角度看,memcached 是一个非阻塞的、基于事件的服务器程序。这种架构可以很好地解决 C10K problem ,并具有极佳的可扩展性。可以参考 A Story of Caching ,这篇文章简单解释了客户端与 memcached 是如何交互的。

memcached 最大的优势是什么?

请仔细阅读上面的问题(即 memcached 是如何工作的)。Memcached 最大的好处就是它带来了极佳的水平可扩展性,特别是在一个巨大的系统中。由于客户端自己做了一次哈希,那么我们很容易增加大量 memcached 到集群中。memcached 之间没有相互通信,因此不会增加 memcached 的负载;没有多播协议,不会网络通信量爆炸(implode)。memcached的集群很好用。内存不够了?增加几台memcached 吧;CPU 不够用了?再增加几台吧;有多余的内存?在增加几台吧,不要浪费了。

基于 memcached 的基本原则,可以相当轻松地构建出不同类型的缓存架构。除了这篇FAQ,在其他地方很容易找到详细资料的。

看看下面的几个问题吧,它们在 memcached、服务器的 local cache 和 MySQL 的 querycache 之间做了比较。这几个问题会让您有更全面的认识。

memcached 和 MySQL 的 query cache 相比,有什么优缺点?

把 memcached 引入应用中,还是需要不少工作量的。MySQL 有个使用方便的 query

cache,可以自动地缓存 SQL 查询的结果,被缓存的 SQL 查询可以被反复地快速执行。

Memcached 与之相比,怎么样呢?

MySQL 的 querycache 是集中式的,连接到该 querycache 的 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,我们可以搭建出各种高效的缓存。比如,可以执行多个独立的查询,构建出一个用户对象(userobject),然后将用户对象缓存到 memcached 中。而 querycache 是 SQL 语句级别的,不可能做到这一点。在小的网站中,query cache 会有所帮助,但随着网站规模的增加,query cache 的弊将大于利。

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

memcached 和服务器的 local cache(比如 PHP 的 APC、mmap 文件等)相比,有什么优缺

点?

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

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

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

  • local cache 面临着严重的内存限制,这一点上面已经提到。

memcached 的 cache 机制是怎样的?

Memcached 主要的 cache 机制是 LRU(最近最少用)算法+超时失效。当您存数据到memcached 中,可以指定该数据在缓存中可以呆多久 Which is forever, or some time in thefuture。如果 memcached 的内存不够用了,过期的 slabs 会优先被替换,接着就轮到最老的未被使用的 slabs。

memcached 如何实现冗余机制?

不实现!我们对这个问题感到很惊讶。Memcached 应该是应用的缓存层。它的设计本身就不带有任何冗余机制。如果一个 memcached 节点失去了所有数据,您应该可以从数据源(比如数据库)再次获取到数据。您应该特别注意,您的应用应该可以容忍节点的失效。不要写一些糟糕的查询代码,寄希望于 memcached 来保证一切!如果您担心节点失效会大大加重数据库的负担,那么您可以采取一些办法。比如您可以增加更多的节点(来减少丢失一个节点的影响),热备节点(在其他节点 down 了的时候接管 IP),等等。

memcached 如何处理容错的?

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

  • 忽略它!在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响。

  • 把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分 key 会因为哈希值的改变而被映射到(与原来)不同的节点上。

  • 启动热备节点,接管失效节点所占用的 IP。这样可以防止哈希紊乱(hashing chaos)。

*如果希望添加和移除节点,而不影响原先的哈希结果,可以使用一致性哈希算法(consistent hashing)。您可以百度一下一致性哈希算法。支持一致性哈希的客户端已经很成熟,而且被广泛使用。去尝试一下吧!

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

想要了解更多Java基础知识,可以点击评论区链接和小编一起学习java吧,此视频教程为初学者而著,零基础入门篇!给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili