赞
踩
本文主要总结一下
之前学习的笔记知识点
Redis框架从入门到学精(全)
以及面试八股文中常见的题目
也可参考一下他人的面试总结题
Redis 常见面试题(2020最新版)
高性能的 key-value
总体来说,它的功能还是多种多样的,比如缓存、数据持久化、支持事务、支持消息队列等
单线程模式(在redis6.0之后引入了多线程io,只是用来处理网络数据的读写和协议的解析,但执行命令还是单线程)
redis 利用队列技术将并发访问变为串行访问
,消除了传统数据库串行控制的开销
部署多个Redis,当作不同服务器使用。也可考虑分片
两种持久化机制 RDB 和 AOF 机制
RDB:在指定的时间间隔内将内存中的数据集快照写入磁盘 写入一个临时文件,持久化结束后,用这个临时文件替换上持久化的文件,达到数据恢复
优点:
缺点:
数据安全性低。RDB 是间隔一段时间
进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失
AOF:
以日志的形式
来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件
优点:
缺点:
文件过大,恢复速度慢
数据集大的时候,比RDB要慢
(1) 定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作。
(2) 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
(3) 定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
从机主动发送
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。(刚开始从机连接主机,主机一次给)
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步 (主机修改了数据会给予从机修改的数据同步,叫做增量复制)
断开之后重新连接,只要是重新连接master,一次完全同步(全量复制)将被自动执行,rdb的数据就会给从机。
主机负责写,从机负责读
Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求
具体的原理:
Sentinal
着眼于高可用,在 master 宕机时会自动将 slave 提升 为 master,继续提供服务Cluster
着眼于扩展性,在单个 redis 内存不足时,使用Cluster 进行分片存储通过启动界面后
在内部输入该命令set requirepass 123456
,启动之后通过auth 123456
也可以在配置文件直接修改,变成永久密码
一个 Redis 集群包含 16384 个插槽(hash slot)也就是使用的是哈希槽
集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽
通过ping命令
具体的命令有这么几个MULTI、EXEC、DISCARD、WATCH
事务开始 MULTI
命令入队
事务执行 EXEC
具体Redis的事务特性有:
事务中的所有命令都会序列化、按顺序地执行
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。
通过使用比较小key-value,可以更加好的紧凑在一起
也就是设计键值的时候,越短越好
好好利用 Hash,list,sorte,set,set 等集合类型数据。内部会针对不同类型存在编码的概念
控制key的数量
redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时分散一些
Redis 的并发竞争Key
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘 记了释放
但是如果setnx之后系统维护了,就不能给锁加时间
正确的应该是同时把 setnx 和 expire 合成一条指令来用的
补充基于zookeeper:
基于zookeeper临时有序节点可以实现的分布式锁。大致思想为:每个客户端对某个方法加锁时,在
zookeeper上的 与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的
方式很简单,只需要判断有 序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即
可。同时,其可以避免服务宕机导致的锁 无法释放,而产生的死锁问题。完成业务流程后,删除对应的
子节点释放锁
主要是因为 Redis 具备高性能和高并发两种特性。
主要是有三个原因:
1、Redis的全部操作都是纯内存的操作;
2、Redis采用单线程,有效避免了频繁上下文切换
;
3,采用了非阻塞I/O多路复用机制
可以使用Redis的数据淘汰策略,Redis 内存数据集大小上升到一定大小的时候,就会施行这种策略。具
体说来,主要有 6种内存淘汰策略:
AOF重写可以产生一个新的AOF文件,这个新的AOF文件和原有的AOF文件所保存的数据库状态一样,
但体积更小。
在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创
建新AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件的工作之后,服务器
会将重写缓冲区中的所有内容 追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态
一致。最后,服务器用新的AOF文件替换旧的 AOF文件,以此来完成AOF文件重写操作。
补充:(实时更新面经的常问题目:)
数据类型 | 可以存储的值 | 操作 | 应用场景 |
---|---|---|---|
string | 字符串、整数或者浮点 | 对整个字符串或者字符串的其中一部分执行操作,对整数和浮点数执行自增或者自减操作 | 做简单的键值对缓存,计数器,共享session以及限速 |
list | 列表 | 从两端压入或者弹出元素,对单个或者多个元素进行修剪,只保留一个范围内的元素 | 存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的 |
set | 无序集合 | 添加、获取、移除单个元素,检查一个元素是否存在于集合中。计算交集、并集、差集。从集合里面随机获取元素 | 交集、并集、差集的操作,比如交集,可以把两个人的粉丝列表整一,或者是用户的喜好标签等 |
hash | 包含键值对的无序散列 | 添加、获取、移除单个键值对。获取所有键值对。检查某个键是否存在 | 结构化的数据,比如一个对象 |
zset | 有序集合 | 添加、获取、删除元素。根据分值范围或者成员来获取元素。计算一个键的排名。 | 去重但可以排序,如获取排名前几名的用户,排行榜等 |
key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到
,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库
通俗的来说:访问的数据缓存找不到,一直转而发送到数据库
解决方案:
一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义
(1)对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
(2)设置可访问的名单(白名单):
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
(3)采用布隆过滤器:(布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。)
将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
(4)进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务
总结如下:
设置空值缓存,而且设置超时时间
通过bitmap的位运算进行存储,数据量比较小
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来
,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
也就是一个key过期,一直访问数据库
解决方案:
key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。
(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长
(3)使用锁:先判断值是否为空再让他进来与否
总结如下:
key对应的数据存在,但在redis中过期
,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key正常访问
解决方案:
(1)构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)
(2)使用锁或队列:
用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
(3)设置过期标志更新缓存:
记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
(4)将缓存失效时间分散开:
比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
总结如下:
系统上线前提前将相关数据加载到缓存系统中
如果不进行预热,刚开始缓存数据为空,对于高并发数据,对数据库有压力
缓存失效或者服务器宕机,不访问数据库,直接访问服务内存数据
通过参考日志提前设置预案:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。