~ Redis基于内存的K-V数据库,访问速度快;
~ 支持数据的持久化(可以将数据保存到硬盘,重启Redis之后可以重新写入内存);
~ 支持丰富数据类型,主要包括string、list、hash、set、zset(sorted set)
Redis5.0新增了Stream类型
~ 支持主从数据备份
~ 支持事务
string
list
hash
set
zset
stream (v5.0)
string类型
~ set:赋值
~ get:获取指定key的值
~ mset:一次为多个key赋值
~ mget:一次获取多个key的值
~ setnx:当设置的key不存在时则进行设置
~ setex:设置key的有效时间
~ incr:对key的值做加加操作,并返回新的值
~ decr:对key的值做减减操作,并返回新的值
⭐如何设置key的失效时间? setEx
list类型
~ lpush:从头部(链表左侧)添加元素;
~ lpop:从list头部获取元素
~ rpush:从尾部(链表右侧)添加元素;
~ rpop:从list尾部获取元素
~ lrange:查看一定的范围的元素
⭐ eg:查看list的所有元素 lrange [name] 0 -1
~ linsert:在某个元素的前后插入元素 linsert [name] before/after 原有元素 新元素
~ lrem:移除元素
⭐ eg: lrem list 2(移除个数) "key"
~ rpoplpush:从原来的list的尾部删除元素插入到新的list的头部
~ lindex:返回指定索引的值
~ llen:返回list的元素个数
hash类型
~ hset:赋值;
~ hget:获取某个key下的某个field的值;
~ hgetall:获取一个key下所有field和value;
~ hkeys:获取所有的key;
~ hvals:获取某个key下所有的value;
~ hexists:测试给定key下的field是否存在;
⭐得到hash中的所有的值用哪个方法?
set类型
~ sadd:添加元素;
~ smembers:获取集合中所有元素
~ sismember:判断元素是否在集合中
~ srem:删除元素
~ scard:获取元素个数,相当于count
~ spop:随机返回删除的元素
~ sdiff:差集,返回在第一个set里面而不在后面任何一个set里面的项(谁在前以谁为标准)
~ sdiffstore:差集并保留结果
~ sinter:交集,返回多个set里面都有的项
~ sinterstore:交集并保留结果
~ sunion:并集
~ sunionstore:并集并保留结果
~ smove:移动元素到另一个集合
zset类型
~ zadd:添加元素
~ zrange:获取索引区间内的元素
~ zrangebyscore:获取分数区间内的元素
首先保证数据不丢失可以使用持久化机制
Redis持久化分成两种方式:RDB(redis database)、 AOF(append only file)
~ rdb:每隔多久使用快照方式将数据持久化到硬盘
~ aof:以追加命令行的方式把写命令写入到一个文件中,若redis进行重启就会去加载aof文件将命令读取到redis
触发方式
~ RDB自动触发,在redis.conf 配置文件中配置
save 900 1 900s内至少有1个key被改变就自动RDB持久化
save 300 10 300s内至少有10个key被改变就自动RDB持久化
save 60 10000 60s内至少有10000个key被改变就自动RDB持久化
~ RDB手动触发,执行命令的方式
save: 执行此命令会阻塞Redis服务器,执行命令期间Redis不能处理其它命令,直到RDB过程完成为止
bgsave: 命令采用异步方式生成快照,Redis会fork出一个子进程进行RDB文件的生成,同时响应客户端的请求,持久化过程由子进程负责,完成后自动结束,阻塞只发生在fork阶段,一般时间很短
~ AOF持久化
默认的AOF持久化策略是每秒钟(everysec)一次同步策略
AOF的同步策略还有always、no、everysec
同时使用 RDB 和 AOF 两种持久化机制时,Redis重启将会优先使用 AOF 来恢复数据,AOF恢复完整度高
当Redis内存数据集大小上升到一定大小的时候,会实行数据淘汰策略(回收策略)
回收策略三种:定期删除 + 惰性删除 + 内存淘汰机制
定期删除
redis每隔100ms就 随机 抽取一部分设置过期时间的key,检查是否已经过期,过期即删除
惰性删除
当获取某个key的时候,发现这个key已经到了过期时间就删除,不返回value
当已使用的内存超过maxmemory的值就会触发内存淘汰机制
内存淘汰机制:
noective:当内存不够存放键值的时候,再去写入就会报错
allkeys-lru:当内存不够存放键值的时候,再去写入,就从所有的键值对中删除最近最少使用的key 常用
allkeys-random:当内存不够存放键值的时候,再去写入,就从所有的键值对中随机删除
volatile-lru:当内存不够存放键值的时候,再去写入就从设置过期时间的键值对中删除最近最少使用的
volatile-randmon:当内存不够存放键值的时候,再去写入就从设置过期时间的键值对中随机删除
volatile-ttl: 当内存不够存放键值的时候,从设置过期时间的键值对中,ttl值越大越优先被删除,也就是更早过期的key会被删除
~ 读取:先读取redis,当redis中读取不到时,再去读取mysql中的数据,同时将数据放入redis一份,下次在进行读取时直接可以读取redis中的数据
~ 写入:先去更新mysql,再去删除redis
⭐此时如果时高并发的场景下,当用户线程删除redis缓存成功后,另一个用户线程又去读取redis数据,发现不存在,就去mysql中读取,读取成功写入redis,这样a用户去更新数据库成功,但是redis数据还是老数据,会导致数据不一致
⭐使用延迟双删策略,先去删除redis,然后再去更新mysql,更新完成后,等待几秒钟,再去删除一次redis中的值
雪崩:大量的请求到redis中,当redis中大量的key值突然到了过期时间,请求发现redis中获取不到key值,就会导致大量请求到了mysql,mysql承受不住大量的请求而导致宕机,这就是缓存雪崩
~ 使用随机数作为过期时间存储redis数据,防止key同一时间过期
~ 开启redis持久化机制,防止redis宕机,数据可以及时恢复
~ 微服务中可以使用 sentinel 限流
穿透:大量请求不存在的key,请求直接查询数据库,数据库中也不存在,从而会有持续的请求打在数据库
解决方案**
~ 缓存一个空值 setNX 设置一个空值 并且设置 过期时间
~ 使用 布隆过滤器,先对请求的key进行筛选,进而过滤大部分的不合法请求
击穿:大量请求同一个key,突然这个key过期,但是高并发的请求一直在持续着请求这个热点key,突然大量的请求就直接到了数据库
~ 更新不频繁的情况下,可以对查询的逻辑加锁,当A用户持有锁去查询数据库中的热点key值,此时B用户请求过来时必须等待A用户执行结束才能获取到锁,当A用户执行结束已经把过期的key值重新放入redis中,当B用户请求时会直接从redis中查询返回,从而保护了数据库
~ 如果是分布式应用,必须使用分布式锁
~ 若不更新缓存可以设置永不过期
~ Redis集群自动分割数据到不同的节点上,整个集群的部分节点失败或者不可达的情况下能够继续处理命令
~ Redis集群引入了哈希槽的概念,集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽
ps: 集群默认不支持批量操作,如不支持mset、mget等命令
如果一个key对应的value是Hash类型的,若Hash对象非常大,是不支持映射到不同节点的,只能映射到集群中的一个节点上
~ Redis对事务的支持比较简单,它是一组命令的集合,命令被依次顺序的执行
1.客户端开启事务命令 multi
2.客户端把事务中本身要执行的具体操作发送给Redis
3.Redis 实例并不会立即执行这些命令,而是存放到命令队列中
4.Redis 接收到 客户端发送的 exec 命令提交事务,就去实际执行命令队列中的所有命令
5.Redis关闭事务 discard
~ 生产上若是采用Redis集群,不同的key是可能分到不同的Redis节点上的,在这种情况下Redis的事务机制是不生效的
~ Redis事务不支持回滚操作