java学习之路

1000道互联网java面试题(五)Memcached 面试题

2021-03-26  本文已影响0人  唯有努力不欺人丶

这本书中间还有个4,是es面试题。仔仔细细读了两遍就劝退我了,分开来每个字都差不多认识,连在一起完全看不明白,而且我也没实践经验,所以就不浪费时间了,直接跳到缓存这里。下面开始一个题一个题整理:

1. Memcached是什么,有什么作用?

首先,Memcached是一个开源的,高性能的内存缓存软件。从名称上看,Mem是内存的意思,cached是缓存、连起来就是内存缓存。
通过在事先规划好的内存空间内临时缓存数据库中的各类数据,以减少业务对数据库的高并发访问。提升数据库的访问性能,加速集群应用的反应能力。
Memcached的应用场景:

  1. 作为数据库的前端缓存应用
    • 完整缓存,静态缓存
      比如商品分类,商品信息。我们可以先放在内存中,再提供前端访问入口。我们把这种先放入内存再访问的,称之为预热。用户访问时可以只读取缓存,而不用访问数据库了。
    • 执点缓存
      即只存热点数据,也就是经常访问的数据。然后我们先预热,存在缓存中,如果缓存中没有再去查询数据库,其实这个我们是经常使用的,一般我们用的Memcached注解版就是这样一个作用。在查询的时候相同的方法参数走缓存查询,缓存中没有去查询数据库,然后存到缓存中并将结果返回。
      当然了这个需要配套的一个功能就是:当数据发生更改时要相应的修改缓存中的数据,或者直接删除等待下次访问再重新查询。

电商秒杀:当如果遇到电商秒杀这种时间短,并发高的场景,一定要事先预热或者采用其他措施来解决。这个其他措施可以是获取资格而不是直接购买。
比如可以在数据库标记0/1.先标记出来再事后去下订单等操作(因为下单是一系列操作。而修改标记只是一个操作)。

2. Memcached服务分布式集群如何实现的?

和mysql不同,Memcached服务每一个都只存一部分数据,这些集群中所有数据加起来才是完整数据。其数据访问有两种方式:

一致hash算法不仅仅是为了每次访问只请求一个服务器,同时也是为了当某一台服务器宕机后,缓存服务器的更新重分配比例降到最低。

3. Memcached的服务特点及工作原理是什么?

4. 简述Memcached内存管理机制原理

早期的Memcached内存管理方式是通过malloc的分配的内存。使用完后通过free来回收内存。这种方式容易产生内存碎片。并降低操作系统对内存的管理效率。加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached进程本身还慢。为了解决 这个问题,Slab Allocation内存分配机制就诞生了。

现在Memcached利用Slab Allocation机制来分配和管理内存。

Slab Allocation

Slab Allocation机制原理是按照预先规定的大小,将分配给memcached的内存分割成特定长度的内存块。再把尺寸相同的内存块分成组。Slab Allocation有重复使用已分配的内存的目的。也就是说分配到的内存不会释放,而是重复利用。
Slab Allocation的主要术语:

5. Memcached是怎么工作的?

神奇的两阶段哈希(two-stage hash)
其实这个是个很有意思的设计。属于两次查询。我们之前说过了Memcached里存储的是KV对的hash表。通过key可以存储或查询任意的数据。
但是这里有个查询问题。在一百个数据中查询一个和在一万个数据中查询一个。肯定是一百个快啊。
所以Memcached的集群差不多如此效果:一万个数据分100个节点存储。一个节点存100个数组。
然後查询的时候先参考节点列表计算出key 的哈希值(阶段一哈希)。进而选中一个节点。
然後在memcached节点中通过一个内部的hash算法(阶段二哈希)查找真正的数据。

6. Memcached最大的优势是什么?

Memcached最大的好处就是它带来了极佳的水平扩展性。特别是在一个巨大的系统中。
由于客户端自己做了一个hash。我们很容易把心的memcached添加到集群中。
memcached之间没有相互通信,所以集群扩招也不会增加memcached的负载。没有多播协议也就不会网络通信量爆炸。
总而言之,这个memcached有点类似与mysql的分库(注意是分库而不是分表)。

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

我看的这本书上说Memcached引用复杂。但是现在2021年了,spring boot都到2了,其自带的Memcached已经配置好了。可以直接使用。注解版的话只需要添加几个注解就可以解决。所以不能说使用复杂了。
然后优点相比于MySQL的query cache有一下几点:

  1. 修改表的时候MySQL的query cache会立刻被刷新。当写操作很频繁的时候MySQL的query cache会经常让所有缓存数据失效。
  2. 多核CPU上,query cache会增加一个全局锁。所以当需要刷新的数据变多时,速度会变慢。
  3. MySQL的query cache只能存储SQL查询结果。而Memcached则可以存储任意的数据。
  4. query cache能利用的内存容量受到MySQL服务器的空闲内存空间的限制。而Memcached只要有空闲的内存都可以用来增加Memcached集群的规模。

简单总结下:Memcached存储不局限于sql语句,query cache只能存sql运行结果。query cache依赖MySQL服务器的空闲内存。Memcached不局限。Memcached更加灵活方便和便于使用。

8. Memcached的cache机制是怎么样的?

这个其实上文已经简单的提到了。主要的cache机制是LRU算法+超时失效。
存数据到Memcached的时候,可以指定该数据在缓存中待多久。然后当Memcached的内存不够用了优先把过期的slabs替换,如果过期都替换了还是不够用,就把最长时间未被使用的slabs替换。

9. Memcached如何实现冗余机制?

这个问题其实是个坑。因为Memcached根本不带任何冗余机制。Memcached应该是应用的缓存层。简单来说应该是一个有了更好,没有也可以的作用。如果就因为没有了Memcached就程序出问题了说明设计的有问题。。。
应该特别注意:我们的应用应该可以容忍任何节点的失效。也就是如果Memcached节点失去了所有的数据,也应该可以从数据源(比如数据库)再次获取到数据。
当然了如果担心节点失效会加大数据库的负担,可以选择别的方式:比如增加更多的节点。热备节点等。

10. Memcached如何处理容错的?

依然是坑。因为结果是不处理。在Memcached节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,下面几种方案可以选择:

  1. 忽略他。down就down了。等修好了再说。反正只是一部分数据而已。数据库一点压力没问题的。
  2. 失效的节点从节点列表移除。 这个很严肃,因为默认情况下(余数式哈希算法)客户端添加或者删除节点会法制所有的缓存数据不可用。会从新分配所有的key的所在节点。
  3. 启动热备节点,就是当有down掉的接管失效节点所占用的ip。防止哈希紊乱。
  4. 两次hash。如果存数据发现第一个hash的节点down了,直接再做一次与第一次不同的hash,存储到另一个节点上。当然取的时候也先去第一个down的节点取,没有结果去第二个取。
    需要注意这种方式的话千万别节点时好时坏。。不然有脏数据的风险。

11. 如何将Memcached中kv对批量导入导出?

这是一个不应该的操作。Memcached的特性(缓存在内存。非阻塞。)如果在导入导出期间数据发生了变化,就会产生脏数据了。
当然了,有些东西比如几乎从不变化,但是因为经常使用所以存在内存(比如省市区,轻易不变化。)我们确实可以在一开始把这些信息导入进缓存。但是注意:
Memcached是可以减轻数据库压力。但是不是说我们有了缓存就高枕无忧了,改优化查询还是要优化查询的!我们应该让Memcached实现的是如虎添翼,雪上添花的功能。而不能说没有了Memcached就整个程序崩溃了。

12. Memcached是如何做身份验证的?

注意这个题又是一个坑!因为Memcached是没有身份认证机制的。Memcached是运行在应用下层的软件。身份验证应该是应用上层的职责
Memcached的客户端和服务端之所以是轻量级的,部分原因就是完全没有实现身份验证机制。这样可以很快的创建新连接。服务端也无需任何配置。

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

Memcached1.2及以上才有多线程模式。多线程允许Memcached能够充分利用多个cpu。并在CPU之间共享所有的缓存数据。Memcached使用一种简单的锁机制来保证数据更新操作的互斥。相比同一个物理机上运行多个Memcached实例。这种方式更能够有效的处理存取。
当然了,如果系统负载并不重的情况下,也许不需要启用多线程工作模式。
简单总结一下:命令解析可以运行在多线程的模式下。Memcached内部对数据的操作是基于很多全局锁的(因为这部分不是多线程)。未来对多线程的改进应该是移除大量全局锁,提高Memcached在负载极高的场景下的性能。

14. Memcached能接受的key的最大长度是多少?

key的最大长度是250个字符。需要注意的是250是memcached服务器端内部的限制。
如果您的客户端支持key的前缀或者类似特性,那么实际key=前缀+原始key。其实最大长度是可以超过250字符的。但是我们推荐使用短的key,因为较短的key可以节省内存和宽带。

15. Memcached对item的过期时间有什么限制?

过期时间最大可以达到30天。Memcached吧传入的过期时间解释成一个时间点(我们可以理解为时间戳)。一旦到了这个时间点,Memcached就把item设置为失效状态。

16. Memcached最大能存储多大的单个item?

1MB(为什么是1MB呢?内存分配器的算法就是这样的!),如果数据大于1MB,可以考虑在客户端压缩或者拆分到多个key中。

17. Memcached如何更有效的使用内存?

Memcached客户端仅仅根据哈希算法来决定将某个key存储在哪个节点上。而不考虑节点的内存大小。因为我们可以在不同的节点上使用大小不等的缓存。但是一般都是这么做的:在拥有较多内存的节点上可以运行多个Memcached示例。使得每个实例使用的内存跟其他节点上的实例相同(人为去控制)。

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

其实这个最开始的时候Memcached确实是使用malloc/free来管理内存的。然后在实际工作中发现这种方式不能很好的工作。因为反复的malloc/free会造成内存碎片。OS最终花费大量的时间去查找连续的内存块来满足malloc的请求而不是运行memcached的进行。
(这一块可以联想java的垃圾回收机制来理解-标记清除的过时原因。)

19. Memcached是原子的么?

所有被发送到Memcached的单个命令都是原子的。这个有点类似于redis。就是保证每一个命令的原子性。如果发送了一个命令组:先set,再get。他们不会影响多方。会被串行化,先后执行。
但是问题来了!!!如果你发送一个命令组:set/get。但是不敢保证你get到的是你set的数据。因为可能有别的线程在你set后有把这个值set成了新值。你get到的也就是新值了。(和redis一毛一样)
然後memcached1.2.5以上提供了一些解决命令序列的原子问题。有点类似CAS的版本号。就是每次修改都带个版本号。版本号不一致写会失败。

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

其实我觉得这个题有点跟Memcached没啥关系了。是设计架构上的 单点登录吧?
反正看到了就要记录一下。先说一下什么是单点登录:Session是运行在一台服务器上的。我们可以根据客户端传来的sessionId获取session。如果session不存在则说明用户没登陆或者登录过期了。这个时候需要重新登陆。
但是问题来了。如果是集群环境下有多台服务器,那么请求会由Nginx转发。用户登录时nginx把请求转发其中一台服务器上。这个服务器创建了session并返回给客户端sessionId。但是如果下次请求被负载到其余的服务器上,那么这个session是不存在的。所以要重新登录。这种情况多了用户体验就不好了。
解决办法其实也很多。简单说几个:

  1. 粘性session
    Nginx将同一个用户请求转发至同一台服务器。(这种我个人觉得不好,而且失去了集群的意义。如果一台服务器挂了呢?并且每次转发也要多处理)
  2. 服务器session复制
    每次session发生变化(增删改)广播给所有集群中的服务器。使得所有服务器上session一致
  3. session共享
    这个有点类似于第二种方式的进化版。想要共享每个客户端都存麻烦的很。直接把session提出来单独存,但是每个服务器都可以读取。这个用redis,memcached都可以。
  4. session持久化
    这个其实目的和2,3一直。都是为了数据共享。只不过实现方式不同。都放到数据库,每个服务器都可以去读。

21. memcached和redis的区别?

这个是memcached的最后一道问答题。其实二者相似点很多,当然了肯定区别也是有的,下面一点点慢慢说

大概Redis和Memcached的区别就这么些吧,主要是内存管理,持久化,cpu利用,存储的数据结构几个方面。

本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注。也祝大家工作顺顺利利吧!愿所有的付出都有回报,愿所有的汗水都不白流!ps:最近正在求职,所以一直啃面试题。欢迎同样的小伙伴们加个好友互通有无哟!

上一篇 下一篇

猜你喜欢

热点阅读