Redis 知识点全面击破,多图告诫

开发者 2024-9-6 23:10:38 105 0 来自 中国
什么是 Redis?

Redis(REmote DIctionary Service)是一个开源的键值对数据库服务器。
Redis 更精确的形貌是一个数据结构服务器。Redis 的这种特殊性子让它在开辟职员中很受接待。
1.png Redis不是通过迭代大概排序方式处置惩罚数据,而是一开始就按照数据结构方式构造。早期,它的利用很像 Memcached,但随着 Redis 的改进,它在许多其他用例中变得可行,包罗发布-订阅机制、流(streaming)和队列。
2.png 告急来说,Redis 是一个内存数据库,用作另一个“真实”数据库(如 MySQL 或 PostgreSQL)前面的缓存,以资助进步应用步伐性能。它通过利用内存的高速访问速率,从而减轻核心应用步伐数据库的负载,比方:

  • 不常常更改且常常被哀求的数据
  • 任务关键性较低且常常变动的数据
上述数据的示例可以包罗会话或数据缓存以及仪表板的排行榜或汇总分析。
3.png 但是,对于许多用例场景,Redis 都可以提供富足的包管,可以将其用作成熟的主数据库。再加上 Redis 插件及其各种高可用性(HA)设置,Redis 作为数据库对于某些场景和工作负载变得非常有效。
另一个告急方面是 Redis 含糊了缓存和数据存储之间的界限。这里要明白的告急一点是,相比于利用 SSD 或 HDD 作为存储的传统数据库,读取和利用内存中数据的速率要快得多。
最初,Redis 最常被比作 Memcached,后者当时缺乏任何非易失性长期化。
这是当前两个缓存之间的功能细分。
5.png 固然如今拥有多种设置方式将数据长期化到磁盘,但当时初次引入长期化时,Redis 是利用快照方式,通过异步拷贝内存中的数据方式来做长期化。不幸的是,这种机制的缺点是大概会在快照之间丢失数据。
Redis 自 2009 年创建到如今已经变的很成熟。我们将先容它的大部门架构和拓扑,以便你可以将 Redis 添加到你的数据存储体系库中。
Redis 架构

在开始讨论 Redis 内部结构之前,让我们先讨论一下各种 Redis 摆设及其权衡弃取。
我们将告急关注以下这些设置:

  • 单个 Redis 实例
  • Redis 高可用性
  • Redis 哨兵
  • Redis 集群
根据你的用例和规模,决定利用哪一种设置。
单个 Redis 实例
6.png 单个 Redis 实例是最直接的 Redis 摆设方式。它答应用户设置和运行小型实例,从而资助他们快速发展和加速服务。但是,这种摆设并非没有缺点。比方,如果此实例失败或不可用,则全部客户端对 Redis 的调用都将失败,从而降低体系的团体性能和速率。
如果有富足的内存和服务器资源,这个实例可以很强大。告急用于缓存的场景大概会以最少的设置得到显着的性能提拔。给定富足的体系资源,你可以在应用步伐运行的同一呆板上摆设此 Redis 服务。
在管理体系内的数据方面,相识一些 Redis 概念是必不可少的。发送到 Redis 的下令起首在内存中处置惩罚。然后,如果在这些实例上设置了长期性,则在某个时间隔断上会有一个fork进程,来天生数据长期化 RDB(Redis 数据的非常紧凑的时间点体现)快照或 AOF(仅附加文件)。
这两个流程可以让 Redis 拥有恒久存储,支持各种复制战略,并启用更复杂的拓扑。如果 Redis 未设置为长期化数据,则在重新启动或故障转移时数据会丢失。如果在重启时启用了长期化,它会将 RDB 快照或 AOF 中的全部数据加载回内存,然后实例可以支持新的客户端哀求。
话虽云云,让我们看看你大概会用到的更多分布式 Redis 设置。
Redis 高可用性
7.png Redis 的另一个盛行设置是主从摆设方式,从摆设保持与主摆设之间数据同步。当数据写入主实例时,它会将这些下令的副本发送到从摆设客户端输出缓冲区,从而到达数据同步的结果。从摆设可以有一个或多个实例。这些实例可以资助扩展 Redis 的读取利用或提供故障转移,以防 main 丢失。
我们如今已经进入了一个分布式体系,因此必要在此拓扑中思量许多新事物。从前简单的事变如今变得复杂了。
Redis 复制
Redis 的每个主实例都有一个复制 ID 和一个偏移量。这两条数据对于确定副本可以继承其复制过程的时间点或确定它是否必要举行完整同步至关告急。对于主 Redis 摆设上发生的每个利用,此偏移量都会增长。
更明白地说,当 Redis 副本实例仅掉队于主实例几个偏移量时,它会从主实例汲取剩余的下令,然后在其数据集上重放,直到同步完成。如果两个实例无法就复制 ID 告竣一致,大概主实例不知道偏移量,则副本将哀求全量同步。这时主实例会创建一个新的 RDB 快照并将其发送到副本。
在此传输之间,主实例会缓冲快照制止和当前偏移之间的全部中央更新指令,如许在快照同步完后,再将这些指令发送到副本实例。如许完成后,复制就可以正常继承。
如果一个实例具有雷同的复制 ID 和偏移量,则它们具有完全雷同的数据。如今你大概想知道为什么必要复制 ID。当 Redis 实例被提拔为主实例或作为主实例从头开始重新启动时,它会被赋予一个新的复制 ID。
这用于推断此新提拔的副本实例是从先前哪个主实例复制出来的。这答应它可以大概实行部门同步(与其他副本节点),由于新的主实例会记着其旧的复制 ID。
比方,两个实例(主实例和从实例)具有雷同的复制 ID,但偏移量相差几百个下令,这意味着如果在实例上重放这些偏移量反面的下令,它们将具有雷同的数据集。如今,如果复制 ID 完全差异,而且我们不知道新降级(或重新参加)从节点的先前复制 ID(没有共同先人)。我们将必要实行昂贵的全量同步。
相反,如果我们知道从前的复制 ID,我们就可以推断怎样使数据同步,由于我们可以大概推断出它们共享的共同先人,而且偏移量对于部门同步再次故意义。
Redis 哨兵(Sentinel)
Sentinel 是一个分布式体系。与全部分布式系同一样,Sentinel 有几个长处和缺点。Sentinel 的操持方式是,一组哨兵进程协同工作以调和状态,从而为 Redis 提供高可用性。毕竟,你不希望保护你免受故障影响的体系有本身的单点故障。
Sentinel 负责一些事变。起首,它确保当前的主实例和从实例正常运行并做出相应。这是须要的,由于哨兵(与其他哨兵进程)可以在主节点和/或从节点丢失的情况下发出警报并采取办法。其次,它在服务发现中发挥作用,就像其他体系中的 Zookeeper 和 Consul 一样。所以当一个新的客户端实行向 Redis 写东西时,Sentinel 会告诉客户端当前的主实例是什么。
因此,哨兵不绝监控可用性并将该信息发送给客户端,以便他们可以大概在他们确实举行故障转移时对其做出反应。
以下是它的职责:

  • 监控——确保主从实例按预期工作。
  • 关照——关照体系管理员 Redis 实例中的事件。
  • 故障转移管理——如果主实例不可用而且富足多的(法定命量)节点同意这是真的,Sentinel 节点可以启动故障转移。
  • 设置管理——Sentinel 节点还充当当前主 Redis 实例的发现服务。
以这种方式利用 Redis Sentinel 可以举行故障检测。此检测涉及多个哨兵进程同意当前主实例不再可用。这个协议过程称为 Quorum。这可以进步鲁棒性并防止一台呆板举动非常导致无法访问主 Redis 节点。
此设置并非没有缺点,因此我们将在利用 Redis Sentinel 时先容一些发起和最佳实践。
你可以通过多种方式摆设 Redis Sentinel。老实说,要提出任何明智的发起,我必要有关你的体系的更多配景信息。作为一样平常引导,我发起在每个应用步伐服务器旁边运行一个哨兵节点(如果大概的话),如许你也不必要思量哨兵节点和实际利用 Redis 的客户端之间的网络可达性差异。
你可以将 Sentinel 与 Redis 实例一起运行,乃至可以在独立节点上运行,只不外它会按照别的方式处置惩罚,从而会让事变变得更复杂。我发起至少运行三个节点,而且至少具有两个法定人数(quorum)。这是一个简单的图表,分解了集群中的服务器数量以及干系的法定人数和可容忍的可连续故障。
9.png 这会因体系而异,但总体思绪是稳定的。
让我们花点时间思考一下如许的设置会出现什么问题。如果你运行这个体系富足长的时间,你会碰到全部这些。

  • 如果哨兵节点超出法定人数怎么办?
  • 如果网络分裂将旧的主实例置于少数群体中怎么办?这些写入会发生什么?(剧透:当体系完全规复时它们会丢失)
  • 如果哨兵节点和客户端节点(应用步伐节点)的网络拓扑错位会发生什么?
没有长期性包管,特殊是长期化到磁盘的利用(见下文)是异步的。尚有一个贫苦的问题,当客户发现新的 primary 时,我们失去了多少写给一个不知道的 primary?Redis 发起在创建新毗连时查询新的主节点。根据体系设置,这大概意味着大量数据丢失。
如果你欺压主实例将写入复制到至少一个副本实例,有几种方法可以减轻丧失水平。请记着,全部 Redis 复制都是异步的,这是有其权衡的思量。因此,它必要独立跟踪确认,如果至少有一个副本实例没有确认它们,主实例将制止继承写入。
Redis 集群
我相信许多人都想过当你无法将全部数据存储在一台呆板上的内存中时会发生什么。目前,单个服务器中可用的最大 RAM 为 24TIB,这是目前 AWS 线上列出来的。固然,这许多,但对于某些体系来说,这还不够,纵然对于缓存层也是云云。
Redis Cluster 答应 Redis 的水平扩展。
起首,让我们摆脱一些术语束缚;一旦我们决定利用 Redis 集群,我们就决定将我们存储的数据分散到多台呆板上,这称为分片。所以集群中的每个 Redis 实例都被以为是整个数据的一个分片。
这带来了一个新的问题。如果我们向集群推送一个key,我们怎样知道哪个 Redis 实例(分片)生存了该数据?有几种方法可以做到这一点,但 Redis Cluster 利用算法分片。
为了找到给定 key 的分片,我们对 key 举行哈希处置惩罚,并通过对总分片数量取模。然后,利用确定性哈希函数,这意味着给定的 key 将始终映射到同一个分片,我们可以推断未来读取特定 key 的位置。
当我们之后想在体系中添加一个新的分片时会发生什么?这个过程称为重新分片。
假设键 'foo' 之前映射到分片 0, 在引入新分片后它大概会映射到分片 5。但是,如果我们必要快速扩展体系,移动数据来到达新的分片映射,这将是迟钝且不切实际的。它还对 Redis 集群的可用性产生倒霉影响。
Redis Cluster 为这个问题操持了一种办理方案,称为 Hashslot,全部数据都映射到它。有 16K 哈希槽。这为我们提供了一种在集群中传播数据的合理方式,当我们添加新的分片时,我们只需在体系之间移动哈希槽。通过如许做,我们只必要将 hashlot 从一个分片移动到另一个分片,并简化将新的主实例添加到集群中的过程。
这可以在没有任何停机时间和最小的性能影响的情况下实现。让我们通过一个例子来谈谈。

  • M1 包罗从 0 到 8191 的哈希槽。
  • M2 包罗从 8192 到 16383 的哈希槽。
因此,为了映射 “foo”,我们接纳一个确定性的键(foo)散列,并通过散列槽的数量(16K)对其举行修改,从而得到 M2 的映射。如今假设我们添加了一个新实例 M3。新的映射将是:

  • M1 包罗从 0 到 5460 的哈希槽。
  • M2 包罗从 5461 到 10922 的哈希槽。
  • M3 包罗从 10923 到 16383 的哈希槽。
如今映射到 M2 的 M1 中映射哈希槽的全部键都必要移动。但是散列槽的各个键的散列不必要移动,由于它们已经被分别到散列槽中。因此,这一级别的误导(misdirection)办理了算法分片的重新分片问题。
Gossiping 协议
Redis Cluster 利用 gossiping 来确定整个集群的康健状态。在上图中,我们有 3 个 M 个节点和 3 个 S 节点。全部这些节点不绝地举行通讯以相识哪些分片可用并准备好为哀求提供服务。
如果富足多的分片同意 M1 没有相应,他们可以决定将 M1 的副本 S1 提拔为主节点以保持集群康健。触发此利用所需的节点数量是可设置的,而且必须精确实行此利用。如果利用不妥而且在分区的两边相称时无法冲破平手,则大概会导致集群被拆分。这种征象称为裂脑。作为一样平通例则,必须拥有奇数个主节点和两个副本,以实现最妥当的设置。
Redis 长期化模子

如果我们要利用 Redis 存储任何范例的数据同时要求安全生存,相识 Redis 是怎样做到这一点很告急。在许多用例中,如果你丢失了 Redis 存储的数据,这并不是天下末日。将其用作缓存或在其支持实时分析的情况下,如果发生数据丢失,则并非天下末日。
在其他场景中,我们希望围绕数据长期性和规复有一些包管。
11.png 无长期化
无长期化:如果你愿意,可以完全禁用长期化。这是运行 Redis 的最快方式,而且没有长期性包管。
RDB文件
RDB(Redis 数据库):RDB 长期化以指定的时间隔断实行数据集的时间点快照。
这种机制的告急缺点是快照之间的数据会丢失。别的,这种存储机制还依靠于主进程的 fork,在更大的数据会合,这大概会导致服务哀求的刹时耽误。话虽云云,RDB 文件在内存中的加载速率要比 AOF 快得多。
AOF
AOF(Append Only File):AOF 长期化记载服务器汲取到的每个写入利用,这些利用将在服务器启动时再次被实行,重修原始数据集。
这种长期性的方法可以大概确保比 RDB 快照更长期,由于它是一个仅附加文件。随着利用的发生,我们将它们缓冲到日记中,但它们还没有被长期化。该日记与我们运行的实际下令一致,以便在必要时举行重放。
然后,如果大概,我们利用 fsync 将其革新到磁盘(当此运行可设置时),它将被长期化。缺点是格式不紧凑,而且比 RDB 文件利用更多的磁盘。
为什么不兼得?
RDB + AOF:可以将 AOF 和 RDB 组合在同一个 Redis 实例中。如果你愿意的话,可以以速率变动长期化是一种折衷方法。我以为这是设置 Redis 的一种可继承的方式。在重启的情况下,请记着如果两者都启用,Redis 将利用 AOF 来重修数据,由于它是最完整的。
Forking
如今我们相识了长期化的范例,让我们讨论一下我们如安在像 Redis 如许的单线程应用步伐中实际实行它。
在我看来,Redis 最酷的部门是它怎样利用 forking 和写时复制来高效地促进数据长期化。
Forking 是利用体系通过创建自身副原来创建新进程的一种方式。如许,你将得到一个新的进程 ID 和一些其他信息和句柄,因此新 forking 的进程(子进程)可以与原始进程父进程通讯。
如今事变变得风趣了。Redis 是一个分配了大量内存的进程,那么它如安在不耗尽内存的情况下举行复制呢?
当你 fork 一个进程时,父进程和子进程共享内存,而且在该子进程中 Redis 开始快照(Redis)进程。这是通过一种称为写时复制的内存共享技能实现的——该技能在创建分叉时转达对内存的引用。如果在子进程长期化到磁盘时没有发生任何更改,则不会举行新的分配。
在发生更改的情况下,内核会跟踪对每个页面的引用,如果某个页面有多个更改,则将更改写入新页面。子进程完全不知道更改以及具有一致的内存快照的事变。因此,在只利用了一小部门内存的情况下,我们可以大概非常快速有效地得到潜在千兆字节内存的时间点快照!
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 04:25, Processed in 0.165007 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表