Redis整理


Redis使用过程中碰到的问题?

问题1:incr命令问题ERR value is not an integer or out of rangejedis.incr(prefixKey + key);

在调用这个方法的时候,如果将值设置为0.0等样式,这样在进行增加操作的时候会有问题,要保证为整形的字符串类型。

问题2:序列化问题

出现原因为,两个项目包名不一致,反序列化失败。

Redis的淘汰策略有哪几种?

volatile-lru    从已设置过期时间的数据集中挑选最近 最少使用的数据淘汰

volatile-ttl    从已设置过期时间的数据集中挑选        将要过期的数据淘汰

volatile-random 从已设置过期时间的数据集中               任意选择数据淘汰

对于以上三种策略,如果没有符合条件的,则和noeviction一样返回错误。

allkeys-lru    从所有数据集中挑选最近最少使用的数据淘汰

allkeys-random 从所有数据集中任意选择数据进行淘汰

noeviction     禁止驱逐数据,默认策略,对于写请求会报错,删除和其他部分请求除外

如何获取或设置淘汰策略?

获取当前内存淘汰策略:

127.0.0.1:6379> config get maxmemory-policy

通过配置文件设置淘汰策略(修改redis.conf文件):

maxmemory-policy allkeys-lru

通过命令修改淘汰策略:

127.0.0.1:6379> config set maxmemory-policy allkeys-lru

Redis高性能的原因?

Redis是单线程的,避免了多线程的上下文切换和并发控制开销;

Redis大部分操作时基于内存,读写数据不需要磁盘I/O,所以速度非常快;

Redis采用了I/O多路复用机制,提高了网络I/O并发性;

Redis提供高效的数据结构,如跳跃表、哈希表等;

Redis到底是单线程还是多线程?

版本5.0之前的版本是单线程,工作线程是单线程。指令串行执行。

6.0版本之后,还是单work线程。但是会开辟单独的IO子线程。去read和write。计算还是在work线程中,将结果返回io子线程中。

Redis的使用场景?

计数器

排行榜计算

生成订单号

点赞功能

消息队列

会话缓存

分布式锁

共同好友

Redis支持哪些数据类型?

String

List

Set

Hash

Zset

Redis的持久化策略有哪些?

AOF文件

将写命令添加到 AOF 文件(Append Only File)的末尾。

使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。

always 每个写命令都同步everysec 每秒同步一次no 让操作系统来决定何时同步always 选项会严重减低服务器的性能;

everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;

no 选项并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量。

RDB快照

将某个时间点的所有数据都存放到硬盘上。

可以将快照复制到其它服务器从而创建具有相同数据的服务器副本。

如果系统发生故障,将会丢失最后一次创建快照之后的数据。

如果数据量很大,保存快照的时间会很长。

例:设置可以如下

Save 900 1

Save 300 10

Save 60 10000  //60秒内超过1万条就备份

Save 是阻塞的,直到rdb创建完毕

Bgsave fork出一个子进程来创建rdb文件,不阻塞

什么是缓存穿透?解决办法?

缓存穿透

访问一个缓存和数据库都不存在的 key,此时会直接打到数据库上,并且查不到数据,没法写缓存,所以下一次同样会打到数据库上。

解决办法

接口校验,可以在最外层先做一层校验:用户鉴权、数据合法性校验等,例如商品查询中,商品的ID是正整数,则可以直接对非正整数直接过滤等等。

缓存空值。当访问缓存和DB都没有查询到值时,可以将空值写进缓存,但是设置较短的过期时间,该时间需要根据产品业务特性来设置。

布隆过滤器。使用布隆过滤器存储所有可能访问的 key,不存在的 key 直接被过滤,存在的 key 则再进一步查询缓存和数据库。

如何保证缓存数据一致性?

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。

更新的时候,先更新数据库,然后再删除缓存。

Redis几种数据结构的实际应用?

String

对象缓存

单值缓存 SET user:1 value(json格式数据)

分布式锁 SETNX product:10001

计数器 INCR article:readcount:{文章id}

序列号生成 INCRBY orderId 1000 //redis批量生成序列号提升性能

Hash  
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。

购物车 添加商品:hset cart:1001 10088 1

List

消息流,消息队列

Set

共同关注 SINTER zhangsanSet yijiaoqianSet--> {lisi, wangwu}

可能认识 SDIFF yijiaoqianSet zhangsanSet->(zhangsan, zhaoliu}

Zset

排行榜 ZREVRANGE hotNews:20201221 0 9 WITHSCORES

什么是多路复用?

redis利用epoll实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。

socket —>多路复用程序 —>队列 —>文件事件分派器

redis客户端先去select循环询问服务端是否可以发起read 这个过程是阻塞的 但是速度很快,当服务端准备好了数据报告诉客户端readable,客户端即可发起read请求,此时因为服务端已经准备好了数据报,直接返回即可。整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的。这种方式避免了线程的阻塞,又称为非阻塞I/O模型

这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗)

什么是缓存击穿?解决办法有哪些?

某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。

解决方案

加互斥锁。在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。

热点数据不过期。直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存。

什么是缓存雪崩?有哪些解决方案?

大量的热点 key 设置了相同的过期时间,导在缓存在同一时刻全部失效,造成瞬时数据库请求量大、压力骤增,引起雪崩,甚至导致数据库被打挂。

(升级版的缓存击穿)

解决方案

  • 过期时间打散。既然是大量缓存集中失效,那最容易想到就是让他们不集中生效。可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。
  • 热点数据不过期。该方式和缓存击穿一样,也是要着重考虑刷新的时间间隔和数据异常如何处理的情况。
  • 加互斥锁。该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算,其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。

Redis的bitmap的应用场景有哪些?

# 设置值,其中value只能是 0 和 1

setbit key offset value

# 获取值

getbit key offset

# 获取指定范围内值为 1 的个数

# start 和 end 以字节为单位

bitcount key start end

# BitMap间的运算

# operations 位移操作符,枚举值

AND 与运算 &

OR 或运算 |

XOR 异或 ^

NOT 取反 ~

# result 计算的结果,会存储在该key中

# key1 … keyn 参与运算的key,可以有多个,空格分割,not运算只能一个key

# 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0。返回值是保存到 destkey 的字符串的长度(以字节byte为单位),和输入 key 中最长的字符串长度相等。

bitop [operations] [result] [key1] [keyn…]

# 返回指定key中第一次出现指定value(0/1)的位置

bitpos [key] [value]

使用过Redis做异步队列么,你是怎么用的?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。

Redis的同步机制了解么?

Redis可以使用主从同步,从从同步。

第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将RDB文件全量同步到复制节点,复制节点接受完成后将RDB镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过AOF日志同步即可,有点类似数据库的binlog。

从海量数据中查询某一固定前缀的key

keys指令会造成堵塞,不建议用

建议用Sacn cursor [MATCH pattern] [COUNT count]

例:sacn 0 match k1* count 10 开始迭代查找k1开头的key10条

每次在程序中需要获取游标的返回值,并在此基础上继续遍历

如何使用redis做异步队列

使用list作为队列,rpush生产消息 lpop消费消息

如果想要一条消息被很多消费者消费,需要使用发布订阅模式 pub/sub,缺点是发布无状态,无法保证可达。

Redis的同步机制