这是我参与「第五届青训营 」伴学笔记创作活动的第 17 天
redis学习:
redis基本概念:
redis是一款用c语言写的基于内存的高性能k-v的nosql数据库,常用于后端程序和数据库之间做缓存,用于弥补DB和后端程序之间的性能差距,DB吞吐跟不上系统并发的时候,避免请求直接进入DB而起到保护作用。
除了做DB缓存还可以做很多功能,例如,计数器、用户在线状态、排行榜、session存储、同时redis性能客观,官方给出10w/s的QPS,实际读7-9w/s,写入6-8w/s。
常用命令:
| 命令 | 作用 |
|---|---|
| keys * | |
| dbsize | |
| exists key | |
| del key | |
| ttl key | |
| expire key seconds | |
| expireat key timestamp | |
数据结构:
前五种:字符串、散列表、列表、集合、有序集合
后四种:bitmaps、hyperloglogs、geospatial、Streams
不过每种数据都不会直接放到
Redis相关概念:
- Redis完全基于内存
- 整体类似于HashMap,查询复杂度为O(1),不需要随机IO或全表查询
- Redis对于客户端处理时单线程的,不用上下文切换。
- 采用了select/epoll多路复用的高效非阻塞IO模型
- 客户端通信采用RESP,简单一度,避免了复杂请求的开销
缓存一致性,雪崩,击穿,穿透:
缓存一致性:
关于Redis与MySQL之间的数据一致性问题其实也考虑过很多方案,比如先删后改,延时双删等等很多方案,但是在高并发情况下还是会造成数据的不一致性,所以关于DB与缓存之间的强一致性一定要保证的话那么就对于这部分数据不要做缓存,操作直接走DB,但是如果这个数据比较热点的话那么还是会给DB造成很大的压力,所以在我们的项目中还是采用先删再改+过期的方案来做的,虽然也会存在数据的不一致,但是勉强也能接受,因为毕竟使用缓存访问快的同时也能减轻DB压力,而且本身采用缓存就需要接受一定的数据延迟性和短暂的不一致性,我们只能采取合适的策略来降低缓存和数据库间数据不一致的概率,而无法保证两者间的强一致性。合适的策略包括合适的缓存更新策略,合适的缓存淘汰策略,更新数据库后及时更新缓存、缓存失败时增加重试机制等。
雪崩:
一时间大量key过期,且大量请求来到,导致大量数据查询DB,使得宕机。解决方案
- 热点key永不过期
- 错开过期时间,
- 使用分布式锁或MQ队列串行请求,不会大量请求落入DB
击穿:
缓存雪崩是大量key过期,而击穿是一个热点key过期,大量请求查询数据最终落到DB。解决方案:
- 热点key永不过期
- 座环redis监控,设置串行化
- 使用mutex锁机制,缓存失效的时候,查询DB前通过mutexkey进行查询。
穿透:
不合理的请求,不能击中缓存,查询DB也不行,例如userId=-1,然后黑客通过肉鸡服务器攻击查询DB,使得宕机,整个系统瘫痪。解决方案
- 对IP限流与黑名单,避免同一IP一瞬间发送大量请求。
- 对于请求做非法校验,对写带非法参数的请求进行过滤
- 对于不存在的数据在Redis中设置“Not Data”并设置短过期时间
- 布隆过滤器
八种淘汰和三种删除策略:
八种淘汰策略:
数据存放在内存中,如果我们没有设置过期时间,那么回浪费内存,redis5.0之前有五种淘汰策略,redis5.0之后有8种策略。大体分为四种类型lru,lfu,random,ttl。
| 策略 | 概述 |
|---|---|
| volatile-lru | 从已设置过期时间的数据集中挑选-最近最少用的 |
| volatile-ttl | 从已设置过期时间的数据集中挑选-即将过期的,ttl值越大优先被淘汰 |
| volatile-random | 从已设置过期时间的数据集中挑选-随机淘汰 |
| volatile-lfu | 从已设置过期时间的数据集中挑选-频率低的数据淘汰 |
| allkeys-lru | 从数据集中-最近最少用的 |
| allkeys-lfu | 从数据集中-频率低的数据淘汰 |
| allkeys-random | 从数据集中-随机淘汰 |
| no-enviction | (默认),不会驱逐数据 |
三种键的删除策略:
key的删除策略:
- 定时删除:设置键的过期时间同时设置一个定时器,当键过期后,定时器马上删除该键
- 惰性删除:key过期后不删除,当有请求使用该key的时候,检测是否过期,然后进行删除。
- 定期删除:每隔一段时间进行随机抽取一些设置了过期时间的key进行删除。类似于定时删除和惰性删除的中间策略。
- redis采用定期+惰性删除的策略。
三种持久化:
数据存储在内存中,那么停电或宕机,数据怎么恢复。三种持久化方式诞生,redis早期采用了AOF、RDB持久化。后期采用混合持久化生成(AOF文件)。
RDB持久化:
默认开启:
数据生成快照到.rdb文件中保存,RDB 是在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,重启时加载这个文件达到数据恢复。分为手动触发和自动触发:
自动触发:
- save 300 10 :300秒内有10个写操作保存
手动触发:
- save:阻塞redis进行保存,
- bgsave:fork redis进行持久化,在关闭的时候会自动进行bgsave
特点-优点:
- 单独线程持久化,不会IO,保证高性能
- 二进制文件,备份、全量复制,可用于灾难备份,加载速度快于AOF文件
特点-缺点:
- 一段时间进行持久化,要是这段时间中故障那么就可能数据丢失。
- 创建子线程开销大。
- 备份时候占用内存。
- 二进制文件新老版本不兼容。
AOF持久化:
用于解决RDB持久化方式造成的数据丢失,不是保存快照数据,而是日志方式记录命令。
三种持久化策略:
- appendfsync always:同步持久化,每次的命令都会追加到AOF文件,每次写入都会IO,受到性能影响,但是数据安全。
- appendfsync everysec:异步操作,每秒将写命令追加到AOF文件中,最多丢失1s数据
- appendfsync no:不进行调用文件同步,操作系统处理。
优点:
- fsync保证数据是最新的,通过后台处理,对请求线程不影响
缺点:
- 文件体积比RDB大很多,数据恢复时需要重新执行指令,恢复慢。
- 高并发下fsync也会造成一些性能问题。
AOF重写原理:
redis运行时间长后,客户端命令越来越多,然后AOF文件变大恢复缓慢,需要通过重写AOF文件来减肥。
4.x之后的混合模式:
通过AOF做增量日志的方式,使得AOF文件不会太大,使用RDB进行存储主要内容。
事务:
事务控制
| 命令 | 作用 |
|---|---|
| multi | 标识事务开始 |
| discard | 取消事务 |
| exec | 实行事务 |
| unwatch | 取消所有key监视 |
| watch key [key ..] | 监视key |