redis内存淘汰策略-------Reservoir Sampling(水库采样)
文章目录
- 过期删除策略和内存淘汰策略
- 内存淘汰策略
- evictionPoolEntry
- evictionPoolPopulate
- Reservoir Sampling
- dictGetRandomKey
- dictGetSomeKeys
- Reservoir Sampling
- chatgpt对Reservoir Sampling的介绍
过期删除策略和内存淘汰策略
详细介绍请参考博客“redis过期删除策略和内存淘汰策略”
内存淘汰策略
为了节省内存,redis并没有采用传统的方法实现LRU和LFU而是基于随机采样的方式,近似实现LRU和LFU,并引入淘汰池进行优化。接下来详细看看是如何淘汰池进行优化的。具体实现在"evict.c"文件中的函数"evictionPoolPopulate"。
/* This is a helper function for performEvictions(), it is used in order* to populate the evictionPool with a few entries every time we want to* expire a key. Keys with idle time bigger than one of the current* keys are added. Keys are always added if there are free entries.** We insert keys on place in ascending order, so keys with the smaller* idle time are on the left, and keys with the higher idle time on the* right. */这个函数是"performEvictions()"的辅助函数。每当想要过期一些key时该函数被用来向淘汰池填充一些数据。当淘汰池未满时,keys总是被添加;反之的话,添加具有更大idle time的keys。淘汰池按照idle time升序排序,即较小idle time的key存储在淘汰池的左边,较大idle time的key存储在淘汰池的右边。
/* When an LFU policy is used instead, a reverse frequency indication is used* instead of the idle time, so that we still evict by larger value (larger* inverse frequency means to evict keys with the least frequent accesses).*/当使用LFU策略时,用反向频率reverse frequency代替idle time。按照reverse frequency升序排序,较大的inverse frequency意味着keys具有较小的lfu值即least frequent accesses。
evictionPoolEntry

evictionPoolPopulate

Reservoir Sampling
count = dictGetSomeKeys(sampledict,samples,server.maxmemory_samples);
接下来看一下随机采样的逻辑。
dictGetRandomKey
首先看一下随即采取一个dictEntry的逻辑
/* Return a random entry from the hash table. Useful to* implement randomized algorithms */
从hash table中返回一个随机entry。用来实现随机算法。

从代码中可以看出,在进行随机采样一个dictEntry时,会判断dict当前是否处于rehashing阶段,如果是的话就进行迁移操作
在"redis7.2.2|Dict"这篇文章中已经介绍过,dict何时会发生rehashing
dictGetSomeKeys
接下来看一下随机采取多个dictEntry的逻辑。
/* This function samples the dictionary to return a few keys from random* locations.** It does not guarantee to return all the keys specified in 'count', nor* it does guarantee to return non-duplicated elements, however it will make* some effort to do both things.** Returned pointers to hash table entries are stored into 'des' that* points to an array of dictEntry pointers. The array must have room for* at least 'count' elements, that is the argument we pass to the function* to tell how many random elements we need.** The function returns the number of items stored into 'des', that may* be less than 'count' if the hash table has less than 'count' elements* inside, or if not enough elements were found in a reasonable amount of* steps.** Note that this function is not suitable when you need a good distribution* of the returned items, but only when you need to "sample" a given number* of continuous elements to run some kind of algorithm or to produce* statistics. However the function is much faster than dictGetRandomKey()* at producing N elements. */
这个函数对字典进行采样,从随机位置返回几个键。
它不保证返回'count'中指定的所有键,也不保证返回不重复的元素,但是它会努力做到这两件事。
返回的指向哈希表项的指针存储在指向dictEntry指针数组的'des'中。
数组必须至少有容纳'count'元素的空间,这是我们传递给函数的参数,用于告诉我们需要多少个随机元素。
该函数返回存储在'des'中的项数,如果哈希表中包含的元素少于'count',或者在合理的步骤中没有找到足够的元素,则可能小于'count'。
请注意,当您需要返回项的良好分布时,此函数不适用,而只适用于需要“抽样”给定数量的连续元素以运行某种算法或生成统计数据时。
然而,在生成N个元素时,该函数比dictGetRandomKey()快得多。
在生成N个元素时,该函数比dictGetRandomKey()快得多。

从代码中可以看出,在进行随机采样一个dictEntry时,会判断dict当前是否处于rehashing阶段,如果是的话就进行迁移操作
在"redis7.2.2|Dict"这篇文章中已经介绍过,dict何时会发生rehashing
- 通过研究代码发现:在生成N个元素时,函数"dictGetSomeKeys"确实要比函数"dictGetRandomKey"快得多。
- 因为对于"dictGetSomeKeys"函数来说,只需要确定一个bucket然后沿着list取样即可。但是对于"dictGetRandomKey"函数每生成一个元素都需要随机找到一个bucket并且还需要计算list的长度并且找到其中一个随机位置。
Reservoir Sampling
/* Collect all the elements of the buckets found non empty while iterating
* To avoid the issue of being unable to sample the end of a long chain,
* we utilize the Reservoir Sampling algorithm to optimize the sampling process.
* This means that even when the maximum number of samples has been reached,
* we continue sampling until we reach the end of the chain.
* See https://en.wikipedia.org/wiki/Reservoir_sampling. */
为了避免在长链末端无法采样的问题,我们采用了Reservoir Sampling算法来优化采样过程。
这意味着即使达到了最大样本数,我们也会继续采样,直到到达链的末端。
有关“Reservior Sampling”的详细介绍见https://en.wikipedia.org/wiki/Reservoir_sampling。
chatgpt对Reservoir Sampling的介绍
水库采样法(Reservoir Sampling)是一种在处理大规模数据流或未知大小的数据集合时,用于从中随机抽取固定数量样本的算法。它特别适用于数据流场景,因为在数据流开始之前并不知道其总量。
核心思想
水库采样的核心思想是在处理一个可能无限大的数据流时,从中抽取固定数量的样本,使得每个数据元素被选中的概率是相同的。
操作步骤
假设我们要从数据流中随机抽取k个元素,具体步骤如下:
- 初始化:创建一个大小为k的“水库”数组,并将前k个元素直接存入水库。
- 替换阶段:
- 对于每一个新的元素(假设这是第n个元素),生成一个随机数r,该随机数的范围是[0, n-1]。
- 如果r的值小于k,则用这个新元素替换水库中的第r个元素。
- 如果r的值大于等于k,则忽略这个元素。
举例说明
假设你有一个数据流,其中包含1000个元素,你想从中随机抽取10个样本。你会按以下步骤进行:
- 将前10个元素直接放入水库。
- 对第11个元素,生成一个随机数r,范围是[0, 10]。如果r的值在0到9之间,则用第11个元素替换水库中对应位置的元素。如果r等于10,则忽略这个元素。
- 重复上述步骤,直到处理完所有的1000个元素。
优势
- 空间效率高:只需要存储k个元素的水库,不论数据流的大小如何,这使得水库采样在内存限制的环境中特别有用。
- 公平性:保证了在最终的k个样本中,数据流中的每个元素被选中的概率是相同的。
应用场景
- 在线广告系统:随机抽取用户的行为数据,用于后续分析。
- 流媒体处理:在数据流不断到来的情况下,实时生成随机样本。
水库采样是一种简单而有效的算法,特别适用于在处理大规模数据时,确保样本具有代表性。
相关文章:
redis内存淘汰策略-------Reservoir Sampling(水库采样)
文章目录 过期删除策略和内存淘汰策略内存淘汰策略evictionPoolEntryevictionPoolPopulate Reservoir SamplingdictGetRandomKeydictGetSomeKeysReservoir Samplingchatgpt对Reservoir Sampling的介绍 过期删除策略和内存淘汰策略 详细介绍请参考博客“redis过期删除策略和内存…...
C++《类和对象》(上)
在之前的C入门基础知识中我们了解了C的发展过程已经重要性,还初步了解了C中一些相比C语言特有的知识点,例如命名空间、缺少参数、函数重载、引用等,接下来在本篇中我们将开始C整个体系中非常重要的一个知识章节——类和对象,类和对…...
LLM大语言模型算法特训
百度 LLM(Large Language Model)大语言模型算法特训是一个深度学习领域的高级培训项目,专门设计用于训练和优化大规模语言模型的开发者和研究人员。本文将详细探讨LLM算法的基本原理、训练技术、应用领域以及参与者可以预期的学习收获和挑战。…...
Docker相关笔记
Docker笔记 1. Dockerfile编译构建docker Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有指令。 Dockerfile 常用的有如下关键字: FROM:指定基础镜像,后续定制操作都是基于这个基础镜像,比如: …...
前端技术day01-HTML入门
一、前端介绍 技术描述HTML用于构建网站的基础结构的CSS用于美化页面的,作用和化妆或者整容作用一样JS实现网页和用户的交互Vue主要用于将数据填充到html页面上的Element主要提供了一些非常美观的组件 二、工具软件 VsCode 在前端领域,有一个公认好用…...
Multisim 用LM358 运放模拟线性稳压器 - 运放输出饱和 - 前馈电容
就是拿运放搭一个可调的LDO 稳压器,类似下面这个功能框图里的感觉。本来应该非常简单,没什么好说的,没想到遇到了两个问题。 原理 - 理想运放 我用PNP 三极管Q2 作为输出,运放输出电压升高时,流过PNP 三极管BE 的电流变…...
宁德大屏第二版总结
碰到难点 1.wss 心跳机制 实现前端和后端双向绑定 只要后端发送了消息 前端通过全局总线去触发你想要的函数。 全局总线 vue3可以全局总线下一个mitt 新建一个eventBus.js import mitt from "mitt"; const eventBus mitt();export default eventBus; 然后wss…...
冥想第一千二百四十七天(1247)
1.今天上午带桐桐去游泳了,买了卡吉诺,吃过最好吃的甜点。推荐。还有鸡排。 2.回来后带着媳妇,先加油。去给丈母娘看腿,等丈母娘等了好久,还帮她推车。 3.回来后,在丈母娘家跑步。很舒服。家长麦田的香味。…...
基于光学动捕定位下的Unity-VR手柄交互
Unity VR 场景手柄交互实现方案 需求 在已创建好的 Unity VR 场景中,接入游戏手柄,通过结合动捕系统与 VRPN,建立刚体,实时系统获取到手柄的定位数据与按键数据,通过编写代码实现手柄的交互逻辑,实现手柄…...
php json_decode 带反斜杠字符串json解析
PHP json_decode 带反斜杠字符串json解析 今天再次遇到了json字符串中包含反斜杠的问题,记录下解决方法 在JSON字符串中,反斜杠\用作转义字符。当JSON_UNESCAPED_SLASHES选项被用于json_encode()函数时,不会在slashes前面添加反斜杠。 但是…...
【NLP】文本张量表示方法【word2vec、词嵌入】
文章目录 1、文本张量表示2、one-hot词向量表示2.1、one-hot编码代码实现:2.2、onehot编码器的使用2.3、one-hot编码的优劣势 3、word2vec模型3.1、模型介绍3.2、CBOW模式3.3、skipgram模式3.4、word2vec的训练和使用3.4.1、获取训练数据3.4.2、训练词向量3.4.3、查…...
疯狂Java讲义_08_泛型
文章目录 泛型的传参若函数里的参数使用基类接受所有的派生类,怎么做? 类型通配符的上限类型通配符的下限 泛型的传参 注意 若类 Base 是类 Derived 的基类(父类),那么数组类型 Base[] 是 Derived[] 的基类࿰…...
HCIA、OSPF笔记
一、OSI参考模型 1、OSI的结构 应用层:把人类语言转化成编码,为各种应用程序提供网络服务。 表示层:定义一些数据的格式,(对数据进行加密、解密、编码、解码、压缩、解压缩,每一层都可以实现,…...
Python删除lru_cache缓存
在 Python 中,lru_cache 是一个装饰器,用于添加缓存功能以提高函数的性能。如果你想清除或者删除 lru_cache 中的缓存,有几种方法可以做到: 手动清除缓存: lru_cache 对象有一个方法叫做 cache_clear(),可以手动清除所有缓存。示例:@lru_cache(maxsize=128) def some_fun…...
Android面试必问题:大白文讲透Android View工作原理
目录 第一章 引言 第二章 Android View 基础概念 2.1 视图(View) 2.2 布局(Layout) 2.3 绘制(Drawing) 第三章 Android View 工作原理详解 3.1 测量过程剖析 3.2 布局流程探究 第四章 Android View 性能优化建议 4.1 视图层级优化 4.2 避免过度的视觉效果 4.…...
WinDbg配置远程调试
WinDbg配置远程调试 1、为什么需要远程调试 某些特殊的场合需要远程调试,如: ①调试特殊的程序,比如在调试全屏程序,内核。 ②需要别人帮助调试或者帮助别人调试。比如由于商业性质不能直接给你pdb和源代码。 ③还有一类就是…...
spl注入实战thinkphp
目录 一、环境的部署 二、本地创建数据库 三、填写数据库连接文件 四、编写控制器 五、访问分析 debug报错会显示物理路径 原因是config.php文件相关配置 六、注入分析 七、进入断点调试 八、通过mysql执行语句查看结果 九、总结: 一、环境的部署 二、本地…...
整理深度学习时最常用的Linux命令(自用)
清华大学镜像源: https://pypi.tuna.tsinghua.edu.cn/simple/tar文件解压 tar -xzvf xxx.tar.gztar xvf xxx.tarzip文件解压 unzip xxx.zip -d path/to/your/fold清理GPU异常内存占用 杀掉 1 号显卡的所有进程 fuser -v /dev/nvidia1 | xargs -t -n 1 kill -9杀掉…...
LVS——>linux 虚拟服务器知识汇总
一、概念: LVS(Linux Virtual Server),是Linux Virtual Server的简写,也就是Linux 虚拟服务器,是一个虚拟的服务器集群系统负载均衡解决方案,它将一个真实服务器集群虚拟成一台服务器来对外提供…...
AI赋能周界安防:智能视频分析技术构建无懈可击的安全防线
周界安全防范是保护机场、电站、油库、监狱、工业园区等关键设施免受非法入侵和破坏的重要措施。传统的周界安防手段主要依靠人员巡查和物理屏障,但这种方式不仅人力成本高,而且效率较低,难以满足日益复杂多变的安全需求。随着AI技术的引入&a…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
