Memcached

本文来自 58沈剑:https://mp.weixin.qq.com/s/zh9fq_e2BgdIeR8RKtY6Sg

memcache是互联网分层架构中,使用最多的的KV缓存。面试的过程中,memcache相关的问题几乎是必问的,关于memcache的面试提问,你能回答到哪一个层次呢?
画外音:很可能关乎,你拿到offer的薪酬档位。

1、第一类问题:知道不知道

这一类问题,考察用没用过,知不知道,相对比较好回答。

关于memcache一些基础特性,使用过的小伙伴基本都能回答出来:

  1. mc的核心职能是KV内存管理,value存储最大为1M,它不支持复杂数据结构(哈希、列表、集合、有序集合等);
  2. mc不支持持久化;
  3. mc支持key过期;
  4. mc持续运行很少会出现内存碎片,速度不会随着服务运行时间降低;
  5. mc使用非阻塞IO复用网络模型,使用监听线程/工作线程的多线程模型;

面对这类封闭性的问题,一定要斩钉截铁,毫无犹豫的给出回答。

2、第二类问题:为什么(why),什么(what)

这一类问题,考察对于一个工具,只停留在使用层面,还是有原理性的思考。

2.1 memcache为什么不支持复杂数据结构?为什么不支持持久化?

业务决定技术方案,mc的诞生,以“以服务的方式,而不是库的方式管理KV内存”为设计目标,它颠覆的是,KV内存管理组件库,复杂数据结构与持久化并不是它的初衷。

当然,用“颠覆”这个词未必不合适,库和服务各有使用场景,只是在分布式的环境下,服务的使用范围更广。设计目标,诞生背景很重要,这一定程度上决定了实现方案,就如redis的出现,是为了有一个更好用,更多功能的缓存服务。
画外音:我很喜欢问这个问题,大部分候选人面对这个没有标准答案的问题,状态可能是蒙圈。

2.2 memcache是用什么技术实现key过期的?

懒淘汰(lazy expiration)。(详见文末)

2.3 memcache为什么能保证运行性能,且很少会出现内存碎片?

提前分配内存。(详见文末)

2.4 memcache为什么要使用非阻塞IO复用网络模型,使用监听线程/工作线程的多线程模型,有什么优缺点?

目的是提高吞吐量。
多线程能够充分的利用多核,但会带来一些锁冲突。

面对这类半开放的问题,有些并没有标准答案,一定要回答出自己的思考和见解。

3、第三类问题:怎么做(how) | 文本刚开始

这一类问题,探测候选人理解得有多透,掌握得有多细,对技术有多刨根究底。
画外音:所谓“好奇心”,真的很重要,只想要“一份工作”的技术人很难有这种好奇心。

3.1 memcache是什么实现内存管理,以减小内存碎片,是怎么实现分配内存的?

开讲之前,先解释几个非常重要的概念:
chunk:它是将内存分配给用户使用的最小单元。
item:用户要存储的数据,包含key和value,最终都存储在chunk里。
slab:它会管理一个固定chunk size的若干个chunk,而mc的内存管理,由若干个slab组成。

画外音:为了避免复杂性,本文先不引入page的概念了。

在这里插入图片描述
如上图所示,一系列slab,分别管理128B,256B,512B…的chunk内存单元。

将上图中管理128B的slab0放大:

在这里插入图片描述
能够发现slab中的一些核心数据结构是:

  • chunk_size:该slab管理的是128B的chunk
  • free_chunk_list:用于快速找到空闲的chunk
  • chunk[]:已经预分配好,用于存放用户item数据的实际chunk空间

画外音:其实还有lru_list。

假如用户要存储一个100B的item,是如何找到对应的可用chunk的呢?

在这里插入图片描述
会从最接近item大小的slab的chunk[]中,通过free_chunk_list快速找到对应的chunk,如上图所示,与item大小最接近的chunk是128B。

为什么不会出现内存碎片呢?

在这里插入图片描述
拿到一个128B的chunk,去存储一个100B的item,余下的28B不会再被其他的item所使用,即:实际上浪费了存储空间,来减少内存碎片,保证访问的速度。
画外音:理论上,内存碎片几乎不存在。

memcache通过slab,chunk,free_chunk_list来快速分配内存,存储用户的item,那它又是如何快速实现key的查找的呢?
没有什么特别算法:
在这里插入图片描述

  • 通过hash表实现快速查找
  • 通过链表来解决冲突

用最朴素的方式,实现key的快速查找。

随着item的个数不断增多,hash冲突越来越大,hash表如何保证查询效率呢?
当item总数达到hash表长度的 1.5倍 时,hash表会动态扩容,rehash将数据重新分布,以保证查找效率不会不断降低。

扩展hash表之后,同一个key在新旧hash表内的位置会发生变化,如何保证数据的一致性,以及如何保证迁移过程服务的可用性呢(肯定不能加一把大锁,迁移完成数据,再重新服务吧)?

哈希表扩展,数据迁移是一个耗时的操作,会有一个专门的线程来实施,为了避免大锁,采用的是“分段迁移”的策略。

当item数量达到阈值时,迁移线程会分段迁移,对hash表中的一部分桶进行加锁,迁移数据,解锁:

  • 一来,保证不会有长时间的阻塞,影响服务的可用性
  • 二来,保证item不会在新旧hash表里不一致

新的问题来了,对于已经存在与旧hash表中的item,可以通过上述方式迁移,那么在item迁移的过程中,如果有新的item插入,是应该插入旧hash表还是新hash表呢?
memcache的做法是,判断旧hash表中,item应该插入的桶,是否已经迁移至新表中:

  • 如果已经迁移,则item直接插入新hash表
  • 如果还没有被迁移,则直接插入旧hash表,未来等待迁移线程来迁移至新hash表

为什么要这么做呢,不能直接插入新hash表吗?
memcache没有给出官方的解释,楼主揣测,这种方法能够保证一个桶内的数据,只在一个hash表中(要么新表,要么旧表),任何场景下都不会出现,旧表新表查询两次,以提升查询速度。

memcache是怎么实现key过期的,**懒淘汰(lazy expiration)**具体是怎么玩的?

实现“超时”和“过期”,最常见的两种方法是:

  • 启动一个超时线程,对所有item进行扫描,如果发现超时,则进行超时回调处理
  • 每个item设定一个超时信号通知,通知触发超时回调处理

这两种方法,都需要有额外的资源消耗。

mc的查询业务非常简单,只会返回cache hit与cache miss两种结果,这种场景下,非常适合使用懒淘汰的方式。

懒淘汰的核心是:

  • item不会被主动淘汰,即没有超时线程,也没有信号通知来主动检查
  • item每次会查询(get)时,检查一下时间戳,如果已经过期,被动淘汰,并返回cache miss

举个例子,假如set了一个key,有效期100s:

  • 在第50s的时候,有用户查询(get)了这个key,判断未过期,返回对应的value值
  • 在第200s的时候,又有用户查询(get)了这个key,判断已过期,将item所在的chunk释放,返回cache miss

这种方式的实现代价很小,消耗资源非常低:

  • 在item里,加入一个过期时间属性
  • 在get时,加入一个时间判断

内存总是有限的,chunk数量有限的情况下,能够存储的item个数是有限的,假如chunk被用完了,该怎么办?

仍然是上面的例子,假如128B的chunk都用完了,用户又set了一个100B的item,要不要挤掉已有的item?

要。

这里的启示是:

  • 即使item的有效期设置为“永久”,也可能被淘汰;
  • 如果要做全量数据缓存,一定要仔细评估,cache的内存大小,必须大于,全量数据的总大小,否则很容易采坑;

挤掉哪一个item?怎么挤?
这里涉及LRU淘汰机制。

如果操作系统的内存管理,最常见的淘汰算法是FIFO和LRU:

  • FIFO(first in first out):最先被set的item,最先被淘汰
  • LRU(least recently used):最近最少被使用(get/set)的item,最先被淘汰

使用LRU算法挤掉item,需要增加两个属性:

  • 最近item访问计数
  • 最近item访问时间

并增加一个LRU链表,就能够快速实现。
画外音:所以,管理chunk的每个slab,除了free_chunk_list,还有lru_list。

思路比结论重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用FastReport报表工具生成报表PDF文档

在我们开发某个系统的时候,客户总会提出一些特定的报表需求,固定的报表格式符合他们的业务处理需要,也贴合他们的工作场景,因此我们尽可能做出符合他们实际需要的报表,这样我们的系统会得到更好的认同感。本篇随笔介绍…

DXSDK_June10安装错误

今天安装DXSDK_Jun10时(下载地址:http://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe),出现错误Error Code:s1023 错误原因: 计算机上有安装过更新版的Microsoft Vi…

相交链表

1、题目描述 编写一个程序,找到两个单链表相交的起始节点。 如下面的两个链表: 在节点 c1 开始相交。 示例 1: 输入:intersectVal 8, listA [4,1,8,4,5], listB [5,0,1,8,4,5], skipA 2, skipB 3 输出:Refe…

Kullback-Leibler Divergence

本文转自:http://www.cnblogs.com/ywl925/p/3554502.html KL距离,是Kullback-Leibler差异(Kullback-Leibler Divergence)的简称,也叫做相对熵(Relative Entropy)。它衡量的是相同事件空间里的两…

Shader 坐标转换

转自:http://www.ownself.org/blog/2010/kong-jian-zuo-biao-zhuan-huan.html 这个比较基础了,不过基础最重要,往往应该理解透彻,并且反复复习。 我们知道在3D画面渲染过程中对于模型的计算的一部分被称为Transforming and Ligh…

致所有.Net者和有梦想的朋友们 - 共勉

这篇文章很早就想写的了,主要是人到了一定的年纪,就想唠叨一些看法,认不认可不重要,重要的是生活给予你的酸甜苦辣,你都想一吐为快。 这里主要基于多年来自己的一个行业感受和以及生活感想,唠叨一下工作以及…

ReLU的起源

论文参考:Deep Sparse Rectifier Neural Networks 网页参考:http://www.mamicode.com/info-detail-873243.html 起源:传统激活函数、脑神经元激活频率研究、稀疏激活性 传统Sigmoid系激活函数 传统神经网络中最常用的两个激活函数&…

Asp.NET Core 轻松学-项目目录和文件作用介绍

前言上一章介绍了 Asp.Net Core 的前世今生,并创建了一个控制台项目编译并运行成功,本章的内容介绍 .NETCore 的各种常用命令、Asp.Net Core MVC 项目文件目录等信息,通过对命令的学习和操作,对项目结构的认识,进一步理…

Dubbo 常见服务治理策略

1、Dubbo体系结构 2、Dubbo容错机制 Dubbo集群容错架构图 各节点关系: 这里的Invoker是Provider的一个可调用Service的抽象,Invoker封装了Provider地址及Service接口信息。Directory代表多个Invoker,可以把它看成List,但与Lis…

IT技术人员的35个特点,你占几个?

作者:zollty,资深程序员和架构师,私底下是个爱折腾的技术极客,架构师社区合伙人!1、价值观对生活的一般看法:追求简单,安定,可控制的生活,但对家庭生活的责任持消极态度草…

asp.net core 腾讯验证码的接入

asp.net core 腾讯验证码的接入Intro之前使用的验证码服务是用的极验验证,而且是比较旧的,好久之前接入的,而且验证码服务依赖 Session,有点不太灵活,后来发现腾讯也有验证码服务,而且支持小程序&#xff0…

ffmpeg加环境变量

转自:http://blog.csdn.net/leixiaohua1020/article/details/19016469 FFMPEG是命令行工具,因此使用起来多少还是会有些不方便。在这记录两点方便使用FFMPEG的方法: 1.任何目录下都可以使用FFMPEG 问题描述:需要转码(播…

.NET Core 微信公众号小程序6种获取UnionID方法,你知道哪几种?

前言获取UnionID是开发微信公众号/小程序中很有必要的一个环节,特别是针对一个公司拥有多个公众号小程序而推出的机制,实现打通账户一体化,用UnionID来区分多平台的唯一性。官方的解释:如果开发者拥有多个移动应用、网站应用、和公…

.NET LINQ分析AWS ELB日志避免996

前言小明是个单纯的 .NET开发,一天大哥叫住他,安排了一项任务:“小明,分析一下我们 超牛逼网站上个月的所有 AWS ELB流量日志,这些日志保存在 AWS S3上,你分析下,看哪个 API的响应时间中位数最长…

网络摄像头实时获取信息

转自&#xff1a;http://blog.csdn.net/yong_hen/article/details/42460387#quote 转自&#xff1a;http://blog.csdn.net/leo2007608/article/details/9885219 代码&#xff1a; openCV版本&#xff1a;2.4.10. 平台&#xff1a;win7 [cpp] view plaincopy #include <op…

[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式

IoC主要体现了这样一种设计思想&#xff1a;通过将一组通用流程的控制权从应用转移到框架之中以实现对流程的复用&#xff0c;并按照“好莱坞法则”实现应用程序的代码与框架之间的交互。我们可以采用若干设计模式以不同的方式实现IoC&#xff0c;比如我们在前面介绍的模板方法…

微软100题第5题

转载自&#xff1a;http://blog.csdn.net/littlestream9527/article/details/8104731 http://blog.csdn.net/v_july_v/article/details/6370650 http://blog.csdn.net/insistgogo/article/details/7689297 下面&#xff0c;我试图用最清晰易懂&#xff0c;最易令人理解的思维…

北京Dotnet分享会 || 精英论坛第三期

编者按&#xff1a;没有一成不变的定律&#xff0c;没有长久不衰的流行&#xff0c;更没有一劳永逸的侥幸&#xff0c;只有自己刻苦努力、脚踏实地、兢兢业业的学习和工作&#xff0c;才会成为这个社会永远不会被淘汰的中流砥柱。一、昨夜西风凋碧树昨夜西风凋碧树&#xff0c;…

微软开源微服务运行时Dapr,赋能云原生应用开发

Dapr 是一个可移植的、由事件驱动的 Serverless 运行时&#xff0c;用于跨云和边缘构建分布式应用程序。10月9日&#xff0c;正式以 MIT 协议开源。Dapr 使开发人员能够轻松地构建弹性、无状态和有状态的微服务&#xff0c;让它们在云和边缘位置上运行&#xff0c;并包含了开发…

最大堆和最小堆

堆和栈的区别&#xff1a;一、堆栈空间分配区别&#xff1a;1、栈&#xff08;操作系统&#xff09;&#xff1a;由操作系统自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈&#xff1b;2、堆&#xff08;操作系统&…