Redis的结构和运作机制
1.数据库的结构

Redis 中的每个数据库,都由一个 redis.h/redisDb 结构表示。
typedef struct redisDb {
// 保存着数据库以整数表示的号码
int id;
// 保存着数据库中的所有键值对数据
// 这个属性也被称为键空间(key space)
dict *dict;
// 保存着键的过期信息
dict *expires;
// 实现列表阻塞原语,如 BLPOP,可用于列表
dict *blocking_keys;
dict *ready_keys;
// 用于实现 WATCH 命令,可用于事务
dict *watched_keys;
} redisDb;
Redis有id 、dict 和 expires 三个重要属性:
- id 保存数据库的号码。Redis 服务器初始化时, 它会创建出 redis.h/REDIS_DEFAULT_DBNUM 个数据库, 并 将所有数据库保存到 redis.h/redisServer.db 数组中, 每个数据库的 id 为从 0 到 REDIS_DEFAULT_DBNUM - 1 的值。当执行 SELECT number 命令时,程序直接使用 redisServer.db[number] 来切换数据库。
- dict 保存着数据库的所有键值对数据。Redis的结构可以看成字典的嵌套,类似json的数据结构。dict的内部依然是字典结构,dict的key是字符串对象,表示name,dict的值则是从string到sort-set中的任意一种对象。而删除数据库的健,实际上就是删除dict中对应的健对象和值对象。
- expires也是一个字典,保存键的过期时间,注意只保存设置过的过期时间,如果没设置,则默认为永久。
1.1 字典的底层实现
hashtable
冲突解决:链表
扩容:渐进式hash,方法是复制出一个hash表,重算hash值(java8已不再重算)。重点是,扩容和收缩不是一次性完成,而是分多次完成。期间,字典的删改查操作可以在两个hashtable上进行,则增加操作只在新hashtable上进行。当字典中保存的数据很多事,可以避免扩容影响性能。
2.过期键的检查和清除
根据不同的清楚策略,通过expires 字典来检查键是否过期:
- 检查键是否存在于 expires 字典:如果存在,那么取出键的过期时间。
- 判断当前 UNIX 时间是否大于键的过期时间,如果是,那么键已经过期。
过期键的清除有三种方式:定时删除、惰性删除和定期删除。
2.1 定时删除
创建一个定时事件,由事件处理 器自动执行键的删除操作。
优点:对内存友好
缺点:可能占用大量cpu时间
2.2 惰性删除
每次从dict字典取出键值时,检查是否过期,如果过期则删除,并返回空。
优点:对cpu友好
缺点:过期键占用内存
核心是 db.c/expireIfNeeded 函数。在读取或写入数据库之前,调用 expireIfNeeded 对输入键进行检查。如果输入键已经过期的话,那么将键、键的值、键保存在 expires 字典中的过期时间都删除掉。
2.3 定期删除
是上面两个策略的结合。每隔一段时间,对 expires 字典进行检查,并执行惰性删除。
核心是redis.c/activeExpireCycle,每当 Redis 的例行处理程序 serverCron 执行时,activeExpireCycle 都会被调用。这个函数在规定的时间限制内,尽可能地遍历各个数据库的 expires 字典,随机地检查一部分键的过期时间,并删除过期键。
2.4 对RDB、AOF和复制的影响
RDB:在创建新的 RDB 文件时,程序会对键进行检查,过期的键不会被写入到更新后的 RDB 文件 中。
AOF:当过期键被惰性删除、或者定期删除后,程序会向 AOF 文件追加一条 DEL 命令,来显式地记录该键已被删除。
复制:当服务器带有附属节点时,过期键的删除由主节点统一控制。主节点再删除过期键后,会会显式地向所有附属节点发送一 个 DEL 命令。附属节点只按DEL命令行动,当它自己碰到过期键时,只向主节点返回键已过期。
3.持久化机制
把数据由内存同步到磁盘,会Fork一个子进程来异步的完成。有三种方式,RDB、AOF和混合方式。
3.1 RDB方式
即快照,定期一次全量备份,将所有缓存进行序列化存到磁盘。
优势:灾难恢复、性能好
劣势:1、归档前断线,则这个归档周期的数据无法恢复。2、子进程工作,如果数据量大,可能影响性能。
配置:
1、修改redis.conf中的save时间:

第一个save的表示每900秒,至少一个key发生变化,则归档一次。第二个save则表示每300秒,至少10个key变化,则归档。第三个同理,是为了应对短时间内的大量服务。
2、也可以修改rdb文件的命名和保存路径:

3.2 AOF方式
以redis网络协议的格式记录对数据库进行的写命令。
优势:append模式写日志,即使宕机,不会影响已记录的日志。
劣势:同数量的数据集,AOF体量比RDB大,效率低。
配置:
在redis.conf中允许打开AOF模式,改为yes:

配置AOF的同步方式,always表示每次修改都要追加日志:

AOF的原理,两个核心函数:
save():aof_buf -> aof文件
write():aof文件 -> 磁盘
共三种模式,第二种综合性性能较好。
3.3 混合方式
增大定期归档的时间跨度,归档间隔期,用AOF记录修改命令。
4.事件
文件事件和时间事件
4.1 文件事件
Redis使用socket进行client和server的通信,来完成实现高效的命令请求处理。采用非阻塞、多路复用IO模式。
在多个客户端中实现多路复用,接受它们发来的命令请求,并将命令的执 行结果返回给客户端。
Redis 将这类因为对套接字进行多路复用而产生的事件称为文件事件。文件事件分为读事件和写事件。
读事件实现了命令请求的接收,生命周期与该客户端和服务器的连接状态相同。
写事件实现了命令结果的返回。
4.2 时间事件
时间事件完成服务器的常规操作,分为单次执行事件和循环执行事件,服务器常规操作 serverCron 就是循环事件。
其实现结构是无序链表,所以查询的时间复杂度为O(N)。
文件事件和时间事件之间是合作关系:一种事件会等待另一种事件完成之后再执行,不会出现抢占情况。由于优先级的问题,时间事件的实际执行时间通常会比预定时间晚一些。
5.参考
《Redis设计和实现》黄健宏
《Redis实战》
Redis的结构和运作机制的更多相关文章
- Redis的内部运作机制
本文将分五个部分来分析和总结Redis的内部机制,分别是:Redis数据库.Redis客户端.Redis事件.Redis服务器的初始化步骤.Redis命令的执行过程. 首先介绍一下Redis服务器的状 ...
- redis(一)内部机制的介绍和启动过程
redis(一)内部机制的介绍和启动过程 redis的基本介绍 redis服务端 redis客户端 redis的持久化 redis中的文件事件和时间时间 redis的启动过程 redis的基本介绍 r ...
- Redis Cluster架构和设计机制简单介绍
之前另一篇文章也介绍了 Redis Cluster (link,在文章的后半部分) 今天看到这一篇,简单说一下(http://hot66hot.iteye.com/blog/2050676) 作者的目 ...
- Redis短结构与分片
本文将介绍两种降低Redis内存占用的方法——使用短结构存储数据和对数据进行分片. 降低Redis内存占用有助于减少创建快照和加载快照所需的时间.提升载入AOF文件和重写AOF文件时的效率.缩短从服务 ...
- AsyncLocal的运作机制和陷阱
这是今天帮柠檬分析一个AsyncLocal相关的问题时发现的. 试想这个代码输出的值是多少? using System; using System.Threading; using System.Th ...
- JVM内存结构,运行机制
三月十号,白天出去有事情出去了一天,晚上刚到食堂就接到阿里电话, 紧张到不行,很多基础的问题都不知道从哪里说了orz: 其中关于JVM内存结构,运行机制,自己笔记里面有总结的,可当天还是一下子说不出来 ...
- Redis系列之----Redis的两种持久化机制(RDB和AOF)
Redis的两种持久化机制(RDB和AOF) 什么是持久化 Redis的数据是存储在内存中的,内存中的数据随着服务器的重启或者宕机便会不复存在,在生产环境,服务器宕机更是屡见不鲜,所以,我们希望 ...
- 《【面试突击】— Redis篇》-- Redis的主从复制?哨兵机制?
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注左上角编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的主从复制?哨兵机制? 在这个 ...
- 《【面试突击】— Redis篇》-- Redis哨兵原理及持久化机制
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis哨兵原理及持久化机制 在这个系列里, ...
随机推荐
- 利用TortoiseGit向Github上传文件
利用TortoiseGit向Github上传文件 第一步:建一个新文件夹,作为本地仓库 第二步:右键选择设置为版本库 若弹出,确认即可 重新打开改文件,会发现多了一个绿色的小勾 在文件夹中会自动生成一 ...
- Go基础结构与类型01---常量变量表达式
// 包名(main包下的main函数是程序的入口) package main // 导入sdk(software developing kit)中的fmt包 import "fmt&quo ...
- Python+Selenium学习笔记2 - 字符串
跟着网络课程学了几个小程序. 1.判断a字符串是否为b字符串的子串 1 # coding = utf-8 2 3 # 判断str_a字符串是否为str_b字符串的子串 4 5 str_a = &quo ...
- 对标 Spring Boot & Cloud ,轻量框架 Solon 1.4.12 发布
Solon 是一个轻量的Java基础开发框架.强调,克制 + 简洁 + 开放的原则:力求,更小.更快.更自由的体验.支持:RPC.REST API.MVC.Job.Micro service.WebS ...
- Keil MDK5 安装教程(附安装包百度云)
关注微信公众号"龙行单片机",后台回复"安装包"获取最新安装包百度云链接. 1.MDK5.11a 安装 双击 mdk511a.exe,进行安装.这里我们将其安装 ...
- 闵可夫斯基引擎Minkowski Engine
闵可夫斯基引擎Minkowski Engine Minkowski引擎是一个用于稀疏张量的自动微分库.它支持所有标准神经网络层,例如对稀疏张量的卷积,池化,解池和广播操作.有关更多信息,请访问文档页面 ...
- 使用NVIDIA GRID vPC支持视频会议和算力工具
随着2020年的发展,远程工作解决方案已成为许多人的新常态.企业正在寻找行之有效的解决方案,如虚拟桌面基础设施(VDI),以使他们的团队能够在任何地方安全地工作.然而,最新的算力和视频会议应用程序需要 ...
- 用华为MindSpore进行分布式训练
技术背景 分布式和并行计算,在计算机领域是非常重要的概念.对于一些行外人来说,总觉得这是一些很简单的工作,但是如果我们纵观计算机的硬件发展史,从CPU到GPU,再到TPU和华为的昇腾(NPU),乃至当 ...
- C#搞跨平台UI,封装Cef作为Cpf的控件支持Windows,Linux,Mac
终于封装完成了,采用离屏渲染方式,支持JS和C#互相调用,C#方法自动绑定到JS里,中文输入有自动调整输入法位置. 基于开源的CefGlue 移植,本来想用CefSharp,不过这个里面有很多C++的 ...
- 深入理解java虚拟机笔记Chapter3-垃圾收集器
垃圾收集器 垃圾收集(Garbage Collection,GC),它的任务是解决以下 3 件问题: 哪些内存需要回收? 什么时候回收? 如何回收? 本节补充知识: ① s:Survivor区 新生代 ...