Python微信订餐小程序课程视频

https://blog.csdn.net/m0_56069948/article/details/122285951

Python实战量化交易理财系统

https://blog.csdn.net/m0_56069948/article/details/122285941
上一章我们讲了 redis 基本类型的数据结构对象系统 ,这篇来说一下单机redis 的知识点。

一、数据库

一个数据库在redis中就有一个结构体,而数据库的结构体是由redisServer这个结构体持有。
也就是redis服务器对应一个redisService 结构体,一个redisServer结构体持有多个redisDB数组,并且存储了数组的大小。

Copystruct redisServer {...// 一个数组保存服务器所有的数据库redisDb *db;// 服务器的数据库的数量//初始默认为16int dbnum;// 过期字典// 保存键的过期时间dict *expires;// 记录rdb 保存条件的数组struct saveparam *saveparam;// 修改计数器long long dirty;// 上一次执行保存的时间time\_t lastsave;// aof 缓冲区sds aof_buf;// 一个链表保存了所有客户端的状态list *client;...
}

![image.png](https://img-blog.csdnimg.cn/img_convert/b4cf07917edf45bd6ffff9b1e191e2a5.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=310&id=ude179a89&margin=[object Object]&name=image.png&originHeight=310&originWidth=827&originalType=binary&ratio=1&rotation=0&showTitle=true&size=53542&status=done&style=none&taskId=u281822f5-ca95-4de7-94ef-6a4e930e2ff&title=redisServer结构图&width=827 “redisServer结构图”)

二、客户端

然后我们再说一下客户端,每个客户端是也是有一个redisClient结构体

Copytypedef struct redisClient {. . .// 客户端的名称,使用Client setname 命令设置rojb *name;// 记录客户端正在使用的数据库redisDb *db;// 套接字描述符号,伪客户端为 -1;客户端为>-1的整数int fd;// 记录了客户端的角色,可以是单个值 也可以多个值int flags;// 客户端输入缓冲区,用来保存客户端输入的请求//不能超过1G,否则会关闭sds querbuf;// 客户端发送服务端请求之后,//服务端解析请求,将命令参数保存在客户端 argv 中,命令个数 保存在argcrobj **argv;int argc;. . .
}

![image.png](https://img-blog.csdnimg.cn/img_convert/0df75950c8d2a12d3df49a3a44171912.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=199&id=uc036b757&margin=[object Object]&name=image.png&originHeight=199&originWidth=1055&originalType=binary&ratio=1&rotation=0&showTitle=true&size=66624&status=done&style=none&taskId=u61aec119-fec2-4f70-b9f1-eb340fa2940&title=服务端结构体 和 客户端结构体 关系图&width=1055 “服务端结构体 和 客户端结构体 关系图”)
客户端的结构体中db 的指针指向 当前正在使用的数据库的地址。
![image.png](https://img-blog.csdnimg.cn/img_convert/36bd74ac9035806293580e4d1d51e203.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=465&id=u5eccfb3d&margin=[object Object]&name=image.png&originHeight=465&originWidth=875&originalType=binary&ratio=1&rotation=0&showTitle=true&size=83460&status=done&style=none&taskId=uc1a4f353-0589-426d-b559-416bc4fd193&title=redisClient 关系图&width=875 “redisClient 关系图”)
![image.png](https://img-blog.csdnimg.cn/img_convert/b5b056525c7b8a87723efb1b216fce6f.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=275&id=ufde892e6&margin=[object Object]&name=image.png&originHeight=275&originWidth=934&originalType=binary&ratio=1&rotation=0&showTitle=true&size=76472&status=done&style=none&taskId=u123a8ca0-f910-49b9-9fba-59f23fa17ee&title=redisclient 客户端argv 属性&width=934 “redisclient 客户端argv 属性”)
所以当我们 使用 SELECT 命令切换数据库的时候就是将 redisClient 的db 指针切换了一个位置
![image.png](https://img-blog.csdnimg.cn/img_convert/446c577e55f26fbc25e34b1143265de1.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=426&id=u9ec6b36a&margin=[object Object]&name=image.png&originHeight=426&originWidth=808&originalType=binary&ratio=1&rotation=0&showTitle=true&size=82259&status=done&style=none&taskId=ua0d8815f-7f64-4a14-9df8-acaa5cd7109&title=client使用select之后 关系图&width=808 “client使用select之后 关系图”)
注意点
![image.png](https://img-blog.csdnimg.cn/img_convert/a7838655e7a0c91a5a44e82cc29cf023.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=244&id=u38fd45f2&margin=[object Object]&name=image.png&originHeight=244&originWidth=1247&originalType=binary&ratio=1&rotation=0&showTitle=false&size=195642&status=done&style=none&taskId=u734de4dd-bee6-4c60-9869-28b4232a98d&title=&width=1247)

三、键空间

我们之前看字典的时候已经讲过,每个数据库其实就是一个字典,我们平常存储的数据在数据库这个字典中,key是字典的key,value 是字典的value。(其实每个key 就是一个SDS结构,所以字典的key 是一个SDS 结构的存储体,value 可能是SDS 可能是 字典、序列等其他基本结构体)
![image.png](https://img-blog.csdnimg.cn/img_convert/5e27542bb6bb7522d24f7c26c8a9562c.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=664&id=Ij66O&margin=[object Object]&name=image.png&originHeight=664&originWidth=1318&originalType=binary&ratio=1&rotation=0&showTitle=true&size=250040&status=done&style=none&taskId=u24155a3a-0eb1-405d-ac94-77e0a4d6f4e&title=redisDB 空间图&width=1318 “redisDB 空间图”)

3.1 添加/更新/删除

其实键的 添加/更新/删除 就是在字典中 添加key-value 键值对 和 更新 删除 键值对的动作。

3.2 键的生存时间/过期时间

我们可以给键 设置一个时间 ,当创建之后过多久就失效生存时间;当到达某个时间点就失效过期时间

3.2.1 SETEX/SEPIRE/PEXPIRE/EXPIREAT/PEXPIREAT

键盘的过期时间,我们可以从redisServer 的结构体中可以看出,其实就是对每个键``存储了一个过期时间
![image.png](https://img-blog.csdnimg.cn/img_convert/119a957eaaf31be7480bfb960dbb2b4f.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=280&id=u228ad928&margin=[object Object]&name=image.png&originHeight=280&originWidth=1313&originalType=binary&ratio=1&rotation=0&showTitle=false&size=189635&status=done&style=none&taskId=u0eb92a1a-881a-402a-bb0e-1de8df137f0&title=&width=1313)
Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在名久)或过期时间
(键什么时候会被删除):

  • EXPIRE

  • PEXPIRE

  • BXPIREAT Stimestamp>命令用于将键 key 的过期时间设置为timestamp所指定的秒数时间戳。

  • PEXPIREAT

虽然有多种不同单位和不同形式的设置命令,但实际上 EXPIRE、PEXPIRE、EXPIREAI
三个命令都是使用 PEXPIREAT 命令来实现的:无论客户端执行的是以上四个命令中的哪-
个,经过转换之后,最终的执行效果都和执行PEXPIREAT命令一样
![image.png](https://img-blog.csdnimg.cn/img_convert/2fa501312e1cbb189467ad0a48e90619.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=275&id=uc37cf6df&margin=[object Object]&name=image.png&originHeight=275&originWidth=430&originalType=binary&ratio=1&rotation=0&showTitle=true&size=39636&status=done&style=none&taskId=u59cbe20e-0701-45db-895c-b22292e1705&title=SEPIRE/PEXPIRE/EXPIREAT/PEXPIREAT 执行关系图&width=430 “SEPIRE/PEXPIRE/EXPIREAT/PEXPIREAT 执行关系图”)
所以最后干活的是PEXPIREAT ,其他的就是对于不同业务下的衍生api 而已。

关于TTL/PTTL 命令
![image.png](https://img-blog.csdnimg.cn/img_convert/aa4f4fe5d626aaa48a3f6386186eb2bc.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=744&id=u66ed1f09&margin=[object Object]&name=image.png&originHeight=744&originWidth=1311&originalType=binary&ratio=1&rotation=0&showTitle=false&size=210351&status=done&style=none&taskId=ua3a629e7-0136-4ccf-9598-66add686e12&title=&width=1311)
![image.png](https://img-blog.csdnimg.cn/img_convert/1eeac767a9b2fccd19020a08346e005c.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=47&id=udd57ab52&margin=[object Object]&name=image.png&originHeight=47&originWidth=1196&originalType=binary&ratio=1&rotation=0&showTitle=false&size=47237&status=done&style=none&taskId=ue3887b1d-08f0-4a4a-b1ba-9a1d12018db&title=&width=1196)

3.2.2 过期键的删除策略

  • 定时删除:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。
  • 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
  • 定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

在这三种策略中,第一种和第三种为主动删除策略,而第二种则为被动删除策略。

三种策略优缺点

定时删除 能够及时释放 内存空间,但是如果遇到大量对键 过期,那么会占用很大对cpu 资源
惰性删除 能够解决cpu 资源对问题,但是 会浪费大量对存储空间,有 内存泄漏 的风险
定期删除 相当于平衡 前两种的优缺点。

一般我们将惰性删除定期删除``配合使用
具体使用:
惰性:所有读写库的redis 数据库执行 命令之前 都会调用expireIfveeded 函数检查过期时间,如果过期,那么就删除
![image.png](https://img-blog.csdnimg.cn/img_convert/e530591eb6c2d453cf72b191d27bb979.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=582&id=ub92309b4&margin=[object Object]&name=image.png&originHeight=582&originWidth=1241&originalType=binary&ratio=1&rotation=0&showTitle=true&size=225843&status=done&style=none&taskId=ubf65c1b3-3e06-4ed3-8ff0-4da25bbe291&title=惰性删除执行过程&width=1241 “惰性删除执行过程”)
定期:redis 周期性 函数Servercron执行 的时候 会调用activeExpireCycle函数,在 规定时间内 遍历一次数据库,随机的访问一些键 查看过期时间,过期删除

3.3 RDB/AOF 持久化时 过期键处理

RDB

生成
对于RDB 快照类型的,如果是过期了,那么下一次生成快照的时候就不会记录在RDB文件中
载入
如果是主服务器 加载RDB文件,那么会对键的过期时间进行检查,如果是过期了(在生成RDB文件和加载RDB文件之间的时间段内过期),那就不会被加载。
如果是从服务器 加载RDB 文件,那么不会检查过期键,全部加载。(但是和主服务器``同步的时候,从服务器的数据库都会被清空

AOF

生成:
只要还没有被删除,那么不会对AOF产生影响,AOF会全部记录,如果执行期间被删除 会增加一条DELE命令
加载:
如果是过期了,那么不会被加载

3.4 复制期间过期间处理

主服务器 删除的时候 会向 从服务器 发送删除命令
从服务器 遇到过期键 不会处理,和平常的键一样,即使客户端查询也会返回。
![image.png](https://img-blog.csdnimg.cn/img_convert/e2659e2ef859bdfe5b0c65454ba81456.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=297&id=u6043421f&margin=[object Object]&name=image.png&originHeight=297&originWidth=860&originalType=binary&ratio=1&rotation=0&showTitle=true&size=95769&status=done&style=none&taskId=u8fff085c-e34c-44be-b56a-d707d8e189a&title=从服务器过期键处理&width=860 “从服务器过期键处理”)
![image.png](https://img-blog.csdnimg.cn/img_convert/de650d6417c3bd2c807833fe3541dd01.png#clientId=ud3c5508d-badf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=233&id=u77239847&margin=[object Object]&name=image.png&originHeight=233&originWidth=987&originalType=binary&ratio=1&rotation=0&showTitle=true&size=84663&status=done&style=none&taskId=u44bafd4b-ee84-4522-ab03-60dd179e071&title=主服务器过期键处理&width=987 “主服务器过期键处理”)
我们知道 redis 是一个内存数据库,也就是所有的数据都在内存中,cpu 取数据的时候直接从内存中查找,不用在调用系统io 从磁盘加载数据了。这也就是为何redis 比其他 存储磁盘的数据库快的原因。
但是在内存中的数据有个极大的缺点:如果服务器一旦关闭,那么数据就不在了,因为内存的数据并没有写到磁盘上,所以redis 需要提供一个能够写入磁盘的机制。
redis 提供了两种持久化机制:rdb持久化 aof持久化

键空间的维护操作

当redis 命令对于数据库的读写时,服务器不仅会对键空间进行客户端的请求命令,还会执行一些额外的操作

  1. 命中率:读取一个键之后,服务器会依据进键是否存在来更新 键空间命中率 和 不命中率
  2. 闲置时间:就是键多久没有访问过了,等到命中这个键时会更新这个值。
  3. 过期键
  4. watch 命令:使用warch 命令监控一个键,那么键修改时会将这个键置成 脏
  5. 脏数据:服务器每修改一个键,会对 脏键 计数器的值+1;
  6. 数据库通知功能:如果开启这个功能,那么修改redis 会通知数据库

四、RDB 持久化

对于RDB 持久化,我们可以认为就是一个内存的快照,也就是将某一瞬间redis 的数据给存储下来。
使用这个持久化有两种命令:SAVE / BGSAVE

SAVE

这个命令持久化的时候,redis 处于阻塞状态,也就是redis 不接受客户端发过来的任何请求,全力的去处理这个请求。

BGSAVE

对于save 来说,我们要是因为持久化导致redis 不能使用,这个显然会有问题。因为如果数据量特别多,那么我们为了持久化,消耗的时间也就很多,业务阻塞了。
和save 不同,为了能够使得持久化同时也能运行客户端请求,redis 对于bgsave 分出一个线程去处理 持久化,这样就不是阻塞的了。

save 和 bgsave 不能够同时执行,考虑防止竞争问题、同时操作io的效率问题。

载入

因为RDB存储的是redis 的快照,所以redis 没有载入 rdb文件的命令,程序启动的时候会自动加载rdb文件。

另外一点需要注意的是:因为aof文件比rdb 更新的更频繁,也就是数据更新,那么存在aof文件,就会加载aof文件而不会加载rdb文件了,可以使用配置将aof文件读取关闭
![image.png](https://img-blog.csdnimg.cn/img_convert/1f94ae1dea853de6417dacbb56355fc9.png#clientId=u052a070d-6f14-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=625&id=ude3ee542&margin=[object Object]&name=image.png&originHeight=1250&originWidth=3338&originalType=binary&ratio=1&rotation=0&showTitle=true&size=959135&status=done&style=none&taskId=u9dc8bed2-c429-49a7-8e58-09ca6ef1981&title=rdb持久化&width=1669 “rdb持久化”)

自动保存条件

redis 对于bgsave 可以设置每隔多久进行一次rdb 保存的,可以通过启动是save 参数进行设置。
我们可以从redisServer 的结构中看出,这个自动保存的条件其实是存储起来的,也就是redisServer持有这个自动存储条件,并在规定条件下进行一次调用BGSAVE命令
![image.png](https://img-blog.csdnimg.cn/img_convert/456f092d64b9b1866b067c5a06f5eaf8.png#clientId=u052a070d-6f14-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=370&id=u699414a1&margin=[object Object]&name=image.png&originHeight=740&originWidth=2774&originalType=binary&ratio=1&rotation=0&showTitle=true&size=553877&status=done&style=none&taskId=u9e560f64-6ac6-40a3-88fc-9c19c090d88&title=Saveparams 结构和redisServer 关系图&width=1387 “Saveparams 结构和redisServer 关系图”)

dirty 计数器 和lastsave 属性

服务器在每执行一次操作都会更新一次dirty计数器,比如dirty 计数器为123,那么说明距离上次保存,服务器执行了123次命令。

服务器 之所以可以 自动保存,是因为 时间事件 不断的去扫描 redisServer 然后看 saveparams 属性 是否满足自动保存。然后在调用bgsave

![image.png](https://img-blog.csdnimg.cn/img_convert/c16672b2fc92180fabfa8b1f1c63c8cc.png#clientId=u052a070d-6f14-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=502&id=u6722fcb2&margin=[object Object]&name=image.png&originHeight=1004&originWidth=2756&originalType=binary&ratio=1&rotation=0&showTitle=true&size=669278&status=done&style=none&taskId=ufd2e680c-6b6a-49aa-b06c-c7e93fc1ddd&title=saveparams/dirty/lastsave 和redisServer关系图&width=1378 “saveparams/dirty/lastsave 和redisServer关系图”)
serverCrom 函数会 遍历 saveparams ,看其中的条件是不是被满足了

RDB文件结构

rdb文件以二进制形式存储,我们可以通过 od 命令来解析 rdb文件

文件结构

![image.png](https://img-blog.csdnimg.cn/img_convert/4a3960728754f32e79b2b0972e47d938.png#clientId=u22da071d-50ad-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=134&id=u37a56b83&margin=[object Object]&name=image.png&originHeight=268&originWidth=2060&originalType=binary&ratio=1&rotation=0&showTitle=true&size=151577&status=done&style=none&taskId=u19520f98-383e-49d0-9248-016f65c3a71&title=RDB 文件结构&width=1030 “RDB 文件结构”)
说明
我们用全大写表示 常量标识;使用全小写标识 变量

  1. REDIS:常量标识符(5字节)
  2. db_version:版本号(4字节)
  3. 数据库:也就是存储的具体数据,具体长度由保存的数据来说明,如果没有数据,那就没有这个字段
  4. EOF:结束标识位(1字节),也就是如果读到这个地方表示 rdb文件正文读取完毕
  5. check_sum:校验位置,就是前面的数字长度;

![image.png](https://img-blog.csdnimg.cn/img_convert/fcc9fcf5380f5f2a3c9eb8d9deb9e231.png#clientId=u22da071d-50ad-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=110&id=ua19a443f&margin=[object Object]&name=image.png&originHeight=220&originWidth=1802&originalType=binary&ratio=1&rotation=0&showTitle=true&size=133657&status=done&style=none&taskId=ubf64b792-d3be-4d11-9aea-4df74437511&title=RDB文件中数据库结构&width=901 “RDB文件中数据库结构”)
SELECTDB:常量(1字节),标识为这里是数据库
db_number:数据库号码(1-5字节不等)
key_value_pairs:数据库中具体存储的值
![image.png](https://img-blog.csdnimg.cn/img_convert/af901a665c4cc1cdb725c08721689df7.png#clientId=u22da071d-50ad-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=117&id=AYDR1&margin=[object Object]&name=image.png&originHeight=234&originWidth=3406&originalType=binary&ratio=1&rotation=0&showTitle=true&size=253228&status=done&style=none&taskId=u1819a6fd-654b-4aa6-94ed-a7f6ac4dd82&title=Rdb文件&width=1703 “Rdb文件”)

rdb文件中 数据库中 数据的值(k-v结构)

![image.png](https://img-blog.csdnimg.cn/img_convert/5adc1c33c18437004f6a95d4c27f6c42.png#clientId=u22da071d-50ad-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=110&id=ua72011a5&margin=[object Object]&name=image.png&originHeight=220&originWidth=2676&originalType=binary&ratio=1&rotation=0&showTitle=false&size=230539&status=done&style=none&taskId=u06678055-33f9-40aa-981f-262253e70c3&title=&width=1338)
EXPIRETIME_MS:常量,标识带有过期键
过期键的时间
KEYTYPE:上图写的是REDIS_RDB_TYPE_SET,这个是 存储的类型,方便读取 value 的值
key: 存储的key
value :存储的value 可能是 SDS、HASH 之类的。

五、AOF 持久化

![image.png](https://img-blog.csdnimg.cn/img_convert/809790a0632cee2e69bd7de7ba624daf.png#clientId=ub61095e0-0144-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=168&id=u70f468bb&margin=[object Object]&name=image.png&originHeight=168&originWidth=683&originalType=binary&ratio=1&rotation=0&showTitle=true&size=47260&status=done&style=none&taskId=u2c7f003f-2348-42ea-8442-322d120fbd1&title=aof 持久化&width=683 “aof 持久化”)
AOF 持久化功能的实现可以分为命令追加(append )文件写人文件同步 (sync)``三个步骤。

命令追加

当 AOF 持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到redisServer 结构体中 的 aof buf 缓冲区末尾如果在来一条命令,那么在向缓冲区末尾添加。

Redis 的服务器进程就是一个事件循环(1oop),这个循环中的文件事件负责接收客户端命令请求,以及向客户端发送命令回复,而时间事件则负责执行像servercron 函数这样需要定时运行的函数。—这段看不懂就略过,其实是 下面要说 的事件

因为服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof buf 缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用 f1ushAppendonlyFile函数,考虑是否需要将 aof buf 缓冲区中的内容写人和保存到 AOF 文件里面。
![image.png](https://img-blog.csdnimg.cn/img_convert/4cffe38880012f34afbab2a4c86e4a14.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=420&id=u98e1cc21&margin=[object Object]&name=image.png&originHeight=420&originWidth=1305&originalType=binary&ratio=1&rotation=0&showTitle=true&size=253827&status=done&style=none&taskId=u90d8ddef-794c-4ac0-aac9-e618571e888&title=AOF 持久化 属性&width=1305 “AOF 持久化 属性”)
![image.png](https://img-blog.csdnimg.cn/img_convert/11a7839c2b2eb103245ad843641b6e4d.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=621&id=u8f8af0fb&margin=[object Object]&name=image.png&originHeight=621&originWidth=1249&originalType=binary&ratio=1&rotation=0&showTitle=false&size=443180&status=done&style=none&taskId=ud606c7d1-eabc-4c21-92d1-5b9e72b8a56&title=&width=1249)
![image.png](https://img-blog.csdnimg.cn/img_convert/987257de9fe261fda3ebd66657476cf4.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=252&id=u47f01ffb&margin=[object Object]&name=image.png&originHeight=252&originWidth=1241&originalType=binary&ratio=1&rotation=0&showTitle=false&size=197373&status=done&style=none&taskId=u6f09c14c-e23c-4ae9-ac5a-08189955313&title=&width=1241)

载入/数据还原

![image.png](https://img-blog.csdnimg.cn/img_convert/d83131a4a1d5dc0a24b77f34e11c9460.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=524&id=uecb445ef&margin=[object Object]&name=image.png&originHeight=524&originWidth=665&originalType=binary&ratio=1&rotation=0&showTitle=true&size=130138&status=done&style=none&taskId=ua186305f-c95c-48d1-b016-8412f2e7d65&title=AOF 载入过程&width=665 “AOF 载入过程”)
创建一个不带网络连接伪客户端(fake client )是因为 Redis 的命令只能客户端上下文执行,而载人 AOF 文件时所使用的命令直接来源于 AOF 文件而不是网络连接,所以服务器使用了一个没有网络连接伪客户,和客户端效果是一样的。

AOF 重写

如果我们redis 运行的事件长了,那么就会使得aof 文件变得很大,而且这个文件中很多命令是浪费空间的,比如 push key v1;push key v2… 所以,redis 对aof 文件进行了重写,让这些命令合并为一条命令,减少aof 的空间

重写原理:

aof 重写 不需要 进行 读取/写入 原 aof 文件,也就是 完全 不操作原文件
他主要是看数据库中 数据的状态,使用命令将 数据库中的数据 写入文件

比如:
数据库中有个 numbers:one,two,three
这样的结构,之前是
push numbers one;
push numbers two;
push numbers three;
三个命令
我们直接读取数据库,我们不清楚过程,所以我们将之前的三个命令变成一个:
push numbers one two three
这样就是压缩了

之前重写aof 文件的时候都是 不接受新的命令,为了不影响 使用,所以使用了后台重写 命令。

后台重写,为了保证数据的一致性,使用了aof 重写缓冲区。
![image.png](https://img-blog.csdnimg.cn/img_convert/7ea98cb88ac95d7d1d6deb7630197a5b.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=315&id=ue83ed35d&margin=[object Object]&name=image.png&originHeight=315&originWidth=755&originalType=binary&ratio=1&rotation=0&showTitle=true&size=77789&status=done&style=none&taskId=ud6545515-e57d-4d72-ba8b-a96fffe5558&title=aof 重写缓冲区&width=755 “aof 重写缓冲区”)

![image.png](https://img-blog.csdnimg.cn/img_convert/7f1d41668f7fb20abd3856b5131bb841.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=811&id=u9bdc03a6&margin=[object Object]&name=image.png&originHeight=811&originWidth=1316&originalType=binary&ratio=1&rotation=0&showTitle=false&size=506993&status=done&style=none&taskId=u9745772f-28a9-499f-aa16-b941ae478fa&title=&width=1316)
![image.png](https://img-blog.csdnimg.cn/img_convert/3059e325225a45b4d107ce4b698895b7.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=494&id=u4fc0e6cd&margin=[object Object]&name=image.png&originHeight=494&originWidth=1249&originalType=binary&ratio=1&rotation=0&showTitle=false&size=401013&status=done&style=none&taskId=ua3252234-6766-4c53-953d-393760486ff&title=&width=1249)
![image.png](https://img-blog.csdnimg.cn/img_convert/f9083aa3ef740b22711dde5493c3bcde.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=297&id=uda7886e0&margin=[object Object]&name=image.png&originHeight=297&originWidth=1243&originalType=binary&ratio=1&rotation=0&showTitle=false&size=198452&status=done&style=none&taskId=u39a3e853-f73f-4a4c-94b6-d5eac9d6949&title=&width=1243)

文件写入和同步

![image.png](https://img-blog.csdnimg.cn/img_convert/d93dd8ab81ed7635456a6b2d933ff11d.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=430&id=ua96c330b&margin=[object Object]&name=image.png&originHeight=430&originWidth=1252&originalType=binary&ratio=1&rotation=0&showTitle=false&size=293289&status=done&style=none&taskId=uf345d45b-fcd5-41be-83cf-78fd4c61e0a&title=&width=1252)

六、事件

Redis 服务器是一个事件驱动程序,服务器需要处理以下两类事件:

  • 文件事件(file event ):Redis 服务器通过套接字(含义就是通过网络链接)与客户端(或者其他 Redis 服务器)进行连接,而文件事件就是服务器套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。
  • 时间事件(time event ):Redis 服务器中的一些操作(比如servercron 两数)需要在给定时间点执行,而时间事件就是服务器对这类定时操作的抽象。

文本事件

Redis 基于 Reactor模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器(file event handler):

  • 文件事件处理器使用 I/0 多路复用(multiplexing)【https://blog.csdn.net/zhangxiaoji/p/16152141.html】程序来同时监听多个套接宇,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。

![image.png](https://img-blog.csdnimg.cn/img_convert/b1b57957b181e89d6d5c11a545a1b4b8.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=242&id=ud718a96e&margin=[object Object]&name=image.png&originHeight=242&originWidth=648&originalType=binary&ratio=1&rotation=0&showTitle=true&size=63213&status=done&style=none&taskId=ubc7c77bf-2956-4cfc-a638-d974aa3d056&title=redis 的I/O多路复用有多个I/O 复用库在实现。&width=648 “redis 的I/O多路复用有多个I/O 复用库在实现。”)

  • 当被监听的套接字准备好执行连接应答(accept)、读取(read)、写人(write入关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件虽然文件事件处理器以单线程方式运行,但通过使用 IO 多路复用程序来监听多个套接宇,文件事件处理器既实现了高性能的网络通信模型(可以理解为 一个服务端使用了一个线程(或者少量的线程)来处理多个客户端请求),又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部单线程设计的简单性

![image.png](https://img-blog.csdnimg.cn/img_convert/3e01f6fb153bf6017804ff8bb4bd1ddd.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=504&id=u779dc75f&margin=[object Object]&name=image.png&originHeight=504&originWidth=677&originalType=binary&ratio=1&rotation=0&showTitle=true&size=141346&status=done&style=none&taskId=ud36e6d28-25fb-4aff-8b10-488dfce4201&title=文本事件处理器&width=677 “文本事件处理器”)
注意:io 多路复用和 文本事件分派器 中间的队列是 单个的,也就是文件事件分派器一次只处理一个事件。
![image.png](https://img-blog.csdnimg.cn/img_convert/f8d294a8425309228a8db1843afc90c0.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=143&id=u8dffd8b0&margin=[object Object]&name=image.png&originHeight=143&originWidth=1109&originalType=binary&ratio=1&rotation=0&showTitle=true&size=63367&status=done&style=none&taskId=u0fc50620-54c2-49f8-9941-48bf6c1823d&title=io多路复用程序 和 文件事件分派器 中 队列模型&width=1109 “io多路复用程序 和 文件事件分派器 中 队列模型”)
![image.png](https://img-blog.csdnimg.cn/img_convert/3914064ad0c6f86cc168b24cab0ec0ec.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=393&id=u397f3021&margin=[object Object]&name=image.png&originHeight=393&originWidth=594&originalType=binary&ratio=1&rotation=0&showTitle=true&size=114829&status=done&style=none&taskId=uddba06b4-e614-44e1-a0d1-f351eb7ab10&title=服务器和客户端通信过程&width=594 “服务器和客户端通信过程”)

时间事件

我们从之前的讲述中可以看到,和时间相关的都是由 redisCron 函数进行处理的,那么它就是我们的 时间事件应用实例了。
Redis 的时间事件分为以下两类:

  • 定时事件:让一段程序在指定的时间之后执行一次。比如说,让程序× 在当前时间
    的 30毫秒之后执行一次。
  • 周期性事件:让一段程序每隔指定时间就执行一次。比如说,让程序Y每隔 30毫秒就执行-
    一次。

个时间事件主要由以下三个属性组成:

  1. id:服务器为时间事件创建的全局唯一四D(标识号)。1D号按从小到大的顺序递增,
    新事件的1D 号比旧事件的1D 号要大。
  2. when:毫秒精度的 UNIX 时间戳,记录了时间事件的到达(arrive)时间。
  3. timeProc:时间事件处理器,一个两数。当时间事件到达时,服务器就会调用相
    应的处理器来处理事件。

事件的调度与执行

因为redis 存在两种事件类型,所以 redis 必须有个调度器去解决何时处理 文本事件 何时 处理 时间事件
这个是 aeProcessEvents函数来进行的
![image.png](https://img-blog.csdnimg.cn/img_convert/d09d94942d3c5462c4658bc628dbb928.png#clientId=u5568bb2a-d214-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=490&id=u03741ed4&margin=[object Object]&name=image.png&originHeight=490&originWidth=687&originalType=binary&ratio=1&rotation=0&showTitle=false&size=116300&status=done&style=none&taskId=ub1edce4e-3152-4093-9e2d-6dc49e92a8a&title=&width=687)

后面对 服务器 和 客户端 在进行详细的研究。

参考资料#
《Redis设计与实现》-黄健宏
部分图片来与百度搜索

共读《redis设计与实现》-单机(一)相关推荐

  1. Redis设计与实现详解二:Redis数据库实现

    Redis设计与实现详解一:数据结构与对象 Redis设计与实现详解三:多机功能实现 Redis设计与实现详解四:其他单机功能 数据库 服务器中的数据库 Redis服务器将所有数据库都保存在服务器状态 ...

  2. Redis | 第6章 事件与客户端《Redis设计与实现》

    第6章 事件与客户端 前言 1. 事件 1.1 文件事件 1.1.1 I/O 多路复用程序的实现 1.1.2 事件类型与 API 1.1.3 文件事件的处理器 1.2 时间事件 1.2.1 API 1 ...

  3. Redis 设计与实现重点回顾

    文章目录 Redis 设计与实现重点回顾 第一部分:数据结构与对象 简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表 对象 第二部分:单机数据库的实现 数据库 RDB 持久化 AOF 持久化 事 ...

  4. Redis 设计与实现读书笔记-第三章

    引言 第三部分,属于多机数据库的实现,相较而言是很受关注的一部分,也是面试的高频考点,总体包含三个部分:主从复制.Sentinel 以及 集群.这三部分(加上之前介绍到的根据 RDB 和 AOF 实现 ...

  5. 《Redis设计与实现》之第七章:压缩列表

    压缩列表是列表键和哈希键的底层实现之一.压缩列表是为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构. [压缩列表是一种数据结构,这种数据结构的功能是将一系列数据与其编码信息存储 ...

  6. 《redis 设计与实现》读书笔记

    大家好,我是烤鸭:     <redis 设计与实现>,读书笔记. 第一部分 数据结构与对象 第2章 简单动态字符串 Redis 使用SDS 作为字符串表示. O(1) 复杂度获取字符串长 ...

  7. 给孩子一束安全的光 明基WiT MindDuo亲子共读灯首发评测

    论一束光的重要性你该听听一个高度近视孩子的自述,论童年陪伴的重要性你该听听一个留守儿童的自述,改善孩子童年的全球第一盏亲子共读台灯,贴合孩子与家长的心灵,量身打造每一种情境的光线去感受孩子成长学习过程 ...

  8. fmea手册_黄老师与您共读新版FMEA手册07-DFMEA功能分析

    前情提要: 黄老师与您共读新版FMEA手册05-DFMEA策划和准备 黄老师与您共读新版FMEA手册06-DFMEA结构分析 在2008发行的AIAG第4版FMEA手册中,FMEA表格的第一个栏位是& ...

  9. 共读ulord项目分析(一)

    本文发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明--一界码农+产品汪+U赞签约作者 个人微信号(liuhua7851) ulo ...

最新文章

  1. 在ASP.NET中值得注意的两个地方
  2. python16进制字节序_第 1 章 套接字、IPv4和简单的客户端/服务器编程
  3. P1020 导弹拦截(最长不上升序列+二分)
  4. 计算机网络应用层笔记--域名系统DNS
  5. android 系统(8)---Android 学习网站汇总
  6. 伟大的RAC和MVVM入门(二)
  7. 生活中的数学(为生活建模)(二)
  8. 自然场景下文本检测主要数据集
  9. OpenCV之感兴趣区域ROI
  10. MATLAB语言初步学习(四)
  11. 使用_thread多线程模块ping主机代码
  12. 无法启动计算机上的服务msdtc,MSDTC服务无法启动解决方法
  13. python ocr 识别中文pdf_基于Python实现对PDF文件的OCR识别
  14. 【Windows 10系统】惠普打印机解决打印机状态已暂停
  15. 在Azure的云服务器上搭建个人网站
  16. 大野耐一的十条管理训诫|优思学院
  17. python入门之运算符的使用【educoder】
  18. 【过一下14】自习室的一天
  19. 计算机python实验报告_Python实验报告六:函数
  20. android paint跑马灯,Android使用Canvas实现跑马灯

热门文章

  1. 2021年山东省职业院校技能大赛高职组“信息安全管理与评估”赛项
  2. 让人才不再稀缺,让就业水到渠成 ——记传智播客总裁黎活明
  3. [内附完整源码和文档] 基于JAVA的房屋中介管理系统
  4. 技术人员谈管理之企业组织文化漫谈
  5. 解决某些软件检测不到java环境问题
  6. 小程序图片缓存策略(不改代码更换OSS图片)
  7. Qt5.10实现图片转文字功能添加截图功能代码分析
  8. 两列模糊对比 oracle,excel 模糊比对两列数据并将比对结果显示出来 | excel表格两列数据模糊对比...
  9. 关系型数据库分库分表中间件之选型
  10. java:错误: 找不到符号