Redis知识点集合

一、Redis基础

 1. 概念RedisRemote Dictionary Server)是一个使用C语言编写的,开源的高性能非关系型(NOSql--Not Only Sql)键值对数据库。

 2. 基础数据结构:Redis可以存储和不同类型数据结构值之间的映射关系。键的类型只能是字符串,而值除了支持最基础的五种数据类型外,还支持一些高级数据类型(如:布隆过滤器,Stream等)

redis支持的基础数据结构

 3. 特性:与传统数据库不同的是Redis的数据是存在内存中的,所以读写速度非常快,因此Redis被广泛应用于缓存方向。官方称每秒可以处理超过10万次读写操作,是已知性能最快的Key - Value 数据库。此外,Redis也经常用来做分布式锁

 4. Redis的优缺点

     优点

    ① 读写性能优异,Redis能的速度是11万次/s,的速度是8.1万次/s。

    ② 支持数据持久化,支持AOF和RDB两种持久化方式。

    ③ 支持事务,Redis的所有操作都是原子性的,同时redis还支持对几个操作合并后的原子性执行。

    ④ 数据结构丰富,除了String类型,还支持hash/set/zset/list等数据结构,每个数据结构都有其独特的函数。

    ⑤ 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

    缺点

    ① 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写。

    ② Redis不具备自动容错恢复功能,主机从机的宕机都会导致前端部分读写请求失效,需要等待机器重启或者手动切换前端ip才能恢复。

    ③ 主机宕机,宕机钱有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的为,降低了系统的可用性

    ④ Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成很大的浪费

 5. 在项目中使用redis的优势:如果我们把数据放在Redis中,也就是直接放在内存之中,让服务器直接去读取内存中的数据,这样会提高系统的响应速度(高性能),并且会极大地减轻数据库的压力(应对高并发)

 6. 使用缓存会出现的问题

    ① 缓存雪崩问题:

     现象:在同一时刻,一批高热度的key同时失效,导致原本访问redis的请求都去访问数据库,造成数据库短时间内CPU和内存压力激增,严重会导致宕机

     出现的原因:缓存数据设置的过期时间是相同的,导致大量key到期被清除

     解决方法:把缓存过期时间设置成随机数,这样会大幅较少同一时间失效的key

缓存雪崩

另外关于Redis服务器宕机,大量请求访问数据库的问题,解决方法如下:

事发前:实现 Redis 的高可用(主从架构 + Sentinel 或者 Redis Cluster),尽量避免 Redis 挂掉这种情况发生。

事发中:万一 Redis 真的挂了,我们可以设置本地缓存(ehcache) + 限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)。

事发后:Redis 持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。 

    ② 缓存穿透问题:

     现象:客户端请求查询一个不存在的key(如负数的id),导致绕过缓存直接访问数据库,如果大量请求,也会导致数据库发生异常。

     出现的原因:请求的数据不命中缓存,导致要查询数据库。

     解决方法:a.使用布隆过滤器提前拦截  b. 把不存在的数据也放到缓存中,设置一个较短的过期时间。

缓存穿透

关于布隆过滤器

它是一个很长的二进制向量,当插入数据时, 运用一系列随机映射函数(hash函数)计算出多个位置,然后将1填充进二进制向量里。当要进行查询的时候,会把key进行同样的hash函数计算,查看相应位置是否都为1,如果有一位为0,那么该key不存在。若计算后出现相同的结果,也不能证明两个数据是一样的。 布隆过滤器只能判断数据是否一定不存在,而无法判断数据是否一定存在。

    redis官方在4.0版本推出了布隆过滤器, 有两个基本指令,bf.add 添加元素,bf.exists 查询元素是否存在。如果想要一次添加多个,就需要用到 bf.madd 指令。同样如果需要一次查询多个元素是否存在,就需要用到 bf.mexists 指令。

布隆过滤器

    ③ 双写一致性问题:

     现象:客户端拿到的数据不是数据库的最新数据(缓存里的是旧数据 )。

     出现原因:在并发环境中,当线程1进行更新操作的以后,线程2从缓存中读取了旧的数据,就会出现数据不一致问题。

       解决方法:a. 先修改数据库,再删除缓存 b. 先删除缓存,再修改数据库

Redis早期为什么选择单线程版本?

1. 使用单线程模型能带来更好的可维护性,方便开发和调试;

2. 使用单线程模型也能并发地处理客户端的请求;(I/O多路复用机制——它使用 I/O 多路复用机制同时监听多个文件描述符的可读和可写状态,一旦受到网络请求就会在内存中快速处理,由于绝大多数的操作都是纯内存的,所以处理的速度会非常地快。)

3. Redis服务中运行的绝大多数操作的性能瓶颈都不是cpu



二、Redis的数据类型

 1. 字典(hash)

 概念:字典是Redis服务器中出现最为频繁的复合型数据结构,除了hash结构的数据会用到字典外,整个Redis数据库的所有keyvalue也组成一个全局字典,还有带过期时间的key也是一个字典。(存储在RedisDb数据结构中)

   结构:Redis中的字典相当于Java中的HashMap,内部实现也差不多类似,都是通过“数组+链表”的链地址法来解决部分哈希冲突。

 扩容机制:字典结构内部包含两个hashTable,通常情况下只有一个hashTable有值,但在字典扩容缩容时,需要分配新的hashTable,然后进行渐进式搬迁(rehash),这时候两个hashTable分别存储旧的和新的hashTable,待搬迁结束后,旧的将被删除,新的hashTable取而代之。

   扩容条件:正常情况下,当hash表中元素的个数等于第一维元素的长度时,就会开始扩容,扩容的新数组是原数组大小的2倍。不过如果当Redis正在做bgsave(持久化命令),为了减少内存也得过多分离,Redis尽量不去扩容,但是如果hash表非常满了,达到了第一维数组长度的5倍,这时候就会强制扩容。当hash表因为元素逐渐被删除变得越来越稀疏时,Redis会对hash表进行缩容,条件是元素个数低于数组长度的10%,缩容不会考虑Redis是否在做bgsave。

    2. 压缩列表

这是Redis为了节约内存而使用的一种数据结构,zsethash容器对象会在元素个数较少的时候,采用压缩列表(ziplist)进行压缩。压缩列表是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空隙。

    压缩列表(zip1ist)是列表和哈希的底层实现之一。

     当一个列表只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做列表的底层实现。   

     当一个哈希只包含少量键值对,比且每个键值对的键和值要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做哈希的底层实现。 

    3. Stream结构

 Redis Stream 从概念来说,就像是一个仅追加内容消息链表,把所有加入的信息都一个一个串起来,每个消息都有一个唯一的ID和内容,这很简单,让它复杂的是从Kafka借鉴的另一种概念:消费者组(Consumer Group),为了不让链表过长,它提供了一个定长 Stream 功能。在 xadd 的指令提供一个定长长度 maxlen,就可以将老的消息干掉,确保最多不超过指定长度

Stream

    Consumer Group:消费者组,可以简单看成记录流状态的一种数据结构。消费者既可以选择使用 XREAD 命令进行 独立消费,也可以多个消费者同时加入一个消费者组进行 组内消费。同一个消费者组内的消费者共享所有的 Stream 信息,同一条消息只会有一个消费者消费到,这样就可以应用在分布式的应用场景中来保证消息的唯一性。   

     last_delivered_id:用来表示消费者组消费在 Stream 上 消费位置 的游标信息。每个消费者组都有一个 Stream 内 唯一的名称,消费者组不会自动创建,需要使用 XGROUP CREATE指令来显式创建,并且需要指定从哪一个消息 ID 开始消费,用来初始化 last_delivered_id 这个变量。

    pending_ids:每个消费者内部都有的一个状态变量,用来表示 已经 被客户端 获取,但是还没有 ack 的消息。记录的目的是为了 保证客户端至少消费了消息一次,而不会在网络传输的中途丢失而没有对消息进行处理。如果客户端没有 ack,那么这个变量里面的消息 ID 就会越来越多,一旦某个消息被 ack,它就会对应开始减少。这个变量也被 Redis 官方称为 PEL (Pending Entries List)。

 Stream和kafka的比较

    Redis 基于内存存储,这意味着它会比基于磁盘的 Kafka 快上一些,也意味着使用 Redis 我们 不能长时间存储大量数据。不过如果您想以 最小延迟 实时处理消息的话,您可以考虑 Redis,但是如果 消息很大并且应该重用数据 的话,则应该首先考虑使用 Kafka。  

     另外从某些角度来说,Redis Stream 也更适用于小型、廉价的应用程序,因为 Kafka 相对来说更难配置一些。

  4. list结构

在版本3.2之前,列表底层的编码是ziplistlinkedlist实现的,当列表对象中元素的长度比较小或者数量比较少的时候,采用ziplist来存储(时间换空间),ziplist是存储在一段连续的内存上,所以存储效率很高;当列表对象中元素的长度比较大或者数量比较多的时候,则会转而使用双向列表linkedlist来存储,便于在表的两端进行push和pop操作,在插入节点上复杂度很低,但是它的内存开销比较大,容易产生内存碎片

但是在版本3.2之后,重新引入 quicklist,列表的底层都由quicklist实现。quickList是一个ziplist组成的双向链表。每个节点使用ziplist来保存数据。本质上来说,quicklist里面保存着一个一个小的ziplist

quitList

quickList就是一个标准的双向链表的配置,有head 有tail;

每一个节点是一个quicklistNode,包含prev和next指针。

每一个quicklistNode 包含 一个ziplist,*zp 压缩链表里存储键值。

所以quicklist是对ziplist进行一次封装,使用小块的ziplist来既保证了少使用内存,也保证了性能。



三、Redis持久化

 1. 概念:Redis的数据全部存储在内存中,如果服务器突然宕机,没来得及持久化的数据就会全部丢失,因此必须要用到Redis的持久化机制,他会将内存中的数据持久化到硬盘里面。

 2. Redis持久化步骤:

    ① 客户端向数据库发送写命令(数据在客户端的内存中)

    ② 数据库接收到客户端的写请求(数据在服务器的内存中)

    ③ 数据库调用系统 API将数据写入磁盘(数据在内核缓冲区中)

    ④  操作系统将写缓冲区传输到磁盘控控制器(数据在磁盘缓存中)

    ⑤ 操作系统的磁盘控制器将数据写入实际的物理媒介(数据在磁盘中)

 3. 持久化方式

    ① RDB:当满足特定条件时,它将生成数据集时间点快照。此条件可以由用户配置 Redis 实例来控制,也可以在运行时修改而无需重新启动服务器。快照作为包含整个数据集的单个 .rdb 文件生成。(如果实例被关闭,会丢失未保存的数据

     ② AOF(Append Only File - 仅追加文件):每次执行修改内存中数据集的写操作时,都会记录该操作。假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。(相对于RDB速度很慢

     ③ 混合持久化:将rdb 文件的内容增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小,于是在 Redis 重启的时候,可以先加载rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。

混合持久化

     ④ RDB与AOF的优缺点:

 RDB的优点:

    1. 只有一个.rdb文件,方便持久化

    2. 容灾性好,文件可以安全地保存到硬盘

    3. 性能最大快,使用fork子进程进行持久化操作,主进程可以继续执行查询命令。使用子进程进行持久化时,主进程不会进行任何IO操作。

    4. 相对于数据集大时,比AOF效率高

   缺点:RDB 是间隔一段时间的持久化策略,在持久化之间Redis发生故障,将会丢失部分数据

 AOF的优点:

    1. 数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 aof 文件中一次。

    2. 通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。

    3. AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall)

 缺点:

     1. AOF 文件比 RDB 文件大,且恢复速度慢。   

2. 数据集大的时候,比 rdb启动效率低

    4. 数据恢复优先级:

    如果只配置 AOF ,重启时加载 AOF 文件恢复数据;

    如果同时配置了 RDB 和 AOF ,启动只加载 AOF 文件恢复数据;

    如果只配置 RDB,启动将加载 dump 文件恢复数据。


四、Redis集群    

 1. 主从复制

     概念:是指将一台Redis服务器的数据,复制到其他服务器里面,前者称为主节点(master),后者称为从节点(slave),而且复制是单向的,只能是主节点到从节点。Redis支持主从复制从从复制

 作用:

     ① 数据冗余:实现了数据的热备份,是持久化之外一种数据冗余的方式。

     ② 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复。

     ③ 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,从节点提供读服务,提高redis服务器的并发量。

     ④ 高可用基石:主从复制还是哨兵和集群能够实施的基础。

redis主从复制

   2. Sentinel 哨兵

Sentinel

 概念:提供主动监控节点状态并自动修复故障的服务。

哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据

数据节点:主节点和从节点都是数据节点;

    功能:

     监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。

     ②自动故障转移(Automatic failover):主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。

     配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前 Redis 服务的主节点地址。

     ④ 通知(Notification):哨兵可以将故障转移的结果发送给客户端。

3. Redis集群

redis集群

     概念:集群中的每一个 Redis 节点都互相两两相连,客户端任意直连到集群中的任意一台,就可以对其他 Redis 节点进行读写的操作。

     原理:Redis 集群中内置了16384 个哈希槽。当客户端连接到 Redis 集群之后,会同时得到一份关于这个集群的配置信息,当客户端具体对某一个 key 值进行操作时,会计算出它的一个 Hash 值,然后把结果对 16384求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,Redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。再结合集群的配置信息就能够知道这个 key 值应该存储在哪一个具体的 Redis 节点中,如果不属于自己管,那么就会使用一个特殊的MOVED 命令来进行一个跳转,告诉客户端去连接这个节点以获取数据。

        优点:

    ①数据分区:数据分区(或称数据分片)是集群最核心的功能。集群将数据分散到多个节点,一方面突破了 Redis 单机内存大小的限制,存储容量大大增加另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。Redis 单机内存大小受限问题,在介绍持久化和主从复制时都有提及,例如,如果单机内存太大,bgsave 和 bgrewriteaof 的 fork 操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出……

    ②高可用:集群支持主从复制和主节点的自动故障转移(与哨兵类似),当任一节点发生故障时,集群仍然可以对外提供服务。

    keys和scan的区别

    使用 keys 指令可以扫出指定模式的 key 列表。但是要注意 keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令

你可能感兴趣的:(Redis知识点集合)