面试:Memcached 面试题

Memcached 的多线程是什么?如何使用它们?

线程就是定律(threads rule)!在 Steven Grimm 和 Facebook 的努力下, Memcached 1.2 及更高版本拥有了多线程模式。多线程模式允许 Memcached 能够充分利用多个 CPU,并在 CPU 之间共享所有的缓存数据。
Memcached 使用一种简单的锁机制来保证数据更新操作的互斥。相比在同一 个物理机器上运行多个 Memcached实例,这种方式能够更有效地处理 multi gets。
如果你的系统负载并不重,也许你不需要启用多线程工作模式。如果你在运行 一个拥有大规模硬件的、庞大的网站,你将会看到多线程的好处。 简单地总结一下:命令解析(Memcached 在这里花了大部分时间)可以运行在多线程模式下。Memcached 内部对数据的操作是基于很多全局锁的(因此 这部分工作不是多线程的)。未来对多线程模式的改进,将移除大量的全局锁, 提高 Memcached 在负载极高的场景下的性能。

Memcached 是什么,有什么作用?

Memcached 是一个开源的,高性能的内存绶存软件,从名称上看 Mem 就是 内存的意思,而 Cache 就是缓存的意思。Memcached 的作用:通过在事先规 划好的内存空间中临时绶存数据库中的各类数据,以达到减少业务对数据库的直接高并发访问,从而达到提升数据库的访问性能,加速网站集群动态应用服务的能力。

Memcached 与 Redis 的区别?

  • Redis 不仅仅支持简单的 K/V类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。而 memcache 只支持简单数据类型,需要客户 端自己处理复杂对象。
  • Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用(PS:持久化在 rdb、aof)。
  • 由于 Memcache 没有持久化机制,因此宕机所有缓存数据失效。Redis 配置为持久化,宕机重启后,将自动加载宕机时刻的数据到缓存系统中。具 有更好的灾备机制。
  • Memcache 可以使用 Magent 在客户端进行一致性 hash 做分布式。Redis 支持在服务器端做分布式(PS:Twemproxy/Codis/Redis-cluster 多 种分布式实现方式)。
  • Memcached 的简单限制就是键(key)和 Value 的限制。最大键⻓为 250个字符。可以接受的储存数据不能超过 1MB(可修改配置文件变大),因 为这是典型 slab 的最大值,不适合虚拟机使用。而 Redis 的 Key ⻓度支 持到 512K。
  • Redis 使用的是单线程模型,保证了数据按顺序提交。Memcache 需要使用 cas 保证数据一致性。CAS(Check and Set)是一个确保并发一致性的 机制,属于“乐观锁”范畴;原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作。
  • CPU 利用:由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数据时比 Memcached 性能更高。而在 100k 以上的数据中,Memcached 性能要高于 Redis 。
  • Memcached 内存管理:使用 Slab Allocation。原理相当简单,预先分配一系列大小固定的组,然后根据数据大小选择最合适的块存储。避免了内 存碎片。(缺点:不能变⻓,浪费了一定空间)Memcached 默认情况下下 一个 slab 的最大值为前一个的 1.25 倍。
  • Redis 内存管理: Redis 通过定义一个数组来记录所有的内存分配情况,Redis 采用的是包装的 malloc/free,相较于 Memcached 的内存 管理方 法来说,要简单很多。由于 malloc 首先以链表的方式搜索已管理的内存 中可用的空间分配,导致内存碎片比较多。

什么是二进制协议,我该关注吗?

关于二进制最好的信息当然是二进制协议规范: 二进制协议尝试为端提供一个更有效的、可靠的协议,减少客户端/服务器端因 处理协议而产生的 CPU 时间。
根据 Facebook 的测试,解析 ASCII协议是 Memcached 中消耗 CPU 时间最多的环节。所以,我们为什么不改进ASCII协议呢?

如果缓存数据在导出导入之间过期了,你又怎么处理这些数据呢?

因此,批量导出导入数据并不像你想象中的那么有用。不过在一个场景倒是很 有用。如果你有大量的从不变化的数据,并且希望缓存很快热(warm)起 来,批量导入缓存数据是很有帮助的。虽然这个场景并不典型,但却经常发生,因此我们会考虑在将来实现批量导出导入的功能。
如果一个 Memcached 节点 down 了让你很痛苦,那么你还会陷入其他很多麻 烦。你的系统太脆弱了。你需要做一些优化工作。比如处理”惊群”问题(比 如 Memcached 节点都失效了,反复的查询让你的数据库不堪重负…这个问题 在 FAQ 的其他提到过),或者优化不好的查询。记住,Memcached 并不是你 逃避优化查询的借口。

如何实现集群中的 session 共享存储?

Session 是运行在一台服务器上的,所有的访问都会到达我们的唯一服务器 上,这样我们可以根据客户端传来的sessionID,来获取 session,或在对应 Session 不存在的情况下(session 生命周期到了/用户第一次登录),创建一个新的 Session;但是,如果我们在集群环境下,假设我们有两台服务器 A, B,用户的请求会由 Nginx 服务器进行转发(别的方案也是同理),用户登录时,Nginx 将请求转发至服务器 A 上,A 创建了新的 session,并将SessionID 返回给客户端,用户在浏览其他⻚面时,客户端验证登录状态,Nginx 将请求转发至服务器 B,由于 B 上并没有对应客户端发来 sessionId 的 session,所以会重新创建一个新的session,并且再将这个新的 sessionID 返 回给客户端,这样,我们可以想象一下,用户每一次操作都有 1/2 的概率进行 再次的登录,这样不仅对用户体验特别差,还会让服务器上的 session 激增, 加大服务器的运行压力。
为了解决集群环境下的 seesion 共享问题,共有 4 种解决方案:

  • 粘性 session
    粘性 session 是指 Ngnix 每次都将同一用户的所有请求转发至同一台服务器 上,即将用户与服务器绑定。
  • 服务器 session 复制
    即每次 session 发生变化时,创建或者修改,就广播给所有集群中的服务器, 使所有的服务器上的 session 相同。
  • session 共享
    缓存 session,使用 Redis, Memcached。
  • session 持久化
    将 session 存储至数据库中,像操作数据一样才做 session。

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

把 Memcached 引入应用中,还是需要不少工作量的。MySQL 有个使用方便 的 query cache,可以自动地缓存SQL 查询的结果,被缓存的 SQL 查询可以 被反复地快速执行。Memcached 与之相比,怎么样呢?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集群的规模,然后你就可以缓存更多的数据。

Memcached 是原子的吗?

所有的被发送到 Memcached 的单个命令是完全原子的。如果你针对同一份数据同时发送了一个 set 命令和一个 get 命令,它们不会影响对方。它们将被串 行化、先后执行。即使在多线程模式,所有的命令都是原子的,除非程序有 bug。
命令序列不是原子的。如果你通过 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 能够更有效地使用内存吗?

Memcache 客户端仅根据哈希算法来决定将某个 key 存储在哪个节点上,而不 考虑节点的内存大小。因此,你可以在不同的节点上使用大小不等的缓存。但 是一般都是这样做的:拥有较多内存的节点上可以运行多个Memcached 实 例,每个实例使用的内存跟其他节点上的实例相同。

Memcached 的内存分配器是如何工作的?为什么不适用 malloc/free?为何要使用 slabs?

实际上,这是一个编译时选项。默认会使用内部的 slab 分配器。你确实确实应 该使用内建的 slab 分配器。最早的时候,Memcached 只使用 malloc/free 来管理内存。然而,这种方式不能与 OS 的内存管理以前很好地工作。反复地 malloc/free 造成了内存碎片,OS 最终花费大量的时间去查找连续的内存块来 满足 malloc 的请求,而不是运行 Memcached 进程。如果你不同意,当然可 以使用 malloc。
slab 分配器就是为了解决这个问题而生的。内存被分配并划分成 chunks,一 直被重复使用。因为内存被划分成大小不等的 slabs,如果 item 的大小与被选 择存放它的 slab 不是很合适的话,就会浪费一些内存。Steven Grimm正在这 方面已经做出了有效的改进。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值