Redis设计与实现——单机数据库的实现
数据库
服务器中的数据库
redisClient切换数据库
redis客户端默认目标数据库为0号数据库,可以通过SELECT命令来切换目标数据库。
客户端状态redisClient结构的db属性记录了客户端当前的目标数据库,这个属性是指向redisdb结构的指针。
typedef struct redisClient{
//记录客户端当前正在使用的数据库
redisDb *db;
} redisClient;
数据库键空间
Redis是一个键值对数据库服务器,服务器中的每个数据库都由一个redis.h/redisDb结构表示,其中redisDB的dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间。
typedef struct redisDb{
// 数据库键空间,保存着数据库中的所有键值对
dict *dict
} redisDb;
键空间和用户所见的数据库是直接对应的:
1)键空间的键也就是数据库的键,每个键都是一个字符串对象。
2)键空间的值也就是数据库的值,每个值可以是字符串对象,列表对象,哈希表对象,集合对象和有序集合对象中任意一种Redis对象。
e.g.
redis > SET message "hello world"
ok
redis > RPUSH alphabet "a" "b" "c" redis > HSET book namr "Redis in Action" redis > HSET book author "Josiah L. Carlson" redis > HSET book publisher "Manning"
读写键空间时的维护操作
当使用Redis命令对数据库进行读写时,服务器不仅对键空间执行指定的读写操作。还会执行一些额外的维护工作。
1)对一个键的读取命中次数和未命中次数,在INFO stats命令的keyspace_hits属性和keyspace_misses属性中查看。
2)读取一个键之后,服务器会更新键的LRU时间,这个值可以用于计算键的闲置时间。
3)读取一个键发现键已经过期了,那么服务器会删除这个过期键,然后才执行余下的其他操作。
4)如果有客户端使用WATCH命令监视某个键,被修改之后会记为脏(dirty),让事务程序注意到这修改。
5)每次修改一个键之后,都会对脏(dirty)键计数器的值增1,这个计数器会触发服务器的持久化以及复制操作。
6)键的修改触发数据库通知功能。
设置键的生存时间或过期时间
保存过期键:
typedef struct redisDb{
//过期字典,保存着键的过期时间
dict *expires;
} redisDb;
移除过期时间,计算并返回剩余生存时间,过期键的判定类似。
过期键删除策略
三种策略;定时删除,惰性删除,定期删除。
redis的过期删除策略
Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,服务器可以很好地合理使用CPU时间和避免浪费内存空间之间取得平衡。
懒性删除策略的实现: 定期删除策略的实现:
AOF,RDB和复制功能对过期键的处理
RDB持久化:
生成RDB文件将过滤过期键。
载入RDB文件,如果是主服务器模式运行,过滤过期键;如果是从服务器模式运行,则一并载入,主从数据同步会清空从节点数据,所以不会有影响。
AOF持久化:
同样对写AOF文件,会过滤过期键。
复制功能:
数据库通知
总结
RDB持久化
RDB文件的创建和载入
保存RDB二进制文件,使用SAVE,BGSAVE,其中save命令会堵塞进程,而bgsave会启动后台进程。如果启动了AOF持久化,那优先载入AOF日志。
自动间隔性保存
#设置保存条件
save 服务器在900秒之内,对数据库进行了至少1次修改
save 服务器在300秒之内,对数据库进行了至少10次修改
save 服务器在60秒之内,对数据库进行了至少10000次修改 #实现
struct redisServer{
//计入了保存条件的数组
struct saveparam *saveparam
//dirty修改计数器 表示服务器在上次保存后,对数据库状态共进行多少次修改
long long dirty
//上一次执行保存的时间
time_t lastsave
} struct saveparam {
//秒数
time_t seconds;
//修改数
int changes
} #检查保存条件是否满足,则每隔100毫秒周期性执行ServerCron函数,遍历条件数组saveparam,对满足条件的数据库,计数器置为0,并更新上次保存时间。
总结:
AOF持久化
与RDB持久化不同的是,aof持久化是通过写命令来保存数据库状态,而RDB保存的是键值对。
AOF持久化实现
AOF持久化功能分为:命令追加,文件写入,文件同步三个步骤。
命令追加:
struct redisServer{
//AOF缓冲区 写命令按照一定格式会追加到缓冲区
sds aof_buf;
}
AOF文件的写入与同步:
def eventLoop():
while True :
#处理文件事件,接受命令请求以及发送命令回复
processFileEvents()
#处理时间事件 类似于ServerCron定期执行函数
processTimeEvents()
#考虑是否将aof_buf中的内容写入和保存到AOF文件里面,三个选项
flushAppendOnlyFile()
AOF文件的载入与数据还原
AOF文件重写
Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同。
但新的AOF文件不包含冗余命令,所以体积相对较小。
AOF后台重写:
为了解决数据不一致问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用。
当子进程完成AOF重写工作之后,会向父进程发送一个信号,父进程会调用一个信号处理函数并执行以下操作:
1)将AOF重写缓冲区中所有内容写入新AOF文件中,这时新AOF保存的数据库状态==服务器当前数据库状态;
2)对新的AOF文件改名,原子替换旧的AOF文件;
注意:只有信号处理函数执行时会对服务器进程造成堵塞,对性能造成的影响降到最低。
总结:
事件
文件事件:
I/O多路复用程序总是会将所有产生事件的套接字都放在一个队列里面,并串行化地向文件事件分派器传送套接字。
时间事件
服务器将所有时间事件都放在一个无序链表中,每当时间事件执行器运行时,它就会遍历整个链表,查找所有已到达的时间事件,并调用相应的事件处理器。
Redis时间事件分为两类:
定时事件:让一段程序在指定的时间之后执行一次。
周期性事件:让一段程序每隔指定时间就执行一次。
事件的调度与执行
总结:
客户端
struct redisServer{
//一个保存所有client的链表
list *clients;
}
客户端属性
typedef struct redisClient{
//套接字描述符
int fd; //名字
robj *name; //标志,记录客户端角色,以及目前所处的状态
int flag; //输入缓冲区 用于保存客户端发出的命令请求
sds querybuf; //其他 如命令参数,参数个数,输出缓冲区,身份认证,时间
}redisClient;
客户端的创建与关闭
当客户端与服务器通过网络建立连接时,服务器就会调用连接处理事件,为客户端创建相应的客户端状态,并将新的客户端状态添加到服务器状态结构clients链表的尾链。
伪客户端:
Lua脚本的伪客户端
AOF文件的伪客户端
总结:
服务端
Redis设计与实现——单机数据库的实现的更多相关文章
- redis实现与分析-单机数据库实现
数据库 1,1个数据库数据结构和上面一样,两个字典,一个包含所有的键,一个包含了键的过期时间 2,redis删除过期键策略:定期+惰性 定期:一段时间开始删,删不全下次继续删 惰性:使用键的时候检察 ...
- 《Redis设计与实现》- 数据库
1. 服务器中数据库结构 Redis 服务器将所有数据库都保存在服务器状态 redisServer 结构的 db 数组中,由 redisDb 结构代表一个数据库 struct redisServer ...
- Redis 设计与实现:数据库
本文的分析都是基于 Redis 6.0 版本源码 redis 6.0 源码:https://github.com/redis/redis/tree/6.0 服务器中的数据库 Redis 服务器将绝大部 ...
- Redis设计与实现2.1:数据库和事件
数据库和事件 这是<Redis设计与实现>系列的文章,系列导航:Redis设计与实现笔记 数据库 数据库的结构定义在 redis.h/redisServer 这个结构体中,这个结构体有许多 ...
- Redis中单机数据库的实现
1. 内存操作层 zmalloc 系接口 redis为了优化内存操作, 封装了一层内存操作接口. 默认情况下, 其底层实现就是最简朴的libc中的malloc系列接口. 如果有定制化需求, 可以通过配 ...
- Redis单机数据库
单机数据库 ·Redis服务器的所有数据库都保存在redisServer.db数组中,而数据库的数量则由redisServer.dbnum属性保存. ·客户端通过修改目标数据库指针,让它指向redis ...
- Redis单机数据库的实现原理
本文主要介绍Redis的数据库结构,Redis两种持久化的原理:RDB持久化.AOF持久化,以及Redis事件分类及执行原理.最后,分别介绍了单机班Redid客户端和Redis服务器的使用和实现原理. ...
- Redis | 第4章 Redis中的数据库《Redis设计与实现》
目录 前言 1. Redis中的数据库 2. 数据库的键空间 3. 键的生成时间与过期时间 4. Redis中的过期键删除策略 5. AOF.RDB和复制功能对过期键的处理 5.1 生成 RDB 文件 ...
- 共读《redis设计与实现》-单机(一)
上一章我们讲了 redis 基本类型的数据结构 和 对象系统 ,这篇来说一下单机redis 的知识点. 一.数据库 一个数据库在redis中就有一个结构体,而数据库的结构体是由redisServer这 ...
随机推荐
- 题解 洛谷 P6351 【[PA2011]Hard Choice】
删边操作不好处理,所以先将操作倒序,将删边转化为加边. 考虑对于两个点的询问,若这两点不连通或这两个点分别处于两个不同的边双连通分量中(两点间存在桥)时,是不满足题目要求的. 可以用\(LCT\)来维 ...
- 用Python爬取双色球开奖信息,了解一下
1工具 2具体方法 1.使用python2.7编写爬取脚本 这里除了正常的爬取操作,还增加了独立的参数设定.如果没有参数,爬取的数据就在当前目录下:如果有参数,可以设定保存目录.保存文件名后缀 ...
- linux上安装mysql 5.7.22
主要步骤可以参照该网址: https://www.cnblogs.com/jxrichar/p/9248480.html 这里记录一下自己遇到的问题 1.在配置 vim /etc/my.cnf 文件的 ...
- APP自动化 -- contexts(上下文切换)
一.上下文是什么? 1.解释 1)在混合型APP中包含了 原生页面 和 H5页面,如果需要进入APP内嵌的H5页面里面去操作就需要先切换进去,如果要继续回到原生页面操作就需要切回来. 2)这个就像是 ...
- 硬核干货:5W字17张高清图理解同步器框架AbstractQueuedSynchronizer
前提 并发编程大师Doug Lea在编写JUC(java.util.concurrent)包的时候引入了java.util.concurrent.locks.AbstractQueuedSynchro ...
- 443端口被占用无法启动解决办法(如何查找进程ID)
摘自CSDN博客,原文地址:http://blog.csdn.net/pet8766/article/details/8186955 netstat -ano|findstr "443&qu ...
- 第四章 常用API(上)
4.1.Object类 描述:该类是所有类的最终根类 方法 描述 public boolean equals(Object obj) 表示某个其它对象是否"等于"此对象 publi ...
- Django学习路4_数据库添加元素,读取及显示到网页上
在 views 中实现对数据库的添加和读取数据库 添加数据 对象 = models 中创建的类名() 对象.列名 = '字段值' 对象.save() 进行保存 return HttpResponse( ...
- 4.9 省选模拟赛 划分序列 二分 结论 树状数组优化dp
显然发现可以二分. 对于n<=100暴力dp f[i][j]表示前i个数分成j段对于当前的答案是否可行. 可以发现这个dp是可以被优化的 sum[i]-sum[j]<=mid sum[i] ...
- lamp分离部署
目录 lamp分离部署 1. 安装httpd 2. 安装mysql 3. 安装php 4. 配置apache并部署项目 4.1 启用代理模块 4.2 配置虚拟主机 4.3 部署PbootCMSPHP企 ...