Redis的常见问题

0、Redis是什么?

Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。

1、Redis的常见数据类型及命令

常见数据类型:
String: 字符串 Hash: 散列 List: 列表 Set: 集合 Sorted Set: 有序集合

EXISTS key  #检查给定 key 是否存在

DEL key  #该命令用于在 key 存在时删除 key

EXISTS key  #检查给定 key 是否存在

EXPIRE key seconds  #为给定 key 设置过期时间,以秒计

MOVE key db  #将当前数据库的 key 移动到给定的数据库 db 当中

TTL key  #以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)

RENAME key newkey  #修改 key 的名称

TYPE key  #返回 key 所储存的值的类型

#Redis 字符串命令

SET key value  #设置指定 key 的值

GET key  #获取指定 key 的值

GETRANGE key start end  #返回 key 中字符串值的子字符

GETSET key value  #将给定 key 的值设为 value ,并返回 key 的旧值(old value)。

SETEX key seconds value  #将值 value 关联到 key ,并将 key 的过期时间设为 seconds (set expire)

SETNX key value  #只有在 key 不存在时设置 key 的值(SET if not exists)

STRLEN key  #返回 key 所储存的字符串值的长度

INCR key  #将 key 中储存的数字值增一

INCRBY key increment  #将 key 所储存的值加上给定的增量值(increment) 

DECR key  #将 key 中储存的数字值减一

APPEND key value  #如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾

2、Redis 最适合的场景  

会话缓存(Session Cache)
  最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的

全页缓存(FPC)
  除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进。

队列
  Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。

排行榜/计数器
  Redis在内存中对数字进行递增或递减的操作实现的非常好。要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,假定根据你用户的分数做递增的排序,我们只需要像下面一样执行即可:
ZRANGE user_scores 0 10 WITHSCORES
  
发布/订阅
  Redis提供的所有特性中,喜欢的人最少的一个。

3、Redis是单线程为什么还这么快?/Redis的并发竞争问题如何解决?

Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。

Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法:

客户端角度:为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。

服务器角度:利用setnx实现锁。

4、Redis和 memcached 的区别

memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型

redis的速度比memcached快很多

redis可以持久化其数据

redis 内存淘汰机制等等。

5、使用redis有哪些好处?

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

支持丰富数据类型,支持 String List Set Sorted Hash

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

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

6、redis持久化的几种方式

RDB 和 AOF 两种持久化方式,RDB 是把采用二进制压缩存储内存中的数据集以快照形式写入磁盘;AOF 是以文本日志的形式记录 Redis 处理的每一个写入或删除操作。

RDB 把整个 Redis 的数据保存在单一文件中,比较适合用来做灾备,但缺点是快照保存完成之前如果宕机,这段时间的数据将会丢失,另外保存快照时可能导致服务短时间不可用。

AOF 对日志文件的写入操作使用的追加模式,有灵活的同步策略,支持每秒同步、每次修改同步和不同步,缺点就是相同规模的数据集,AOF 要大于 RDB,AOF 在运行效率上往往会慢于 RDB。

7、缓存常见问题

缓存更新方式

缓存的数据在数据源发生变更时需要对缓存进行更新,数据源可能是 DB,也可能是远程服务。更新的方式可以是主动更新。数据源是 DB 时,可以在更新完 DB 后就直接更新缓存。

当数据源不是 DB 而是其他远程服务,可能无法及时主动感知数据变更,这种情况下一般会选择对缓存数据设置失效期,也就是数据不一致的最大容忍时间。

这种场景下,可以选择失效更新,key 不存在或失效时先请求数据源获取最新数据,然后再次缓存,并更新失效期。

但这样做有个问题,如果依赖的远程服务在更新时出现异常,则会导致数据不可用。改进的办法是异步更新,就是当失效时先不清除数据,继续使用旧的数据,然后由异步线程去执行更新任务。这样就避免了失效瞬间的空窗期。另外还有一种纯异步更新方式,定时对数据进行分批更新。实际使用时可以根据业务场景选择更新方式。

数据不一致
第二个问题是数据不一致的问题,可以说只要使用缓存,就要考虑如何面对这个问题。缓存不一致产生的原因一般是主动更新失败,例如更新 DB 后,更新 Redis 因为网络原因请求超时;或者是异步更新失败导致。

解决的办法是,如果服务对耗时不是特别敏感可以增加重试;如果服务对耗时敏感可以通过异步补偿任务来处理失败的更新,或者短期的数据不一致不会影响业务,那么只要下次更新时可以成功,能保证最终一致性就可以。

缓存穿透
缓存穿透。产生这个问题的原因可能是外部的恶意攻击,例如,对用户信息进行了缓存,但恶意攻击者使用不存在的用户id频繁请求接口,导致查询缓存不命中,然后穿透 DB 查询依然不命中。这时会有大量请求穿透缓存访问到 DB。

解决的办法如下。

对不存在的用户,在缓存中保存一个空对象进行标记,防止相同 ID 再次访问 DB。不过有时这个方法并不能很好解决问题,可能导致缓存中存储大量无用数据。

使用 BloomFilter 过滤器,BloomFilter 的特点是存在性检测,如果 BloomFilter 中不存在,那么数据一定不存在;如果 BloomFilter 中存在,实际数据也有可能会不存在。非常适合解决这类的问题。

缓存击穿
缓存击穿,就是某个热点数据失效时,大量针对这个数据的请求会穿透到数据源。

解决这个问题有如下办法。

可以使用互斥锁更新,保证同一个进程中针对同一个数据不会并发请求到 DB,减小 DB 压力。

使用随机退避方式,失效时随机 sleep 一个很短的时间,再次查询,如果失败再执行更新。

针对多个热点 key 同时失效的问题,可以在缓存时使用固定时间加上一个小的随机数,避免大量热点 key 同一时刻失效。

缓存雪崩
缓存雪崩,产生的原因是缓存挂掉,这时所有的请求都会穿透到 DB。

解决方法:

使用快速失败的熔断策略,减少 DB 瞬间压力;

使用主从模式和集群模式来尽量保证缓存服务的高可用。

posted @ 2022-03-28 21:06  Code7Rain  阅读(91)  评论(0编辑  收藏  举报