(一)为什么要使用Redis?
最近看过不少学习技术的文章,这些文章给了我不少的感触。我认为学习技术的时候不应该买一本很厚书就一头专进去。而应该按照以下方式来进行学习:
1. 先了解这些技术解决了什么样的问题,为什么这些要使用这些技术作为起始点; 2. 了解了技术解决了什么问题之后?我们就可以继续深入下去了。如果我们对其中一个技术点感兴趣或者面试需要,那么我们可以 查找相关的书籍或者博客了解这个技术点是怎么实现的。 3. 如果你还想继续深入学习,那么最后应该做的就是“对比性学习”了,不知道大家有没有感触:在大四的时候需要学论文,你会 参考多篇文章,这样进行对比,你对所需要学习的知识就会更加深入的理解。
这篇文章我将陈述Redis解决了什么问题。大部分内容都在网络上已经出现了,我只是进行简单的整理,文章的最后我会将参考文章的链接给出。
Redis解决了什么问题?
大规模读写数据与数据库读写能力之间的矛盾
简单回顾一下CPU高速缓存的发展历程,为了解决CPU的计算速度与内存的读取速度之间的巨大差异,CPU使用高速缓存来存放指令和数据。高速缓存从最初的主板缓存到现在的3级缓存,缓存大小也不断变大。来自网络的数据表明:CPU高速缓存的命中率大约为80%。
类比电脑发展过程中CPU与内存的矛盾,可以察觉到大型网站中大规模读写数据与数据库读写能力之间的矛盾与此矛盾类似。我们也可以在数据库与应用之间构建一块比数据库速度更快存储区域——缓存。大家最熟悉的也莫过于Redis用作缓存,我们知道Redis的作者设计Redis的初衷是因为他使用关系型数据库时,无论如何优化,性能都不能达到自己的期望,于是便自己手写了一个内存数据库。
在作为缓存的情况下,我们有一下应用场景:
1. 热点数据 例如我们可以将SQL查询结果保存在内存中,也可以将用户经常查看的图片保存在内存中。
2. 排行榜 基于Redis提供的zset这种数据结构我们可以更加便捷的实现排行榜。实现排行榜的相关内容可以参考排行榜算法设计实现比较。在小规模数据的情况下,使用Mysql实现排行榜没有多少问题,但是一旦数据量上去了,那么持续的进行Mysql读写将会成为瓶颈。
3. 计数器/限速器 计数器的应用场景之一是统计用户的点赞数,限速器的应用场景之一是限制用户ip的访问次数。之所以Redis能用于计数器是因为Redis是单线程的,每次都必须前一个指令执行完,再执行下一个指令。这样就保证不会同时执行多条指令;也即不会出现并发问题。限速器的原理类似。
4. 共同好友 利用Redis提供的Set数据结构的求交集操作sinter可以更加便捷地求两个Set集合的交集;而使用数据库的连表查询将造成性能的开销很多,因为大型网站的用户数量巨大。
5. 简单消息队列 Redis的提供的发布/订阅是一个极其简单的消息系统。它不像Kafka那样提供了分成不同的topic并且分成不同的分区并且提供持久化的功能。Redis的消息队列用在不需要高可靠的场景。
6. session共享 Session是用来记录是用户是谁。当在应用使用集群方式部署的时候,我们需要一个统一管理session的地方,可以使用数据库来记录session,但是这时对数据库的性能要求较高,此外session通常是具有时效性的,这段逻辑我们需要在代码中实现,但是如果使用Redis来共享session,那么不会出现这样的问题。
上面的许多应用场景也可以使用其他技术解决问题,只是Redis这样的技术在一定资源限制的情况下,会是更好的解决方案。
在学习redis的过程中,一直有一个疑问:当我们开发数据库应用程序时,可以使用MyBatis的一二级缓存,Guava中的缓存模块,甚至 是Java自带的Map数据结构来达到缓存数据的目的,为什么还要使用Redis作为缓存呢? 参考一篇博客总结如下: 1. 无论MyBatis的缓存,还是Guava,Map数据结构作为缓存,它们的生命周期都是随着JVM的销毁而结束。在微服务或者应用程序挂掉的 时候,我们并不希望缓存也消失。 2. 在多个实例的情况下,存在数据不一致。如一个微服务启动多个实例,或者多个节点上部署同一个微服务,这时不同实例内缓存的数据 不一致。
在上面的应用场景使用Redis解决问题不是一蹴而就的,而是在Redis的发展过程中,通过添加新的特性并且修改已有算法或者数据结构逐步得到支持和优化的。