1 概念
redis是一个基于内存的NoSql的key-value数据库。
它可以存储key与不同类型的value之间的映射关系。
2 redis特点
单线程:redis是单线程的,因此不存在多线程并发上下文切换的资源消耗。
IO多路复用:基于非阻塞的IO多路复用技术,单线程可以处理多个socket连接。
支持持久化:redis数据存储在内存,但是也可以持久化到磁盘。
有多种数据结构:String、List、Set、Hash、Sorted Set等。
3 redis有哪些数据结构
a)String
字符串,值可以是string或整数。
常用命令:
set key value;
get key;
del key;
exists key;
b)List
列表,双向链表。常用作队列。比如一些需要根据时间或数量顺序存储的数据,可存储在队列中。
lpush key value1 value2 ... 从头部插入,返回插入后的列表长度
rpush key value1 value2 ... 从尾部插入,返回插入后的列表长度
lpop key 从头部弹出,返回弹出元素
rpop key 从尾部弹出,返回弹出元素
llen key 返回列表长度
lrange key start end 返回子列表元素,含start和end
lindex key index 查看指定下标的元素值
lset key index value 给指定下标设置元素值
linsert key before/after pivot value 在指定元素前/后插入元素
c)Hash
字典。value值是一个map
常用命令:
hset key field value 一次设置一个字段
hmset key field1 value1 field2 value2 一次设置多个字段
hget key field 获取指定field的值
hmget key field1 field2 获取指定多个field的值
hexists key field 是否存在某个field
hgetall key 获取全部field及value
hkeys key 获取map里的全部key
hvals key 获取map里的全部value
hsetnx key field value 当field不存在时,添加;存在,则不执行。
c)Set
集合。集合中每个元素不重复且没有顺序的概念。可以进行元素的增删改查,以及求交集、并集、差集。
sadd key value1 value2 ... 向集合中添加元素
srem key value 删除集合中的元素
smembers key 获取集合中的全部元素
sismember key value 检查集合中是否存在某个元素
sdiff key1 key2 两个集合的差集
sinter key1 key2 两个集合的交集
sunion key1 key2 两个集合的并集
sdiffstore key key1 key2 将两个集合的差集存储到一个新的集合中
srandmember key count 随机取得几个元素
f)Sorted-Set/Zset
有序集合。与集合的区别是:每个元素除了有value值外,还有另一个属性,用来排序的分数字段。有序集合是使用散列表和跳跃表实现的。
zadd key score1 value1 score2 value2 向zset中添加元素
zscore key value 查找某个元素的排序字段值
zrange key start stop [withscores] 根据value区间获取部分元素,withscores表示返回带分数值,否则仅返回元素值
zrangebyscore key min max [withscores] 根据分数区间获取部分元素
zcard key 获取元素数量
zrem key value1 value2 删除元素
4 为什么redis访问那么快
redis的特性,决定了它的速度快。基于内存所以数据访问速度快。虽然单线程但是采用了多路复用IO,可以处理多个socket连接,吞吐量高。
5 redis的持久化方式
a)RDB模式
将redis在内存中的数据间隔一定时间dump到磁盘中保存。dump全部数据。
以快照的方式在定时间隔时间内写入到临时文件中,写入完成后替换原来的文件,二进制压缩存储。当前进程会以fork出一个子进程,由子进程完成这些操作。只是在fork子进程的时候会造成阻塞。
优点是占用内存少,数据恢复快,但是在异常情况下恢复时会丢失一部分数据。fork子进程需要占用内存。
b)AOF模式
将redis的操作日志以追加的方式写入文件中。只追加对redis造成修改的命令,以文本的方式记录。因为每一条命令都追加,会造成文件占用空间大。
为此,当追加的文件变的庞大的时候可以进行重写,比如有连续多个set key xxx,可以整合成一条命令,多条increment命令也可以整合成一条set命令,在重新的过程中不会影响到原来文件。
重写的好处是减少命令数量,相当于压缩aof文件大小,减小内存占用,且数据恢复时速度会变快。重写时不读取旧的aof文件,而是从内存中将所有命令全部导出一份到新的aop文件中。
优点有更高的数据安全性。但是,相同数量的数据集,aof文件占用空间更大,且恢复速度相对较慢。
6 redis的过期键删除机制
a)立即删除:占用cpu过多,对内存友好,对cpu最不友好。
b)定时删除:限制对过期键处理的时间消耗,减少cpu占用。同时定时删除一些过期键,减轻对内存的长期占用造成的内存浪费。
c)惰性删除:浪费内存。对cpu最友好,对内存最不友好。
实际上使用的是:定时与惰性删除相结合的方式。
7 redis的淘汰策略
redis内容已经满了,这时有新的缓存要加入,怎么办?
a)FIFO
剔除最早进入的key
b)LRU
剔除最近最少使用的key
c)LFU
剔除最近使用频率最低的key
8 redis存在的问题
a)缓存穿透:
key对应的数据源不存在,key对应的数据在redis中不存在,在数据库中也不存在。比如根据一个不存在的用户id查询用户信息。因此,每次访问这个key,因为在redis中查不到,就会去db中查找,从而增加了访问数据库的压力。
解决方法:布隆过滤器。bitmap,将所有使用的key加入,无效的key会被过滤器过滤掉。还可以进行限流、降级、熔断。
b)缓存击穿:
key对应的数据源存在,但是key在redis中失效了。这时,如果有大量请求同时到来,因为在redis中查不到,就会去查db,从而大量请求涌向数据库,严重时会造成服务器宕机。这种通常是当热数据缓存失效时会出现的。
解决方法:热数据的缓存永不失效。设置兜底数据。使用互斥锁,当一个请求访问db获取到数据后会回设到redis中,这样之后的所有请求都可以继续使用redis缓存了。
c)缓存雪崩:
当大量key同时在redis中失效时,会大量请求涌向db,从而引发缓存雪崩现象。
解决方法:缓存失效时间分散开来,避免集中。设置缓存有效期后可以再加一个随机数。