redis知识整理
1、Redis是什么?
简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以存写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
2、Redis 有哪些应用场景
1、热点数据的缓存:由于redis访问速度块、支持的数据类型比较丰富,所以redis很适合用来存储热点数据。
2、分布式锁:多并发情况下,使用 setnx和expire(原子性操作下)加锁,以及当线程执行到一定时间还未结束使用守护线程,用来给快要过期的锁“续航”。
3、做计数器:redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。
等。。
3、Redis 支持哪些数据类型?
String(字符串)、List(列表)、Set(集合)、Zset(Sorted Set:有序集合)、以及Hash(哈希)。
4、Redis 持久化有什么用?
用于快速恢复数据。Redis为了内部数据的安全考虑,会把本身的数据以文件的形式保存在硬盘中一份,在重启之后会自动把硬盘的数据恢复到内存(redis)里面。
5、Redis 持久化之RDB和AOF
1、Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。
2、RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差(镜像全量持久化)。
3、Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中(增量持久化)。
4、AOF 的数据完整性比RDB高,但记录内容多了,会影响数据恢复的效率。
5、Redis 针对 AOF文件大的问题,提供重写的瘦身机制。
6、若只打算用Redis 做缓存,可以关闭持久化。
7、若打算使用Redis 的持久化。建议RDB和AOF都开启。其实RDB更适合做数据的备份,留一后手。AOF出问题了,还有RDB。
AOF的重写机制:
AOF的工作原理是将写操作追加到文件中,文件的冗余内容会越来越多。所以聪明的 Redis 新增了重写机制。当AOF文件的大小超过所设定的阈值时,Redis就会对AOF文件的内容压缩。
重写的原理:Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中,最后替换旧的aof文件。
6、什么是Redis跳跃表?
跳跃表:将有序链表改造为可以支持链表式“二分查找”算法,可以快速的进行插入、删除、查找。
7、Redis 内存满了怎么办?
1、通过配置文件配置
通过在Redis安装目录下面的redis.conf配置文件中添加以下配置设置内存大小
maxmemory 100mb
2、内存淘汰策略
内存淘汰策略相当于清除掉那些占用内存并且使用不太频繁的数据,淘汰掉这些不活跃数据来清理内存。
a)LRU 剔除最近最少使用
volatile-lru:从全数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
b)LFU剔除最近使用频率最低
volatile-lfu:从全数据集(server.db[i].dict)中挑选最近使用频率最低的数据淘汰
allkeys-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最近使用频率最低的数据淘汰
c)Random随机剔除
volatile-lfu:从全数据集(server.db[i].dict)中随机数据淘汰
allkeys-lfu:从已设置过期时间的数据集(server.db[i].expires)中随机数据淘汰
d)其他
noeviction:默认策略,不驱逐,不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。
volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
8、Redis6.0之后支持多线程,开启多线程后,是否会存在线程并发安全问题?
不会,Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。
9、Redis使用的I/O多路复用epoll
I/O多路复用:单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。select, poll, epoll 都是I/O多路复用的具体的实现。
三者区别:
1、底层数据结构
select:数组,poll:链表,epoll:红黑树。
2、支持一个进程所能打开的最大连接数
select 单个进程所能打开的最大连接数有1024(x86)或2048(x64)。poll无上限。epoll 虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。
3、FD剧增后带来的IO效率问题
Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
4、消息传递方式
select/poll 内核需要将消息传递到用户空间,都需要内核拷贝动作。epoll通过内核和用户空间共享一块内存来实现的。
10、假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,生产环境下,如何将它们全部找出来?
redis的命令是单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。
这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
11、什么是缓存穿透,缓存雪崩,缓存击穿?如何解决或预防?
我一个QPS不到10的项目,天天问我缓存穿透、缓存击穿、缓存雪崩,我是真滴难T T。
a)缓存穿透:
访问一个缓存和数据库都不存在的 key,此时会直接打到数据库上,并且查不到数据,没法写缓存,所以下一次同样会打到数据库上。
此时,缓存起不到作用,请求每次都会走到数据库,流量大时数据库可能会被打挂。此时缓存就好像被“穿透”了一样,起不到任何作用。
解决预防方案:
1、接口校验。在正常业务流程中可能会存在少量访问不存在 key 的情况,但是一般不会出现大量的情况,所以这种场景最大的可能性是遭受了非法攻击。可以在最外层先做一层校验:用户鉴权、数据合法性校验等,例如商品查询中,商品的ID是正整数,则可以直接对非正整数直接过滤等等。
2、缓存空值。当访问缓存和DB都没有查询到值时,可以将空值写进缓存,但是设置较短的过期时间,该时间需要根据产品业务特性来设置。
3、布隆过滤器
布隆过滤器应用场景:
- 在爬虫时,对爬虫网址进行过滤,已经存在布隆中的网址,不在爬取。
- 垃圾邮件过滤,对每个发送邮件的地址进行判断是否在布隆的黑名单中,若是在就判断为垃圾邮件。
- 缓存穿透。
布隆过滤器特性:
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
原理:在一个足够大的足够大的 bitmap中,插入时与多个不同的hash函数生成多个哈希值,将对应位置置1。查找时如果发现所有hash函数对应位都是1说明存在,只要有一个为0则认为这个元素不存在。(hash冲突会导致一定的误识别率)
b)缓存雪崩:
缓存雪崩:指在某一个时间段,缓存集中过期失效。Redis宕机。
解决预防方案:
1、优化缓存过期时间:设计缓存时,让过期时间尽量均匀,避免大量的 key 在同一时刻同时失效,造成缓存雪崩。
2、集群:可以把缓存层设计成高可用的,即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务。利用sentinel或cluster实现。
3、构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)。
c)缓存击穿:
指一个热点key被大并发量请求,热点key突然失效时,大批量请求涌向数据库,导致数据库的压力瞬间过大。
解决预防方案:
1、预先设置热门数据
在Redis高峰访问之前,把一些热门数据提前存入Redis中,并且加大这些热门数据key的时长。
2、互斥锁:用分布式锁控制访问的线程,其他线程等待,等到抢到锁的线程从数据库中加载数据完毕。
3、本地缓存:把缓存数据取出时直接加载到本地缓存(Ehcache、Guava Cache),这样访问热key时就可以直接访问呢自己缓存了。
12、redis集群三种方式
1、主从模式:可以一主多从,主从数据同步保证数据完整性,且可以实现写主、读从,性能有所提升,但主节点故障后写受影响,没有故障选举功能,且无监控各主从运行状态功能。
2、哨兵模式:哨兵(sentinel)监控各节点运行状态,主节点发生故障后长(经历主观下线和客观下线),可以通过再次选举产生主节点,实现故障恢复,但若从节点挂了不能实现从节点的故障转移;
选举机制:
如果主节点被判定为客观下线之后,就要选取一个哨兵节点来完成后面的故障转移工作,选举出一个leader的流程如下:
a)每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵3)主节点下线时,会向其它哨兵发is-master-down-by-addr
命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;
b)当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者;
c)如果哨兵3发现自己在选举的票数大于等于num(sentinels)/2+1以及quorum数
时,将成为领导者,如果没有超过,继续选举
3、cluster集群:Redis Cluster 是一种服务器 Sharding 技术(分片和路由都是在服务端实现),采用多主多从,每一个分区都是由一个 Redis 主机和多个从机组成,片区和片区之间是相互平行的。Redis Cluster 集群采用了 P2P 的模式,完全去中心化。
工作原理:
- 集群完全去中心化,采用多主多从;所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。
- 客户端与 Redis 节点直连,不需要中间代理层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
- 每一个 master 节点负责维护一部分槽,以及槽所映射的键值数据;集群中每个节点都有全量的槽信息,通过槽每个 node 都知道具体数据存储到哪个 node 上。根据公式
HASH_SLOT=CRC16(key) mod 16384
,计算出映射到哪个分片上,然后Redis会去相应的节点进行存取操作。 - 为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。
13、如何保证 Redis 缓存与数据库双写一致性
1、加分布式读写锁(适合读多写少场景):通过加锁保证并发读写,写写的时候按顺序排好队,读读不影响。(加读写锁可能会导致系统变得沉重,系统变慢)
2、为缓存设置超时时间(适合允许一段时间DB和缓存不一致的场景):每隔一段时间自动刷新缓存。
3、使用Canal解决缓存一致性问题: Mysql 数据库更新操作后再 binlog 日志中我们都能够找到相应的操作,那么我们可以订阅 Mysql 数据库的 binlog 日志对缓存进行操作。(用Canal需要额外增加Canal中间件,加重系统复杂度)。
原文地址:https://www.cnblogs.com/luoyanyu/p/15226578.html
- JavaWeb(三)servlet
- PL/SQL 编程(三 )程序包和包体,触发器,视图,索引
- 一次关于js事件出发机制反常的解决记录
- Java综合题目
- Ubuntu 16.04下为TITAN 1080 显卡安装驱动及Gpu版TensorFlow|深度学习
- 给新生成的节点(动态生成节点)绑定事件方法总结
- JavaWeb(四)JDBC操作Oracle
- JavaWeb(六)Listener监听器
- JSP引入 - UEditor 富文本编辑器
- JavaWeb(五)Filter过滤器
- JavaWeb(七)Cookie,EL表达式,标准标签库
- JavaWeb(八)JQuery
- 程序员如何提一个好问题
- JavaWeb(九)AJAX
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法