缓存
- Memcached
- redis
- Redis常见数据类型和使用
- Redis缓存持久化
- RDB-快照
- AOF-追加文件
- Redis数据过期机制
- 惰性删除
- 定期删除
- Redis缓存淘汰策略(8种)
- 算法
- LRU (Least Recently Used):最近最少使用
- LFU(Least Frequently Used):最近最少频率使用
- Redis事务
- Redis为什么要用分布式缓存
- Redis集群
- 主从模式 - 最简单的
- 哨兵模式
- Redis Cluster
- Redis常见问题及解决方案
- 缓存击穿
- 缓存穿透
- 缓存雪崩
- bigKey
- 热Key
- 慢查询命令
- 如何保障数据库和缓存数据的一致性
- 延时双删
- 异步更新缓存
- MongDB
Memcached
简洁的key-value存储系统,其实是内存中维护一张巨大的Hash表。不支持集群,Memcached彼此之间不进行通信,所以,可能会造成数据丢失。
和redis对比
Memcached | Redis | |
---|---|---|
数据类型 | 只支持key-value | |
数据持久化 | Memcached 把数据全部存在内存之中 | Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用 |
集群模式支持 | 没有原生的集群模式 | 3.0 版本起是原生支持集群模式的 |
线程模型 | 多线程,非阻塞 IO 复用的网络模型 | 单线程的多路 IO 复用模型 |
特性支持 | Redis 支持发布订阅模型、Lua 脚本、事务等功能 | |
过期数据删除 | 只用了惰性删除策略 | 惰性删除策略、定期删除策略 |
redis
redis是一个缓存中间件。
数据基于内存,内存的访问速度比磁盘快很多
单线程,基于I/O多路复用
- 6.0后支持多线程,但是命令执行还是单线程
Redis 除了可以用作缓存之外,还可以用于分布式锁、限流、消息队列、延时队列等>场景
- 延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)
- 消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。(Rpush +Lpop)
Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。- 限流: 通过 Redis + Lua 脚本的方式来实现限流。key是ip,value是访问次数
- redis搜索引擎:借助 RediSearch
- redis延时任务
Redis常见数据类型和使用
5 种基础数据类型
String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
- String,二进制安全的,可以存储图片或者序列化的对象,值最大存储为512M
set key value
get key
- Hash
hset key field value
hget key field
- List
lpush key value [value ...]
lrange key start end
- Set(集合)
sadd key element [element ...]
smembers key
- ZSet(有序集合)
zadd key score member [score member ...]
zrank key member
3 种特殊数据类型
HyperLogLog(基数统计)、Bitmap (位图)、Geospatial
(地理位置)。除了上面提到的之外,还有一些其他的比如 Bloom filter(布隆过滤器)open in new
window、Bitfield(位域)。
场景应用:排行耪
选用ZSet,这是一个有序集合。根据score来排序
Zrange (从小到大排序)、 ZrevRange (从大到小排序)、ZrevRank (指定元素排名)。
Redis缓存持久化
4.0之后,RDB 和 AOF 混合使用实现持久化
RDB-快照
AOF-追加文件
Redis数据过期机制
设置expire(过期时间)后才会触发。
Redis 采用的是 定期删除+惰性/懒汉式删除 结合的策略
惰性删除
当查询key时候,先看该key是否过期,没有过期就返回数据;负责,删除该key,且不返回数据
定期删除
在一定时间,随机抽取设置过期时间的key,若这些含的key大部分过期,就删除这些过期key
-
Redis 的定期删除过程是随机的(周期性地随机从设置了过期时间的 key 中抽查一批),所以并不保证所有过期键都会被立即删除。这也就解释了为什么有的 key 过期了,并没有被删除。
-
并且,执行时间已经超过了阈值,那么就中断这一次定期删除循环,以避免使用过多的 CPU 时间
-
可在配置文件中设置频率
由 hz 参数控制的。hz 默认为 10,代表每秒执行 10 次
Redis缓存淘汰策略(8种)
当redis内存不够用的时候,当一个新key需要存放时候就会按某种规则将内存中的数据删掉,这个删除规则就是淘汰策略。
- noeviction:默认策略。不删除任何key,新增的key也不写入,内部不足直接报错
- volatile-ttl:对设置TTL时间的key,剩余时间越短的先删除
- allkeys-random:对全体key随机淘汰
- volatile-random:对设置TTL时间的key随机淘汰
- allkeys-LRU:对全体key使用LRU短发淘汰
有明显冷热数据区分- volatile-LRU: 对设置TTL时间的key使用LRU短发淘汰
数据有置顶的需求 — 置顶数据不设置过期时间,这些数据就一直不被删除,会淘汰其他设置过期时间的数据- allkeys-LFU:对全体key使用LFU短发淘汰
- volatile-LFU: 对设置TTL时间的key使用LFU短发淘汰
算法
LRU (Least Recently Used):最近最少使用
用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
LFU(Least Frequently Used):最近最少频率使用
会统计每个key的访问频率,值越小淘汰优先级越高。
Redis的数据淘汰策略有哪些 ?- 以下回答背熟,大概用时1min。
redis有个策略叫数据淘汰策略,具体指的是当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉。这个策略redis提供了8种方案,默认的叫noeviction,就是不删除任何数据,内部不足直接报错。方案的切换是可以在redis的配置文件中进行设置的,里面有两个非常重要的概念,一个是LRU,另外一个是LFU。
LRU,即Least Recently Used,意思就是最近最少使用,我们用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
LFU,即Least Frequently Used,意思就是最近最少频率使用。我们会统计每个key的访问频率,值越小淘汰优先级越高。
Redis事务
redis提供了一种命令,可以将多个命令打包一起后按顺序执行,执行途中不会被影响
MULTI(开始事务),EXEC(执行事务)直接包着命令集
Redis为什么要用分布式缓存
Redis集群
https://segmentfault.com/a/1190000043133394
主从模式 - 最简单的
这里是引用
Redis主从复制优点: 做到读写分离,提高服务器性能;
Redis主从复制缺点: 在主从模式中,一旦Master节点由于故障不能提供服务,需要人工将Slave节点晋升为Master节点
哨兵模式
当主服务器宕机后,需要手动把一台从服务器切换为主服务器,需要人工干预费事费力,为了解决这个问题出现了哨兵模式
哨兵模式优点:最大的优点就是主从可以自动切换,系统更健壮,可用性更高;哨兵模式缺点:最大的缺点就是还要多维护一套哨兵模式,实现起来也变的更加复杂增加维护成本;
Redis Cluster
主要是针对海量数据+高并发+高可用的海量数据场景,Redis集群模式的性能和高可用性均优于哨兵模式。
Redis常见问题及解决方案
缓存击穿
热key在缓存中过期了,所以不在缓存中,会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。
解决方案:
- 永不过期(不推荐):设置热点数据永不过期或者过期时间比较长。
- 提前预热(推荐):针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。
- 加锁(看情况);:在缓存失效后,通过设置互斥锁确保只有一个请求去查询数据库并更新缓存
缓存穿透
大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中 。导致这些请求直接到了数据库上对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。
解决方案:
- 首先做好参数校验,不合法的参数请求直接抛出异常信息返回给客户端
- 缓存无效 key,SET key value EX 10086 设置过期时间
- 布隆过滤器
- 接口限流,用户或者 IP 对接口进行限流,对于异常频繁的访问行为,还可以采取黑名单机制
缓存雪崩
缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力
解决方案:
- 针对 Redis 服务不可用的情况:
Redis 集群
多级缓存(本地缓存+Redis 缓存的二级缓存组合)- 针对大量缓存同时失效的情况
设置随机失效时间
针对热点数据提前预热,并设置合理的时间
对于某些关键性和变化不频繁的数据,持久缓存永不过期
bigKey
一个 key 对应的 value 所占用的内存比较大,那这个 key 就可以看作是 bigkey.
- String 类型的 value 超过 1MB
- 复合类型(List、Hash、Set、Sorted Set 等)的 value 包含的元素超过 5000 个
产生原因:
- 设计不当---- 使用string存储较大文件的二进制流
- 数据规模考虑不到位---- 使用集合类型没有考虑到数据量的快速增长
带来什么问题 — 阻塞
- 客户端超时阻塞:redis是单线程的,操作大key时候耗时
如果解决
- bigkeys 命令去扫描(redis-cli -p 6379 --bigkeys -i 3 表示扫描过程中每次扫描后休息的时间间隔为 3 秒)
- 找到后,手动清理;用合适的数据结构
热Key
访问频率较高的Key。
会出现的问题
- 某个热点数据访问量暴增 占用大量的 CPU 和带宽,影响redis的其他请求处理;严重情况下,导致宕机
如果查看
- 可以通过hotkeys 参数来查找
如果解决
- 读写分离:主节点处理写请求,从节点处理读请求。
- 使用 Redis Cluster:将热点数据分散存储在多个 Redis 节点上
- 二级缓存:hotkey 采用二级缓存的方式进行处理,将 hotkey 存放一份到 JVM 本地内存中(可以用 Caffeine)。
慢查询命令
为什么会有慢
如何保障数据库和缓存数据的一致性
延时双删
写入库的前后,都删除缓存【redis.del(key)操作】
步骤
先删除缓存 —> 再写数据库 —> 休眠 500 毫秒 —> 再次删除缓存
缺点:
最差的情况就是在超时时间内数据存在不一 致,而且又增加了写请求的耗时。
异步更新缓存
MySQL binlog 增量订阅消费+消息队列+增量数据更新到 redis
步骤
MongDB
分布式文件储存的数据库
- 存储数据:数据库中存储的对象设计BSON,一种类似json的二进制文件,由键值对组成
- 链接方式(默认为27017)
mongodb://[username:password@]host1[:port1][,host2[:port2]- 库简单认识
文档 - row
集合 - table
数据库 - database- 复制工作
MongoDB的复制工作是基于主从复制实现的。其中一个节点被定义为主节点,其他的节点被定义为备份节点,数据会进行实时同步。在某些情况下,主节点可能会失效或消失,这时候从节点将被提升为主节点继续工作。- 支持存储过程吗
支持,它是javascript写的,保存在db.system.js表中。