Redis数据持久化和缓存淘汰机制
mhr18 2024-11-26 12:07 21 浏览 0 评论
Redis数据持久化和缓存淘汰机制
1、Redis持久化
- 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。持久化的话是Redis高可用中比较重要的一个环节,因为Redis数据在内存的特性,持久化必须得有。
- Redis 提供 RDB 和 AOF 两种持久化机制,RDB是Redis默认的持久化方式。
1.1、RDB原理
- RDB持久化产生的RDB文件是一个经过压缩的二进制文件,这个文件被保存在硬盘中,redis可以通过这个文件还原数据库当时的状态。
- RDB文件可以通过两个命令来生成: SAVE:阻塞redis的服务器进程,直到RDB文件被创建完毕。BGSAVE:派生(fork)一个子进程来创建新的RDB文件,记录接收到BGSAVE当时的数据库状态,父进程继续处理接收到的命令,子进程完成文件的创建之后,会发送信号给父进程,而与此同时,父进程处理命令的同时,通过轮询来接收子进程的信号。
- RDB 是把内存中的数据集以快照形式写入磁盘,实际操作是通过 fork 子进程执行,采用二进制压缩存储;使用 fork 的目的最终一定是为了不阻塞主进程来提升 Redis 服务的可用性
快照实现过程
- Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
- 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
- **在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令 ),操作系统会将该片数据复制一份以保证子进程的数据不受影响,**所以新的RDB文件存储的是执行fork一刻的内存数据。
1.2、AOF原理
- AOF持久化是备份数据库接收到的命令,所有被写入AOF的命令都是以redis的协议格式来保存的。
- AOF 是以文本日志的形式记录 Redis处理的每一个写入或删除操作。在AOF持久化的文件中,数据库会记录下所有变更数据库状态的命令,除了指定数据库的select命令,其他的命令都是来自client的,这些命令会以追加(append)的形式保存到文件中。
- redis可以在AOF文件体积变得过大时,自动在后台重写AOF,重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合,整个重写操作是绝对安全的,
- 因为redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中停机,现有的AOF文件也不会丢失。而一旦新AOF文件创建完毕,redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。
1.3、小结
- RDB 是把内存中的数据集以**快照形式写入磁盘,实际操作是通过 fork 子进程执行,采用二进制压缩存储;AOF 是以文本日志的形式**记录 Redis 处理的每一个写入或删除操作。
- RDB 把整个 Redis 的数据保存在单一文件中,比较适合用来做灾备,但缺点是快照保存完成之前如果宕机,这段时间的数据将会丢失,另外保存快照时可能导致服务短时间不可用。
- AOF对日志文件的写入操作使用的追加模式,有灵活的同步策略,支持每秒同步、每次修改同步和不同步,缺点就是相同规模的数据集,AOF 要大于 RDB,AOF 在运行效率上往往会慢于 RDB。
- Redis本身的机制是 AOF持久化开启且存在AOF文件时,优先加载AOF文件; 因为AOF的数据是比RDB更完整的
2、Redis缓存淘汰机制
2.1、key过期策略
- Redis key的过期时间和永久有效分别EXPIRE和PERSIST命令进行设置
- Redis的过期策略,是有定期过期和惰性过期两种 定期过期:每隔一定的时间,会随机扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。默认100ms就随机抽一些设置了过期时间的key,去检查是否过期,过期了就删了。 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。
“
但是仅仅通过设置过期时间还是有问题的。如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期 key 堆积在内存里,导致 Redis 内存块耗尽了。怎么解决这个问题呢? Redis 内存淘汰策略
2.2、内存淘汰策略
Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
- noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。 设置过期时间的键空间选择性移除
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
“
Redis的内存淘汰策略的选取并不会影响过期的key的处理。
内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。
3、常见缓存淘汰算法
FIFO(先入先出)
- FIFO (First In FIrst Out) 是最简单的算法,原理跟名字一样,“如果一个数据最先进入缓存中,则应该最早淘汰掉”。
- 把缓存中的数据看成一个队列,最先加入的数据位于队列的头部,最后加入位于队列的尾部。当缓存空间不足需要执行缓存淘汰操作时,从队列的头部开始淘汰。
LRU(最近最少被使用)
- LRU (Least Recently Used) 的核心思想是基于**“如果数据最近被访问过,它在未来也极有可能访问过”**。
- 同样把缓存看成一个队列,访问一个数据时,如果缓存中不存在,则插入到队列尾部;如果缓存中存在,则把该数据移动到队列尾部。当执行淘汰操作时,同样从队列的头部开始淘汰。
- Java 中可以直接使用 LinkedHashMap 来实现
LFU(最不经常使用)
- LFU (Least Frequently Used)的核心思想是**“如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小”**,会记录数据访问的次数,当需要进行淘汰操作时,淘汰掉访问次数最少的数据。
- 如果一开始 1 被连续访问了两次,接下来 2 被访问一次,3 被访问一次,按照访问次数排序,访问次数少的处于队列头部。当 4 加入时,执行缓存淘汰,2 位于队列头部被淘汰。
4、手写LRU
“
手写LRU是leetcode原题,同时也是我面试腾讯的一面面试真题,请务必会写!!!
4.1、题目描述
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
- 获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
- 写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
4.2 题解
LeetCode原题地址
LRU 缓存算法的核心数据结构就是哈希链表,双向链表和哈希表的结合体。
class LRUCache {
// key -> Node(key, val)
private HashMap<Integer, Node> map;
// Node(k1, v1) <-> Node(k2, v2)...
private DoubleList cache;
// 最大容量
private int cap;
public LRUCache(int capacity) {
this.cap = capacity;
map = new HashMap<>();
cache = new DoubleList();
}
public int get(int key) {
if (!map.containsKey(key))
return -1;
int val = map.get(key).val;
// 利用 put 方法把该数据提前
put(key, val);
return val;
}
public void put(int key, int val) {
// 先把新节点 x 做出来
Node x = new Node(key, val);
if (map.containsKey(key)) {
// 删除旧的节点,新的插到头部
cache.remove(map.get(key));
cache.addFirst(x);
// 更新 map 中对应的数据
map.put(key, x);
} else {
if (cap == cache.size()) {
// 删除链表最后一个数据
Node last = cache.removeLast();
map.remove(last.key);
}
// 直接添加到头部
cache.addFirst(x);
map.put(key, x);
}
}
//定义双向链表节点类 为了简化,key 和 val 都认为是 int 类型
class Node{
private int key,value;
private Node prev, next;
public Node(int key,int value){
this.key = key;
this.value = value;
}
}
// Node 类型构建一个双链表,实现几个需要的 API 这些操作的时间复杂度均为 O(1)
class DoubleList {
private Node head, tail; // 头尾虚节点
private int size; // 链表元素数
public DoubleList() {
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
size = 0;
}
// 在链表头部添加节点 x
public void addFirst(Node x) {
x.next = head.next;
x.prev = head;
head.next.prev = x;
head.next = x;
size++;
}
// 删除链表中的 x 节点(x 一定存在)
public void remove(Node x) {
x.prev.next = x.next;
x.next.prev = x.prev;
size--;
}
// 删除链表中最后一个节点,并返回该节点
public Node removeLast() {
if (tail.prev == head)
return null;
Node last = tail.prev;
remove(last);
return last;
}
// 返回链表长度
public int size() { return size; }
}
}
末
我是一名后端开发工程师,个人公众号:任冬学编程
如果文章对你有帮助,不妨收藏,转发,在看起来~
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)