目录
一、Redis介绍
简单来说Redis是一款高性能非关系型的键值对数据库。与传统数据库不同的是Redis的数据是存储在内存中,所以读写速度非常快。因此被广泛应用于缓存方面,每秒可处理超过10W次的读写操作,Redis也经常用来做分布式锁,此外,Redis支持事务、持久化、LUA脚本、LRU驱动事件、多集群方案。
Redis可以存储键和五种不同类型的值之间的映射,键类型只能为字符串,支持五种数据类型:String、List、Set、ZSet、Hash。
1.1数据类型
数据类型 | 可以存储的值 | 操作 | 应用场景 |
---|---|---|---|
STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作 对整数和浮点数执行自增或者自减操作 | 做简单的键值对缓存 |
LIST | 列表 | 从两端压入或者弹出元素 对单个或者多个元素进行修剪, 只保留一个范围内的元素 | 存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的数据 |
SET | 无序集合 | 添加、获取、移除单个元素 检查一个元素是否存在于集合中 计算交集、并集、差集 从集合里面随机获取元素 | 交集、并集、差集的操作,比如交集,可以把两个人的粉丝列表整一个交集 |
HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对 获取所有键值对 检查某个键是否存在 | 结构化的数据,比如一个对象 |
ZSET | 有序集合 | 添加、获取、删除元素 根据分值范围或者成员来获取元素 计算一个键的排名 | 去重但可以排序,如获取排名前几名的用户 |
1.2优缺点
优:
读写速度快
支持数据持久化,AOF和RDB两种方式
支持事务
数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构
支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
缺:
数据库受物理内存限制,不适合海量数据高性能读写,一般作用于小数据量的高性能操作和运算
Redis不具备自动容错和恢复功能,主从机的宕机都有可能造成读写失败,需等待重启或前端手动更改IP才能恢复
主机宕机前有部分数据未能同步到从机,切换IP后有可能造成数据不一致的问题,降低了系统可用性能
Redis较难支持在线扩容,在集群容量达到上限后在线扩容会变得复杂,运维人员得在运行前确保有足够的容量
二、为什么要使用Redis/缓存?
2.1高性能
如用户第一次获取数据时是从数据库获取,因数据是从硬盘上读取,相对缓慢一些。将此次请求数据存于缓存,再次访问数据时是从缓存中获取,是直接操作内存,速度相对会快很多。如果数据库中数据发生变化,则把相应Key缓存数据删除,下次获取数据又会和第一次获取数据一样,且确保数据是最新数据。
2.2高并发
直接操作缓存请求远远大于直接请求数据库,以秒杀/抢红包为例,在活动开始前把数据存储在缓存中,活动结束后再同步redis数据到数据库。
三、持久化
3.1什么是持久化?
持久化就是将数据存储到磁盘,以防宕机数据丢失无法恢复。
3.2持久化机制
3.2.1Redis DataBase(简称RDB)
执行机制:快照,直接将databases中的key-value的二进制形式存储在了rdb文件中
优点:性能较高(因为是快照,且执行频率比aof低,而且rdb文件中直接存储的是key-values的二进制形式,对于恢复数据也快)使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能
缺点:在save配置条件之间若发生宕机,此间的数据会丢失
RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
3.2.3Append-only file (简称AOF)
执行机制:将对数据的每一条修改命令追加到aof文件
优点:数据不容易丢失
可以保持更高的数据完整性,如果设置追加file的时间是1s,如果redis发生故障,最多会丢失1s的数据;且如果日志写入不完整支持redis-check-aof来进行日志修复;AOF文件没被rewrite之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的flushall)
缺点:性能较低(每一条修改操作都要追加到aof文件,执行频率较RDB要高,而且aof文件中存储的是命令,对于恢复数据来讲需要逐行执行命令,所以恢复慢)
AOF文件比RDB文件大,且恢复速度慢。
四、Redis过期键的删除策略
4.1常见删除策略
定时删除:每个设置过期时间的Key都会创建一个定时器,到期就会定时删除,该策略会立即删除过期数据,对内存很友好。但是相对的会占用大量的CPU资源去处理过期数据处理,从而会影响缓存响应时间及吞吐量。
惰性删除:对CPU来说是最友好,只会在程序读取该数据时校验数据是否存在,不存在就删除。但是相对的对内存来说不友好,比如一些已经过去的数据,不去读取时永远不知道是否过期,更不会删除,这个键就一直存在,占用着内存资源。
定期删除:就是前两种策略的整合和折中,每隔一段时间程序执行一次过期键删除操作,通过限制删除的频率和时长来减少删除操作对CPU的影响。有效的减少了过期键对内存资源的占用
五、Redis内存淘汰策略
Redis内存淘汰策略是指在内存不足时,新数据怎么申请额外的空间数据。
5.1全局的键空间选择性移除
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
5.2设置过期时间的键空间选择性移除
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。
六、缓存异常
6.1缓存雪崩
缓存雪崩是指缓存数据同一时间大面积过期,造成所有请求都访问数据库,因短时间请求压力过大从而造成数据库崩掉。
解决方案:
随机设置过期时间,避免同一时间过期
并发量不是特别多的,最多处理方式是加锁排队
给每个缓存数据添加标记,记录缓存是否失效,如果失效则更新缓存
6.2缓存穿透
缓存穿透是指数据库和缓存中都没有数据,造成所有请求都访问数据库,因短时间请求压力过大从而造成数据库崩掉。
解决方案:
接口增加校验,如用户ID<0的直接拦截
从缓存获取不到数据,数据库也不存在该数据,则设置一个Key-Value,Value=null的缓存,缓存时间可以设置30S,这样可以防止重复用一个ID暴力攻击。
采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力
6.3缓存击穿
缓存击穿是指没有获取到缓存数据(一般是缓存过期),由于并发用户量大,同时获取一条数据,没从缓存中获取的,请求全到数据库上,造成数据库压力过大。和缓存雪崩不同的是,缓存击穿是并发查询同一条数据,而缓存雪崩是大片数据过期,很多数据查不到都查询数据库。
解决方案:
热点数据永不过期
添加互斥锁,对缓存查询加锁,如果KEY不存在,就加锁,然后查数据库入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入数据库查询
评论 (0)