Redis知识点本文就够

一、 Redis数据结构

(1)String 字符串

使用场景:

1.缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。
2.计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。
3.session:常见方案spring session + redis实现session共享,

(2)Hash 哈希

使用场景:

1.缓存: 能直观,相比string更节省空间,的维护缓存信息,如用户信息,视频信息等。

(3)List链表

使用场景:

1.timeline:例如微博的时间轴,有人发布微博,用lpush加入时间轴,展示新的列表信息

(4)Set集合

使用场景:

1.标签(tag),给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。
2.点赞,或点踩,收藏等,可以放到set中实现

(5)Zset有序集合

使用场景:

1.排行榜:有序集合经典使用场景。例如小说视频等网站需要对用户上传的小说视频做排行榜,榜单可以按照用户关注数,更新时间,字数等打分,做排行。

二、 Redis单线程模型为啥这么快?

(一)基于内存操作

Redis将所有需要存储的数据都存放在内存中,基于内存的随机访问速度是磁盘的10万倍左右,即使是SSD也遥不可及,这是Redis操作快速的重要物理基础。

(二)C语言实现

相同逻辑下的C语言程序,执行效率要比其他语言的高很多。C语言与当前主流的操作系统之间有着独特的关系,抛开开发难度来看,执行速度还是蛮快的。

(三)简单的数据结构

内存数据库的另一个优点是,基于内存的数据结构要比基于硬盘的数据结构更加简单,对数据的操作也更加简单,因此Redis可以做很多事情,内部复杂性很小。Redis占用的内存空间也是比较少。

(四)I/O多路复用模型

单个线程通过记录跟踪每一个Sock(I/O流)的状态来同时管理多个I/O流。主要有select, poll, epoll三种实现方式。
1、select poll每次循环调用时,都需要将描述符和文件拷贝到内核空间;epoll 只需要拷贝一次;
2、select每次返回后,都需要遍历所有的描述文件才能找到就绪的,时间复杂度为O(n),而epoll则需要O(1);
3、poll比select的改进,就是使用链表来保存fd,使能监听的数量远远大于1024

(五)单线程模型

避免了多线程的启动、销毁、上下文切换、加锁、解锁等消耗资源的操作。单线程简单,不仅能避免上下文切换这种非常消耗资源的操作,而且可以避免死锁的情况。大大提升CPU的利用率。如果是多核服务器,可以通过启动多个Redis实例来利用多个CPU。

三、持久化之RDB与AOF

Redis 是一种基于内存的数据库,一旦断电、重启,Redis 中的数据将不复存在。Redis 提供了 RDB 和 AOF 两个持久化的方式。当 Redis 实例重启时,可以使用已持久化的数据(文件)来还原内存数据集。

(一)RDB

这种持久化方式是将当前Redis内存中的数据生成 快照(Snapshot) 文件保存到硬盘,简单粗暴。RDB也是Redis默认开启的持久化方式。
1、 触发持久化
save
在之前已经废弃的 save 命令来实现RDB持久化数据,save 命令持久化时会一直阻塞,直到持久化完成。数据量越大,持久化过程带来的阻塞时间就越长。
bgsave
现在可以使用 bgsave 命令来代替 save。bg就是background,使用 bgsave 方式RDB持久化时,Redis工作进程会 fork 一个子进程,该子进程专门来负责耗时的RDB持久化,而工作进程会继续工作,阻塞时间只发生在短暂的 fork 阶段。
除了主动触发命令外,Redis还是提供了自动触发RDB持久化命令 bgsave ,该命令表示在seconds秒内,Redis内存数据修改的次数达到changes次时,将触发RDB持久化。比如 bgsave 7200 10 表示在2个小时内,数据被更改10次时将自动触发RDB持久化。
(注意changes计数并不包含查询语句,当然被操作的key一定存在,否则也不会进行计数)
2、 数据快照存储
首先,工作目录默认为当前Redis目录,那么持久化的RDB数据快照将存储在该目录,可通过 dir ./ 参数进行修改。生成的数据存储快照名称默认为 dump.rdb ,可通过 dbfilename dump.rdb 参数进行修改。RDB持久化先生存一个临时快照,待数据持久化完成,这个临时快照会替换原快照,以防持久化过程出现问题。
RDB存储快照默认是使用LZF算法压缩功能,压缩后的文件体积将大大减少。压缩文件但并不是十全十美,RDB快照压缩时也会消耗CPU,数据量越大,消耗CPU资源就越多,但官网还是极力推荐我们开始此功能。
RDB持久化时可能出现权限问题、存储空间不够用等问题,Redis 默认开启stop-writes-on-bgsave-error yes 参数,意味着出现 error时,Redis将停止向快照文件写入数据。
在Redis保存/恢复数据时,并不是一股脑进行保存/恢复,默认会对RDB快照文件进行检查,性能会受到影响(大约10%),因此可以禁用它以获得最大的性能。(推荐开启)

(二)AOF

这种持久化方式是通过保存写命令来记录操作日志,在数据恢复时,重新执行已记录的写命令,来达到数据恢复。
1、 AOF原理
默认情况下,AOF是关闭的,可以通过修改 appendonly no 为 appendonly yes 来开启 AOF 持久化。内存的Output的带宽远大于磁盘Input的带宽,如果内存瞬时将大量的数据写入磁盘,必然发生IO堵塞,对于单线程工作的Redis也将会在性能上大打折扣。所以所有的写命令并不会直接写入AOF文件,而是先将写命令存储至AOF Buffer缓冲区,最后在同步至AOF文件。
生成的AOF文件名,默认为 appendonly.aof ,可以修改 appendfilename “appendonly.aof” 参数来更改生成的AOF文件名。
从缓冲区同步至磁盘,Redis提供了三种同步方式:
always: 写命令被追加到AOF缓存后,调用系统fsync函数将缓冲区的数据同步至磁盘,最后返回
everysec: 写命令被追加到AOF缓存后,调用系统write函数,在write函数执行完成,然后返回,会触发系统将对缓冲区的数据进行同步至磁盘
no: 写命令被追加到AOF缓存后,调用系统write函数,然后返回,后续的同步由系统负责
其中 everysec 不仅是默认的方式,也是推荐的方式。
2、 AOF重写机制
AOF持久化文件存储的是Redis写命令,这比仅仅是数据的存储文件要大了很多。在AOF重写机制中,首先遍历数据库,如果数据库为空库,则跳过该库。对于非空的数据库,则遍历所有的key,如果key过期则跳过该key,如果key有过期时间则设置key的过期时间。
AOF的重写机制并不是随机触发的,默认是当前写入AOF文件大小较上次重写后文件大小增长了 100% 时就触发重写机制。比如上次重写后的文件大小是1G,经过一段时间,AOF文件体积增长了 1G ,那么增长率就是 100% ,就会触发AOF重写。可以通过设置 auto-aof-rewrite-percentage 100 来调节文件增长率的触发阈值。
如果AOF的文件较少,不足以影响太大性能,所以没必要重写AOF文件。可以通过 auto-aof-rewrite-min-size 64mb 来设置AOF文件重写的最小阈值。
aof-load-truncated yes 参数表示,在Redis恢复数据时,最后一条命令可能不完整,开启则表示忽略最后一条不完整的命令。

(三)RDB和AOF对比

RDB开始压缩后,生成一个体量更小、更紧凑的二进制文件,占有空间小。RDB不仅有着较快的数据恢复能力,而且可以直接复制RDB文件至其他Redis实例进行回复数据,有着良好的容灾体验。RDB适用于定时复制、全量复制、快速恢复的场景,由于RDB文件生成时间长,数据有存储延迟,不适用于近实时持久化的场景。
AOF以追加命令的方式,持续的、近实时的写入文件(秒级别)。而且,在一定程度时,AOF不断的重写持久化文件,不断的优化。特别是在数据完整性上要比RDB好很多,例如,使用默认的数据同步策略,Redis在发生服务器断电等重大事件时,可能只丢失一秒钟的写入时间,或者在Redis进程本身发生错误但操作系统仍在正常运行时丢失一次写入时间。所以AOF比较适合对数据实时性和数据完整性要求比较高的场景。AOF相较于RDB,缺点是文件相对较大,而且恢复数据时因为要执行全部的写命令,所以数据恢复比较慢,特别在是在被依赖的应用系统高负载的情况下,较长时间的数据恢复,对后端系统是不可容忍的。
但AOF和RDB持久性可以同时启用,不会出现问题。如果在启动时启用了AOF,redis将加载AOF,即具有更好的持久性保证的文件。而且在较新的版本还支持混合模式。
RDB-AOF混合持久化
Redis从 4.0 开始支持RDB-AOF混合持久化,默认是关闭状态,可以通过 aof-use-rdb-preamble yes 开启。AOF文件在重写之后,将生成一份记录已有数据的RDB快照文件,再生成一份记录最近写命令的AOF文件,作为对RDB快照的补充。这样的混合持久化模式,将兼具RDB和AOF的双优特性。

四、 主从复制与故障转移

(一)数据复制的意义

1、读写分离,降低单节点的读写压力;
2、容灾转移,单机出现问题,从节点接替。

(二)Redis注册复制原理

首先,通过上述配置主从复制,从节点保存主节点的信息,然后建立 socket 连接。Redis的ping命令是用于客户端检测服务端是否正常运作或消息延时的一种命令,是一种心跳机制,在这里从节点就是客户端,主节点就是服务端。从节点发送ping命令至主节点,如果主节点正常运作则返回pong,这样才能表示双方网络通达。紧接着,如果主节点开启 requirepass foobared 参数(foobared 可以认为是安全校验密码),主节点会对从节点进行权限校验。密码正确后,才进行数据同步,最后不断的、陆陆续续的、持续复制后面的数据,实现这一持续复制数据的实现方式就是复制其操作命令。

(三)故障转移

对于单个节点而言,有可能出现故障(fail),为了保证该服务的可用性,需要使用其他冗余或备用节点来接替该节点工作,这种拯救方式就是 故障转移(Failover) 。
比如一个 一主两从 的高可用方案,主节点工作,从节点作备用:
如果主节点(master节点)出现故障,那么服务不可用,从节点(slave节点)也无法从master节点持续复制数据,如何实现故障转移呢?下面是基于客户端的实现。
1、客户端使用心跳机制,定时检测 master、slave节点活性,比如使用ping命令;
2、如果master节点在一定时间内无回复,则认为master节点此时不可用;
3、从slave节点中随机选择或选择一个ping-pong网络较好的一个节点晋升为master,比如6380节点;
4、6380节点和6381节点先与6379断开复制关系 slaveof no one;
5、然后以6380为master节点,6381为salve节点建立复制关系;
建立新的主从复制
6、通过心跳检测6379节点故障恢复后,作为salve节点与master节点建立主从复制关系;
屏幕快照 2019-02-16 下午4.10.30.png
7、故障转移完成。(其实到了第3步选取6380为主节点后,服务就可用了)
客户端为了高可用,也可以做成多节点,在Redis的master节点出现故障时,客户端多节点通过选举方式来产生新的master节点。从Redis 2.8 版本开始,新加入了 Redis Sentinel 来实现高可用。

五、 高可用与 Sentinel 哨兵

Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

(一)sentinel的功能

1.监控
Sentinel会不断地检查你的主服务器和从服务器是否运作正常。
2.提醒
当被监控的某个Redis服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知。
3.自动故障迁移
当一个主服务器不能正常工作时,Sentinel会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器。

六、分布式缓存与 Redis Cluster

redis最开始使用主从模式做集群,若master宕机需要手动配置slave转为master;后来为了高可用提出来哨兵模式,该模式下有一个哨兵监视master和slave,若master宕机可自动将slave转为master,但它也有一个问题,就是不能动态扩充;所以在3.x提出cluster集群模式。
Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

七、缓存击穿(缓存穿透)、缓存雪崩

(一) 缓存击穿(缓存穿透)

缓存(Cache) 是分布式、高并发的场景下,为了保护后端数据库,降低数据库的压力,引入的一种基于内存的数据访问机制,能加快数据的读取与写入,进而提高系统负载能力。

缓存击穿(缓存穿透) 是访问不存在缓存中的数据,进而直接访问数据库。
缓存击穿 和 缓存穿透 更为详细的分类:
在这里插入图片描述
在缓存穿透这种情形下,如果缓存和数据库都没有需要被访问的数据,那么访问缓存时没有数据则直接返回空,避免重复访问数据库,造成不必要的后端数据库压力。
解决方案
1.缓存空值: 如果第一次访问一个不存在的数据,那么将此key与value为空值的数据缓存起来,下次再有对应的key访问时,缓存直接返回空值,通常要设置key的过期时间,再次访问时更新过期时间;
2.布隆过滤: 类似散列集合(hash set),判断key是否在这个集合中。实现机制在于比特位,一个key对应一个比特位,并且存储一个标识,如果key有对应的比特位,并且标识位表示存在,则表示有对应的数据。比如使用Redis 的 Bitmap实现。

(二)缓存雪崩

大量的缓存击穿意味着大量的请求怼在数据库上,轻者造成数据库响应巨慢,严重者造成数据库宕机。比如缓存内的数据集体定时刷新、服务器重启等。
解决方案
1、降低缓存刷新频率;
2、部分缓存刷新,刷新数据时按照一定规则分组刷新;
3、设置key永远不过期,如果需要刷新数据,则定时刷新;
4、分片缓存,在分布式缓存下,将需要缓存的数据 散列 分布到多个节点,尽量将热点数据均匀分布到多节点。

八、Redis热点Key

在一定时间内,被频繁访问的key称为 热点key 。比如突发性新闻,微博上常见的热搜新闻,引起千千万万人短时间内浏览;在线商城大促活动,消费者比较关注的商品突然降价,引起成千上万消费者点击、购买。热点key会导致流量过于集中,缓存服务器的压力骤然上升,如果超出物理机器的承载能力,则缓存不可用,进而可能诱发缓存击穿、缓存雪崩的问题。
解决方案
1、 读写分离
通过将数据的写入与读取分散去各个节点,通过数据复制到达各个节点数据一致性的目的。在写少的情形下,master节点写入数据,在读取请求压力大的情形下,配置多个slave节点,数据横向同步(拓扑结构)。结合Redis Sentinel (或其他高可用技术)实现缓存节点的高可用。
2、 阿里云云数据库 Redis 版解决方案
在热点 Key 的处理上主要分为写入跟读取两种形式,在数据写入过程当 SLB 收到数据 key1 并将其通过某一个 Proxy 写入一个 Redis,完成数据的写入。假若经过后端热点模块计算发现 key1 成为热点 key 后, Proxy 会将该热点进行缓存,当下次客户端再进行访问 key1 时,可以不经 Redis。最后由于 Proxy 是可以水平扩充的,因此可以任意增强热点数据的访问能力。
3、 热点key不过期
如果key存在,那么不要设置key过期时间,如果key对应的数据不可用(比如删除了),那么从缓存中删除key。从请求来说,如果在缓存找到对应的key,表明该key及其value就是用户需要的数据。如果缓存中不存在对应的key,表明无对应的数据,返回空值。比如微博发来爆料某明星文章,短时间内访问量直接上升,如果key不过期,那么请求永远命中缓存。只有当文章被删除的时候,才从缓存中删除对应的key,如果此时还有请求访问,在缓存中查无数据时,直接返回空值,表明文章被删除。当然也可以更新key对应的value值,返回想要表达的value。

九、布隆过滤

布隆过滤器是一个神奇的数据结构,可以用来判断一个元素是否在一个集合中。很常用的一个功能是用来去重。布隆过滤器本质是一个位数组,位数组就是数组的每个元素都只占用 1 bit 。每个元素只能是 0 或者 1。
布隆过滤器除了一个位数组,还有 K 个哈希函数。当一个元素加入布隆过滤器中的时候,会进行如下操作:
1、使用 K 个哈希函数对元素值进行 K 次计算,得到 K 个哈希值。
2、根据得到的哈希值,在位数组中把对应下标的值置为 1。
3、当要判断一个值是否在布隆过滤器中,对元素再次进行哈希计算,得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值在布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。

  • 布隆过滤器说某个元素在,可能会被误判。
  • 布隆过滤器说某个元素不在,那么一定不在。

十、Redis内存管理机制

(一)最大内存限制

Redis使用 maxmemory 参数限制最大可用内存,默认值为0,表示无限制。
1、用于缓存场景,当超出内存上限 maxmemory 时使用 LRU 等删除策略释放空间。
2、防止所用内存超过服务器物理内存。因为 Redis 默认情况下是会尽可能多使用服务器的内存,可能会出现服务器内存不足,导致 Redis 进程被杀死。

(二)内存回收策略

(1)删除过期键对象

采用惰性删除和定时任务删除机制实现过期键的内存回收。
惰性删除是指当客户端操作带有超时属性的键时,会检查是否超过键的过期时间,然后会同步或者异步执行删除操作并返回键已经过期。这样可以节省 CPU成本考虑,不需要单独维护过期时间链表来处理过期键的删除。
Redis 内部维护一个定时任务,默认每秒运行10次(通过配置控制)。定时任务中删除过期键逻辑采用了自适应算法,根据键的过期比例、使用快慢两种速率模式回收键。

(2)内存溢出控制策略

当内存达到 maxmemory 时触发内存溢出控制策略,强制删除选择出来的键值对象。

每次Redis执行命令时如果设置了maxmemory参数,都会尝试执行回收内存操作。当Redis一直工作在内存溢出(used_memory>maxmemory)的状态下且设置非 noeviction 策略时,会频繁地触发回收内存的操作,影响Redis 服务器的性能。

猜你喜欢

转载自blog.csdn.net/wh672843916/article/details/112434844
今日推荐