Redis,一个开源的数据结构服务器,最近赢得了越来越高的声誉。为什么 Redis 如此受欢迎?是因为Redis具有高度可扩展的架构、它的高性能、适合用于缓存、消息代理、计数器和队列。Redis 在各种场景下的高性能和易用性让它成为 Web 应用程序的首选。
在 2007 年,有个意大利西西里岛的小哥 Salvatore Sanfilippo(antirez) 和朋友创建了一个访客信息网站:LLOOGG.com。这个网站为其他网站提供各种信息的统计(包括访客 Ip、操作系统、浏览器、使用的搜索关键词、所在地区、访问的网页地址等信息)。
而对信息的收集在概念上并不复杂:多个网站把访客信息连续不断的推送到 LLOOGG.COM 服务器,而 LLOOGG.COM 服务器需要为每个网站保存一定数量的最新页面访问记录,并通过网页将这些记录实时地展示给用户观看。
LLOOGG.COM 可以查看最多 10000 条的最新浏览记录。这样的话,它需要为每一个网站创建一个队列,不同网站的访问记录进入到不同的队列。如果队列的长度超过了用户指定的长度,它需要把最早的记录删除。(先进先出)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dx0djxQa-1691983863594)(/Users/liziheng/Library/Application Support/typora-user-images/image-20230812220050402.png)]
随着 LLOOGG.com 的用户越来越多,LLOOGG.com 要维护的列表数量也越来越多,要执行的推入和弹出操作也越来越多。LLOOGG.com 当时使用 MySQL 数据库,而 MySQL 每次执行推入和弹出操作都要进行硬盘写入和读取,程序的性能严重受制于硬盘 I/O 。 最终 LLOOGG.com 所使用的 MySQL 再也没办法在当时的 VPS 上处理新增的大量负载,因为 LLOOGG.com 当时还没有找到盈利模式,所以为了尽量节约开支,antirez 没有选择直接升级 LLOOGG.com 所使用的 VPS ,而是打算另寻 办法,在现有硬件的基础上,通过提升列表操作的性能来解决负载问题。
为了解决 LLOOGG.com 的负载问题,antirez 决定自己写一个具有列表结构的内存数据库原型。这个数据库原型支持O(1) 复杂的推入和弹出操作,并且将数据储存在内存而不是硬盘,所以程序的性能不会受到硬盘 I/O 限制,可以以极快的速度 执行针对列表的推入和弹出操作。于是 antirez 使用C 语言写了这个内存数据库,并给它加上了持久化功能,2009年2月26日Redis(Remote Dictionary Server 远程字典服务)就此诞生!
在最大负载达到每秒数千条页面记录的情况下,无论我使用什么样的数据库模式(schema),无论我如何进行优化,我所使用的关系数据库都没办法在这个小虚拟机上处理如此大的负载。因为囊中羞涩,我没办法对虚拟机进行升级,并且我觉得应该有更简单的方法来处理一个由推入值组成的列表。最终,我决定自己写一个实验性质的内存数据库原型(prototype),这个数据库使用列表作为基本数据类型,并且能够对列表的两端执行常数时间复杂度的弹出(pop)和推入(push)操作。长话短说吧,这个内存数据库的想法的确奏效了,于是我用 C 语言重写了最初的数据库原型,并给它加上了基于子进程实现的持久化特性,Redis 就这样诞生了。 ———— Salvatore Sanfilippo(antirez)
Redis 全称 Remote Dictionary Server(即远程字典服务),它是一个基于内存实现的键值型非关系(NoSQL)数据库,由意大利人 Salvatore Sanfilippo 使用 C 语言编写。
Redis 官网:https://redis.io/
Redis 官网-中文:http://www.redis.cn/
Redis 遵守 BSD 协议,实现了免费开源,其最新版本是 6.20,常用版本包括 3.0 、4.0、5.0。自 Redis 诞生以来,它以其超高的性能、完美的文档和简洁易懂的源码广受好评,国内外很多大型互联网公司都在使用 Redis,比如腾讯、阿里、Twitter、Github 等等。
与 SQL 型数据库截然不同,Redis 没有提供新建数据库的操作,因为它自带了 16 (0—15)个数据库(默认使用 0 库)。在同一个库中,key 是唯一存在的、不允许重复的,它就像一把“密钥”,只能打开一把“锁”。键值存储的本质就是使用 key 来标识 value,当想要检索 value 时,必须使用与 value 相对应的 key 进行查找。
Redis 数据库没有 “表” 的概念,它通过不同的数据类型来实现存储数据的需求,不同的数据类型能够适应不同的应用场景,从而满足开发者的需求。
常见的内存型数据库,除 Redis 之外,还有 Oracle Berkeley DB(甲骨文旗下的一款产品)、SQlite(轻量级内存数据库)、Memcache(键值型分布式缓存数据库)、Altibase(基于内存的高性能数据库)。
与其他内存型数据库相比,Redis 具有以下特点:
下面对 Redis 的优势进行了简单总结:
Redis 基于内存来实现数据的存储,因此其速度非常快。但是我们知道,计算机的内存是非常珍贵的资源,所以 Redis 不适合存储较大的文件或者二进制数据,否则会出现错误,Redis 适合存储较小的文本信息。理论上 Redis 的每个 key、value 的大小不超过 512 MB。
总得来说,上述数据库各有优势,当我们选用数据库时,也要因地制宜,选择一款与业务场景最相符合的数据库。如果在合适的场景使用好 Redis,它就会像一把瑞士军刀一样所向披靡、无往不利!!!
简单来说,Redis 在 Java Web 主要有两个应用场景:
在日常对数据库的访问中,读操作的次数远超写操作,比例大概在 1:9
到 3:7
,所以需要读的可能性是比写的可能大得多的。当我们使用 SQL 语句去数据库进行读写操作时,数据库就会去磁盘把对应的数据索引取回来,这是一个相对较慢的过程。
如果我们把数据放在 Redis 中,既直接放在内存之中,让服务端直接去读取内存中的数据,那么这样速度明显就会快上不少,并且会极大减小数据库的压力,但是使用内存进行数据存储开销也是比较大的,限于成本的原因,一般我们只是使用 Redis 存储一些常用和主要的数据,比如用户登录的信息等。
一般而言在使用 Redis 进行存储的时候,我们需要从以下几个方面来考虑:
在考虑了这些问题之后,如果觉得有必要使用缓存,那么就使用它!
使用 Redis 作为缓存的读取逻辑如下图所示:
从上图我们可以知道以下两点:
从上面的分析可以知道,读操作的可能性是远大于写操作的,所以使用 Redis 来处理日常中需要经常读取的数据,速度提升是显而易见的,同时也降低了对数据库的依赖,使得数据库的压力大大减少。
使用 Redis 作为缓存的写入逻辑如下图所示:
从流程可以看出,更新或者写入的操作,需要多个 Redis 的操作,如果业务数据写次数远大于读次数那么就没有必要使用 Redis。
在如今的互联网中,越来越多的存在高并发的情况,比如天猫双 11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流失,重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!
所以我们需要使用 Redis 来应对这样的高并发需求的场合,我们先来看看一次请求操作的流程图:
我们来进一步阐述这个过程:
Redis 根据使用数据类型的不同,对应的使用场景有很多,例如: