Redis相关的知识点

redis技术基础

Redis是一个开源,使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据结构服务器,可用作数据库,高速缓存和消息队列代理。

使用 redis 的好处:

(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)。速度快的原因:①绝大部分请求是纯粹的内存操作;②采用单进程单线程,避免了不必要的上下文切换和竞争条件;③非阻塞IO(多路复用io)。

(2) 支持丰富数据类型,支持string,list,hash,set,sorted set。

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

(4) 丰富的特性:可用于缓存,消息队列,按key设置过期时间,过期后将会自动删除。

redis的数据结构

redis对象的数据结构:

(1) string(字符串对象

字符串对象的编码可以是int、raw或者embstr。

普通的字符串有两种,embstr和raw。embstr应该是Redis 3.0新增的数据结构,在2.8中是没有的。如果字符串对象的长度小于39字节,就用embstr对象。否则用传统的raw对象。

(2) list(列表对象

列表对象的编码可以是ziplist或者linkedlist。

ziplist是一种压缩列表,它的好处是更能节省内存空间,因为它所存储的内容都是在连续的内存区域当中的。当列表对象元素不大,每个元素也不大的时候,就采用ziplist存储。但当数据量过大时ziplist就不是那么好用了。因为为了保证存储内容在内存中的连续性,插入的复杂度是O(N),即每次插入都会重新进行realloc。

linkedlist是一种双向链表。它的结构比较简单,节点中存放pre和next两个指针,还有节点相关的信息。当每增加一个node的时候,就需要重新malloc一块内存。

(3)hash(哈希对象

哈希对象的底层实现可以是ziplist或者hashtable。

ziplist中的哈希对象是按照key1,value1,key2,value2这样的顺序存放来存储的。当对象数目不多且内容不大时,这种方式效率是很高的。

hashtable的是由dict这个结构来实现的。

(4)set(集合对象

集合对象的编码可以是intset或者hashtable。如果value能够表示为整数,则使用intset类型保存value。intset是一个整数集合,里面存的为某种同一类型的整数.intset使用和ziplist相似的实现方式保存整数;数据量大时,切换为使用hash table保存各个value。集合中最大的成员数为 2^32 - 1.

(5)zset(有序集合对象

有序集合的编码可能两种,一种是ziplist,另一种是skiplist与dict的结合。

ziplist作为集合和作为哈希对象的存储是一样的,member和score顺序存放。按照score从小到大顺序排列。它的结构不再复述。

skiplist是一种跳跃表,它实现了有序集合中的快速查找,在大多数情况下它的速度都可以和平衡树差不多。但它的实现比较简单,可以作为平衡树的替代品。

 

redis的数据淘汰策略

redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  4. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  6. no-enviction(驱逐):禁止驱逐数据(永不回收数据)

如何保证缓存热点数据?

mySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据。

数据淘汰策略,LRU,局部性定理,最近使用的数据后面很可能会用到。

redis缓存和mysql数据库同步

目的:mysql中的数据修改后,redis中的数据要做一定的操作,不然会出现不一致的问题

Cache Aside Pattern(先更新数据库,后删除缓存)

失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。

命中:应用程序从cache中取数据,取到后返回。

更新:先把数据存到数据库中,成功后,再让缓存失效(删除缓存)。

Redis的缓存失效策略

定时删除:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除。

惰性删除:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。

定期删除:每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作。

Redis采用的过期策略

惰性删除+定期删除

①惰性删除流程

 

  1. 在进行get或setnx等操作时,先检查key是否过期;
  2. 若过期,删除key,然后执行相应操作;
  3. 若没过期,直接执行相应操作;

②定期删除流程

 

  1. 遍历每个数据库;
  2. 检查当前库中的指定个数的key(默认是每个库检查20个key,注意相当于该循环执行20次);
  3. 如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历;
  4. 随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key;
  5. 判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除;

缓存穿透

用户查询的时候,在缓存中找不到,每次都要去数据库中查询。大并发的缓存穿透会导致缓存雪崩

解决方案

(1)如果查询数据库也为空,直接设置一个默认值存放到缓存(但它的过期时间会很短,最长不超过五分钟),这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。(用假的数据返回给假的请求)

(2)根据缓存数据Key的规则进行过滤。在做缓存规划的时候,Key有一定规则的话,可以采取这种办法。这种办法只能缓解一部分的压力,过滤和系统无关的查询,但是无法根治。

(3)采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的BitSet中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查询压力。

Redis持久化问题

RDB持久化

RDB持久化可以在指定的时间间隔内生成数据集的时间点快照,默认redis是会以快照的形式将数据持久化到磁盘的。

优点:

(1)RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。

(2)RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心。

(3)RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作

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

缺点:

(1)如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。 因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。

(2)每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比较庞大时, fork()可能会非常耗时,造成服务器在某某毫秒内停止处理客户端; 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据的耐久性都不会有任何损失。

原理:

当redis需要做持久化时,redis会fork一个子进程;子进程将数据写到磁盘上一个临时RDB文件中;当子进程完成写临时文件后,将原来的RDB替换掉,这样的好处就是可以copy-on-write(写时复制)。

 

AOF持久化

AOF持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,AOF文件中全部以redis协议的格式来保存,新命令会被追加到文件的末尾,redis还可以在后台对AOF文件进行重写,文件的体积不会超出保存数据集状态所需要的实际大小。

优点:

(1)很高的安全性,数据丢失率比RDB小的多;

(2)AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题;

(3)Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

(4)AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单。

缺点:

(1)对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。

(2)根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

原理:

首先redis会fork一个子进程;子进程将最新的AOF写入一个临时文件;父进程增量的把内存中的最新执行的修改写入(这时仍写入旧的AOF,rewrite如果失败也是安全的);当子进程完成rewrite临时文件后,父进程会收到一个信号,并把之前内存中增量的修改写入临时文件末尾;这时redis将旧AOF文件重命名,临时文件重命名,开始向新的AOF中写入。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值