Redis 是一个开源的内存数据结构存储系统,它可以用作数据库、缓存和消息中间件。以下是 Redis 的发展史:
- 2009 年:Salvatore Sanfilippo 开始编写 Redis。
- 2010 年:Redis 发布了 1.0 版本。这个版本包含了许多常用的数据结构,例如字符串、哈希表、列表、集合和有序集合。
- 2012 年:Redis 发布了 2.6 版本,引入了持久化机制和 Lua 脚本支持。
- 2014 年:Redis 发布了 3.0 版本,添加了 Cluster 功能,允许将多个 Redis 实例组成分布式集群。
- 2015 年:Redis 发布了 3.2 版本,引入了模块化扩展功能,允许开发者编写自定义的 Redis 模块。
- 2018 年:Redis 发布了 5.0 版本,引入了 Streams 数据类型和更好的集群管理工具。
- 2021 年:Redis 发布了 6.2 版本,添加了 RedisRaft 模块,使得 Redis 可以支持强一致性分布式系统。
随着时间的推移,Redis 已经成为了一个非常流行的开源项目,并被广泛应用于互联网和企业级应用程序中。
1、Redis基础
1.1、数据类型
1)String(字符串):最基本的数据结构,可以存储任何类型的字符串、数字或二进制数据。
2)Hash(哈希表):类似于关联数组或字典,可以存储多个字段和对应的值,常用于存储对象属性或配置信息。
3)List(列表):一个有序的字符串列表,支持在列表两端进行插入和删除操作,还提供了多种操作,如查找、裁剪、排序等。
4)Set(集合):一个无序的字符串集合,支持添加、删除、查找和求交、并、差等操作,还提供了多种操作,如求随机元素、判断元素是否存在等。
5)ZSet(有序集合):和 Set 类型相似,但是每个元素都有一个分数(score),根据分数进行排序,可以支持按照分数范围进行查找、插入和删除操作。
1.2、持久化机制
Redis 的持久化机制有两种:RDB(Redis Database)和AOF(Append Only File)。
1)RDB 持久化:将 Redis 内存中的数据以快照的形式保存到硬盘中,即生成一个 RDB 文件。可以手动或自动设置定时保存 RDB 文件。当 Redis 重启时,会从 RDB 文件中读取数据并恢复数据库状态。RDB 持久化适用于大规模的数据集和较长时间的备份。
2)AOF 持久化:将 Redis 执行的写命令追加到 AOF 文件中,记录了 Redis 修改数据的所有操作。由于 AOF 文件是一个完整的 Redo 日志,因此当 Redis 重启时可以通过重新执行 AOF 文件中的所有写命令来还原数据。AOF 持久化适用于需要高耐久性的场景,比如金融、电商等行业。
在使用 Redis 的持久化机制时,还需要注意以下几点:
- 如果同时开启了 RDB 和 AOF,Redis 支持首先使用 AOF 进行数据恢复,然后再使用 RDB 文件进行备份。
- RDB 文件和 AOF 文件都可能比内存中的数据要旧,因此如果数据非常关键,最好同时开启 RDB 和 AOF,保证不丢失数据。
- 定期保存 RDB 文件和 AOF 文件的频率应该根据实际需求进行调整,以平衡数据备份和性能损耗之间的关系。
- Redis 还提供了 BGSAVE 和 BGREWRITEAOF 命令来异步执行 RDB 和 AOF 持久化操作,避免阻塞 Redis 主线程。
当然生产上大多数是这两种机制同时使用,以保证数据的安全性和可靠性。
1.3、部署方式
1)Sentinel 实例进行监控和故障转移,实现 Redis 的自动故障恢复和主备切换。
2)Redis Cluster:Redis Cluster 是 Redis 官方提供的分布式集群方案,支持数据分片和节点扩展,可以在不丢失数据的前提下动态增加或减少节点数量,提高了集群的可扩展性和容错性。
3)Codis:Codis 是一个开源的 Redis 数据库中间件,基于 Redis 的主从复制和分片机制,提供了多种功能,如数据分片、节点管理、读写分离、高可用性等,并且可以与 ZooKeeper 等 Apache 开源软件进行整合。
4)Twemproxy:Twemproxy(也称为 Nutcracker)是一个类似于代理服务器的 Redis 中间件,支持多个 Redis 实例的负载均衡和故障转移,可以提高 Redis 集群的性能和可靠性。
2、Redis应用场景
2.1、缓存
Redis 最常见的应用场景就是作为缓存来提高读写性能。由于 Redis 基于内存读写,响应速度非常快,因此可以用来缓存热点数据,如网站首页、商品信息等。通过使用 TTL(time to live)机制来设置缓存过期时间,可以避免缓存数据过期而导致的问题。
2.2、分布式锁
Redis 可以用作分布式锁,通过设置一个唯一的键值对来控制访问某个资源的并发数。当一个客户端需要访问该资源时,先去获取分布式锁,执行完后再释放锁,以保证同时只有一个客户端在访问该资源。这种方式可以有效避免因为并发访问而导致的数据冲突和竞争问题。
Redis实现分布式锁的技术方案有很多,其中比较常用的包括:
1)基于SETNX命令+Lua脚本:使用SETNX命令创建一个键值对,如果该键不存在,表示加锁成功;否则表示加锁失败。释放锁时,使用DEL命令删除该键。配合Lua脚本可以让加锁和释放锁过程封装成原子性操作,避免出现误删等问题。
2)Redisson:是一个Java实现的Redis客户端,提供了完整的分布式锁解决方案,支持多种锁模式(例如可重入锁、公平锁等),并提供了超时自动释放锁、异步执行等功能。
3)Spring Boot + LockRegistry(推荐):LockRegistry是Spring Boot提供的接口,可以轻松地将分布式锁嵌入到应用程序中。LockRegistry接口可以与不同的分布式锁提供者(如Redis)集成,并提供了简单易用的API,使开发人员无需关注底层实现细节。
需要注意的是,在选择分布式锁方案时,需要根据实际情况进行考虑。不同的方案具有不同的特点和适用场景,需要根据业务需求和系统负载情况进行选择和优化。同时,分布式锁的实现过程需要特别注意死锁和误删等问题,必要时可以借助第三方库进行实现。
2.3、实时排行榜
Redis 可以用来实现实时排行榜,通过将用户行为数据记录下来,如点赞数、评论数等,然后通过 ZSET(有序集合)数据类型来实现实时排名和排序。这种方式可以很好地满足诸如游戏排名、电商销量排行等实时统计的需求。
2.4、计数器/自增ID
Redis 还可以用作计数器,通过使用 INCR 命令来实现。当需要对某个计数器进行增加操作时,只需要执行一次 INCR 命令即可。由于 Redis 的原子性操作,可以保证在高并发场景下的数据一致性。
2.5、消息队列
Redis 也可以用作消息队列,在分布式系统中起到重要的作用。生产者将消息存入队列中,消费者从队列中取出消息进行处理。通过使用 Redis 的 PUB/SUB(发布/订阅)功能或者 Stream来实现消息的发布和订阅,保证了消息传递的可靠性和高效性。
2.6、地理位置应用
Redis 还具有地理位置服务的特性,可以记录每个用户的位置信息,并将其保存在 Redis 中。然后通过 GeoHash 和 Geospatial 数据类型来实现位置信息的查找和计算,以实现类似于附近的人、打车等服务。
3、Redis进阶
3.1、数据类型
除了常见的 String、Hash、List、Set、ZSet 等数据类型,Redis 还支持以上提到的其他数据类型,如 Bitmaps、HyperLogLog、Geo 和 Streams 等。
1)JSON
虽然Redis在自身的核心中并不原生支持JSON数据类型,但是通过Redis模块系统,可以使用第三方扩展模块来支持JSON数据类型。Redis 4.0及以上版本引入了Modules(模块)系统,允许开发者编写自己的扩展模块来扩展Redis的功能。目前有一些第三方模块已经实现了对JSON数据类型的支持,例如RedisJSON和ReJSON等。
2)发布订阅/Redis Streams:
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。Redis中的订阅发布模式, 当没有订阅者时, 消息会被直接丢弃(Redis不会持久化保存消息)。
Redis Stream 是 Redis 5.0 版本新增加的数据结构。Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
3)Geo
Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。
3.2、Redis管道技术
Redis管道技术是一种优化Redis客户端与服务器之间交互的方式,它可以将多个命令打包在一起发送到Redis服务器,从而减少了网络传输和客户端/服务器之间的通信次数,提高了Redis的性能。具体来说,Redis管道技术的工作流程如下:
1)客户端向Redis服务器发送多个命令。
2)Redis服务器将这些命令缓存到队列中,并等待客户端的响应。
3)客户端接收到服务器响应后,再一次性地发送所有命令的响应结果。
4)Redis服务器处理这些响应结果,并将它们返回给客户端。
通过使用Redis管道技术,可以显著降低Redis客户端与服务器之间的延迟,并提高数据读写效率。此外,Redis管道技术还具有批量操作、事务处理等功能,可以简化编程和管理复杂性。
需要注意的是,虽然Redis管道技术可以提高Redis的性能,但也会增加系统复杂性和内存负担。因此,在实际使用中,需要根据业务需求和系统负载情况进行合理调整和配置。
4、相关问题
1)Redis为什么那么快?
(1)内存存储:Redis将数据存储在内存中,使得读写速度非常快。同时,Redis也提供持久化机制,可以将内存数据异步地写入磁盘中,保证数据的安全性和可靠性。
(2)非阻塞I/O多路复用机制:Redis使用非阻塞I/O模型,避免了线程上下文切换和系统调用带来的开销,从而大幅提高了并发吞吐量。
(3)单线程架构:Redis采用单线程架构,避免了多线程间的同步和锁竞争等问题,简化了代码实现和维护。
(4)数据结构优化:Redis内置了多种数据结构(如哈希表、有序集合等),并对其进行了优化,使得操作复杂度低,并能在很短的时间内完成大量的数据处理。
(5)预分配内存:Redis在初始化时会预先分配一定量的内存空间,避免了频繁的内存分配和释放过程,提高了性能。
2)Redis为什么使用单线程?
Redis官方的回复:
“Redis的性能瓶颈通常不在CPU上,而是其他因素(如磁盘I/O和网络请求等)限制了系统的性能。”
3)Redis支持多线程吗?
Redis采用单线程模型,不支持多线程操作。这是因为Redis是一个基于内存的数据存储系统,大部分操作都需要访问内存,而内存访问通常是CPU密集型任务,多线程情况下会存在线程之间的上下文切换和锁竞争等问题,反而会降低效率。
虽然Redis 6.0+ 引入多线程IO,但只是用来处理网络数据的读写、协议的解析及日志操作等,而执行命令依旧是单线程,所以不需要去考虑set/get、事务、lua等的并发问题。
4)Redis有哪些数据结构?
Redis支持字符串、哈希表、列表、集合和有序集合等五种数据结构。
5)Redis的持久化机制有哪些?它们之间有什么区别?
Redis支持RDB(快照)和AOF(追加式文件)两种持久化机制。RDB会定期将内存数据快照写入磁盘文件,而AOF则将所有操作命令追加到一个日志文件中。相比而言,AOF更为可靠,但同时也需要更多的磁盘空间和IO资源。
6)Redis如何实现分布式锁?
Redis可以通过SETNX命令创建一个键值对作为锁,并使用Lua脚本实现原子性的加锁和释放锁操作。此外,还可以使用第三方库如Redisson提供的分布式锁解决方案。
7)Redis支持哪些类型的命令?
Redis支持基本的读写命令,如GET/SET/HGETALL等,以及一些高级命令,如事务、发布订阅等。
8)Redis的线程模型是什么?
Redis采用单线程架构,但通过使用事件驱动和非阻塞I/O技术,可以处理大量并发请求。
9)Redis如何保证数据的一致性?
Redis采用原子性操作和持久化机制来保证数据的一致性。例如,可以使用Redis事务(MULTI/EXEC)、管道技术、Lua脚本等方式实现原子性操作;通过开启持久化功能,可以将内存数据写入磁盘文件并在服务器重启后恢复数据。
10)Redis如何处理大量的并发请求?
Redis采用非阻塞I/O多路复用和事件驱动模型,可以高效地处理大量并发请求,并提供了线程池和缓冲区等机制来进一步优化性能。
11)Redis有哪些常见的应用场景?
Redis常见的应用场景包括缓存、计数器、消息队列、分布式锁等。
12)Redis的集群模式有哪些?
Redis支持主从复制、Sentinel哨兵模式和Cluster集群模式三种集群模式。其中,主从复制和Sentinel模式适用于较小的系统或需要高可用的场景,而Cluster模式则适用于更大规模的系统。
13)Redis如何实现发布订阅功能?
Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
=================================
如果文章对你有帮助,请不要忘记加个关注、点个赞!!!