最全Redis原理

Redis是一个高性能的key-value数据库,支持数据持久化、多种数据结构、事务和发布/订阅等功能。Redis采用单线程模型,但在Redis6中引入了多线程来提高网络IO性能。Redis的集群通过主从复制、哨兵模式和Cluster模式实现高可用性和数据分片。此外,文章还介绍了Redis的持久化机制,如RDB和AOF,以及它们的优缺点。
摘要由CSDN通过智能技术生成
  1. 什么是 Redis?

Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

Redis 与其他 key - value 缓存产品相比有以下三个特点:

  • Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

  • Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。

  • Redis 支持数据的备份,即 master-slave 模式的数据备份。

Redis 优势:

  • 性能极高:Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s。

  • 丰富的数据类型:Redis 支持二进制案例的 Strings,Lists,Hashes,Sets 及 Ordered Sets 数据类型操作。

  • 原子:Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来。

  • 丰富的特性:Redis 还支持 publish/subscribe,通知,key 过期等等特性。

Redis 与其他 key-value 存储有什么不同?

Redis 有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis 的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

Redis 运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样 Redis 可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

  1. Redis 的数据类型?

1.Redis 支持五种数据类型:

string(字符串),

hash(哈希),

list(列表),

set(集合),

zsetsorted set(有序集合)

2.有哪些应用场景?

1)String:缓存、限流、分布式锁、计数器、分布式 Session 等。

2)Hash:用户信息、用户主页访问量、组合查询等。

3)List:简单队列、关注列表时间轴。

4)Set:赞、踩、标签等。

  1. ZSet:排行榜、好友关系链表。

3.常用命令

终端连接

`redis-cli -h 127.0.0.1 -p 6379`

key

keys *  # 获取所有的key
select 0  # 选择第一个库
move myString 1  # 将当前的数据库key移动到某个数据库,目标库有,则不能移动
flush db  # 清除指定库
randomkey  # 随机key
type key  # 类型
    
set key1 value1   # 设置key
get key1  # 获取key
mset key1 value1 key2 value2 key3 value3
mget key1 key2 key3
del key1  # 删除key
exists key  # 判断是否存在key
expire key 10  # 10s 过期
pexpire key  # 1000 毫秒
persist key  # 删除过期时间

订阅发布

subscribe chat1 # 订阅频道
publish chat1 "hell0 ni hao"  # 发布消息
pubsub channels  # 查看频道
pubsub numsub chat1  # 查看某个频道的订阅者数量
unsubscrible chat1  # 退订指定频道 或 punsubscribe java.*
psubscribe java.*  # 订阅一组频道

ref redis常用命令大全

  1. 使用 Redis 有哪些好处?

  • 速度快,因为数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O1)

  • 支持丰富数据类型,支持 string,list,set,Zset,hash 等

  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

  • 丰富的特性,可用于缓存,消息,按 key 设置过期时间,过期后将会自动删除

  1. Redis 与Memcached?

  • 存储方式 Memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis 有部分存在硬盘上,这样能保证数据的持久性。

  • 数据支持类型 Memcache 对数据类型支持相对简单。Redis 有复杂的数据类型。

  • 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

  1. Redis 线程?

  1. 为何使用单线程?

  1. 官方答案

因为 Redis 是基于内存的操作,CPU 不会成为 Redis 的瓶颈,而最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。

  1. 详细原因

1)不需要各种锁的性能消耗

Redis 的数据结构并不全是简单的 Key-Value,还有 List,Hash 等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。

2)单线程多进程集群方案

单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。

所以单线程、多进程的集群不失为一个时髦的解决方案。

  1. 多线程

1.Redis 6 之前真的是单线程吗?

Redis 在处理客户端的请求时,包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的单线程。但如果严格来讲从 Redis 4 之后并不是单线程,除了主线程外,它也有后台线程在处理一些较为缓慢的操作,例如清理脏数据、无用连接的释放、大 key 的删除等等。

2.Redis 6 之前为什么使用单线程?

使用了单线程后,可维护性高。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。

同时 Redis 通过 AE 事件模型以及 IO 多路复用等技术,即使单线程处理性能也非常高,因此没有必要使用多线程。单线程机制使得 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等 “线程不安全” 的命令都可以无锁进行。

3.Redis 6 为何引入多线程?

随着目前行业内越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的 QPS。常见的解决方案是在分布式架构中对数据进行分区并采用多个服务器,但该方案有非常大的缺点,比如:

1)要管理的 Redis 服务器太多,维护代价大;

2)某些适用于单个 Redis 服务器的命令不适用于数据分区;

3)数据分区无法解决热点读/写问题;

4)数据偏斜,重新分配和放大/缩小变得更加复杂等等。

从 Redis 自身角度来说,因为读写网络的 read/write 系统调用占用了 Redis 执行期间大部分 CPU 时间,瓶颈主要在于网络的 IO 消耗, 优化主要有两个方向:

1)提高网络 IO 性能,典型的实现比如使用 DPDK 来替代内核网络栈的方式;

2)使用多线程充分利用多核,典型的实现比如 Memcached。

协议栈优化的这种方式跟 Redis 关系不大,支持多线程是一种最有效最便捷的操作方式。所以总结起来,Redis 支持多线程主要就是两个原因:

可以充分利用服务器 CPU 资源,目前主线程只能利用一个核;

多线程任务可以分摊 Redis 同步 IO 读写负荷。

4.多线程如何开启以及配置?

Redis 6 的多线程默认是禁用的,只使用主线程。如需开启需要修改 redis.conf 配置文件中的 io-threads-do-reads yes。

开启多线程后,还需要设置线程数,否则是不生效的。同样修改 redis.conf 文件中的 io-threads [n] 配置。

关于线程数的设置,官方有一个建议:4 核的机器建议设置为 2 或 3 个线程,8 核的建议设置为 6 个线程,线程数一定要小于机器核数。还需要注意的是,线程数并不是越大越好,官方认为超过了 8 个基本就没什么意义了。

5.Redis 多线程的实现机制?

大致流程如下:

1)主线程负责接收建立连接请求,获取 socket 放入全局等待读处理队列;

2)主线程处理完读事件之后,通过 RR(Round Robin) 将这些连接分配给这些 IO 线程;

3)主线程阻塞等待 IO 线程读取 socket 完毕;

4)主线程通过单线程的方式执行请求命令,请求数据读取并解析完成,但并不执行;

5)主线程阻塞等待 IO 线程将数据回写 socket 完毕;

6)解除绑定,清空等待队列。

该设计的特点:

1)IO 线程要么同时在读 socket,要么同时在写,不会同时读或写。

2)IO 线程只负责读写 socket 解析命令,不负责命令处理。

6.多线程是否会导致线程安全问题?

从上面的实现机制可以看出,Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。所以我们不需要去考虑控制 key、lua、事务,LPUSH/LPOP 等等的并发及线程安全问题。

7.Redis 和 Memcached 多线程区别?

相同点:都采用了 master 线程 - worker 线程的模型。

不同点:Memcached 执行主逻辑也是在 worker 线程里,模型更加简单,实现了真正的线程隔离,符合我们对线程隔离的常规理解。而 Redis 把处理逻辑交还给 master 线程,虽然一定程度上增加了模型复杂度,但也解决了线程并发安全等问题。

ref Redis 6.0 新特性-多线程连环13问!

  1. Redis集群?

1. 集群模式

1.Redis 集群搭建有几种模式?

主从模式

和 MySQL 需要主从复制的原因一样,Redis 虽然读写速度非常快,但是也会产生性能瓶颈,特别是在读压力上,为了分担压力,Redis 支持主从复制。Redis 的主从结构一主一从,一主多从或级联结构,复制类型可以根据是否是全量而分为全量同步和增量同步。

哨兵模式

在主从复制实现之后,如果想对 master 进行监控,Redis 提供了一种哨兵机制,哨兵的含义就是监控 Redis 系统的运行状态,通过投票机制,从 slave 中选举出新的 master 以保证集群正常运行。

还可以启用多个哨兵进行监控以保证集群足够稳健,这种情况下,哨兵不仅监控主从服务,哨兵之间也会相互监控。

Cluster 集群模式

ref Redis集群搭建的三种方式

2.Redis 主从复制的实现?

主从复制可以根据需要分为全量同步的增量同步两种方式。

全量同步

Redis 全量复制一般发生在 slave 的初始阶段,这时 slave 需要将 master 上的数据都复制一份,具体步骤如下:

1)slave 连接 master,发送 SYNC 命令;

2)master 接到 SYNC 命令后执行 BGSAVE 命令生产 RDB 文件,并使用缓冲区记录此后执行的所有写命令;

3)master 执行完 BGSAVE 后,向所有的 slave 发送快照文件,并在发送过程中继续记录执行的写命令;

4)slave 收到快照后,丢弃所有的旧数据,载入收到的数据;

5)master 快照发送完成后就会开始向 slave 发送缓冲区的写命令;

6)slave 完成对快照的载入,并开始接受命令请求,执行来自 master 缓冲区的写命令;

7)slave 完成上面的数据初始化后就可以开始接受用户的读请求了。

增量同步

增量复制实际上就是在 slave 初始化完成后开始正常工作时 master 发生写操作同步到 slave 的过程。增量复制的过程主要是 master 每执行一个写命令就会向 slave 发送相同的写命令,slave 接受并执行写命令,从而保持主从一致。

ref Redis主从复制原理总结

3.Redis 的主从同步策略?

主从同步刚连接的时候进行全量同步,全量同步结束后开始增量同步。

如果有需要,slave 在任何时候都可以发起全量同步,其主要策略就是无论如何首先会尝试进行增量同步,如果失败则会要求 slave 进行全量同步,之后再进行增量同步。

注意:如果多个 slave 同时断线需要重启的时候,因为只要 slave 启动,就会和 master 建立连接发送SYNC请求和主机全量同步,如果多个同时发送 SYNC 请求,可能导致 master IO 突增而发送宕机。所以我们要避免多个 slave 同时恢复重启的情况。

4.哨兵模式的原理?

哨兵主要用于管理多个 Redis 服务器,主要有以下三个任务:监控、提醒以及故障转移。

每个哨兵会向其它哨兵、master、slave 定时发送消息,以确认对方是否还存活。如果发现对方在配置的指定时间内未回应,则暂时认为对方已挂。若“哨兵群”中的多数 sentinel 都报告某一 master 没响应,系统才认为该 master “彻底死亡”,通过一定的 vote 算法从剩下的 slave 节点中选一台提升为 master,然后自动修改相关配置。

5.哨兵模式故障迁移流程?

1)首先是从主服务器的从服务器中选出一个从服务器作为新的主服务器。

选点的依据依次是:

网络连接正常 -> 5 秒内回复过 INFO 命令 -> 10*down-after-milliseconds 内与主连接过的 -> 从服务器优先级 -> 复制偏移量 -> 运行id较小的。

2)选出之后通过 slaveif no ont 将该从服务器升为新主服务器;

3)然后再通过 slaveof ip port 命令让其他从服务器复制该信主服务器。

缺点

主从服务器的数据要经常进行主从复制,这样会造成性能下降

当主服务器宕机后,从服务器切换成主服务器的那段时间,服务是不可用的

2.2 Cluster 集群

1、什么是一致性 Hash 以及解决什么问题?

一致性 hash 其实是普通 hash 算法的改良版,其 hash 计算方法没有变化,但是 hash 空间发生了变化,由原来的线性的变成了环。

缓存 key 通过 hash 计算之后得到在 hash 环中的位置,然后顺时针方向找到第一个节点,这个节点就是存放 key 的节点。

由此可见,一致性 hash 主要是为了解决普通 hash 中扩容和宕机的问题。

同时还可以通过虚拟节点来解决数据倾斜的问题:就是在节点稀疏的 hash 环上对物理节点虚拟出一部分虚拟节点,key 会打到虚拟节点上面,而虚拟节点上的 key 实际也是映射到物理节点上的,这样就避免了数据倾斜导致单节点压力过大导致节点雪崩的问题。

ref 什么是一致性hash

2.Cluster 模式的原理?

其实现原理就是一致性 Hash。Redis Cluster 中有一个 16384 长度的槽的概念,他们的编号为 0、1、2、3 …… 16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster 中的每个 Master 节点都会负责一部分的槽,当有某个 key 被映射到某个 Master 负责的槽,那么这个 Master 负责为这个 key 提供服务。

至于哪个 Master 节点负责哪个槽,这是可以由用户指定的,也可以在初始化的时候自动生成(redis-trib.rb脚本)。这里值得一提的是,在 Redis Cluster 中,只有 Master 才拥有槽的所有权,如果是某个 Master 的 slave,这个slave只负责槽的使用,但是没有所有权。

3.Cluster 的分片机制?

为了使得集群能够水平扩展,首要解决的问题就是如何将整个数据集按照一定的规则分配到多个节点上。对于客户端请求的 key,根据公式 HASH_SLOT=CRC16(key) mod 16384,计算出映射到哪个分片上。而对于 CRC16 算法产生的 hash 值会有 16bit,可以产生 2^16-=65536 个值。

Redis 集群提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以下线部分节点进行缩容。可以说,槽是 Redis 集群管理数据的基本单位,集群伸缩就是槽和数据在节点之间的移动。

4、Cluster 集群的扩容流程?

当一个 Redis 新节点运行并加入现有集群后,我们需要为其迁移槽和数据。首先要为新节点指定槽的迁移计划,确保迁移后每个节点负责相似数量的槽,从而保证这些节点的数据均匀。

1)首先启动一个 Redis 节点,记为 M4。

2)使用 cluster meet 命令,让新 Redis 节点加入到集群中。新节点刚开始都是主节点状态,由于没有负责的槽,所以不能接受任何读写操作,后续给他迁移槽和填充数据。

3)对 M4 节点发送 cluster setslot { slot } importing { sourceNodeId } 命令,让目标节点准备导入槽的数据。

4)对源节点,也就是 M1,M2,M3 节点发送 cluster setslot { slot } migrating { targetNodeId } 命令,让源节点准备迁出槽的数据。

5)源节点执行 cluster getkeysinslot { slot } { count } 命令,获取 count 个属于槽 { slot } 的键,然后执行步骤 6)的操作进行迁移键值数据。

6)在源节点上执行 migrate { targetNodeIp} " " 0 { timeout } keys { key... } 命令,把获取的键通过 pipeline 机制批量迁移到目标节点,批量迁移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。

7)重复执行步骤 5)和步骤 6)直到槽下所有的键值数据迁移到目标节点。

8)向集群内所有主节点发送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配给目标节点。为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽执行新节点。

5、Cluster 集群收缩流程?

收缩节点就是将 Redis 节点下线,整个流程需要如下操作流程。

1)首先需要确认下线节点是否有负责的槽,如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性。

2)当下线节点不再负责槽或者本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有的节点忘记改节点后可以正常关闭。

ref Redis Cluster数据分片机制

6、客户端如何路由?

既然 Redis 集群中的数据是分片存储的,那我们该如何知道某个 key 存在哪个节点上呢?即我们需要一个查询路由,该路由根据给定的 key,返回存储该键值的机器地址。

常规的实现方式便是采用如下图所示的代理方案,即采用一个中央节点(比如HDFS中的NameNode)来管理所有的元数据,但是这样的方案带来的最大问题就是代理节点很容易成为访问的瓶颈,当读写并发量高的时候,代理节点会严重的拖慢整个系统的性能。

Redis 并没有选择使用代理,而是客户端直接连接每个节点。Redis 的每个节点中都存储着整个集群的状态,集群状态中一个重要的信息就是每个桶的负责节点。在具体的实现中,Redis 用一个大小固定为 CLUSTER_SLOTS 的 clusterNode 数组 slots 来保存每个桶的负责节点。

typedef struct clusterNode {
    ...
    unsigned char slots[CLUSTER_SLOTS/8];
    ...
} clusterNode;

typedef struct clusterState {
    // slots记录每个桶被哪个节点存储
    clusterNode *slots[CLUSTER_SLOTS];
    ...
} clusterState;

在集群模式下,Redis 接收任何键相关命令时首先计算键对应的桶编号,再根据桶找出所对应的节点,如果节点是自身,则处理键命令;否则回复 MOVED 重定向错误,通知客户端请求正确的节点,这个过程称为 MOVED 重定向。重定向信息包含了键所对应的桶以及负责该桶的节点地址,根据这些信息客户端就可以向正确的节点发起请求。

ref Redis集群详解(上)

7、为什么是 163834 个槽位?

从前面的 Cluster 集群原理我们已经了解到集群中的所有节点在握手成功后悔定期发送 ping/pong 消息,交换数据信息。

先来了解一下消息体传递了哪些数据:

typedef struct {
    //消息的长度(包括这个消息头的长度和消息正文的长度)
    uint32_t totlen;
    //消息的类型
    uint16_t type;
    //消息正文包含的节点信息数量
    //只在发送MEET 、PING 、PONG 这三种Gossip 协议消息时使用
    uint16_t count;
    //发送者所处的配置纪元
    uint64_t currentEpoch;
    //如果发送者是一个主节点,那么这里记录的是发送者的配置纪元
    //如果发送者是一个从节点,那么这里记录的是发送者正在复制的主节点的配置纪元
    uint64_t configEpoch;
    //发送者的名字(ID )
    char sender[REDIS_CLUSTER_NAMELEN];
    //发送者目前的槽指派信息
    unsigned char myslots[REDIS_CLUSTER_SLOTS/8];
    //如果发送者是一个从节点,那么这里记录的是发送者正在复制的主节点的名字
    //如果发送者是一个主节点,那么这里记录的是REDIS_NODE_NULL_NAME
    //(一个40 字节长,值全为0 的字节数组)
    char slaveof[REDIS_CLUSTER_NAMELEN];
    //发送者的端口号
    uint16_t port;
    //发送者的标识值
    uint16_t flags;
    //发送者所处集群的状态
    unsigned char state;
    //消息的正文(或者说,内容)
    union clusterMsgData data; 
} clusterMsg; 

上图展示的消息体结构无外乎是一些节点标识,IP,端口号,发送时间等,但需要注意一下标红的 myslots 的 char 数组,长度为 16383/8,这其实是一个 bitmap,每一个位代表一个槽,如果该位为1,表示这个槽是属于这个节点的。

消息体大小上的考量

至于这个消息体有多大?显然最占空间的就是 myslots 数组:16384÷8÷1024=2kb。如果槽位达到 65536,则所占空间提升到 65536÷8÷1024=8kb,极大浪费带宽。

Redis 集群主节点数量基本不可能超过 1000 个

集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。

槽位越小,节点少的情况下,压缩比高

ref 为什么Redis集群有16384个槽

ref 集群之间的消息

8、集群的故障发现与迁移?

故障发现

当集群内某个节点出现问题时,需要通过一种健壮的方式保证识别出节点是否发生了故障。Redis 集群内节点通过 ping/pong 消息实现节点通信,消息不但可以传播节点槽信息,还可以传播其他状态如:主从状态、节点故障等。因此故障发现也是通过消息传播机制实现的。 主要环节包括:

主观下线(PFAIL-Possibly Fail)

集群中每个节点都会定期向其他节点发送ping消息,接收节点回复pong消息作为响应。如果在cluster-node-timeout时间内通信一直失败,则发送节点会认为接收节点存在故障,把接收节点标记为主观下线(PFail)状态。

客观下线(Fail)

Redis 集群对于节点最终是否故障判断非常严谨,只有一个节点认为主观下线并不能准确判断是否故障。当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播,通过Gossip消息传播,集群内节点不断收集到故障节点的下线报告。当半数以上持有槽的主节点都标记某个节点是主观下线时。触发客观下线流程。

故障恢复

故障节点变为客观下线后,如果下线节点是持有槽的主节点则需要在它的从节点中选出一个替换它,从而保证集群的高可用。下线主节点的所有从节点承担故障恢复的义务,当从节点通过内部定时任务发现自身复制的主节点进入客观下线时,将会触发故障恢复流程。

ref 018.Redis Cluster故障转移原理

  1. Redis 的持久化机制是什么?各自的优缺点?

1. Redis 的 RDB?

RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式。也就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为 dump.rdb。

RDB 支持 同步(save 命令)、后台异步(bgsave)以及自动配置三种方式触发。

优点

RDB 文件紧凑,全量备份,非常适合用于进行备份和灾难恢复

生成 RDB 文件时支持异步处理,主进程不需要进行任何磁盘IO操作

RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快

缺点

RDB 快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。且在快照持久化期间修改的数据不会被保存,可能丢失数据。

2.Redis 的 AOF?

全量备份总是耗时的,有时候我们提供一种更加高效的方式 AOF,其工作机制更加简单:会将每一个收到的写命令追加到文件中。

随着时间推移,AOF 持久化文件也会变的越来越大。为了解决此问题,Redis 提供了 bgrewriteaof 命令,作用是 fork 出一条新进程将内存中的数据以命令的方式保存到临时文件中,完成对AOF 文件的重写。

AOF 也有三种触发方式:1)每修改同步 always 2)每秒同步 everysec 3)不同no:从不同步。

优点

AOF 可以更好的保护数据不丢失,一般 AOF 隔 1 秒通过一个后台线程执行一次 fsync 操作

AOF 日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损

AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写

AOF 日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复

缺点

对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大

AOF开启后,支持的写 QPS 会比RDB支持的写 QPS 低,因为 AOF 一般会配置成每秒 fsync 一次日志文件,当然,每秒一次 fsync,性能也还是很高的

  1. RDB 和 AOF 该如何选择?

命令

RDB

AOF

启动优先级

体积

恢复速度

数据安全性

丢数据

取决于刷盘策略

轻重

  1. Redis 常见性能问题和解决方案

  • Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务。

  • 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一。

  • 为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网。

  • 尽量避免在压力很大的主库上增加从。

  • 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1<- Slave2 <- Slave3……这样的结构方便解决单点故障问题,实现 Slave 对 Master 的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其他不变。

  1. Redis 过期键的删除策略?

  • 定时删除:在设置键的过期时间的同时,创建一个定时器 timer。让定时器在键的过期时间来临时,立即执行对键的删除操作。

  • 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。

  • 定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

  1. Redis 的回收策略(淘汰策略)?

  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  • no-enviction(驱逐):禁止驱逐数据

注意这里的 6 种机制,volatile 和 allkeys 规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的 lru、ttl 以及 random 是三种不同的淘汰策略,再加上一种 no-enviction 永不回收的策略。

使用策略规则:

  • 如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 allkeys-lru

  • 如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用 allkeys-random

  1. Redis 事务

1.怎么理解 Redis 事务?

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

2.Redis 事务相关的命令有哪几个?

MULTI、EXEC、DISCARD、WATCH。

  1. Redis分布式锁

先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。

如何实现分布式锁:

「互斥性」: 任意时刻,只有一个客户端能持有锁

「锁超时释放」:持有锁超时,可以释放,防止不必要的资源浪费,也可以防止死锁

「可重入性」:一个线程如果获取了锁之后,可以再次对其请求加锁

「高性能和高可用」:加锁和解锁需要开销尽可能低,同时也要保证高可用,避免分布式锁失效

「安全性」:锁只能被持有的客户端删除,不能被其他客户端删除

RedLock 加锁步骤:

1)按顺序向集群中所有 master 节点请求加锁;

2)根据设置的超时时间来判断,是不是要跳过该 master 节点;

3)如果大于等于半数节点( N/2+1 )加锁成功,并且使用的时间小于锁的有效期,即可认定加锁成功啦;

4)如果获取锁失败,解锁!

  1. 缓存三大问题以及解决方案?

  1. 缓存穿透:查询数据不存在

  1. 缓存空值

  1. key 值校验,如布隆筛选器 ref

  1. 缓存击穿:缓存过期,伴随大量对该 key 的请求

  1. 互斥锁

  1. 热点数据永不过期

  1. 熔断降级

  1. 缓存雪崩:同一时间大批量的 key 过期

  1. 热点数据不过期

  1. 随机分散过期时间

Redis是一种基于内存的高性能键值存储系统。它以其快速的读写能力和丰富的数据结构而闻名,被广泛应用于缓存、队列、计数器等场景。 Redis的核心原理包括以下几个方面: 1. 内存存储:Redis将数据存储在内存中,以实现低延迟的读写操作。它使用了一种叫做"跳表"(Skip List)的数据结构来实现有序集合和有序哈希表,以及哈希表和字符串等其他数据结构。 2. 持久化:Redis支持两种持久化方式,分别是RDB(Redis Database)和AOF(Append-Only File)。RDB是一种快照方式,将内存中的数据定期保存到磁盘上;AOF则是将写命令追加到一个日志文件中,通过重新执行这些命令来恢复数据。 3. 复制:Redis支持主从复制机制,在一个Redis服务器上配置一个或多个从服务器,从服务器会自动复制主服务器上的数据。主从复制可以提高系统的可用性和读取性能。 4. 高可用:Redis提供了哨兵(Sentinel)和集群(Cluster)两种方式来实现高可用。哨兵监控主服务器的状态,并在主服务器失效时自动将一个从服务器升级为主服务器;集群则将数据分散到多个节点上,每个节点负责一部分数据。 5. 事务:Redis支持简单的事务操作,通过MULTI、EXEC、WATCH和UNWATCH等命令来实现。事务中的命令在执行EXEC命令时原子地被提交,保证了相关操作的一致性。 这些是Redis的一些核心原理,它们共同构成了Redis的高性能和可靠性。当然,Redis还有很多其他的特性和功能,比如发布订阅、Lua脚本等,可以根据具体需求进行使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值