1、什么是Redis?

Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被广泛应用于缓存,另外,Redis也经常用来做分布式锁。除此之外,Redis支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。

Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。

Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。

2、Redis客户端通信协议

Redis制定了RESP(Redis Serialization Protocol,Redis序列化协议)实现客户端与服务端的正常交互,这种协议简单高效,既能够被机器解析,又容易被人类识别。

指令格式:

发送请求

Copy* CRLF$ CRLF CRLF...$ CRLF CRLF

例子:

set hello world这个命令为例子

Copy*3$3SET$5hello$5world

Copy*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n

发送响应

CopyRedis的返回结果类型分为以下五种:
正确回复:在RESP中第一个字节为”+”
错误回复:在RESP中第一个字节为”-“
整数回复:在RESP中第一个字节为”:”
字符串回复:在RESP中第一个字节为”$”
多条字符串回复:在RESP中第一个字节为”*”

(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。
(-) 表示一个错误信息,具体信息是当前行-后面的字符。
(*) 表示消息体总共有多少行,不包括当前行,*后面是具体的行数。
(KaTeX parse error: Can’t use function ‘\r’ in math mode at position 21: …一行数据长度,不包括换行符长度\̲r̲\n,后面则是对应的长度的数据。
( 表示返回一个数值,:后面是相应的数字节符。

3、Redis客户端对比

Redis支持多种语言的客户端,如下是三个JAVA客户端:

  • Jedis 是老牌的 Redis 的 Java 实现客户端,提供了比较全面的 Redis 命令的支持.不支持异步,线程不安全。

  • lettuce ([ˈletɪs]),是一种可扩展的线程安全的 Redis 客户端,支持异步模式。

  • Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格,类比spring,提供了一套开箱即用的相关功能。Redisson 的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上

4、Redis的五种基本类型

5、缓存问题

缓存穿透

缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。

通俗点说,读请求访问时,缓存和数据库都没有某个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。

产生原因:

  • 业务设计不合理

  • 开发失误,缓存或者数据库数据被误删除

  • 黑客的非法攻击

解决方案:

  • 如果是非法请求,校验API参数

  • 如果数据库为空,给缓存设置空值即可。如果是写,那么同步更新缓存。并设置缓存过期时间。

  • 布隆过滤器判断。

布隆过滤器原理:它由初始值为0的位图数组和N个哈希函数组成。一个对一个key进行N个hash算法获取N个值,在比特数组中将这N个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。

缓存雪崩

指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至down机。

产生原因:

  • 大量数据同时过期。

  • redis服务器宕机了。

解决方案:

  • 采用一个较大固定值+一个较小的随机值,设置过期时间分散

  • redis高可用集群

缓存击穿

指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。

缓存击穿看着有点像,其实它两区别是,缓存雪奔是指数据库压力过大甚至down机,缓存击穿只是大量并发请求到了DB数据库层面。可以认为击穿是缓存雪奔的一个子集吧。有些文章认为它俩区别,是区别在于击穿针对某一热点key缓存,雪奔则是很多key。

解决方案:

  • 永不过期

  • 使用互斥锁方案

6、热key问题

什么是热key问题?

如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。

产生原因

  • 秒杀,热点新闻

  • 分片过于集中

提前识别热Key

  • 凭经验判断哪些是热key

  • 客户端统计上报

  • 服务代理层上报

解决方案

  • Redis集群扩容

  • 将热key分散到不同的服务器中

  • 使用二级缓存

7、过期策略

定时过期

惰性过期

定期过期

8、内存淘汰策略

volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。
allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰;
volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;。
allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰;
noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。