redis计数写入mysql_Redis实现单机数据库原理—中篇

Redis不同的持久化方式:RDB持久化和AOF持久化Redis是内存数据库,如果不想办法将存储在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据状态也会消失不见。为了解决这个问题,Redis提供了RDB持久化功能。既可以是手动执行,也可以定期执行。生成的RDB文件是一个经过压缩之后的二进制文件。

第一种方式:RDB持久化

(1)RDB文件的创建与载入创建RDB文件的命令是save以及bgsave,save会阻塞服务器进程,bgsave会派生出一个子进程。

RDB文件的载入工作是在服务器启动时自动执行的。

另外,因为AOF文件的更新频率要比RDB文件高,所以如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状态* 创建和载入RDB文件的过程如下:图1 创建和载入RDB文件的过程

(2)自动间隔性保存用户可以通过save选项设置多个保存条件,只要其中的任意一个条件被满足,服务器就会执行BGSAVE命令。在time_t秒内至少发生了changes次修改会进行自动保存。

save选项所设置的保存条件都保存在redisSever结构的saveparams属性。

struct saveparam{

//秒数

time_t seconds;

//修改数

int changes;

//修改计数器,服务器在上次保存之后,对数据库状态进行了多少次修改(注意这里的修改指的是命令修改了多少次数据库而不是执行了几条命令)

long long dirty;

//上一次执行保存的时间

time_t lastsave;

}

(3)RDB文件结构总体结构图2 总体部分1、最开头是REDIS部分,是一个常量,保存着REDIS五个字符,用来判断所载入的文件是否是RDB文件

2、 db_version:记录了RDB文件的版本号

3、 databases:包含着零个或者多个数据库以及各个数据库中的键值对数据

4、EOF:常量,标志RDB文件正文内容的结束

5、 check_sum:保存着一个校验和,这个校验和是程序通过对前面四个部分的内容进行计算得出的以此来检查RDB文件是否有出错或者损坏的情况出现databases部分:每个非空数据库在RDB文件中的结构图3 每个非空数据库在RDB文件中的结构SELECTDB:常量,当读入程序遇到这个值的时候,知道接下来读入的将是一个数据库db_number:保存着数据库号码,当程序读入改值时,服务器会调用SELECT命令key_value_pairs:保存了数据库中所有键值对数据

举个例子:图4 每个非空数据库在RDB文件中的结构例子key_value_pairs部分:保存了一个或者一个以上数量的键值对,包括键值对的过期时间

不带过期时间的格式:图5 不带过期时间的格式EXPIRETIME_MS:常量,告知程序接下来将读入的是一个以毫秒为单位的过期时间* ms:时间戳,记录了键值对的过期时间value部分编码:值对象根据TYPE属性可以是不同类型

(1)字符串对象:REDIS_RDB_TYPE_STRING两种编码方式:

redis_encoding_int:长度不超过32位的整数

编码对象结构:ENCODING的值可以是redis_rdb_enc_int8、redis_rdb_enc_int16、redis_rdb_enc_int32三个常量中一个分别表示rdb文件使用8位、16位、32位来保存整数值图6 编码方式

举个例子:用8位来保存整数图7 举例redis_encoding_raw:保存一个字符串。如果长度<=20字节,原样保存,反之压缩保存。

原样保存结构:len表示长度,string就是保存的字符串。图8 原样保存结构压缩保存结构:第一个常量表示字符串已经被LZF算法压缩过了图9 压缩保存结构

(2)列表对象:REDIS_RDB_TYPE_LIST编码:REDIS_ENCODING_LINKEDLIST

结构:图9 列表结构

举个例子:第一个3表示列表的长度是3,后面跟着分别是第一个、第二个以及第三个列表项。第一个列表项的5表示第一个列表项的长度是5,内容就是保存的值,以此类推。图10 列表结构举例

(3)集合对象:REDIS_RDB_TYPE_SET编码:REDIS_ENCODING_HT

结构:图11 集合对象结构

举个例子:第一个4记录了集合的大小,之后跟着四个元素,第一个元素长度为5值为"apple",第二个元素长度是6值为"banana",以此类推。图12 集合对象结构举例

(4)哈希表对象:REDIS_RDB_TYPE_HASH编码:REDIS_ENCODING_HT

结构:图13 哈希表对象结构更详细的结构:图14 哈希表对象更详细结构

举个例子:2表示记录了哈希表的键值对数量,之后跟着两个键值对,第一个键值对的键长度为1的字符串"a",值是长度为5的字符串"apple",以此类推。图15 哈希表对象更详细结构举例

(5)有序集合对象:REDIS_RDB_TYPE_ZSET编码:REDIS_ENCODING_SKIPLIST

结构:图16 有序集合对象结构更详细的结构:图17 有序集合对象更详细结构

举个例子:第一个2表示有序集合的元素数量,之后跟着两个有序集合元素,第一个元素的成员是长度为2的字符串"pi",分值被转换成字符串之后变成了长度为4的字符串"3.14"。第二个元素的成员是长度为1的字符串"e",分值被转换成字符串之后变成了长度为3的字符串"2.7"。图18 有序集合对象更详细结构举例

(6)INTSET编码的集合:REDIS_RDB_TYPE_SET_INTSETvalue保存的就是一个整数集合对象,RDB文件保存这种对象的方法是先将整数集合转换为字符串对象再将字符串对象保存到RDB文件里。同样地,读取的时候先读入字符串对象,再将这个字符串对象转换成原来的整数集合对象

(7)ZIPLIST编码的列表、哈希表或者有序集合:REDIS_RDB_TYPE_LIST_ZIPLIST、REDIS_RDB_TYPE_HASH_ZIPLIST、REDIS_RDB_TYPE_ZSET_ZIPLIST编码:REDIS_RDB_TYPE_LIST_ZIPLIST、REDIS_RDB_TYPE_HASH_ZIPLIST、REDIS_RDB_TYPE_ZSET_ZIPLIST

value保存的是一个压缩列表对象,保存方式就是将压缩列表转换成一个字符串对象,将字符串对象保存到RDB文件。读取的时候再转换成原来的压缩列表对象,并根据TYPE的值,设置压缩列表对象的类型。如果TYPE是REDIS_RDB_TYPE_LIST_ZIPLIST,那么压缩列表对象的类型为列表,如果是REDIS_RDB_TYPE_HASH_ZIPLIST,那么压缩列表对象的类型是哈希表等等。

重点回顾

(1)RDB文件用于保存和还原Redis数据库中所有的键值对数据

(2)SAVE命令是Redis服务器直接执行,会阻塞主流程。执行BGSAVE命令Redis服务器会开辟一个子进程来保存,所以不会阻塞服务器

(3)服务器状态中会保存所有用save选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行BGSAVE命令

(4)RDB文件是一个经过压缩的二进制文件,由不同部分组成

(5)对于不同类型的键值对,RDB文件会使用不同的方式来保存

第二种方式:AOF持久化(Append Only File)

1、AOF持久化是通过保存Redis服务器锁所执行的写命令来记录数据库状态的,主要步骤包括命令追加(append)、文件写入、文件同步(sync)三个步骤图19 AOF持久化步骤命令追加:当AOF持久化功能处于打开状态,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾

文件写入与同步:Redis的服务器进程其实就是一个事件循环,这个循环中的文件事件负责接收客户端发送的命令请求以及向客户端发送回复,而时间事件负责执行像serverCron函数这样需要定时运行的函数。服务器在每次结束一个事件循环之前都会调用flushAppendOnlyFile函数,考虑是否需要将aop_buf缓冲区中的内容保存到AOF文件中。这个函数的行为由服务器配置的appendfsync选项的值来决定表1 appendfsync选项值

2、AOF文件的载入和数据还原图20 AOF文件的载入和数据还原

3、AOF文件重写功能:为了解决AOF文件体积膨胀的问题实际上,AOF文件重写并不需要对现有的AOF文件进行读取、分析或者写入操作,而是通过读取服务器当前的数据库状态来实现的。从数据库中读取键现在的值,然后用一条命令记录键值对,代替之前记录这个键值对的多条命令。

AOF重写程序是放到子进程里执行的,这样不会阻塞服务器继续处理命令请求。另外子进程带有服务器进程的数据副本,使用子进程而不是线程,可以避免使用锁的情况下,保证数据的安全性。

使用子进程需要解决的一个问题是:因为子进程在进行AOF重写期间,服务器进程还需要继续处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使得服务器当前的数据库状态和重写后的AOF文件所保存的数据库状态不一致

举个例子:当子进程开始进行文件重写时,数据库中只有k1一个键,当子进程完成AOF文件重写之后,服务器进程的数据库中已经新设置了k2、k3、k4三个键,因此重写后的AOF文件和服务器当前的数据库状态不一致表2 AOF文件重写时的服务器进程和子进程如何解决:Redis服务器设置了一个AOF重写缓存区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓存区。

在子进程执行AOF重写期间,服务器进程需要执行:执行客户端发来的命令

将执行后的写命令追加到AOF缓冲区和AOF重写缓冲区图21 子进程执行AOF重写期间服务器进程执行步骤当子进程完成AOF重写工作之后,会向父进程发送一个个信号,父进程接收到该信号后,会调用信号处理函数,并执行以下工作:将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致

对新的AOF文件进行改名,原子地覆盖现有的AOF文件,完成新旧两个文件替换

信号处理函数处理完毕之后,父进程就可以继续接受处理客户端命令了。在整个过程中,只有信号处理函数执行时会对服务器进程造成阻塞,这样AOF重写对服务器性能造成的影响降低到了最低。这也是BGREWRITEAOF命令的实现原理表3 BGREWRITEAOF实现原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值