Redis

基础

redis为什么这么快 (高)

[!NOTE]

  • 最首要的是Redis是纯内存操作, 比磁盘要快3个数量级
  • 同时在与内存操作中采用了非阻塞I/O多路复用机制来提高并发量
  • 并且基于Redis的IO密集型,采用单线程操作, 免去了线程切换开销
  • Redis 内置了多种优化过后的数据结构实现. 如跳表

14分钟掌握Redis底层原理(IO多路复用、文件描述符、内核空间)_哔哩哔哩_bilibili

redis高性能怎么实现的?

性能一般基于两个方面, 一个是计算操作, 一个是读写操作.

  • 计算操作, 由于redis是基于内存的, 所以计算操作(命令执行)很快, 然后单线程执行命令比较快. 所以redis的性能瓶颈不在计算操作, 而在于网络io

  • 单线程执行为啥快, 那是因为单线程执行的话你就不需要加锁来控制了, 锁是很重的很耗费资源.

  • 多线程的话, 也需要线程上下文切换, 这样的话性能也会降低.

  • 读写操作, 无非就是网络io和磁盘io

  • 磁盘io优化: rdb持久化时, 会创建一个子进程来生成RDB文件, 这样可以避免主线程的阻塞. 这也是一种写入时复制的思想

  • 网络io优化:

  • io多路复用: select epoll, 可以同时监听多个socket连接请求

  • 事件派发机制: 有很多不同性质的socket, redis有不同的handler来处理这些socket事件, redis6.0使用多线程来处理这些handler

Redis常用的数据结构有哪些?(高)

  • 5种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)
  • 4种特殊数据类型:HyperLogLogs(基数统计)、Bitmap(位存储)、geo(地理位置)、stream(消息队列)

redis每种数据类型的使用场景(高)

  • String: 最常规的 set/get 操作,Value 可以是 String 也可以是数字。一般做一些复杂的计数功能的缓存。

  • Hash: 这里 Value 存放的是结构化的对象,比较方便的就是操作其中的某个字段。如果单纯做对象的存储,那么直接使用string即可,如果需要对对象中的字段做操作,那么用hash.

  • List:list支持两端存取,不能从中间取。若从一侧存取,则是栈。若从异侧存取,则是队列。- 使用 List 的数据结构,可以做简单的消息队列的功能。另外,可以利用 Irange 命令,做基于 Redis 的分页功能,性能极佳,用户体验好

  • Set: 因为 Set 堆放的是一堆不重复值的集合。所以可以做全局去重的功能。我们的系统一般都是集群部署,使用 JVM 自带的 Set 比较麻烦。另外,就是利用交集、并集、差集等操作,交集就可以计算共同喜好,共同关注,共同好友,共同粉丝等功能。差集就可以实现好友推荐,音乐推荐功能.

  • Sorted Set: Sorted Set 多了一个权重参数 Score,集合中的元素能够按 Score 进行排列。可以做排行榜应用,取 TOP(N) 操作。也可以做优先级任务队列。

  • geo: 地理位置计算

  • bitmap: 可以用来做布隆过滤器,或者统计签到次数等

  • HyperLogLog: 统计页面 UV

  • Stream: 做一个简单的消息队列

本地缓存和Redis缓存的区别,优缺点?(低)

本地缓存是指将数据存储在本地应用程序或服务器上,通常用于加速数据访问和提高响应速度。本地缓存通常使用内存作为存储介质,利用内存的高速读写特性来提高数据访问速度。

优点:

  • 访问速度快:本地缓存存储在本地内存中,访问速度非常快
  • 减轻网络压力:本地缓存能够降低对远程服务器的访问次数,从而减轻网络压力
  • 低延迟:本地缓存位于本地设备上,能够提供低延迟的访问速度,适用于对实时性要求较高的应用场景

缺点:

  • 可扩展性有限:本地缓存的可扩展性受到硬件资源的限制,无法支持大规模的数据存储和访问

分布式缓存(Redis)是指将数据存储在多个分布式节点上,通过协同工作来提供高性能的数据访问服务。分布式缓存通常使用集群方式进行部署,利用多台服务器来分担数据存储和访问的压力

优点:

  • 可扩展性强:分布式缓存的节点可以动态扩展,能够支持大规模的数据存储和访问需求。

  • 易于维护:分布式缓存通常采用自动化管理方式,能够降低维护成本和管理的复杂性。
    缺点:

  • 访问速度相对较慢:相对于本地缓存,分布式缓存的访问速度相对较慢,因为数据需要从多个节点进行访问和协同。但是这也比访问数据库要快的多

  • 网络开销大:分布式缓存需要通过网络进行数据传输和协同操作,相对于本地缓存来说,网络开销较大

redis的常见应用场景/你平时会用redis做什么(中)

  • 缓存:通过将热点数据存储在内存中,可以极大地提高访问速度,减轻数据库压力
  • 排行榜:Redis的有序集合结构非常适合用于实现排行榜和排名系统,可以方便地进行数据排序和排名
  • 分布式锁:Redis的特性可以用来实现分布式锁,确保多个进程或服务之间的数据操作的原子性和一致性
  • 计数器:由于Redis的原子操作和高性能,它非常适合用于实现计数器和统计数据的存储,如网站访问量统计、点赞数统计等
  • 消息队列:Redis的发布订阅功能使其作为一个轻量级的消息队列,可以用来实现发布和订阅模式。(Redis高版本新增Stream数据结构,可以直接作为一个轻量级MQ使用)

线程模型

Redis 为什么设计成单线程的 (中)

  • 多线程处理会涉及到锁,并且多线程处理会涉及到线程切换而消耗 CPU。采用单线程,避免了不必要的上下文切换和竞争条件
  • 其次 CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存或者网络带宽。所以 redis 网络 io 操作采用了多线程.

Redis一定是单线程的吗 (中)

  • Redis 单线程指的是执行命令是由一个主线程来完成的
  • 但是 Redis 在磁盘 io (持久化操作) 和网络 io 会使用多线程来处理,是因为这些任务的操作都是很耗时的,如果把这些任务都放在主线程来处理,那么 Redis 主线程就很容易发生阻塞,这样就无法处理后续的请求了

Redis 6.0 之后为什么引入了多线程? (中)

Redis执行命令一直是单线程模型

因为 Redis 的性能瓶颈有时会出现在网络 I/O 的处理上,故在 Redis 6.0 版本之后,采用了多个 I/O 线程来处理网络请求,提高网络 I/O 的并行度

但是对于命令的执行,Redis 仍然使用单线程来处理

内存与持久化

redis的过期策略(高)

每当我们对一个key设置了过期时间时,Redis会把该key带上过期时间存储到一个过期字典(expires dict)中,也就是说「过期字典」保存了数据库中所有key的过期时间

过期策略:定期删除+惰性删除

  • 定期删除就是Redis默认每隔100ms就随机抽取一些设置了过期时间的key,检测这些key是否过期,如果过期了就将其删除
  • 惰性删除是在你要获取某个key的时候,redis会先去检测一下这个key是否已经过期,如果没有过期则返回给你,如果已经过期了,那么redis会删除这个key,不会返回给你

但是,仅仅通过给key设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期key的情况。这样就导致大量过期key堆积在内存里,然后就Out of memory了。

怎么解决这个问题呢?Redis内存淘汰机制

为什么Key过期不立即删除?(高)

在过期key比较多的情况下,删除过期key可能会占用相当一部分CPU时间,在内存不紧张但CPU时间紧张的情况下,将CPU时间用于删除和当前任务无关的过期键上,会对服务器的响应时间和吞吐量造成影响

内存淘汰机制(高)

1#noeviction −>- >> 当内存不够时,不淘汰任何数据,只是抛出异常(一般不使用)
2#yvolatile-lru −>- >> 从设置过期时间的数据中,淘汰最近最长时间没有被使用的数据
3#allkeys-lru −>- >> 从所有数据中,淘汰最近最长时间没有被使用的数据
4#volatile-lfu −>- >> 从设置过期时间的数据中,淘汰一段时间内使用次数最少数据
5#allkeys-lfu −>- >> 从所有数据中,淘汰一段时间内使用次数最少的数据
6#volatile-random −>- >> 从设置过期时间的数据中,随机淘汰一批数据
7#allkeys-random −>- >> 从所有数据中随机淘汰一批数据
8#volatile-ttl −>- >> 淘汰快超时的数据

名词解释

  • LRU [Least Recently Used]: 最近最久未使用; LRU是淘汰最长时间没有被使用的数据。
  • LFU [Least Frequently Used]: 最近最少使用; LFU是淘汰一段时间内,使用次数最少的数据。
  • TTL: time to live, 过期时间

Redis持久化机制(高)

RDB: 按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二进制文件。即Snapshot快照存储,对应产生的数据文件为dump.rdb.

Redis提供了两个命令来生成RDB文件,分别是save和bgsave,他们的区别就在于是否在「主线程」里执行:

  • 执行了save命令,就会在主线程生成RDB文件,由于和执行操作命令在同一个线程,所以如果写入RDB文件的时间太长,会阻塞主线程;
  • 执行了bgsave命令,会创建一个子进程来生成RDB文件,这样可以避免主线程的阻塞;执行bgsave过程中,Redis依然可以继续处理操作命令的,也就是数据是能被修改的。写时复制技术(Copy-On-Write)

AOF: Redis会将每一个收到的写命令追加到文件最后,类似于MySQL的binlog。当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。

  • AOF保存的数据更加完整,但是性能相比RDB稍差

在Redis的配置文件中存在三种不同的AOF持久化方式

1 appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
2 appendfsync everysec #每次写操作命令执行完后,先将命令写入到AOF文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘
3 appendfsync no #让操作系统决定何时进行同步

  • 为了兼顾数据和写入性能,可以用appendfsync everysec,让Redis每秒同步一次AOF文件,对Redis性能影响不大.

  • 即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据

混合持久化

Redis 4.0 提出混合使用 AOF 日志和内存快照,也叫混合持久化。

  • 当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。
  • 使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
  • 好处在于,重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快
  • 加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令,可以使得数据更少的丢失。

故一般都会用混合持久化方式

缓存问题(常考)

缓存击穿 (高)

一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。

无论是哪种方案,其目标都是保证某个key过期,大量请求访问它,但是只有一个请求能访问数据库,重建缓存

  1. 互斥锁方案:
  • 如果 redis 中没查到数据,缓存未命中。则获取互斥锁(setnx),获取失败则休眠重试,获取成功则再次查询缓存是否存在(双重检测),没查到则查询数据库进行缓存重建

也就是说能拿到锁的线程去做缓存重建,没拿到锁的线程阻塞等待。待缓存重建完成,没拿到锁的线程直接查redis即可。互斥锁注重一致性,但是性能较差,需要数据库与缓存强一致性选择互斥锁

  1. 逻辑过期方案:

需要在将要缓存的数据中加上时间属性作为逻辑过期时间,然后在redis中设置永不过期。查询时从redis中获取数据,对比逻辑过期时间看否过期,未过期直接返回数据。过期则获取互斥锁。获取锁失败则说明已经有人进行缓存重建了,那么直接返回旧数据。获取锁成功(需要双重检测)则开启新线程进行缓存重建,原线程直接返回保证效率。也就是说,拿到锁的线程去做缓存重建,没拿到锁的线程返回旧数据(因为redis中没设置过期时间,所以总能拿到旧数据)。逻辑过期性能好,但是一致性差,需要高性能选择逻辑过期

缓存穿透(高)

请求的数据在数据库和缓存中都不存在,那么请求就会直接访问数据库。

方案一:可以缓存空对象。

  • 优点是实现简单,维护方便
  • 缺点是空对象会带来额外的内存消耗,有可能出现短暂的数据不一致问题,当每次的key都不一样时失效

方案二:使用布隆过滤器。

  • 优点是不会有多余key,内存占用少
  • 缺点是实现复杂,且有误判的可能

缓存雪崩 (高)

同一时间大量的key都过期了,或者redis宕机了,导致大量请求访问数据库。

  1. 如果是大量key同一时间过期,则给key添加固定的过期时间的基础上,再增加一个随机的过期时间。
  2. 如果是redis宕机,那么就使用主从或者集群保证可用性。
  • 万一真的发生服务雪崩,应该做好服务限流降级熔断的处理。

缓存预热 (中)

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。

这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

缓存读写策略 (高)

1. CacheAside(旁路缓存)策略

核心思想是应用程序直接操作缓存

读优先读缓存,缓存中没有数据,读数据库,在由应用程序写缓存。

  • 写优先更新数据库,确保数据持久化后,删除缓存。

我们业务中常见的Redis缓存方案就是旁路缓存。区别于读穿/写穿 策略

2. Read/Write Through(读穿/写穿)策略

Read/Write Through(读穿/写穿)策略Read/Write Through(读穿/写穿)策略原则是应用程序只和缓存交互,不再和数据库交互,而是由缓存和数据库交互,相当于更新数据库的操作由缓存自己代理了

Read Through 策略:

  • 先查询缓存中数据是否存在,如果存在则直接返回
  • 如果不存在,则由缓存组件负责从数据库查询数据,并将结果写入到缓存组件,最后缓存组件将数据返回给应用

Write Through 策略:

  • 当有数据更新的时候,先查询要写入的数据在缓存中是否已经存在:
  • 如果缓存中数据已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中,然后缓存组件告知应用程序更新完成。
  • 如果缓存中数据不存在,直接更新数据库,然后返回;

WriteBack(写回)策略:
在更新数据的时候,只更新缓存,同时将缓存数据设置为脏的,然后立马返回,并不会更新数据库。对于数据库的更新,会通过批量异步更新的方式进行

WriteBack策略特别适合写多的场景,但是带来的问题是,数据不是强一致性的,而且会有数据丢失的风险

WriteBack是计算机体系结构中的设计,比如CPU的缓存、操作系统中文件系统的缓存都采用了WriteBack(写回)策略。电脑在突然断电之后,之前写入的文件会有部分丢失,就是因为 Page Cache 还没有来得及刷盘造成的。

缓存与数据库一致性的问题(高)

先更新数据库,后更新缓存(不推荐)
  1. 操作失败的情况:

如果数据库更新成功,缓存更新失败,那么此时数据库中是新值,缓存中是旧值。出现不一致

  1. 高并发的情况:

假设现在有线程A和线程B同时要进行更新操作,那么可能会这样:

(1)线程A更新了数据库;(2)线程B更新了数据库;(3)线程B更新了缓存;(4)线程A更新了缓存;

此时数据库是线程B更新的值,缓存中是线程A的旧值。出现不一致

先删除缓存,后更新数据库(不推荐)

高并发的情况下会出问题

假设同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么可能会这样:

(1)请求A进行写操作,删除缓存;

(2) 请求B查询发现缓存不存在;(3) 请求B去数据库查询得到旧值;(4) 请求B将旧值写入缓存;(5) 请求A将新值写入数据库;缓存和数据库不一致

延迟双删(一般推荐)

先删除缓存,再更新数据库,等过一段时间后再对缓存进行一次删除,比如5s之后。

读写分离场景,可能产生问题如下一个请求A进行更新操作,另一个请求B进行查询操作。

(1)请求A进行写操作,删除缓存;(2)请求A将数据写入数据库了;(3)请求B查询缓存发现,缓存没有值;(4)请求B去从库查询,这时还没有完成主从同步,因此查询到的是旧值;(5)请求B将旧值写入缓存;(6)数据库完成主从同步,从库变为新值;出现缓存不一致

延迟删除缓存的时间到底设置要多久才合适呢?

  • 问题1:延迟时间要大于「主从复制」的延迟时间- 问题2:延迟时间要大于线程B读取数据库 + 写入缓存的时间但是,这个时间在分布式和高并发场景下,其实是很难评估的。

很多时候,我们都是凭借经验大致估算这个延迟时间,例如延迟1- 5s,只能尽可能地降低不一致的概率。

采用这种方案,也只是尽可能保证一致性而已,极端情况下,还是有可能发生不一致。

先更新数据库,后删除缓存(配合mq/监听binlog重试才推荐)
  1. 操作失败的情况:

如果数据库更新成功,缓存删除失败。用户读取数据时会先从缓存中读取,而缓存中存储的是旧的数据。出现不一致

  1. 高并发的情况:

一个请求A做查询操作,一个请求B做更新操作。

(1)缓存刚好失效;

(2)请求A查询数据库,得一个旧值;

(3)请求B将新值写入数据库;

(4)请求B删除缓存;

(5)请求A将查到的旧值写入缓存;

这种情况下确实也会产生脏数据,不过这种情况发生的概率是很小的。为什么呢?

  • 要出现以上情况,步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。但是写操作基本不会快于读操作,所以出现不一致的概率很低。

那么如何解决由操作失败导致的不一致性呢?重试!

  • 消息队列重试(推荐):将删除缓存的操作放入mq中。

  • 更新数据库,发mq消息,mq接受到消息后,异步删除缓存。删除失败可以重试:mq可以保证消息可靠性。

  • 消息队列保证可靠性:写到队列中的消息,成功消费之前不会丢失(重启项目也不担心)- 消息队列保证消息成功投递:下游从队列拉取消息,成功消费后才会删除消息,否则还会继续投递消息给消费者(符合重试的需求)

  • 订阅binlog日志重试(推荐):监听binlog来删除缓存。

  • 使用类似于阿里的canal的中间件,监听mysql binlog。更新数据库后,监听到binlog变化,删除缓存。- 无需考虑写消息队列失败情况:只要写MySQL成功,Binlog肯定会有- binlog订阅者(消费者)直接获取变更的数据,然后删除缓存。

总结:想要保证数据库和缓存一致性,推荐采用「先更新数据库,再删除缓存」方案,并配合「消息队列重试」或「监听binlog重试」的方式来做,但是即便是这样也不能完全保证一致性,所以完全保证缓存和数据库一致性是很难的。

分布式锁 (高)

基本的分布式锁实现

基于Redis的分布式锁实现思路:

  • 利用setnx获取锁,并设置过期时间,保存线程标识- 释放锁时先判断线程标识是否与自己一致,一致则删除锁。判断锁是否为自己的然后再释放,这个过程必须是原子性的否则有可能释放别人的锁,这就需要lua脚本。

特性:

  • 利用setnx满足互斥性
  • -利用setex保证故障时锁依然能释放,避免死锁,提高安全性
  • 利用Redis集群保证高可用和高并发特性

释放错锁的问题

  • 线程1获取锁后阻塞,锁超时时间一到,锁自动释放
  • 线程2获取锁,开始执行线程2的业务。此时线程1执行完业务释放锁,就会释放掉线程2的锁。
  • 线程3又获取了锁,执行业务。此时线程2执行完毕又释放了线程3的锁。

因此,释放锁之前需要判断锁是否是自己的

获取锁的值,判断锁是否是自己的,释放锁,这三步不具有原子性。所以会产生如下问题

  • 线程1执行完业务准备释放锁,从redis中查到了锁的值,判断锁是自己的。此时,线程1阻塞。然后锁过期了。

  • 线程2获取锁, 开始执行业务. 线程1又醒来开始释放锁, 此时就释放了线程2的锁.

所以释放锁的逻辑必须写在lua脚本中, 保证原子性.

如何实现可重入锁/redisson可重入锁原理

由于自己写的锁使用了string类型的 setnx, 只要方法1上锁, 方法1调用的方法二需要再上锁是无法做到的, 会直接返回false

而redisson的可重入锁, 使用了hash类型, key为lock, field为线程名, value为数字.

  • 加锁

    • 方法1加锁后, value=1, 方法1调用方法2
    • 方法2加锁, redisson判断锁标识是否是自己(field字段是否为同一线程), 若是则value++, value为2
    • 同理, 方法3加锁, value=3
  • 释放锁

    • 方法3执行完毕, 释放锁, value–, value=2
    • 方法2释放锁, value=1
    • 方法1释放锁, value=0, 此时删除redis的该数据, 锁完全释放.

所以使用hash结构, hsetnx就可以实现可重入锁

如何实现锁的可重试

redis的发布订阅机制实现等待、唤醒, 获取锁失败的重试机制

  • 先直接获取锁, 如果获取失败, 并不是直接重试, 因为现在立即重试大概率其他线程正在执行业务. 获取锁失败会先订阅一下, 然后等待
  • -获取锁成功的线程在释放锁时会发布一条消息.
  • 当其他线程得到该消息时, 就会重新获取锁, 如果再次获取锁失败, 就会再次等待.- 但是不是无限制的等待, 因为他会有一个等待时间, 超过该时间则不重试直接返回false

业务线程没执行完, 锁超时释放了怎么办/如何实现超时续约

超时续约:利用watchDog看门狗机制, 每隔一段时间, 重置锁的超时时间

  • 看门狗机制会创建一个守护线程, 当锁快到期但是业务线程没执行完时为锁增加时间 (续命).
  • 当然看门狗也不会无限地增加超时时间, redisson有一个参数用来设置加锁的时间, 超过这个时间后锁便自动解开了, 不会延长锁的有效期

锁的主从一致性问题

redis为了保证高可用, 使用主从架构. 一主多从

  • 获取锁时, 往redis主节点setnx. 主节点加锁成功后宕机, 此时数据未同步到从节点.- 某个从节点成为新主节点. 但是新主节点没有锁信息. 此时其他线程还可以加锁.- 这就产生了主从架构锁丢失问题.

解决方案:redisson联锁机制,使用多个独立的Redis主节点,多主,或者多主多从

获取锁时,往每一个redis主节点都写入key.即便其中一台redis宕机,其他redis依旧有锁信息并且必须在所有节点都获取到锁,才算获取锁成功Redison分布式联锁RedisonMultiLock对象可以将多个RLock锁对象关联为一个联锁,可以把一组锁当作一个锁来加锁和释放。

redlock红锁

联锁机制配合redis多主节点还存在问题:

联锁必须在所有节点都获取到锁,才算获取锁成功.那么当某个redis主节点网络较慢,就导致加锁时间会很长.很容易出现加锁超时失败的情况如果某个redis主节点宕机,也会加锁失败

而redlock规定,只需要半数以上节点加锁成功,就算这次加锁成功并且规定了严格的加锁时间,一定时间内无法加锁成功,则直接返回

避免了某个redis主节点网络较慢,就导致加锁时间会很长的问题只需要半数以上节点加锁成功就可以,避免了频繁加锁失败问题

但是redlock对redis部署的要求很高,需要多主部署,或者部署多个独立的redis集群.并且redlock复杂度和成本都很高,所以其实redlock并不推荐使用.哈哈哈哈看了这么久以为redlock是最牛逼的最终解决方案,结果并不推荐使用.别生气,虽然它不推荐使用,但是可以用来给面试官吹牛逼,毕竟很多面试官对分布式锁的了解都没有深入到redlock,懂了把

高可用

如何保证Redis服务高可用?(中)

主从或者集群

什么是主从复制 (中)

  • 主从复制就是将一台Redis主节点的数据复制到其他的Redis从节点中,尽最大可能保证Redis主节点和从节点的数据是一致的。
  • 主从复制是Redis高可用的基石,Redis Sentinel以及RedisCluster都依赖于主从复制。- 主从复制这种方案不仅保障了Redis服务的高可用,还实现了读写分离,提高了系统的并发量,尤其是读并发量。

主从复制与Sentinel哨兵机制 (中)

  • 主从复制方案下,master发生启机的话可以手动将某一台slave升级为master,Redis服务可用性提高。
  • slave可以分担读请求,读吞吐量大幅提高。
  • 但其缺陷也很明显,一旦master容机,我们需要从slave中手动选择一个新的master,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要手动处理,很麻烦,很容易出问题。
  • redis的Sentinel哨兵机制可以自动帮选主。

Sentinel(哨兵) 有什么作用? (中)

  • 监控Redis节点的运行状态并自动实现故障转移。
  • 当master节点出现故障的时候,Sentinel会自动根据一定的规则选出一个slave升级为master,确保整个Redis系统的可用性。整个过程完全自动,不需要人工介入

Redis缓存的数据量太大怎么办? (中)

分片集群,数据被分散到集群不同的redis节点上,避免了单个redis缓存的数据量过大问题。

RedisCluster的作用?(中)

高并发场景下,使用Redis主要会遇到的两个问题:

缓存的数据量太大:实际缓存的数据量可以达到几十G,甚至是成百上千G;并发量要求太大:Redis号称单机可以支持10w并发,但是并发超过10w怎么办?

主从复制和Redis Sentinel这两种方案本质都是通过增加slave数量的方式来提高Redis服务的整体可用性和读吞吐量,不支持横向扩展来缓解写压力以及解决缓存数据量过大的问题。

这时候,redis分片集群就可以解决这个问题.通过部署多台Redis主节点(master),然后将key分散到不同的主节点上,客户端的请求通过路由规则转发到目标master上,这就是分片集群.

注意,这些节点之间平等,并没有主从之说,同时对外提供读/写服务。

分片集群很方便拓展,只需要增加redis主节点即可

Redis Cluster 是如何分片的?/Redis Cluster中的数据是如何分布的?/怎么知道key应该在哪个哈希槽中?(中)

  • Redis Cluster并没有使用一致性哈希,采用的是哈希槽分区,每一个键值对都属于一个哈希槽
  • Redis Cluster通常有16384个哈希槽,要计算给定key应该分布到哪个哈希槽中,我们只需要先对每个key计算CRC-16(XMODEM)校验码,然后再对这个校验码对16384(哈希槽的总数)取模,得到的值即是key对应的哈希槽

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/93536.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/93536.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/93536.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++字符串(string)操作解析:从基础到进阶

1. 字符串基础&#xff1a;大小与容量cppvoid test1() {string s1("Hello World");cout << "size : " << s1.size() << endl; // 输出字符串长度cout << "capacity " << s1.capacity() << endl; // 输出字…

蘑兔音乐:音乐创作的魔法棒

在这个充满创意与可能的时代&#xff0c;人人都有一颗渴望表达音乐之心。但传统音乐创作&#xff0c;复杂的乐理、昂贵的设备&#xff0c;总让人望而却步。别担心&#xff01;蘑兔 AI 音乐强势来袭&#xff0c;它就是那个能让音乐小白也能搞创作的神奇工具&#xff01;​灵感模…

从传统到智能:RFID 技术如何重构压缩机生产线

从传统到智能&#xff1a;RFID 技术如何重构压缩机生产线在工业 4.0 与中国制造 2025 战略的深入推进下&#xff0c;作为空调核心部件的压缩机制造业正加速从传统生产模式向智能化转型。压缩机生产以高精度、大批量为显著特点&#xff0c;长期面临生产数据断层、柔性化不足、质…

HTML5二十四节气网站源码

一. 二十四节气文化主题网站概述 本网站以中国传统文化瑰宝“二十四节气”为核心&#xff0c;通过现代Web技术打造沉浸式文化体验平台&#xff0c;融合视觉美学与交互创新&#xff0c;全方位展现节气的自然规律与人文内涵。网站采用响应式布局设计&#xff0c;适配多终端设备&…

微服务架构实战指南:从单体应用到云原生的蜕变之路

&#x1f31f; Hello&#xff0c;我是蒋星熠Jaxonic&#xff01; &#x1f308; 在浩瀚无垠的技术宇宙中&#xff0c;我是一名执着的星际旅人&#xff0c;用代码绘制探索的轨迹。 &#x1f680; 每一个算法都是我点燃的推进器&#xff0c;每一行代码都是我航行的星图。 &#x…

超越Transformer:大模型架构创新的深度探索

引言&#xff1a; 以GPT、Claude、Gemini等为代表的大语言模型&#xff08;LLMs&#xff09;已成为人工智能领域的核心驱动力。它们基于Transformer架构构建&#xff0c;在理解和生成人类语言方面展现出惊人的能力。然而&#xff0c;随着模型规模指数级增长和对更长上下文、更高…

完整设计 之 智能合约系统:主题约定、代理协议和智能合约 (临时命名)--腾讯元宝答问

本文要点和任务整体设计&#xff08;符号学 &#xff1a;为了诠释学实践运用 形。而上理论&#xff0c;将自己作为 两者结合的 条带 &#xff09;&#xff0c;包括三部分&#xff1a;内核&#xff08;设置-组态-主动把握的操作&#xff09;是认知学&#xff08;语义&#xff09…

同创物流学习记录2·电车光电

灯在闪烁&#xff0c;照到你前面的东西了&#xff0c;它可以照前面&#xff0c;可以照6米远。你那个电车前面五六米感应到东西了&#xff0c;它就会减速&#xff0c;然后到3米的样子&#xff0c;它会再减速。然后再到1米2的样子&#xff0c;它就会停下来。电车前侧光电这个区域…

linux I2C核心、总线与设备驱动

一、 linux I2C体系结构linux的I2C体系结构分为3个组成部分1&#xff09;I2C核心I2C核心提供了I2C总线驱动与设备驱动的注册、注销方法&#xff0c;I2C通信方法&#xff08;即Algorithm&#xff09;上层的与具体适配器无关的代码及其探测设备、检测设备地址的上层代码等…

跑实验记录

1.下载git&#xff08;base) mqmq-MS-7A59:~/桌面$ sudo apt update && sudo apt install git2.克隆项目&#xff08;base) mqmq-MS-7A59:~/桌面$ sudo apt update && sudo apt install git3.canda创建环境(base) mqmq-MS-7A59:~$ conda create -n HyTE python…

微软动手了,联合OpenAI + Azure 云争夺AI服务市场

❝开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;共3300人左右 …

Reading Coach-微软推出的免费AI阅读教练

本文转载自&#xff1a;Reading Coach-微软推出的免费AI阅读教练 - Hello123工具导航 ** 一、智能阅读辅助工具 Reading Coach 是微软推出的 AI 驱动阅读训练平台&#xff0c;通过个性化故事生成与实时发音反馈&#xff0c;帮助学生提升阅读流利度与词汇量。平台采用自适应学…

《软件工程导论》实验报告五 设计建模工具的使用(一)类图

目 录 一、实验目的 二、实验环境 三、学时分配 四、实验内容与步骤 1. 百度搜索1-2张类图&#xff0c;请重新绘制它们&#xff0c;并回答以下问题&#xff1a; 2. 根据以下描述&#xff0c;提取这个问题涉及的类&#xff0c;定义各个类之间的关系&#xff0c;并画出类图…

智慧景区导览系统:基于WebGL的手绘地图导览设计与应用,DeepSeek大模型赋能精准游客引导服务

本文面向 景区信息化负责人、后端开发者、全栈工程师&#xff0c;旨在解决传统景区导览系统静态地图信息有限、人工导游成本高、景区服务人员咨询压力大 的核心痛点&#xff0c;提供从技术选型到落地部署的全链路解决方案。如需获取智慧景区导览系统解决方案请前往文章最下方获…

使用uniapp自定义组件双重支付密码

自定义组件双重支付密码父组件<template><view class"container"><view class"top"></view><navbar navTitle"修改支付密码"></navbar><!-- 双重支付密码 --><view class"box">//核心…

C语言+安全函数+非安全函数

在C语言中&#xff0c;许多标准库函数&#xff08;如 strcpy、scanf、gets 等&#xff09;由于缺乏边界检查&#xff0c;容易导致 ​缓冲区溢出&#xff08;Buffer Overflow&#xff09;​、内存越界访问​ 等安全问题。为了解决这些问题&#xff0c;C11标准引入了 ​安全函数&…

android build.gradle中的namespace和applicationId的区别

namespace 和 applicationId 确实容作用&#xff1a;1. namespace引入版本&#xff1a;Android Gradle Plugin (AGP) 7.0 开始引入&#xff0c;替代 AndroidManifest.xml 里的 package 属性。作用&#xff1a; 用于 代码中的 R 文件、BuildConfig 生成的 Java/Kotlin 包名。决定…

数据结构初阶(15)排序算法—交换排序(快速排序)(动图演示)

2.3 交换排序 2.3.0 基本思想交换排序的基本思想&#xff1a;基本思想根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置。&#xff08;比较结果→交换位置&#xff09;特点将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。比 换…

Apache Hudi:数据湖的实时革命

Apache Hudi是一个开源的数据湖存储格式和框架&#xff0c;它通过引入类似数据库的事务机制&#xff0c;解决了传统数据湖在实时更新、低延迟查询和增量消费方面的痛点。Hudi最初由Uber于2016年开发并应用于生产环境&#xff0c;2017年开源&#xff0c;2019年成为Apache孵化项目…

深度解析和鲸社区热门项目:电商双 11 美妆数据分析的细节与价值

在数据驱动决策的时代&#xff0c;电商大促期间的行业数据分析总能为从业者和学习者提供宝贵参考。今天&#xff0c;我们来详细拆解和鲸社区&#xff08;heywhale&#xff09;上一个备受关注的实战项目 ——《电商双 11 美妆数据分析》&#xff0c;看看它能给我们带来哪些启发。…