**命令**
String类型
String类型包含多种类型的特殊类型,且是二进制安全的。值可以是数值,可以是字符串,也可以是二进制数据。(单值)
命令格式 | 功能 |
set key value | 将key-value缓存到redis中 |
get key | 从redis中获取key对应的value值 |
incr key | 将key对应value值+1 |
decr key | 将key对应value值-1 |
setex key seconds valule | 将key-value缓存到redis中,seconds秒后失效 |
ttl key | 查看key存活时间 |
del key | 从redis中删除key |
setnx key value | 如果key已存在,不做任何操作;如果key不存在,直接添加 |
命令格式 | 功能 |
incrby key increment | 给key对应值加increment |
mset k1 v1 k2 v2… | 批量添加k1v1,k2v2 |
mget k1 k2… | 批量获取k1,k2的值 |
append key value | 在key对应的value中拼+value |
setrange key offset value | 修改key对应的value值,替换为指定value,从offset索引位置开始 |
Hash类型
Hash类型是String类型的field和value的映射表,或者说是一个String集合,适合存储对象,相较而言,将一个对象存储在Hash类型里比存储在String类型里占用更少的内存空间。(单值)
在如下示例中需要特别注意:
存储模型相当于key<field,value>
key:Redis中的主键,用于标识整个Hash数据结构
field:Hash内部的字段,相当于小型键
value:对应field的值
命令格式 | 功能 | 示例 |
hset key field value | 将field value对缓存到redis中的hash中,键为key | hset user name RunsEasy |
hget key field | 从key对应hash列表中获取field的value | |
hexists key field | 判断key对应hash列表中的field是否存在 | |
hdel key field | 删除key对应hash列表中的field | |
hincrby key field increment | 给key对应hash列表中的field的value+increment | |
hlen key | 查看key对应的hash列表中有多少个field | |
hkeys key | 查看key对应的hash列表中所有的field | |
hvals key | 获取key对应的hash列表中所有field的value | |
hgetall key | 获取key对应的hash列表中所有的filed-value |
List类型
List类型是一个有序可重复的链表结构的列表,其主要功能有push、pop、获取元素等。更详细地说,List类型是一个双端链表的结构,我们可以通过相关操作进行列表的头部或者尾部添加、删除元素,List的设计既可以作为栈,也可以作为队列,满足绝大多数需求。(多值)
命令格式 | 功能 | 示例 |
rpush key value | 从右边往key列表中添加value值 | |
lpush key value | 从左边往key列表中添加value值 | |
lrange key start end | 从左边开始列出key列表,从start位置开始,end位置结束(对应索引) | lrange faction 0 -1(查询所有数据) |
lpop | 删除key列表中最左边的数据value | |
rpop | 删除key列表中最右边的数据value | |
llen key | 获取key列表的长度 |
命令格式 | 功能 |
linsert key before pivot value | 操作key列表,在pivot值前面插入value |
linsert key after pivot value | 操作key列表,在pivot值后面插入value |
lset key index value | 操作key列表,更新索引为index位置的值为value |
lrem key count value | 操作key列表,删除count个value值 |
ltrim key start end | 操作key列表,保留从start到end值,其他的值都删除 |
lindex key index | 操作key列表,获取索引为index位置的数据 |
Set类型
Set集合是String类型的无序不重复集合,Set是通过HashTable实现的,对集合可以取交集、并集、差集。(多值)
命令格式 | 功能 | 示例 |
sadd key members[] | 向key集合中members添加元素 | sadd chars a b c |
smembers key | 遍历key集合中的所有元素 | |
srem key members[] | 删除key集合中的members元素 | |
spop key count | 随机删除key集合中count个元素 | |
sinter key1 key2 | 返回key1和key2集合的交集 | |
sunion key1 key2 | 返回key1和key2集合中所有元素去重后的集合(并集) | |
sdiff key1 key2 | 返回key1中特有的元素(差集) |
命令格式 | 功能 |
sdiffstore dest key1 key2 | 返回key1集合中特有的元素,并将返回值缓存到dest集合中 |
sinterstore dest key1 key2 | 返回key1和key2集合的交集,并缓存到dest集合中 |
sunionstore dest key1 key2 | 返回key1和key2集合的并集,并缓存到dest集合中 |
smove key1 key2 member | 将key1集合中member元素移动到key2集合 |
sismember key member | 判断member元素是否在key集合中 |
srandmember key count | 随机获取key集合中count个元素 |
SortedSet (ZSet)类型
SortedSet也叫ZSet类型,是一种具有排序效果的Set集合,他和Set集合一样,也是String类型元素的集合,且不允许存在重复元素,并且要求每个元素都会关联一个double类型的分数(排序依据)。后续可以通过分数来为集合中的成员进行从小到大的排序。
SortedSet集合是通过哈希表实现的,所以添加、删除、查询的复杂维度都是O(1)。(排序多值)
命令格式 | 功能 | 示例 |
zadd key score member | 向key集合中添加member元素,分数为score | zadd players 100 a 200 b |
zincrby key increment member | 将key集合中的member元素分数+increment | |
zrange key start end [withscores] | 将key集合中的元素按分数升序排列[显示分数] | |
zrevrange key start end [withscores] | 将key集合中的元素按分数降序排列[显示分数] | |
zrank key member | 返回member元素在key集合中的升序排名(index) | |
zrevrank key member | 返回member元素在key集合中的降序排名(index) | |
zcard key | 返回key集合中元素的个数 |
命令格式 | 功能 |
zrangebyscore key min max [withscores] | 按[min,max]的分数范围返回key集合中的元素(升序) |
zrevrangebyscore key max min [withscores] | 按[max,min]的分数范围返回key中的元素(降序) |
zrem key member | 删除key集合中member元素和分数 |
zremrangebyscore key min max | 按[min,max]的分数范围删除key集合中的元素 |
zremrangebyrank key start end | 删除key集合中升序排名的index在[start,end]范围的元素 |
zcount key min max | 按分数范围[min,max]统计key集合中元素的个数 |
Redis全局命令
全局命令针对的是所有的key,大部分情况用来做运维和数据管理的
命令格式 | 功能 | 示例 |
keys pattern | 按照pattern匹配规则,列出redis中所有的key | keys player_info:* |
exists key | 判断key是否存在 | |
expire key seconds | 给现有的key设置过期时间为seconds | |
persist key | 取消key过期时间 | |
select index | 切换redis数据库到index,默认是0,共有[0,15] | |
move key_name index | 把名为key_name的key移动到index号数据库 | |
randomkey | 随机取出一个key | |
rename key newkey | 把key的名字修改为newkey | |
echo message | 在控制台打印message | |
dbsize | 返回当前数据库key的数量 | |
info | 查看当前redis信息 | |
config get * | 查看所有redis配置信息 | |
flushdb | 清空当前数据库 | |
flushall | 清空所有数据库 |
**Redis事务**
Reids中的事务更像是对命令队列形式的处理。Redis的事务不会因为一条执行失败而回滚上一条命令或不执行下一条命令
单个Redis命令的执行是原子性的,但是Redis没有在事务上增加任何维持原子性的机制,所以Redis事务的执行并不是原子性的
Redis的事务以multi开始,然后将多个命令输入到事务队列中,最后由exec命令触发事务,触发后会一并执行事务中的所有命令
示例:
redis 127.0.0.1:6379> multi
"OK"
redis 127.0.0.1:6379> set name "Crows"
"QUEUED"
redis 127.0.0.1:6379> set name RunsEasy
"QUEUED"
redis 127.0.0.1:6379> sadd flag Java "C++" C#
"QUEUED"
redis 127.0.0.1:6379> get name
"QUEUED"
redis 127.0.0.1:6379> smembers flag
"QUEUED"
redis 127.0.0.1:6379> exec
1) "OK"
2) "OK"
3) "0"
4) "RunsEasy"
5) 1) "Java"
2) "C++"
3) "C#"
**Redis持久化机制**
Redis持久化机制目前有3种:
- 快照方式(RDB,Redis DataBase)
- 优点:
- RDB快照文件是一个紧凑压缩的二进制文件。适用于全量备份等场景。开发中可以按照每6小时执行一次bgsave备份,用于容灾备份
- Redis加载RDB恢复数据速度远快于AOF方式
- 缺点:
- RDB无法做到实时持久化/秒级持久化,每次bgsave时都需要fork子进程,频繁执行时间成本较大
- RDB快照文件不同版本格式可能会不一样,有版本兼容问题
- 优点:
- 文件追加方式(AOF,Append Only File)
- 优点:
- AOF方式数据安全性更高,配置得当,最多损失1秒的数据量
- 在不小心(你是故意的还是不小心的?doge )执行flushall命令时,也可以通过AOF方式恢复(删除最后一个命令(flushall)即可)
- AOF日志是一个增量日志文件,不会存在断电时出现损坏的问题。即使出现问题,redis-check-aof工具也能轻松恢复
- 当AOF变得太大时,Redis能够在后台自动重写AOF
- 缺点:
- 相同数据量来说,AOF文件体积通常大于RDB文件
- 数据持久化性能上来说,AOF比RDB慢
- 优点:
- 混合持久化方式(RDB-AOF,Redis4版本以后)
快照方式(RDB)
Snapshotting(快照),是Redis 4.0 之前的默认方式,将内存数据中以快照的方式写入到二进制文件中,默认为dump.rdb。
触发RDB持久过程分手动触发和自动触发。
手动触发:
- 使用save命令:会阻塞当前Redis队列,直到RDB过程完成为止,如果内存数据较多,会造成长时间的阻塞,影响其他命令的使用,不建议随意使用。
- 使用bgsave命令:Redis进程执行fork指令创建子进程(这个过程会让其它未执行子进程直接返回,优先让fork指令先执行),由子进程实现RDB持久化,有需要时建议使用此命令。
自动触发:
- 使用save相关配置,命令格式:save m n(标识m秒内数据存在n次修改则触发bgsave命令)。
文件追加方式(AOF)
AOF是以独立日志的方式记录每次执行的命令,重启时再重新执行AOF文件中命令,达到恢复数据的目的。解决了数据持久化的实时性问题。
Redis默认是不开启的,需要使用时,请配置:appendonly yes
AOF有3种文件同步策略
策略 | 解释 |
appendfsync always | 收到命令就会立即写到磁盘,效率最慢,但是能保证完全的持久化 |
appendfync everysec | 每秒写入磁盘一次,在性能和持久化方面做了很好的折中 |
appendfync no | 完全依赖os(操作系统),一般同步周期是30秒 |
混合持久化方式(RDB-AOF)
混合持久化是Redis 4.0之后推出的,其作为默认配置来使用
混合持久化是结合了RDB和AOF的优点,在写入的时候,先把当前的数据以RDB形式写入文件的开头,再将后续操作命令以AOF的格式存入文件。即以RDB作为全量备份,AOF作为增量备份,来提高备份效率。这样既能保证Redis重启时的速度,又能防止数据丢失的风险。
**Redis内存淘汰机制**
Redis内存淘汰机制也可以称之为key内卷机制,当资源不足时会触发。
市面上内存淘汰算法简介
常见的内存淘汰机制分为四类:
- LRU:LRU是Least Recently Used,最近没使用过的意思。简单的理解就是从数据库中删除近期没使用过的数据,该算法认为,如果数据长期未使用,那么该数据再次被访问的概率也就很小了,所以LRU算法会将其淘汰。
- LFU:LFU是Least Frequently Used,最不经常使用的意思。简单的理解就是淘汰一段时间内,使用次数最少的数据,这个与频次和时间有关系。
- TTL:Redis种,有的数据时设置了过期时间的,二设置了过期时间的这部分数据,就是该算法要解决的对象。如果该数据快到期了且内存现在不够的情况下,就会先让快要到期的数据被淘汰。
- 随即淘汰:随机淘汰数据。
Redis淘汰策略
Redis通过配置maxmemory-policy
来配置指定具体的淘汰机制。
Redis种有8种淘汰机制,这在Redis 5.0 的配置文件中有说明:
针对设置了过期时间的key:
- volatile-lru -> 找出已经设置过期时间的数据集,将近期未使用的数据淘汰
- volatile-ttl -> 找出已经设置过期时间的数据集,将即将过期的数据淘汰
- volatile-random -> 找出已经设置过期时间的数据集,随即淘汰数据
- volatile-lfu -> 找出已经设置过期时间的数据集,将一段时间内,使用次数最少的数据淘汰
针对所有key:
- allkeys-lru -> 针对所有数据集,将近期未使用的数据淘汰
- allkeys-lfu -> 针对所有数据集,将一段时间内,使用次数最少的数据淘汰
- allkeys-random -> 针对所有数据集,随机淘汰数据
系统默认选择:
- no-envication -> 报错,警告内存不足,这样的好处是可以保证数据不丢失
**Redis过期Key处理**
Redis针对过期key给出了3种实现方案:
- 惰性删除:当访问Key时,才去判断它是否过期,如果过期则直接删除。这种方式对CPU友好,但如果一个Key长期不用,会一直存在内存里,导致内存浪费。
- 定时删除:设置Key的过期时间的同时,创建一个定时器,当到达过期时间点,立即执行Key的删除操作,这种方式对CPU不友好,需要额外让CPU维护定时器。
- 定期删除:隔一段时间,对数据进行一次检查,删除里面的过期Key,至于要删除多少过期Key,检查多少数据,则由算法(配置)决定。
Redis服务器实际使用的是 惰性删除和定期删除两种策略,通过配合使用这两种删除策略,可以很好地在合理使用CPU和避免浪费内存之间取得平衡。
**Redis击穿、穿透、雪崩的定义及解决方案**
- 击穿:是指单个Key在缓存中失效或者过期,从而请求都进入数据库操作,正常情况下无影响,但如果在高并发的情况下可能会导致数据库崩溃
- 解决方案:
- 互斥锁,单个Key失效相当于多个线程去数据库执行同一操作,所以可以在第一个操作请求上使用一个synchronized来锁住它,等它执行完毕后,其它请求就能在缓存中进行操作
- 热点Key永不过期
- 解决方案:
- 穿透:是指缓存和数据库种都没有这条数据,但由于缓存中没有数据,最终请求会到达数据库。利用这个不存在的Key频繁请求应用接口,并且量级非常大的话,也会造成数据库崩溃的清空(一般被认为是恶意攻击)
- 解决方案:
- 布隆过滤器
- 参数校验
- 拉恶意攻击黑IP
- 解决方案:
- 雪崩:是指多个Key在缓存中失效或者过期,从而大批量的请求进入数据库操作,导致数据库压力过大宕机
- 解决方案:
- 设置Key随机过期时间,避免大量Key同时过期
- 不设置过期时间
- 定时任务,在缓存失效前刷进新的缓存
- 解决方案:
总结:击穿是指单个热点Key失效,穿透是指请求缓存和数据库都不存在的key,雪崩是指大面积Key失效。而最终受害者都是数据库