redis总结

1.redis

redis高性能的key-value数据库,支持持久化,不仅仅支持简单的key-value,还提供了list,set,zset,hash等数据结构的存储,支持数据的备份(master-slave模式)

redis:性能极高,丰富的数据类型,原子操作,丰富的特性

2.redis数据类型

String-字符串,hash-哈希,list-列表,set-集合, zset-有序集合
3.好处

速度快,丰富的数据类型,支持事务(操作原子性),丰富的特性(用于缓存,消息,按key设置过期时间,过期后将自动删除)

4.memcached与redis区别

  • 存储方式:memcached把数据全部存在内存之中,redis可以持久化
  • memcached数据类型简单,redis丰富
  • redis速度更快
  • 底层模型不同,redis直接自己构建了vm机制。

5.redis是单进程单线程的,利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销

6.一个字符串类型的值能存储最大容量是 512M

7.redis持久化机制是什么,优缺点?

持久化机制:RDB和AOP

  • RDB持久化:原理是将Redis在内存中的数据库记录定时dump到磁盘上的RDB持久化

  • AOF持久化:原理是将Redis的操作日志以追加的方式写入文件

rdb和aof

8.常见性能问题和解决方案

  • master不要写内存快照,如果master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响非常大,会间断性暂停服务
  • 如果数据比较重要,某个slave开启aop备份数据,策略设置为每秒同步
  • 为了主从复制的速度和连接的稳定性,master和slave最好在同一个局域网
  • 尽量避免在压力很大的主库上增加从
  • 主从赋值不要用图装结构,用单向链表结构更为稳定,即master<-slave1<-slave2,这样方便解决单点故障问题,实现slave对master的替换,如果master挂了,可以立刻启用slave1做master,其他不变。

9.redis过期键的删除策略

  • 定时删除:设置键的过期时间时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作
  • 惰性删除:放任键过期不管,但每次从键空间获取键时,检查取得的键是否过期,过期删除,不过期返回。
  • 定期删除:隔一段时间,检查一次,删除过期键。

10.redis回收策略(淘汰策略)

  • volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
  • allkey-lru:从数据集中挑选最近最少使用的数据淘汰
  • allkey-random:从数据集中任意选择数据淘汰
  • no-enviction:禁止驱逐数据

使用策略规则

  • 如果数据呈现幂律分布,即一部分数据访问频率高,一部分低,则使用allkeys-lru
  • 如果数据呈现平等分布,即所有的数据访问频率都相同,则使用allkeys-random

11为什么redis需要把所有数据放到内存中?

为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。

12.redis同步机制

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

  • 第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer。
  • 待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。
  • 加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

13.pipeline的好处

可以将多次io往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性,使用redis-benchmark进行压测的时候可以发现影响redis的qps峰值的一个重要因素是pipeline批次指令的数目。

14.redis集群的原理

  • redis sentinal着眼于高可用,在master宕机时会自动将slave提升为master继续提供服务
  • redis cluster着眼于扩展性,单个redis内存不足时,使用cluster进行分片存储。

15.redis集群方案什么情况下会导致整个集群不可用

有ABC三个节点的集群,在没有复制模型的情况下,如果节点b失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用。

Redis Sentinel 及 Redis Cluster

16.redis哈希槽的概念?

redis集群有16384个哈希槽,每个key通过crc16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。集群最大节点个数:16384个

17.redis集群的主从复制模型?

为了使在部分节点失败或大部分节点无法通信的情况下集群仍然可用,所有集群使用了主从复制模型,每个节点都会有N-1个复制品。复制方式:异步复制

18.redis事务

  • 事务是一个单独的隔离操作,事务中的所有命令都会序列化,按顺序地执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子的操作,事务中的命令要么全部被执行,要么全部都不执行。
  • 事务相关的命令:MULTI、EXEC、DISCARD、WATCH

19.redis内存优化

尽可能使用散列表(散列表里面存储的数少,使用内存非常小),尽可能将数据模型抽象到一个散列表里面,eg:一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所欲信息存储到一张散列表里面。

20.redis回收进程如何工作?

客户端运行新的命令,添加新的数据,redis检查内存使用情况,如果大于maxmemory限制,则根据设定好的策略进行回收。

通过不断达到边界然后不断地回收回到边界以下,如果一个命令的结果导致大量内存被使用,不用多久内存限制就会被这个内存使用量超越。

21.降低redis内存使用情况

如果使用的是32位redis实例,可以利用hash,list等集合类型数据。

22.redis内存用完会发生什么

如果达到设置的上限,redis的写命令会返回错误信息(读命令正常返回),或者可以将redis当缓存来使用配置淘汰机制,当redis达到内存上限时会冲刷掉旧的内容。

23.mysql里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?

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

24.redis最适合的场景?

  • 会话缓存
  • 全页缓存
  • 队列
  • 排行榜/计数器
  • 发布/订阅

25.假如redis里有1亿个key,其中10w个key是以某个固定的已知的前缀开头的,如果将他们全部找出来?

keys指令可以扫出指定模式的key列表。

但由于redis是单线程的,keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。

可以用scan指令,可以无阻塞的提取出指定模式的key列表,但有一定的重复概率,在客户端做一次去重就可以了,但整体时间会比直接用keys长。

26.redis做异步队列?

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

不用sleep?blpop在没有消息的时候,他会阻塞住直到消息到来。

生产一次消费多次?使用pub/sub主题订阅者模式,可以实现1:N的消息队列

pub/sub缺点:消费者下线的情况,生产的消息会丢失,使用专业的消息队列如rabbitMQ

redis实现延时队列:使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。

Redisson 的分布式延时队列 RedissonDelayedQueue 运行流程

java 复制代码
//发送消息
String queueKey
RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(queueKey);
RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
delayedQueue.offer(value, delay, timeUnit);

//获取消息
RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(queueCode);
redissonClient.getDelayedQueue(blockingDeque);
return (T) blockingDeque.take();

redisson 源码里一共创建了三个队列:

  • 消息延时队列:利用按照到期时间排序的特性,可以很快找到下一个要到期的消息,客户端内部自己定时到【消息目标队列】取
  • 消息顺序队列:
  • 消息目标队列:存放到期的消息,供消费端取

流程:

发送延迟消息,发送的延迟消息会先存在【消息延时队列】和【消息顺序队列】,如果【消息延时队列】原本是空的,会发布订阅信息提醒有新的消息。

获取延迟消息只需要从【消息目标队列】阻塞的取就行了,因为里面都是到期数据。

初始化延时队列:判断时间到了,把【消息延时队列】里的消息移动到【消息目标队列】里

定时从【消息延时队列】查询最新到期时间,定时去把【消息延时队列】里的消息移动到【消息目标队列】里。

如果【消息延时队列】是空的,就不会再定时查,而是等待发布订阅信息提醒,再定时把【消息延时队列】里的消息移动到【消息目标队列】里。

27.redis分布式锁

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放

setnx之后执行expire之前进程意外crash或者要重启维护了,会怎么样?

set指令的复杂参数,可以把setnx和expire合成一条指令用的。

28.解决key冲突

  • 业务隔离
  • key的设计:业务模块+系统名称+关键(id),针对用户可以加入(userid)
  • 分布式锁:场景:多个客户端并发写key----客户端拿到锁,才能进行操作,避免多个客户端竞争该key
  • 时间戳:key拼接时间戳,根据时间戳保证多个客户端的业务执行顺序

29 什么是缓存穿透

  • 缓存穿透:一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。
  • 解决:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert之后清理缓存。对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该Bitmap过滤。

缓存雪崩

  • 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一时间段失效,这样在失效的时候,会给后端系统带来很大的压力,导致系统崩溃。
  • 解决:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待;做二级缓存;不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀;

30 保证缓存和数据库数据的一致性

  • 淘汰缓存:数据如果为较为复杂的数据时,进行缓存的更新操作就会变得异常复杂,推荐选择淘汰缓存,而不是更新缓存。

  • 选择先淘汰缓存,再更新数据库:假如先更新数据库,再淘汰缓存,如果淘汰缓存失败,那么后面的请求都会得到脏数据,直至缓存过期。假如先淘汰缓存再更新数据库,如果更新数据库失败,只会产生一次缓存穿透,相比较而言,后者对业务则没有本质上的影响。

  • 延时双删策略:

    如下场景:同时有一个请求A进行更新操作,另一个请求B进行查询操作。

    • 请求A进行写操作,删除缓存
    • 请求B查询发现缓存不存在
    • 请求B去数据库查询得到旧值
    • 请求B将旧值写入缓存
    • 请求A将新值写入数据库

次数便出现了数据不一致问题。采用延时双删策略得以解决。

public void write(String key,Object data){

redisUtils.del(key);

db.update(data);

Thread.Sleep(100);

redisUtils.del(key);

}

这么做,可以将1秒内所造成的缓存脏数据,再次删除。这个时间设定可根据俄业务场景进行一个调节。

数据库读写分离的场景

两个请求,一个请求A进行更新操作,另一个请求B进行查询操作。

  • 请求A进行写操作,删除缓存
  • 请求A将数据写入数据库了,
  • 请求B查询缓存发现,缓存没有值
  • 请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值
  • 请求B将旧值写入缓存
  • 数据库完成主从同步,从库变为新值
    依旧采用延时双删策略解决此问题。
相关推荐
月光水岸New2 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6752 小时前
数据库基础1
数据库
我爱松子鱼2 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo3 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser4 小时前
【SQL】多表查询案例
数据库·sql
Galeoto4 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
希忘auto4 小时前
详解Redis在Centos上的安装
redis·centos
人间打气筒(Ada)4 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231114 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
喝醉酒的小白4 小时前
PostgreSQL:更新字段慢
数据库·postgresql