1、Redis概述
Redis(Remote Dictionary Server),全称为远程字典服务。是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。
Redis提供了多种数据类型的存储,来适应不同场景下的存储需求。并提供多种语言的API,兼容多种方式的集成。
Redis是一种 NoSQL(not-only sql,泛指非关系型数据库)的数据库,可以用作数据库、缓存、消息中间件、分布式锁等。
2、主要特点
(1)、基于内存
redis是内存数据库,即所有的数据都保存在内存中。所以redis的读写速度相比传统数据库基于磁盘IO的模式来说会快上很多,支持并发 10W QPS(每秒查询量),性能优秀。
(2)、I/O多路复用机制
Redis 是一个高性能的内存数据库,它的核心设计之一就是使用 I/O 多路复用来处理大量的客户端连接。它可以在一个线程中同时处理多个客户端请求,避免了为每个客户端创建独立的线程或进程,从而减少了上下文切换的开销,提高了系统的并发性和性能。
理解:redis是通过一个线程来处理多个客户端的请求(通过 I/O 多路复用实现),意在减少CPU上下文的切换,提升系统的并发性和性能。
重点概念理解下:
1、什么是文件描述符?
文件描述符: 是操作系统为每个打开的文件、套接字、管道等 I/O 资源分配的一个整数标识符。它用于唯一标识进程与某个 I/O 资源之间的连接。
文件描述符是操作系统内核管理 I/O 资源的方式,应用程序通过文件描述符与这些资源进行交互。
简单理解下:
一个进程可以访问多个文件(或其他网络终端或通道连接等)资源,这些访问都需要进程与文件建立连接后才能进行数据传输。操作系统为了能清晰区分这些连接,不导致数据传输错乱,会给每一个的这种连接(进程和文件通信)都添加一个唯一整数标识,就是文件描述符。
如:一个快递站可以给人发快递(快递站如:操作系统),每个人通过快递站给别人寄快递(寄快递如:建立传输连接),快递站需要对这次寄件添加唯一的快递单号(快递单号如:添加文件描述符),这样才能保证寄件的安全对吧。
2、有哪些类型的文件描述符?
(1)、文件:普通文件(如文本文件、图片文件等)。
(2)、套接字:网络连接(如 TCP/UDP 连接)。
(3)、管道:进程间通信的通道。
(4)、设备:如终端、打印机等硬件设备。
(3)、存储方式(key-value)
Redis存储数据都是基于key-value方式,类似于HashMap,其查找和操作的时间复杂度都是O(1)。
(4)、多数据结构支持
Redis提供了丰富的数据类型支持(5+3+1)。这里先介绍下,在后续会有详细示例。
1、String(字符串):最基本的类型,可以存储字符串、整数或浮点数。支持原子的递增和递减操作。
2、List(列表):双端链表,可以从两端插入和删除元素。适用于队列和栈的实现。
3、Set(集合):无序集合,成员是唯一的。支持交集、并集、差集等集合运算。
4、Sorted Set(有序集合):类似于集合,但是每个成员关联一个分数,可以根据分数排序。
5、Hash(哈希表):类似于 Java 中的 HashMap,可以存储字段和值的映射关系。适用于对象的存储。
6、Bitmaps(位图):一种特殊的字符串类型(2进制串),可以用来表示布尔数组,支持高效的位操作。
7、HyperLogLog(基数):用于估算集合中不同元素的数量,具有很高的空间效率。
基数:大规模数据集中的不同元素。(如:1,2,5,2,3的不同元素为1,2,3,5,即基数为4)。
8、Geospatial Indexes(地理空间索引):支持地理坐标点的存储和查询,可以计算两点之间的距离、查找附近的点等。
9、Streams(流):引入于 Redis 5.0,是一种类似消息队列的数据结构,支持消费组和消息回溯等功能。
(5)、支持事务
Redis 提供了简单的事务机制,Redis 事务的本质是一组命令的集合。当执行redis事务时,即一次性按照添加顺序依次执行这些命令,中间不会被打断或者干扰。
Redis 的事务机制并不像关系型数据库中的事务那样提供完整的ACID特性(原子性、一致性、隔离性和持久性),但它确实提供了一种方式来确保一组命令作为一个整体被执行。
(6)、发布/订阅(Pub/Sub)
Redis 发布/订阅(Publish/Subscribe,简称 Pub/Sub)是一种消息传递模式,允许客户端订阅一个或多个通道(channel),并接收其他客户端发布到这些通道的消息。
实现该模式,主要包含3个部分:
1、发布者(Publisher):发布者可以向指定的通道发送消息。每个消息会被发送给所有订阅了该通道的客户端。
2、订阅者(Subscriber):订阅者可以订阅一个或多个通道,并接收订阅通道的消息。订阅者不会直接与发布者交互,它们只负责监听通道中的消息。
3、通道(Channel):通道是消息传递的媒介。发布者将消息发布到特定的通道,订阅者从这些通道接收消息。通道的名字是一个字符串,可以是任意的标识符。
(7)、持久化
前面也说过redis是基于内存的数据库,基于内存大大优化了性能问题。但也面临着意外的风险,比如突然停电或者意外宕机了,重启电脑后内存中的数据就都不存在了!所以为了数据安全一定要做持久化处理(将数据写入到磁盘中),这样即使宕机后重启也可以通过持久化文件将数据恢复。
Redis 的持久化的两种方式:
RDB(默认):快照形式是直接把内存中的数据保存到 dump.rdb 文件中,定时全量保存,保存的是数据。
AOF:把所有的对 Redis 的服务器进行修改的命令都保存到 appendonly.aof 文件中,定时向文件中追加,保存的是命令。
(8)、主从复制/读写分离
主从复制是 Redis 提供的一种数据冗余机制,允许你创建一个或多个从服务器(Slaves),它们会实时地复制主服务器(Master)的数据。这样可以在主服务器发生故障时提供备份,并且可以分担读取请求的负载,提高系统的整体性能。
读写分离是指将写操作定向到主服务器,而将读操作分散到从服务器上。这有助于减轻主服务器的压力,提升读取性能,因为通常读操作比写操作更频繁。
示例图如下:
原理:
数据同步原理:当主服务器接收到写操作时,它会将这些更改记录到自己的命令日志中(称为 AOF 或 RDB 文件)。然后,主服务器会将这些更改发送给所有连接的从服务器,从服务器接收并应用这些更改。完成数据同步主要分为两个过程:
(1)、初次同步(全量同步):当一个新的从服务器加入时,它会与主服务器进行全量同步,即从服务器会下载主服务器的一个快照(RDB 文件),并将其加载到内存中。之后,它会继续接收增量更新。
(2)、持续同步(增量同步):在初次同步完成后,从服务器会持续接收来自主服务器的命令,以保持数据的一致性。
配置方式:
在 redis.conf 中设置 slaveof 来指定主服务器的 IP 和端口。
(9)、哨兵机制(Sentinel)
Redis 哨兵机制(Sentinel)是一个监控和故障转移的机制,用于管理 Redis 主从架构中的节点,以提升redis系统整体的可用性,即实现redis高可用性。
它会自动监控主服务器和从服务器的状态,并在主服务器不可用时自动执行故障转移,选择一个健康的从服务器晋升为主服务器。
工作原理:
(1)、节点监控:Sentinel 持续监控主服务器和从服务器的心跳,以检测它们的健康状态。
(2)、故障通知:当 Sentinel 检测到主服务器不可用时,它会通知其他 Sentinel实例和客户端。
(3)、选举和故障恢复:如果大多数 Sentinel 实例同意主服务器已经失效,它们会投票选出新的主服务器。然后,选中的从服务器会被晋升为主服务器,其余的从服务器会重新配置为新主服务器的从服务器,继续完成工作。
(4)、配置更新:Sentinel 会自动更新客户端的配置信息,使它们能够正确地连接到新的主服务器。
配置方式:
在sentinel.conf文件中定义哨兵实例的配置,包括主服务器的地址、哨兵之间的通信端口等。
(10)、集群(Cluster)
Redis 集群(Cluster)是 Redis 的分布式解决方案,它允许你将数据分布在多个节点上,从而实现水平扩展。集群通过分片(Sharding)技术将键空间划分成多个片段,每个片段由不同的节点负责存储。此外,集群还支持自动故障转移和数据冗余。
工作原理:
(1)、分片:Redis Cluster使用哈希槽(hash slots)来分配键。共有16384个哈希槽,每个键根据其哈希值映射到一个具体的槽,而每个槽可以被分配给任意一个节点。
(2)、故障转移:每个节点都可以有多个从节点,用于提供冗余。如果主节点失败,集群会自动将一个从节点晋升为主节点。
(3)、一致性哈希:客户端在发送请求时,需要计算键对应的哈希槽,然后根据当前的槽-节点映射找到正确的节点。如果槽-节点映射发生变化(例如因为故障转移),客户端需要更新其本地缓存。
(4)、容错能力:即使某些节点失效,只要大多数节点仍然可用,集群就可以继续工作。
配置:
(1)、使用 redis-cli --cluster create 命令来初始化一个新的 Redis Cluster。
(2)、每个节点的 redis.conf 文件中需要启用集群模式(cluster-enabled yes),并配置集群公告 IP 和端口(cluster-announce-ip 和 cluster-announce-port)。
(11)、Lua脚本
Redis 支持使用 Lua 脚本来执行复杂的操作,这为 Redis 提供了更强的灵活性和性能优化能力。通过 Lua 脚本,你可以在服务器端执行一系列命令,而不需要多次往返客户端与服务器之间,从而减少了网络延迟并提高了效率。此外,Lua 脚本是原子性的,这意味着在脚本执行期间,其他客户端的请求不会被处理,确保了数据的一致性。
(12)、丰富的客户端库
Redis 拥有几乎所有编程语言的客户端库,方便开发者集成到各种应用中。
3、单线程模型
Redis 采用单线程模型来处理客户端请求,这意味着在任意时刻只有一个命令被执行。这种设计简化了 Redis 的实现,并确保了高并发环境下的数据一致性。尽管 Redis 是单线程的,但它通过高效的内存管理和网络 I/O 操作,仍然能够处理非常高的吞吐量。
上图即为redis的请求处理流程。可以看到redis接收到用户的请求后,全部推送到一个队列里,然后交给文件事件分派器,而它是单线程的工作方式,所以说 Redis 是单线程的。
4、默认配置
(1)、默认的数据库:redis总共有16个数据库,不指定的话默认连接第0个数据库。每个数据库的数据不共享。
(2)、key和value的限制:
Redis 对键(key)和值(value)的大小以及使用个数有一定的限制,这些限制旨在确保 Redis 的性能和稳定性。
长度限制:
redis的key和value的最大长度上限都是512M。当key大于10k时,称得上是大key。通常建议将键的长度保持在合理的范围内(例如 64 字节以内),以确保高效的内存使用和快速的查找。
数量限制:
Redis 没有明确的键数量限制,理论上可以存储 2^64 - 1 个键(即 18,446,744,073,709,551,615 个键)。然而,实际的键数量取决于你的硬件资源(如内存、CPU 等)和 Redis 的配置。
1byte(字节)= 8bit(位),1k = 1024byte,1M = 1024k,1G = 1024M,bit = 字节,一个汉字占2个bit,一个英文(不区分大小写)占1bit,中文标点占3个bit,英文占1个bit。
学海无涯苦作舟!!!