文章目录
Redis复习笔记
redis为什么这么快
developer.aliyun.com/article/709851
-
基于内存
- 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
-
高性能的数据结构
- 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
- i利用空间换时间的思想:空间预分配
-
多路复用I/O模型
-
一个线程处理多个io流
-
多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。
-
-
单线程
-
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;完全基于内存,没有磁盘IO的限制。在redis中对数据进行持久化的时候
resp通信协议
-
使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
-
redis的数据结构
- 简单动态字符串
- redis是有用C语言编写的,重新定义了一种数据类型:简单动态字符串
时间复杂度
- 数组:O1
- 链表:On
Redis 使用了一个哈希表来保存所有键值对 O(1)
redis的优缺点
优势:
- 业务角度:加快请求效率,提升使用体验
- 技术角度:减轻服务器、数据库压力,提升系统性能
劣势:
-
成本方面,代码、业务成本,服务器成本,部署和运维维护成本
-
维护成本增加
-
缓存失效
- 缓存穿透
- 访问不存在的key.缓存和数据库中都没有的数据,在缓存中查不到,就去查询数据库,数据库中也查不到,而用户大量请求。比如:id = -1
- 解决:
- 接口层增减校验,如用户校验,id基础校验,id<=0 的直接拦截
- 当缓存中没有的时候,在缓存中塞一个数据,id = -1,value = null,
- 布隆过滤器
- 缓存击穿
- 缓存中没有而数据库中有的数据(如缓存中的数据失效了,过期了),这时由于并发用户特别多,同事缓存中没有读取到数据,就会取数据库取数据,引起了数据库的压力大增
- 解决
- 针对业务场景,对热点数据设置缓存不过期。数据量小的情况下,不可能对所有的数据都这样
- 加互斥锁,牺牲性能来规避出错
- 缓存雪崩
- 缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机,和缓存击穿不同的是:缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了
- 解决
- 过期时间设置不同时间,防止同一时间大量数据过期
- 如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中
- 设置热点数据永不过期(数据量小的情况下)
- 缓存穿透
-
缓存与数据库数据同步问题
-
常规写法
- (多线程情况下)先删数据库,再删缓存:弊端:查询的数据不准
- (多线程情况下)先删缓存,再删数据库
-
延时双删(推荐)
使用互斥锁解决查询到的脏数据
清空缓存是直接删除key
redis基本数据类型
redis只是为了缓解数据库的压力,其中存储的数据应该不能影响服务器迁移
-
String(字符串)
- 场景:看是否发送过短信,发送过一次,记录一下,之后不再发送
-
Hash(哈希)
- 场景:用户登录信息,可以存object
- 自增自减
- 分布式锁,setns()
- 存储图片,二进制文件
-
List(列表)
- 场景:消息队列(一般不使用redis,一般使用mq)
-
Set(集合)
- 场景1:用户标签组,没有重复数据
- 场景2:好友列表,可获取两个用户的共同好友
- 场景3:ip白名单,当有这个ip即在白名单中
-
zset(sorted set:有序集合)
- 场景:排行榜
redis高级用法
-
位图 bitmap
- 体积小,10M可存8千万bit,最大允许512M
-
布隆过滤器
- https://developer.aliyun.com/article/773205
-
GEO 经纬度
-
只支持直线距离
-
场景摇一摇功能,周边餐饮,快递距离
-
-
HyperLogLog
- 用于计数,存在一定误差,误差最大值在1%以下。如果业务需求不能有误差,那么不能使用这个。
- 实际上不会存储每个元素的值,它使用的是概率算法,通过hash值的第一个1的位置,来计算元素的数量
- 计数比较小时采用稀疏矩阵来进行村相互,空间占用了从还是很小的,只有达到一定阈值后才会变成稠密矩阵空间才会达到12KB。
- 场景:大数据量下的统计。在大数据下1%的误差可以忽略不几计
-
Lua脚本
- 为什么会有lua脚本
- redis服务器会单线程原子性执行lua脚本,保证lua脚本在处理的过程中不会被其他请求打断
- 有什么作用
- 为什么会有lua脚本
-
分布式锁
Jedis 和 Redisson 都是Java中对Redis操作的封装。Jedis 只是简单的封装了 Redis 的API库,可以看作是Redis客户端,它的方法和Redis 的命令很类似。Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能,相比于Jedis 更加大。但Jedis相比于Redisson 更原生一些,更灵活
- 自己实现:使用jedis
- 引入依赖
- 封装一个RedisLock,加锁、解锁等
- redisson
- 引入依赖
- 直接使用
- 自己实现:使用jedis
-
订阅与退订
结合实际情况使用。
-
特点
- redis无法对消息持久化存储
- 不能消费过去时间的消息
- redis没有提供消息传输保障
- 服务端不知道用户端是否已消费成功
- redis协议支持较少,扩展性受限制
删除方式(淘汰策略)todo
- 被动删除:惰性删除
- key过时了,但是不立即删除,等查询的时候发现过期了再删除
- 主动删除:定期删除(比如过一个小时,就删了)
- 主动删除(贪心策略):redis会周期性的随机测试一批设置了过期时间的key并进行处理,redis 3.0.0的默认值是10,代表每秒总调用10词后台任务,即每秒进行10次随机测试。
- redis lru过期策略
- 最近最少使用
- redis lfu过期策略
- (最不经常使用算法)
- redis无法对消息持久化存储
持久化方式
-
RDB
- redis默认的方案。再指定的时间间隔内,执行指定次数的写操作,将内存中的数据写入的磁盘中。即再指定目录
- 优点
- 适合大规模的数据恢复
- 如果业务对数据完整性和一致性要求不高,适合使用
- 缺点
- 数据的完整性和一致性不高,因为rdb可能在最后一次备份时宕机了
- 备份时占用内存,因为redis再备份时会独立创建一个子进程,此时内存中的数据时原来的两倍。所以凌晨的时候比较合适
-
AOF
-
AOF (Append Only File)方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。
我们通过配置 redis.conf 中的 appendonly yes 就可以打开 AOF 功能。如果有写操作(如 SET 等),redis 就会被追加到 AOF 文件的末尾
-
redis默认不开启,他的出现时为了弥补rdb的不足:数据的不一致性。
-
特点:数据的完整性的一致性更高,但是因为aof记录内容多,文件会越来越大,数据恢复会越来越慢
-
redis集群
todo
-
-
-
-