什么是Redis
在开始之前,先讲讲什么是Redis.
在相对原始的情况下,一个服务会有程序和数据库两个部分,其中数据库通常是MySQL等持久化数据库。在访问量较小的情况下,这样做是没有问题的,虽然数据读取可能会慢一些。
但是随着访问量逐渐增大,对MySQL的读写频率也不断上升,最后导致MySQL的吞吐量严重影响了系统的性能。这时就到了Redis出场的机会。
MySQL之所以读取慢一些,原因之一是它的数据读写是发生在磁盘中的。而Redis把数据放在了内存中,这就使得读写效率比数据库要高了好几个数量级。
Redis本质上是一种KV数据库,存入数据的键和值,根据键来读取值。
Redis的一些用法
- 用来检查用户是否连续签到。例如用户签到的时候,在数据库存入一条该用户已签到的数据,并设置后天0点删除该数据。这样第二天签到时,可以检查Redis里是否存了已签到的信息,如果没有就说明没有连续签到。
- 用作消息通知。例如某篇文章发生了内容变化,那么可以把发生变化这件事写入redis,之后其它程序就可以通过读取redis知道文章发生了变化,并更新文章信息。
- 计数。redis有一个hash数据结构,可以用来存储文章的阅读数、点赞数等等,之后读取数据可以直接从redis获取。
- 实现排行榜。这里也需要依赖redis的数据结构zset,这是一种有序集合。通过有序的特性可以实现快速更新排行榜,而无需去修改磁盘里的数据库。
- 限流。可以用redis存储当前系统1秒内通过多少请求,如果超额就拒绝后续请求。这一功能实现同样需要依赖内存的快速特性。
Redis使用的一些注意事项
大Key、热Key问题
对于大于10KB的string 或者元素大于5000/字节数大于10MB的Hash/Zset/Set等集合类型,统一被称为大Key. 显而易见这类存在会严重影响读写性能。又因为redis的读写是单线程的,这类大Key会严重阻塞后续读写。
为了防止发生这种情况,通常需要把单个Key拆分为多个小Key, 如单个字符串拆分成多个字符串。集合类型同样可以拆分,也可以把过多的数据存入数据库,只缓存使用频率最高的一批。
而热Key通常是指每秒请求大于500的Key. 大量的读写同样会影响其它Key读写的性能。
要解决这个问题,一方面可以在程序中,如Java的Guava,再设一层缓存,单独存储热Key. 也可以把热key以相同的值存在多个key中以实现均衡访问,不过这样可能会有数据不一致的问题。
慢查询
慢查询有很多导致的原因,如单批次传入超过100的处理、对大小超过5k的zset进行操作、操作大Key等。
缓存穿透、缓存雪崩
缓存穿透是大量请求访问不存在的数据,由于不存在,redis自然不会缓存,于是所有查询请求都会打到数据库上,就造成了数据库瞬时的高访问。
缓存雪崩有两种,第一种是短时间内大量key过期,导致这些请求全部变成了查询数据库;
第二种是一个热Key过期,结果所有请求都绕过redis打到数据库上了。这种也叫缓存击穿。
缓存穿透可以通过把空值也缓存来解决。例如发现该数据不存在,也在redis存一个空,这样后续请求只会查到空并返回,而不会查到数据库。第二章是使用布隆过滤器来缓存合法的key,不合法的就拦截。
对于缓存雪崩,可以将key的失效时间改为随机值而非固定值,这样可以防止一批Key同时集体过期。另外如果是redis宕机导致的缓存雪崩,可以通过部署redis集群来防止。
缓存击穿在分布式情况下应该用分布式锁来解决,不过其本质是热Key问题。理想情况下应该让热Key实现永不过期,或者只要有访问,就定期刷新过期时间。