redis的一些重要的基础知识

news2024/11/15 9:22:02

文章目录

    • 1. rehash
      • 1.1 redis的hash表的数据结构
    • 2. AOF日志
      • 2.1 简要介绍
      • 2.2 AOF重写
    • 3. RDB快照
      • 3.1 执行过程
      • 3.2 存在问题
      • 解决方式

1. rehash

本文只介绍数据结构和结果图,如果要看文字描述过程,可以参考链接:rehash的详细过程

1.1 redis的hash表的数据结构

在这里插入图片描述
dictType类型:

type dictType struct {
    hashFunction   func(key interface{}) uint32
    keyDup         func(privdata interface{}, key interface{}) interface{}
    valDup         func(privdata interface{}, obj interface{}) interface{}
    keyCompare     func(privdata interface{}, key1 interface{}, key2 interface{}) int
    keyDestructor  func(privdata interface{}, key interface{})
    valDestructor  func(privdata interface{}, obj interface{})
}
//hashFunction:哈希函数,用于计算键的哈希值; MurmurHash方法
//keyDup:键复制函数,用于插入插入键值对
//valDup:值复制函数, 用于插入键值对
//keyCompare:键比较函数,用于比较两个键是否相等,用于查找键值对;
//keyDestructor:键销毁函数,用于释放键占用的内存;
//valDestructor: 值销毁函数,用于释放值占用的内存;

dict类型:

type dict struct {
    ht [2]*dictht //两个hash表
    rehashIndex int // 表示重新哈希的索引位置(如果等于 -1,则表示没有进行重新哈希)
    iterators uint32 //当前正在迭代的迭代器数
    randomSeed uint64 //是一个随机种子,用于在哈希函数中生成随机值
    privdata interface{} //私有数据,保存着dictType结构中函数的 参数,保存哈希表的一些额外信息
    type_ *dictType //指向了一个 dictType 结构体,用于实现哈希表的各项功能。
}

dictht类型:

//dict结构中ht[0]、ht[1]哈希表的数据结构
type dictht struct {
    table []dictEntry 存放一个数组的地址,数组中存放哈希节点dictEntry的地址
    size int 哈希表table的大小,初始大小为4
    sizemask int 用于将hash值映射到table位置的索引,大小为(size-1)
    used int  //记录哈希表已有节点(键值对)的数量
}

dictEntry类型

type dictEntry struct {
    key interface{}
    v   dictEntryValue
    next *dictEntry
}
type dictEntryValue struct {
    ptr interface{}
    integer int64
    uinteger uint64
    _float float64
}

2. AOF日志

2.1 简要介绍

  • 主要作用:redis是内存存储,如果系统崩溃可能会导致数据丢失,而AOF的作用就是用来redis崩溃后数据恢复的;
  • 格式实例:AOF是直接将redis命令进行记录的,set testKey testValue这个命令:
    在这里插入图片描述
  • 该日志属于写后日志:在redis执行命令后在插入日志
    • 优点:不会阻塞当前写操作;确保写入的命令是正确执行的;
    • 缺点:redis执行成功后,数据写入AOF日志缓冲区没能及时同步,导致数据丢失,从而数据不一致;这个时候就需要选择合理的同步策略:
      在这里插入图片描述

2.2 AOF重写

  • 重写原因:作为文本记录的AOF日志,随着命令的增加,记录越来越多,从而导致了文件也越来越大,在数据恢复的时候会对系统产生较大的负担;
  • 重写步骤:
    • 主线程fork一个子线程来进行重写,用主线程如果文件过大,会阻塞主流程;
    • 子线程对AOF日志进行重写,重写过程中新来的命令记录在AOF日志和重写AOF日志缓冲区中,避免数据不一致。重写完成后,将缓冲区中的数据加入到日志中,从而完成重写。
    • 重写逻辑:即将多个命令合并成一个命令。通过这种方式,可以有效地减少AOF文件的大小,提高数据恢复的速度,并解决上述问题。因此,AOF重写确实是因为AOF日志中重复key的操作合并,以提高数据持久化的效率和效果‌。
      在这里插入图片描述
//代码浅浅编写:
func aofRewrite(newAofFileName string) {
    // 创建新的 AOF 文件
    f := createFile(newAofFileName)
    
    // 遍历数据库
    for _, db := range redisServer.db {
        // 忽略空数据库
        if db.isEmpty() {
            continue
        }
        
        // 写入 SELECT 命令,指定数据库号码
        f.writeCommand("SELECT", db.id)
        
        // 遍历数据库中的所有键
        for _, key := range db {
            // 忽略已过期的键
            if key.isExpired() {
                continue
            }
            
            // 根据键的类型对键进行重写
            switch key.type {
            case String:
                rewriteString(key, f)
            case List:
                rewriteList(key, f)
            case Hash:
                rewriteHash(key, f)
            case Set:
                rewriteSet(key, f)
            case SortedSet:
                rewriteSortedSet(key, f)
            }
            
            // 如果键带有过期时间,那么过期时间也要被重写
            if key.haveExpireTime() {
                rewriteExpireTime(key, f)
            }
        }
    }
    
    // 写入完毕,关闭文件
    f.close()
}

func rewriteString(key *Key, f *File) {
    // 使用 GET 命令获取字符串的值
    value := redis.Get(key).Val()

    // 使用 SET 命令重写字符串键
    f.writeCommand("SET", key, value)
}

func rewriteList(key *Key, f *File) {
    // 使用 LRANG 命令获取列表键包含的所有元素
    items := redis.LRange(key, 0, -1).Val()

    // 使用 RPUSH 命令重写列表键
    args := []interface{}{key}
    for _, item := range items {
        args = append(args, item)
    }
    f.writeCommand("RPUSH", args...)
}

func rewriteHash(key *Key, f *File) {
    // 使用 HGETALL 命令获取哈希键包含的所有键值对
    fieldVals := redis.HGetAll(key).Val()

    // 使用 HMSET 命令重写哈希键
    args := []interface{}{key}
    for field, value := range fieldVals {
        args = append(args, field, value)
    }
    f.writeCommand("HMSET", args...)
}

func rewriteSet(key *Key, f *File) {
    // 使用 SMEMBERS 命令获取集合包含的所有元素
    elems := redis.SMembers(key).Val()

    // 使用 SADD 命令重写集合键
    args := []interface{}{key}
    for _, elem := range elems {
        args = append(args, elem)
    }
    f.writeCommand("SADD", args...)
}

func rewriteSortedSet(key *Key, f *File) {
    // 使用 ZRANG 命令获取有序集合包含的所有元素
    memberScores := redis.ZRangeWithScores(key, 0, -1).Val()

    // 使用 ZADD 命令重写有序集合键
    args := []interface{}{key}
    for _, memberScore := range memberScores {
        args = append(args, memberScore.Score, memberScore.Member)
    }
    f.writeCommand("ZADD", args...)
}

func rewriteExpireTime(key *Key, f *File) {
    // 获取毫秒精度的键过期时间戳
    timestamp := getExpireTimeInUnixStamp(key)

    // 使用 PEXPIREAT 命令重写键的过期时间
    f.writeCommand("PEXPIREAT", key, timestamp)
}

3. RDB快照

3.1 执行过程

在这里插入图片描述

3.2 存在问题

如果快照间隔时间太短:
在这里插入图片描述
如果间隔时间过长,可能会导致数据大量丢失

解决方式

在这里插入图片描述
本文的目的只是做一个简单的记录,详细的可以参考链接:https://blog.csdn.net/m0_70325779/article/details/132409948

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

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

相关文章

最近 3 个 火火火火 的开源项目!

01 为你的敏感照片添加安全水印 EasyWatermark 是由开发者 rosuH 发起的一个开源项目,旨在帮助用户安全、轻松地为他们的照片添加水印。 这个工具不仅能够保护你的知识产权,还能在一定程度上防止照片被未经授权的人使用。EasyWatermark的核心功能包括&am…

WGCNA加权基因共表达网络一步法分析学习

WGCNA(Weighted Gene Co-expression Network Analysis,加权重基因共表达网络分析) WGCNA是一种用于分析基因表达数据的系统生物学方法。主要用于识别在基因表达数据中呈现共表达模式的基因模块,并将这些模块与样本特征&#xff0…

LSTM-Autoencoder深度学习模型在电动机异常检测中的应用

LSTM-Autoencoder深度学习模型在电动机异常检测中的应用 LSTM-Autoencoder Deep Learning Model for Anomaly Detection in Electric Motor Citation: Lachekhab, F.; Benzaoui, M.; Tadjer, S.A.; Bensmaine, A.; Hamma, H. LSTM-Autoencoder Deep Learning Model for Anoma…

Stable Diffusion绘画 | LightFlow工作流插件:一键导入,高效生图

LightFlow 是腾讯开源的工作流插件,通过它可以非常轻松地导入和导出工作流文件,从而快速地加载整个工作流。 下载后,放置在:SD安装目录\extensions,重载UI 即可使用,插件位置在生成图片区域下方&#xff1…

2024年8月31日CSDN自动提示的用法

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

视频结构化从入门到精通———检索比对类应用

检索比对类应用 1 认识“检索比对” 1.检索和比对的区别 检索和比对是信息处理和数据分析中常见的两种操作,虽然二者在一定程度上都有涉及到信息的提取和分析,但其侧重点和应用场景有所不同。检索主要关注从大规模数据集中定位相关信息,而比…

腾讯云TRTC无UI集成——分享屏幕主流、辅流(Vue2+JS+TRTC无UI集成)

先阐述一下问题,在项目中用到腾讯云的TRTC,A端发布A1、A2两个视频源,在B端订阅A1、A2使用两个view进行播放渲染 问题主流视频源和辅流视频源渲染在同一view上,控制台报错 // 播放远端视频 TRTCService.js; setRemoteVideo(view)…

智慧工地可视化整体解决方案(Word完整版)

第 一 章 系统总体设计 1.1 总体架构 1.1.1 系统拓扑 1.1.2 系统组成 1.2 设计概述 1.3 平台系统功能 1.3.1 总部数据看板 1.3.2 项目部数据看板 1.3.3 视频联网系统 1.3.4 实名制考勤系统 1.3.5 安全生产系统 1.3.6 塔吊安全监控子系统 1.3.7 施工升降机安全监控管系统 1.3.8 …

Codeforces Round 969 (Div. 2 ABCDE题) 视频讲解

A. Dora’s Set Problem Statement Dora has a set s s s containing integers. In the beginning, she will put all integers in [ l , r ] [l, r] [l,r] into the set s s s. That is, an integer x x x is initially contained in the set if and only if l ≤ x ≤…

Java程序天生就是多线程程序Java程序天生就是多线程程序吗?

一个Java程序从main()方法开始执行,然后按照既定的代码逻辑执行,看似没有其他线程参与,但实际上Java程序天生就是多线程程序,因为执行main()方法的是一个名称为main的线程。而一个Java程序的运行就算是没有用户自己开启的线程&…

AIGC提示词(2):塑造未来内容创作的核心力量

引言 🌟 在这个数字化的时代,人工智能生成内容(AIGC)正变得越来越普遍。从自动写作到图像生成,AI正以前所未有的速度和多样性创造内容。然而,要实现高质量和相关性强的内容生成,关键在于有效地…

Python变量类型

参考: Python 变量类型 | 菜鸟教程 (runoob.com) 变量赋值 Python 中的变量赋值不需要类型声明(重点注意这一点)。 每个变量在内存中创建,都包括变量的标识,名称和数据这些信息。 每个变量在使用前都必须赋值&#xff…

golang zap日志模块封装sentry

我们自己写个log日志包,把zap和sentry封装到一起。 下面直接贴上主要部分代码(两个模块初始化部分的代码请自行查阅官方文档): logger.go package logimport ("github.com/getsentry/sentry-go""go.uber.org/zap…

使用Redis如何实现集群会话同步?

使用Redis如何实现集群会话同步? 1、为什么选择Redis?2、如何实现?1. 环境准备2. 配置Web服务器3. 测试与验证4. 监控与优化 💖The Begin💖点点关注,收藏不迷路💖 在分布式Web应用中&#xff0c…

探索全能型AI与专业型AI的未来趋势

目录 前言1. 全能型AI与专业型AI的对比1.1 经济市场与用户吸引力1.2 精度与效果 2. AI模型的全面评估与比较2.1 精度2.2 速度2.3 鲁棒性 3. 专精化与可扩展性的权衡3.1 专精化的优势与挑战3.2 全能型AI的可扩展性 结语 前言 在人工智能领域,随着技术的迅猛发展&…

解决:pip install flash-attn安装失败案例【cuda】【torch】【flash-attn】

问题描述 在一个容器中部署项目环境中,遇到的flash-attn库总是安装失败,报错信息大致是:FileNotFoundError: [Errno 2] No such file or directory: :/usr/local/cuda/bin/nvcc,以及后来可能会提示’torch’未安装,却…

Android中服务(service)的基本用法

文章目录 Android中服务(service)的基本用法服务是什么定义一个服务启动和停止服务 Android中服务(service)的基本用法 服务是什么 服务(Service)是Android中实现程序后台运行的解决方案,它非…

智能停车场管理小程序的设计

管理员账户功能包括:系统首页,个人中心,用户管理,车位信息管理,车位预订管理,系统管理 微信端账号功能包括:系统首页,地图,我的 开发系统:Windows 架构模式…

Golang | Leetcode Golang题解之第386题字典序排数

题目&#xff1a; 题解&#xff1a; func lexicalOrder(n int) []int {ans : make([]int, n)num : 1for i : range ans {ans[i] numif num*10 < n {num * 10} else {for num%10 9 || num1 > n {num / 10}num}}return ans }

如何处理时间序列异常值?理解、检测和替换时间序列中的异常值

异常值的类型 (欢迎来到雲闪世界) 异常值是与正常行为有显著偏差的观察结果。 时间序列可能会因某些异常和非重复事件而出现异常值。这些异常值会影响时间序列分析&#xff0c;并误导从业者得出错误的结论或有缺陷的预测。因此&#xff0c;识别和处理异常值是确保时间序列建模…