标题:Redis-大厂程序员是怎么用的 - 掘金
Redis是什么? Redis(Remote Dictionary Server)是一个开源的、基于内存的键值存储系统。它可以用作数据库、缓存和消息中间件。除了简单的键值对,Redis还支持多种复杂的数据结构,如字符串(Strings)、散列(Hashes)、列表(Lists)、集合(Sets)、有序集合(Sorted Sets)、位图(Bitmaps)、HyperLogLogs和地理空间(Geospatial)索引半径查询。
为什么需要Redis?
- 性能和低延迟:由于Redis基于内存,它能够提供非常快速的读写速度,通常在微秒级。
- 灵活的数据结构:与传统的关系型数据库相比,Redis支持多种数据结构,使其更加灵活以满足不同的应用场景。
- 持久化:虽然Redis是一个基于内存的系统,但它也提供了多种持久化方法,可以根据需要将数据保存到磁盘。
- 扩展性和高可用性:Redis支持主从复制,允许多个Redis节点之间的数据同步,以及分片以实现水平扩展。
- 原子性:Redis操作是原子性的,意味着如果两个客户端并发访问,Redis服务器能够接收修改数据的更新请求,而无需外部同步。
- 丰富的客户端支持:几乎所有语言都有Redis客户端,包括Java、Python、PHP、C、C++、C#、JavaScript、Node.js、Ruby等。
Redis的工作原理:
- 基于内存:Redis主要存储在内存中,这意味着它的数据访问速度非常快,但也意味着数据量受到物理内存的限制。
- 单线程模型:Redis使用单线程模型来处理命令,保证每个命令的原子执行。这意味着在给定时刻,只有一个操作在执行。
- 事件驱动:Redis使用事件驱动程序模型来实现其非阻塞I/O。
- 持久化:Redis提供了两种主要的持久化方法:RDB快照和AOF日志文件。RDB是在指定的时间间隔内对数据进行快照存储,而AOF会记录服务器接收到的每一个写操作。
- 数据复制:Redis支持主从数据复制,从服务器可以是其他主服务器的从服务器,这种方式称为级联复制。数据复制可以用于数据备份、故障恢复或为读取操作分担负载。
- 分片:为了超越物理内存限制并增加读写吞吐量,数据可以在多个Redis节点之间进行分片。
简而言之,Redis是一个高性能、支持多种数据结构的内存存储系统,它的设计目标是实现快速、灵活且可靠的数据管理。 Redis支持两种主要的持久化方法:AOF (Append-only file) 和 RDB (Redis Database Snapshot)。这两种方法有各自的优势和用途。
1. RDB (Redis Database Snapshot):
-
工作方式:RDB持久化方法会在指定的时间间隔内对你的数据集进行快照存储。
-
文件:数据被保存到一个叫作dump.rdb的文件中。
-
配置:你可以配置Redis在给定的时间段内有多少次更新操作时,就自动保存数据快照。例如,“每10分钟,如果至少有1000次写操作,就保存一次”。
-
优点:
- RDB文件是压缩的二进制文件,因此通常比相应的AOF文件小。
- RDB可以最大化Redis的性能:父进程在保存数据快照时并不执行任何I/O操作,真正的保存工作是由子进程完成的。
- 快速数据加载:当Redis启动时,它可以非常快速地加载RDB文件。
-
缺点:
- 可能会丢失数据:因为RDB文件是在指定的时间间隔内保存的,所以你可能会丢失最后一次快照后的所有数据。
- 对于大数据集,生成RDB文件可能会需要一些时间,这可能会导致某些延迟。
2. AOF (Append-only file):
-
工作方式:AOF持久化方式会记录服务器接收到的每一个写操作,并将其追加到AOF文件的末尾。在Redis重启时,它会重新执行这些命令来重建原始数据。
-
文件:命令被追加到一个叫作appendonly.aof的文件中。
-
配置:Redis可以配置为每执行一个写命令后立即同步AOF文件,或者每秒同步一次,或者完全依赖于操作系统来决定何时同步。
-
优点:
- 数据安全性更高:通常,AOF文件比RDB方式更加持久和安全。
- 你可以调整AOF的同步频率以平衡数据安全性和写入性能。
-
缺点:
- 对于相同的数据集,AOF文件通常比RDB文件大。
- 根据同步策略的选择,AOF可能比RDB慢一些。
RDB与AOF的选择:
- 如果需要更高的数据安全性,请使用AOF。
- 如果你的数据可以容忍一些丢失,并且希望更快的快照保存与重载速度,则可以使用RDB。
- 你还可以同时启用RDB和AOF,以结合两者的优势。
在实际的生产环境中,根据数据安全性和性能需求,开发者可以选择最合适的持久化策略,或同时使用RDB和AOF。
Redis实例:
SDS
SDS是Redis内部用来替代C语言标准库中的字符串的数据结构。它有几个优势:
- O(1)的时间复杂度来获取字符串长度:与C语言的字符串不同,sds不依赖于空字符结尾来确定字符串长度。SDS在内部维护了一个长度字段,这意味着无需遍历整个字符串就可以知道其长度。
- 减少缓冲区溢出的风险:由于SDS知道其长度,所以在添加或修改字符串内容时,Redis可以确保分配适当的内存,这大大降低了缓冲区溢出的风险。
- 空间预分配:当字符串被修改并需要扩展时,SDS可能会预分配额外的未使用的内存。这减少了将来再次扩展字符串时的内存重新分配次数。
- 惰性空间释放:当字符串被缩小时,SDS并不立即释放多余的内存,而是使用一个单独的字段来记录这些未使用的空间,以备将来使用。这有助于减少频繁的内存重新分配操作。
SDS在Redis中的应用非常广泛,不仅仅是字符串数据类型,几乎所有Redis内部的字符串表示都使用SDS。
quicklist
quicklist 是一个压缩链接列表(compressed linked list)的数据结构,它结合了 listpack(紧凑列表)和双向链表的特点,为 Redis 的列表提供了一个更加内存高效的实现。
Hash
有两种扩容的方法:1、rehash: rehash操作是将ht[0]中的数据,全部迁移到ht[1]中。数据量小的场景下,直接将数据从ht[O]拷贝到ht[1]速度是较快的。数据量大的场景,例如存有上百万的KV时,迁移过程将会明显阻塞用户请求。 2、渐进式rehash:为避免出现这种情况,使用了rehash方案。基本原理就是,每次用户访问时都会迁移少量数据。将整个迁移过程,平摊到所有的访问用不请求过程中。
zset数据结构
该数据类型是由跳跃表SkipList和哈希表组成的
跳跃链表的结构:
- 跳跃链表由多个层组成,基础层是一个简单的排序链表。
- 高层(每个层都是随机选择的)包含了子集的元素。越高的层包含的元素越少。
- 每一个元素在跳跃链表中有一个或多个前进指针,每个指针指向当前层的下一个元素。
插入、删除和查找:
- 查找:从最上面的层开始,使用前进指针移动直到找到一个大于或等于目标值的元素或到达该层的末尾。然后下降到下一层,并继续此过程,直到在最底层的链表中进行普通的线性搜索。
- 插入:首先查找要插入的位置。然后,使用抛硬币的方式决定元素应该被插入到多少层。例如,可以使用一个随机过程,其中元素有1/2的机会出现在层1,1/4的机会出现在层2,1/8的机会出现在层3,依此类推。
- 删除:首先查找要删除的元素,然后简单地移除它和它所有的前进指针。
优势和应用:
- 性能:跳跃链表的查找、插入和删除操作的平均时间复杂度和最坏情况的时间复杂度都是O(log n)。
- 简单性:实现跳跃链表比实现平衡树简单得多。
- 可扩展性:跳跃链表是对并发友好的,因为它们不需要重新平衡,这使得它们在多线程环境中特别有用。
跳跃链表主要被用作内存数据库和应用中的排序数据结构,例如Redis。虽然它们不如平衡搜索树那样常见,但由于其性能特性和简单性,它们在某些应用中是一个有吸引力的选择。
在Redis中,
zset(有序集合)是一个非常强大的数据结构,允许用户存储键值对,并根据值来排序。为了实现这种功能并保持高效性,Redis使用了一个结合了哈希表和跳跃链表的设计。
- 跳跃链表:它为有序集合的元素提供排序功能。当你需要按分数范围或按排名范围来获取元素时,跳跃链表允许你进行有效的范围查询。
- 哈希表:它为每个成员提供快速的访问时间。当你想知道一个特定成员的分数,或者更新/删除一个成员时,哈希表可以在常数时间内找到该成员。
这种结合的好处是:
- 快速查找:哈希表确保了O(1)的查找时间。
- 有序访问:跳跃链表提供了O(log n)的有序访问和范围查询时间。
- 快速更新:由于哈希表,更新一个成员的分数或其他信息都是很快的。
简单来说,哈希表用于快速地定位和操作成员,而跳跃链表则用于维护成员之间的排序关系。结合这两种数据结构,zset可以非常高效地支持各种操作,如添加、删除、更新、范围查询等。