300分钟吃透分布式缓存-10讲:MC是怎么定位key的?

我们在进行 Mc 架构剖析时,除了学习 Mc 的系统架构、网络模型、状态机外,还对 Mc 的 slab 分配、Hashtable、LRU 有了简单的了解。本节课,将进一步深入学习这些知识点。

接下来,进入 Memcached 进阶的学习。会讲解 Mc 是如何进行 key 定位,如何淘汰回收过期失效 key 的,还将分析 Mc 的内存管理 slab 机制,以及 Mc 进行数据存储维护的关键机理,最后还会对 Mc 进行完整的协议分析,并以 Java 语言为例,介绍 Mc 常用的 client,以及如何进行调优及改进。

key 定位

哈希表

Mc 将数据存储在 Item 中,然后这些 Item 会被 slabclass 的 4 个 LRU 管理。这些 LRU 都是通过双向链表实现数据记录的。双向链表在进行增加、删除、修改位置时都非常高效,但其获取定位 key 的性能非常低下,只能通过链表遍历来实现。因此,Mc 还通过 Hashtable,也就是哈希表,来记录管理这些 Item,通过对 key 进行哈希计算,从而快速定位和读取这些 key/value 所在的 Item,如下图所示。
在这里插入图片描述
哈希表也称散列表,可以通过把 key 映射到哈希表中的一个位置来快速访问记录,定位 key 的时间复杂度只有 O(1)。Mc 的哈希表实际是一个一维指针数组,数组的每个位置称作一个 bucket,即一个桶。性能考虑的需要,Mc 的哈希表的长度设置为 2 的 N 次方。Mc 启动时,默认会构建一个拥有 6.4万 个桶的哈希表,随着新 key 的不断插入,哈希表中的元素超过阀值后,会对哈希表进行扩容,最大可以构建 2 的 32 次方个桶的哈希表,也就是说 Mc 哈希表经过多次扩容后,最多只能有不超过 43亿 个桶。

哈希表设计

对于哈希表设计,有 2 个关键点,一个是哈希算法,一个是哈希冲突解决方案。Mc 使用的哈希算法有 2 种,分别是 Murmur3 Hash 和 Jenkins Hash。Mc 当前版本,默认使用 Murmur3 Hash 算法。不同的 key 通过 Hash 计算,被定位到了相同的桶,这就是哈希冲突。Mc 是通过对每个桶启用一个单向链表,来解决哈希冲突问题的。

定位 key

Memcached 定位 key 时,首先根据 key 采用 Murmur3 或者 Jenkins 算法进行哈希计算,得到一个 32 位的无符号整型输出,存储到变量 hv 中。因为哈希表一般没有 2^32 那么大,所以需要将 key 的哈希值映射到哈希表的范围内。Mc 采用最简单的取模算法作为映射函数,即采用 hv%hashsize 进行计算。由于普通的取模运算比较耗时,所以 Mc 将哈希表的长度设置为 2 的 n 次方,采用位运算进行优化,即采用 hv&hashmask 来计算。hashmask 即 2 的 n 次方 减 1。

定位到 key 所在的桶的位置后,如果是插入一个新数据,则将数据 Item 采用头部插入法插入桶的单向链表中。如果是查找,则轮询对应哈希桶中的那个单向链表,依次比对 key 字符串,key 相同则找到数据 Item。
在这里插入图片描述
如果哈希表桶中元素太多,这个链表轮询耗时会比较长,所以在哈希表中元素达到桶数的 1.5 倍之后,Mc 会对哈希表进行 2 倍扩容。由于哈希表最多只有 43 亿左右个桶,所以性能考虑,单个 Mc 节点最多存储 65亿 个 key/value。如果要存更多 key,则需要修改 Mc 源码,将最大哈希,即 HASHPOWER_MAX, 进行调大设置。

哈希表扩容

当 Mc 的哈希表中,Item 数量大于 1.5 倍的哈希桶数量后,Mc 就对哈希表进行扩容处理。如下图所示,Mc 的哈希扩容是通过哈希维护线程进行处理的。准备开始扩容时,哈希维护线程会首先将所有 IO 工作线程和辅助线程进行暂停,其中辅助线程包括 LRU 维护线程、slab 维护线程、LRU 爬虫线程。待这些线程暂停后,哈希维护线程会将当前的主哈希表设为旧哈希表,然后将新的主哈希表扩容之前的 2 倍容量。然后,工作线程及辅助线程继续工作,同时哈希维护线程开始逐步将 Item 元素从旧哈希表迁移到主哈希表。
在这里插入图片描述
Mc 在启动时,会根据设置的工作线程数,来构建 一个 Item 锁哈希表,线程越多,构建的锁哈希表越大,对于 4 个线程,锁哈希表有 4096 个桶,对于 10 个线程,锁哈希表会有 8192 个桶,Item 锁哈希表最多有 32k 个桶,1k 是 1024,即最多即 32768 个桶。Mc 的锁哈希表中,每个桶对应一个 Item 锁,所以 Mc 最多只有 32768 个 Item 锁。

Mc 哈希表在读取、变更以及扩容迁移过程中,先将 key hash 定位到 Item 锁哈希表的锁桶,然后对 Item 锁进行加锁,然后再进行实际操作。实际上,除了在哈希表,在其他任何时候,只要涉及到在对 Item 的操作,都会根据 Item 中的 key,进行 Item 哈希锁桶加锁,以避免 Item 被同时读写而产生脏数据。Mc 默认有 4096 个锁桶,所以对 key 加锁时,冲突的概率较小,而且 Mc 全部是内存操作,操作速度很快,即便申请时锁被占用,也会很快被释放。

Mc 哈希表在扩容时,哈希表维护线程,每次按 桶链表纬度 迁移,即一次迁移一个桶里单向链表的所有 Item 元素。在扩容过程中,如果要查找或插入 key,会参照迁移位置选择哈希表。如果 key 对应的哈希桶在迁移位置之前,则到新的主哈希表进行查询或插入,否则到旧哈希表进行查询和插入。待全部扩容迁移完毕,所有的处理就会全部在新的主哈希表进行。

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

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

相关文章

QT应用软件【协议篇】周立功CAN接口卡代码示例

文章目录 USBCAN系列CAN接口卡规格参数资料下载QT引用周立功的库安装sdk代码USBCAN系列CAN接口卡 USBCAN系列CAN接口卡兼容USB2.0全速规范,可支持1/2/4/8路CAN接口。采用该接口卡,PC机可通过USB连入CAN网络,进行CAN总线数据采集和处理,主要具备以下几大优势特点: 支持车载…

正交匹配追踪(Orthogonal Matching Pursuit, OMP)的MATLAB实现

压缩感知(Compressed Sensing, CS)是一种利用稀疏信号的先验知识,用远少于奈奎斯特采样定理要求的样本数目恢复整个信号的技术。正交匹配追踪(Orthogonal Matching Pursuit, OMP)是一种常见的贪婪算法(Gree…

【CF】团队训练赛2 J-Palindrome Reversion 题解

传送门:Palindrome Reversion 标签:字符串 题目大意 规定一个操作:选择字符串中的一段区间[l,r]并使其翻转。现在给出一个字符串s,你要判断能否通过一次操作使其变为回文串。 输入:一个字符串,其长度不超…

在苹果电脑MAC上安装Windows10(双系统安装的详细图文步骤教程)

在苹果电脑MAC上安装Windows10(双系统安装的详细图文步骤教程) 一、准备工作准备项1:U盘作为系统安装盘准备项2:您需要安装的系统镜像 二、启动转换助理步骤1:找到启动转换助理步骤2:启动转换助理步骤3&…

波奇学Linux:进程通信管道

进程通信 管道:基于文件级别的单向通信 创建父子进程,使得进程的struct file*fd_array[]的文件描述符指向同一个struct file文件,这个文件是内存级文件。 父进程关写端,子进程再关闭读端。实现单向通信 子进程写入,父进…

Java面向对象(三)

一、封装: 一般意义的封装:把一段重复代码抽取成一个函数,称为代码的封装(包装)面向对象语言的封装:将类的某些信息隐藏在类的内部(通过使用不同的访问权限修饰符),不许…

C++ Primer 笔记(总结,摘要,概括)——第3章 字符串、向量和数组

目录 3.1 命名空间的using声明 3.2 标准库类型string 3.2.1 定义和初始化string对象 3.2.2 string对象上的操作 3.2.3 处理string对象中的字符 3.3 标准库类型vector 3.3.1 定义和初始化vector对象 3.3.2 向vector对象中添加元素 3.3.3 其他vector操作 3.4 迭代器介绍 3.4.…

如何使用rocketmq实现分布式事务?

什么是rocketmq事务消息 事务消息是 Apache RocketMQ 提供的一种高级消息类型,支持在分布式场景下保障消息生产和本地事务的最终一致性。 RocketMQ的分布式事务又称为“半消息事务”。 事务消息处理流程 RocketMQ是靠半消息机制实现分布式事务 事务消息&#x…

Spring之AOP源码解析(上)

Aop相关注解 EnableTransactionManagementEnableAspectJAutoProxyEnableAsync... 从注解切入来看看这些注解都干了什么 Import注解作用简述 注入的类一般继承ImportSelector或者ImportBeanDefinitionRegistrar接口 继承ImportSelector接口:selectImports方法返回…

pandas/geopandas 笔记:判断地点在不在路网上 不在路网的点和路网的距离

0 导入库 import osimport pandas as pd pd.set_option(display.max_rows,5)import osmnx as oximport geopandas as gpd from shapely.geometry import Point 1 读取数据 假设我们有 如下的数据: 1.1 新加坡室外基站位置数据 cell_stationpd.read_csv(outdoor…

TSINGSEE青犀AI智能分析网关V4初始配置与算法相关配置介绍

TSINGSEE青犀AI智能分析网关V4内置了近40种AI算法模型,支持对接入的视频图像进行人、车、物、行为等实时检测分析,上报识别结果,并能进行语音告警播放。硬件管理平台支持RTSP、GB28181协议、以及厂家私有协议接入,可兼容市面上常见…

通过例子学习golang的Goroutine

Go 语言中的 Goroutine 是一种轻量级的并发执行单位。它可以与其他 Goroutine 并发地执行,而不需要显式地管理线程的创建和销毁。Goroutine 是 Go 语言并发模型的核心组成部分,它使得编写并发程序变得更加简单和高效。 例一 创建两个function&#xff0…

linux下ffmpeg调用GPU硬件解码(VDPAU/VAAPI)保存文件

本文讲解在linux下面,如何通过ffmpeg调用GPU硬件解码,并保存解码完的yuv文件。 其实,ffmpeg自带的例子hw_decode.c这个文件,就已经能满足要求了,因此,本文就尝试讲解以下hw_decode这个例子。hw_decode.c可以…

watchpoint

前言 内存被踩,通过 watchpoint 找到真凶 实例 以 smsc911x 网卡驱动为基体,进行实验,和网卡本身功能无关, 每执行一次 ifconfig eth0 up,就会调用一次 smsc911x_open(),我在这里设计了一段代码&#xf…

数学知识(四)(容斥原理、博弈论)

一、容斥原理 容斥原理公式 一共加或者减的式子个数 (一)利用容斥原理解决求能被质数整除的数的个数 890计算能被整除的数的个数 因为一共有2^n-1种选法,可以用位运算的方式枚举,对于得到的每一种选法,根据存在的数…

六、回归与聚类算法 - 逻辑回归与二分类

线性回归欠拟合与过拟合线性回归的改进 - 岭回归分类算法:逻辑回归模型保存与加载无监督学习:K-means算法 1、应用场景 2、原理 2.1 输入 2.2 激活函数 3、损失以及优化 3.1 损失 3.2 优化 4、逻辑回归API 5、分类的评估方法 5.1 精确率和召回率 5.2…

找出作弊的人

文章目录 题目描述输入描述输出描述样例1解释:样例2代码 题目描述 公司组织了一次考试,现在考试结果出来了,想看一下有没人存在作弊行为,但是员工太多了,需要先对员工进行一次过滤,再进一步确定是否存在作弊行为。 过滤的规则为:找到分差最小的员工ID对(p1,p2)列表…

【Spring】IoC容器 控制反转 与 DI依赖注入 配置类实现版本 第四期

文章目录 基于 配置类 方式管理 Bean一、 配置类和扫描注解二、Bean定义组件三、高级特性:Bean注解细节四、高级特性:Import扩展五、基于注解配置类方式整合三层架构组件总结 基于 配置类 方式管理 Bean Spring 完全注解配置(Fully Annotatio…

Kotlin学习 6

1.接口 interface Movable {var maxSpeed: Intvar wheels: Intfun move(movable: Movable): String}class Car(var name: String, override var wheels: Int 4, _maxSpeed: Int) : Movable {override var maxSpeed: Int _maxSpeedget() fieldset(value) {field value}overr…

C语言读取 ini 配置文件,修改/添加键值对

C语言读取 ini 配置文件,修改/添加键值对 C语言读取 ini 配置文件,对section中的键值对进行修改/添加,如果section不存在,则在末尾将新的section/key/value 添加进去。 一、了解什么是INI文件? ini 文件是Initializ…