Redis基础知识

Redis基础知识

Redis主从复制

https://zhuanlan.zhihu.com/p/151740247,这个网址讲的很好。

全量复制

Redis通过psync命令进行全量复制的过程如下:

(1)从节点判断无法进行部分复制,向主节点发送全量复制的请求;或从节点发送部分复制的请求,但主节点判断无法进行部分复制;具体判断过程需要在讲述了部分复制原理后再介绍。

(2)主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令

(3)主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态

(4)主节点将前述复制缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态

(5)如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态。
在这里插入图片描述

部分复制

由于全量复制在主节点数据量较大时效率太低,因此Redis2.8开始提供部分复制,用于处理网络中断时的数据同步。

部分复制的实现,依赖于三个重要的概念:

a. 复制偏移量
b. 复制积压缓冲区
c. 服务器运行ID(runid)
下面我们分别讲解一下这三个概念:

复制偏移量

执行复制的双方,主从节点,分别会维护一个复制偏移量offset: 主节点每次向从节点同步了N字节数据后,将修改自己的复制偏移量offset+N 从节点每次从主节点同步了N字节数据后,将修改自己的复制偏移量offset+N.

offset用于判断主从节点的数据库状态是否一致: 如果二者offset相同,则一致; 如果offset不同,则不一致,此时可以根据两个offset找出从节点缺少的那部分数据。

例如,如果主节点的offset是1000,而从节点的offset是500,那么部分复制就需要将offset为501-1000的数据传递给从节点。而offset为501-1000的数据存储的位置,就是下面要介绍的复制积压缓冲区。

复制积压缓冲区

主节点内部维护了一个固定长度的、先进先出(FIFO)队列 作为复制积压缓冲区,其默认大小为1MB 在主节点进行命令传播时,不仅会将写命令同步到从节点,还会将写命令写入复制积压缓冲区。

由于复制积压缓冲区定长且是先进先出,所以它保存的是主节点最近执行的写命令;时间较早的写命令会被挤出缓冲区。因此,当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。

为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小(通过配置repl-backlog-size);例如如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。

从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制:

如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制;
如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。
复制积压缓冲区示意图:
在这里插入图片描述

服务器运行ID(runid):

每个Redis节点,都有其运行ID,运行ID由节点在启动时自动生成,主节点会将自己的运行ID发送给从节点,从节点会将主节点的运行ID存起来。 从节点Redis断开重连的时候,就是根据运行ID来判断同步的进度:

如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);
如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。
在这里插入图片描述

Redis持久化

RDB持久化

RDB持久化,指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

在这里插入图片描述
RDB持久化配置
a.save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
b.save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
c.save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

AOF持久化

AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
在这里插入图片描述

AOF持久化配置

appendfsync always #每次有数据修改发生时都会写入AOF文件
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no #从不同步。高效但是数据不会被持久化。

AOF持久化的实现

1)命令追加,当服务器执行完一个命令时,将这条命令追加到服务器aof_buf的末尾。
2)文件的写入和同步
def eventLoop():
while True:
processFileEvents(); //处理文件事件,接收命令请求,并恢复,建命令添加到aof_buf.(事件监听)
processTimeEvents(); //处理时间时间。那个事件发生。
flushAppendOnlyFile() //考虑是否要将aof_buf缓冲区的内容写入和保存的AOF文件里。
flushAppendOnlyFile函数的行为可根据服务器配置的appendfsync值,来决定不同的行为。
这里理解写入aof文件,是aof_buf文件,写到对应的缓冲区,并没有同步到磁盘上。同步指的是,将对应的缓冲区数据,同步到磁盘。
always:每次事件循环将aof_buf的内容写入并同步到aof文件。
everysec:有一个单独的线程负责处理,如果上次同步的时间距离现在超过1秒钟,则再次对AOF文件进行同步操作。写入是,将aof_buf的内容写入到aof文件。
no.将aof_buf的内容写入到aof文件。但不对aof文件同步,何时同步由操作系统决定。

c.AOF文件的载入和数据还原
aof文件的载入会创建一个没有网络连接的伪客户端(因为redis命令只能在客户端的上下文执行),利用为客户端执行命令,当所有aof命令执行完成后,恢复数据库的状态。
d.AOF文件的重写。
AOF文件的重写指的是,将AOF文件中一些命令进行整合,并生成新的AOF文件。
e.AOF文件的后台重写
1)利用子进程重写AOF文件,不阻塞服务器进程,服务器进程可以正常处理请求。
会引起的问题,子进程重写期间,服务器执行的命令还未同步到aof文件,会引起不一致问题。
解决办法:服务器进程执行命令时,将命令写到aof缓冲区的同时,也写入到aof重写缓冲区。从创建子进程开始,服务器命令就将命令发送到aof重写缓冲区。 当子进程完成aof重写后,会向主进程发送信号,主服务器进程收到信号后会,将aof重写缓冲区内容,写入到新的aof文件,对新的aof文件进行改名。
对主服务器进程的影响,只有服务器进程收到信号后的一些数据处理。

redis的过期策略以及内存淘汰机制

1.定时删除
redis为键设置过期时间时,同时设置定时器,定时器在键的过期时间来临时,定时删除,增加cpu压力,减少内存, 为key设置事件。
2.定期删除
过期的键都在过期字典中,程序每个一段时间去删除过期间,删除那个库的和删除多少,有算法控制。
3.惰性删除
只有redis获取这个key时,查看键的时间是否过期,过期就删除,用内存换cpu,减少cpu压力。

redis的五种数据类型和底层实现

字符串类型

字符串底层实现为SDS。
数据结构:
struct sdshdr {
int len;
int frees;
char buf[];
}

列表类型

底层实现:
1.当列表只包含少量的列表项,并且每个列表项存储的字符串较短,则使用压缩列表。
2.双向链表

哈希类型
   底层实现:
   1.当hash类型,只存储的少量的键值对,并且键值对的字符串长度较少,则使用压缩列表。
   2.dict类型 
    redis的dict扩容,https://www.cnblogs.com/williamjie/p/11205593.html,  https://www.jianshu.com/p/05bf8a945944。
集合

底层实现:
1.当集合只包含整数,并且元素数量不多,则集合使用整数集合数据结构存储元素。
typedef struct intset{
//编码方式
uint32_t encoding;
//集合包含元素数量
uint32_t length;
//保存元素的数组:
int8_t contents[];
}
2.dict字典类型,value为NULL。

有序集合

底层实现:
1.压缩列表
2.跳表,粗俗的讲解
在这里插入图片描述

https://blog.csdn.net/a2796749/article/details/48084717。精确讲解看书。
a.redis的跳表实现有两个数据结构,zskiplist , zskilistNode.
b.每个跳跃表节点的层高为1到32之间。
c.节点对象必须唯一,分值相同时,节点按照成员对象的字典序排序。
d.有序集合中每个元素,都有数值占比。
在这里插入图片描述

  1. dict字典类型, dict字典类型方便从key定位到value。 跳表方便从value定位到key,适合范围查询。
  2. dict数据结构的扩容,渐进式扩容,dict数据集合扩容时,会为h[1]哈希表初始化空间,会渐进式的扩容,避免对服务器性能造成影响(单线程扩容,计算量大),操作辅助hash,定时辅助hash.两种方式来渐进式扩容。(redis的dict类型的hash表有两个,h[0], h[1]=null, 当扩容时,给h[1],表创建空间,当每次增删时,除了本身的操作还会在将h[0]表上的元素重新hash)
  3. https://blog.csdn.net/qq_38262266/article/details/107727116。

Redis缓存

https://blog.csdn.net/kongtiao5/article/details/82771694
redis缓存数据一致性:先删除缓存,在更新数据库。

Redis速度快的原因

1.单线程处理请求,避免线程切换,通过io多路复用。
2.基于内存操作。

Redis事务

事务不具备,原子性,隔离性。
https://www.cnblogs.com/DeepInThought/p/10720132.html,
开始事务
命令入队
执行事务
在这里插入图片描述
放弃事务
在这里插入图片描述
若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行
在这里插入图片描述
若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。

Redis高可用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值