点进来的都是大佬,文章持续更新,欢迎关注浪迹IT圈子的搬砖人。
微信公众号、B站【我在北京写代码】首发。
一、文章目录
redis简介
redis为什么高性能
redis数据类型
redis数据应用场景
redis过期(Expires)
redis内存淘汰机制(算法)
redis持久化
redis管道(Pipelining)
redis大量插入数据
redis事务
redis发布/订阅(Pub/Sub)
redis分区(Partitioning)
redis分布式锁(Distributed locks)
redis缓存雪崩、穿透
redis哨兵
redis集群(高可用)
lua脚本
二、
(1)redis
redis是一个高性能的key-value内存数据库。
(2)redis为什么高性能?
Redis是单线程(严格意义上不是单线程),从而避开了多线程中上下文 频繁切换的操作。
Redis是纯内存操作。
使用多路I/O复用模型算法,非阻塞I/O。(给自己挖坑 如果大厂面试官肯定会问多路复用原理?)
多路复用原理: 例子 100个请求进来,计算机处理方式:
1、顺序执行(效率低下,中间有一个错误 影响下面请求)
2、多线程、开启100个线程执行。(效率高 ,线程协作,浪费一定资源,线程数有上线,并且有线程安全等问题)
3、I/O多路复用、基于事件驱动,请求处理完了通知,计算机再去处理,只在一个线程处理(类似交卷,谁做完谁举手,再去处理)
(3)redis数据类型有哪些?
string(字符串)、hash(哈希)、list(列表)、set(无序集合)、zset(sorted set:有序集合)
挖坑,项目用过那个,怎么实现的
挖坑:五种类型的适合的应用场景:
string:常规存储,可以用做数字计数
hash:哈希是key-value映射表,适合用于存储对象(类似存储个人信息-key是id,value一串字符串)
list:列表,适合存储排列的数据(消息列表、粉丝列表等)、据说可做高性能分页。
set: 实现交集、并集、差集的操作
zset:可以排序,适合一些需要排序的集合(榜单排名等)
(4)项目中的应用?
大多是用作缓存。
(高频数据缓存、redis session共享(分布式应用服务)验证码X分钟有效,只能登陆X次 等等(过期key应用))
(5)redis过期(Expires)
设置key的过期时间,超过时间后,将会自动删除该key。
常用场景:验证码等
如何淘汰过期的keys:被动和主动方式。
(6) redis内存淘汰机制(算法)
noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
allkeys-random: 回收随机的键使得新添加的数据有空间存放。
volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
(7)既然是内存型数据库,关机或重启数据丢失了怎么办? redis持久化
1、Redis提供两种持久化方案RDB和AOF。
RDB
RDB文件是经过压缩的二进制数据文件,LZF算法对RDB文件进行压缩(RDB文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度(20字节)时才会进行)。
RDB配置如图
一般在配置文件中save m n,指定当m秒内发生n次变化时,会触发bgsave。
save 900 1的含义是:当时间到900秒时,如果Redis数据发生了至少1次变化,则执行bgsave
bgsave是啥
bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求。
还有一个save命令,但是会阻塞Redis服务器进程。
AOF
AOF持久化将Redis执行的每次写命令记录到单独的日志文件中。(文件会较大)
AOF的执行流程如下图
1.先写入缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。
2.同步文件策略有三种
(1)always:命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,写缓存和写硬盘是同时的(这样硬盘IO性能瓶颈)
(2)no: 命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。)
(3)everysec:命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,推荐配置。
3.文件重写(rewrite)
文件重写目的压缩AOF文件(过期的数据,无效的命令,相近的命令合并等),提升性能。
两种方式开启文件重写
(1)手动bgrewriteaof命令
(2)配置文件
和RDB一样都是新建子进程进行,都不造成堵塞。
redis重启怎么加载这两种备份文件呢?
当AOF开启时,Redis启动时会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会载入RDB文件恢复数据。
持久化策略选择
待更。
(8)现在要向redis服务器一次性发送多个命令,如何?
管道(节省往返时间)
(9)生成一个10亿的`keyN -> ValueN’的大数据集
待更新。
(10)事务
多个命令,要不全部执行,要不全部失败。
开始事务。以 MULTI 开始
命令入队。执行命令(多个)
执行事务。 EXEC 命令触发事务
(11)用redis实现 发布/订阅(Pub/Sub)
待更新
(12)redis分区
待更新
扩展:最终数据在redis存储是什么类型?**
二进制。
---------------------------------为什么要分割线--------------------------------------------------
(13)分布式锁?
挖坑: 都有哪些锁,怎么用,什么是分布式,redis实现分布式锁实现方案?
(14)、缓存雪崩、穿透*
1、缓存穿透。先上图
分析上图流程,没有命中缓存情况下,去DB里拿数据,但是DB里也没有数据呢?
是不是后续步骤就打断了,并且下次同样请求进来也会再去请求一次DB。
问题就出来了,像这种情况基本缓存基本就没用了,变成了: 读请求–>没有命中–>去DB查询–>返回null
对,请求量少是没有问题的,但是毕竟在网络上,网络攻击这样还是很常见的。
总结
请求的数据在数据库不存在,无数的这种请求进来,都会直接打到DB,就像所有狙击枪子弹打到同一个点穿透一样, 致使DB宕机。
真实场景:
user表,有一条数据userid=1当成key存储
常规:根据key,1 先查redis,没有则查询db,吧查询出来的值放进redis,以供下一次直接从redis查询,这样减少db请求
重点来了:我现在用key=0,去继续上面的常规操作,看会引起什么
先从redis查询,没数据,进db查询,还是没有数据,返回nll,
请求量小这样没问题,但是并发量一旦上来了 就像直接穿透了redis,全部去打到DB就宕掉了。
解决方案
1、参数做校验,不合法参数拦截(考虑误拦截)
2、使用互斥锁(在根据key获得的value值为空时,先锁上,再从数据库加载,加载完毕,释放锁。若其他线程发现获取锁失败,则睡眠50ms后重试)。锁的类型,单机环境用并发包的Lock类型就行,集群环境则使用分布式锁( redis的setnx)
3、布隆过滤器(分布式要自己写)
扩展
4、平常用户是不会在单秒内发起这么多次请求,网关层可以设置,ip单秒请求次数
2 缓存雪崩
引起原因:同一时间key大面积失效(过期),缓存层宕掉。就像无数散弹枪子弹打满全部靶子。
解决方案:
1、每个Key的失效时间尽可能分散不一致(随机数或者现在时间做处理)推荐
2、使用锁或队列,本质没有增加并发量,只是减轻数据库的压力(高并发不推荐)
3、特别热点的数据不设置更新时间(永不过期)
4、二级缓存(本地缓存)
5、redis哨兵或集群(从服务器上升,还是会被大流量打死)
6、使用netflix的hystrix(限流&降级)。
(15)、Redis高可用
。
** 哨兵 见下图(画的丑请忽略)**
优点:(监控主从机及哨兵间互相监控,比起主从复制架构好多了,不用人为干预,不管哪台宕机都可自带切换)。
缺点: 单机扩容问题,没能实现负载。如果想要更好的扩展显然哨兵还很不足。
(16)集群,官方推荐。
待更
(17)lua脚本
代更