Java后端八股文之Redis

文章目录

  • 1. Redis是什么?
  • 2. Redis为什么这么快?
  • 3. 为什么要使用缓存?
  • 4. Redis几种使用场景:
  • 5. Redis的Zset底层为什么要使用跳表而不是平衡树、红黑树或者B+树?
  • 6.Redis持久化
    • 6.1 什么是RDB持久化
      • 6.1.1RDB创建快照会阻塞主线程吗?
    • 6.2 什么是AOF持久化
      • 6.2.1 AOF持久化流程
    • 6.3 如何选择RDB和AOF
      • 6.3.1 RDB比AOF优秀的地方
      • 6.3.2 AOF比RDB优秀的地方
      • 6.3.3 结论
  • 7.Redis单线程模型
    • 7.1 既然是单线程,那怎么监听大量的客户端连接呢?
  • 8.Redis 6.0之后为什么引入了多线程?
  • 9.过期数据的删除策略?
  • 10.Redis内存淘汰机制?
  • 11.大量key集中过期的问题
  • 12. bigkey 大key问题
  • 13. bigkey 是怎么产生的?有什么危害?
  • 14. 缓存穿透
    • 14.1 什么是缓存穿透?
  • 14.2 如何解决缓存穿透?
  • 15.缓存击穿
    • 15.1 什么是缓存击穿?
    • 15.2 解决办法
  • 16. 缓存雪崩
    • 16.1 什么是缓存雪崩
    • 16.2 如何解决
      • 16.2.1 针对Redis服务不可用情况
      • 16.2.2 针对热点缓存失效情况
    • 16.3 缓存预热如何实现?
  • 17.Redis sentinel 哨兵
    • 17.1什么是 Sentinel?有什么用?
    • 17.2 Sentinel 如何检测节点是否下线?主观下线与客观下线的区别?
    • 17.3 Sentinel 是如何实现故障转移的?
    • 17.4 为什么建议部署多个 sentinel 节点(哨兵集群)?
    • 17.5 Sentinel 如何选择出新的 master(选举机制)?
    • 17.6 如何从 Sentinel 集群中选择出 Leader ?
    • 17.7 Sentinel 可以防止脑裂吗?
  • 18. Redis cluster
    • 18.1 为什么需要 Redis Cluster?解决了什么问题?有什么优势?
    • 18.2 Redis Cluster 是如何分片的?
    • 18.3 为什么 Redis Cluster 的哈希槽是 16384 个?
    • 18.4如何确定给定 key 的应该分布到哪个哈希槽中?
    • 18.5 Redis Cluster 支持重新分配哈希槽吗?
    • 18.6 Redis Cluster 扩容缩容期间可以提供服务吗?
    • 18.7 Redis Cluster 中的节点是怎么进行通信的?

八股文之Redis篇
在这里插入图片描述

1. Redis是什么?

Redis(Remote Dictionary Server)是一个基于 C 语言开发的开源 NoSQL 数据库(BSD 许可)。与传统数据库不同的是,Redis 的数据是保存在内存中的(内存数据库,支持持久化),因此读写速度非常快,被广泛应用于分布式缓存方向。并且,Redis 存储的是 KV 键值对数据。

为了满足不同的业务场景,Redis 内置了多种数据类型实现(比如 String、Hash、Sorted Set、Bitmap、HyperLogLog、GEO)。并且,Redis 还支持事务、持久化、Lua 脚本、多种开箱即用的集群方案(Redis Sentinel、Redis Cluster)。

2. Redis为什么这么快?

Redis 内部做了非常多的性能优化,比较重要的有下面 3 点:

  • Redis 基于内存,内存的访问速度是磁盘的上千倍;
  • Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用(Redis 线程模式后面会详细介绍到);
  • Redis 内置了多种优化过后的数据类型/结构实现,性能非常高。

请添加图片描述

3. 为什么要使用缓存?

  • 1、高性能: 假如用户第一次访问数据库中的某些数据的话,这个过程是比较慢,毕竟是从硬盘中读取的。但是,如果说,用户访问的数据属于高频数据并且不会经常改变的话,那么我们就可以很放心地将该用户访问的数据存在缓存中。这样有什么好处呢? 那就是保证用户下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。
  • 2、高并发: 一般像 MySQL 这类的数据库的 QPS 大概都在 1w 左右(4 核 8g) ,但是使用 Redis 缓存之后很容易达到 10w+,甚至最高能达到 30w+(就单机 Redis 的情况,Redis 集群的话会更高)。

由此可见,直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而,我们也就提高了系统整体的并发。

4. Redis几种使用场景:

    1. 分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。
    1. 限流:一般是通过 Redis + Lua 脚本的方式来实现限流。
    1. 消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka,有主题和消费组的概念,支持消息持久化以及 ACK 机制。
    1. 延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)。
    1. 分布式 Session :利用 String 或者 Hash 数据类型保存 Session 数据,所有的服务器都可以访问。
    1. 复杂业务场景:通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 Bitmap 统计活跃用户、通过 Sorted Set 维护排行榜。

5. Redis的Zset底层为什么要使用跳表而不是平衡树、红黑树或者B+树?

  • 平衡树 vs 跳表:平衡树的插入、删除和查询的时间复杂度和跳表一样都是 O(log n)。对于范围查询来说,平衡树也可以通过中序遍历的方式达到和跳表一样的效果。但是它的每一次插入或者删除操作都需要保证整颗树左右节点的绝对平衡,只要不平衡就要通过旋转操作来保持平衡,这个过程是比较耗时的。跳表诞生的初衷就是为了克服平衡树的一些缺点。跳表使用概率平衡而不是严格强制的平衡,因此,跳表中的插入和删除算法比平衡树的等效算法简单得多,速度也快得多。
  • 红黑树 vs 跳表:相比较于红黑树来说,跳表的实现也更简单一些,不需要通过旋转和染色(红黑变换)来保证黑平衡。并且,按照区间来查找数据这个操作,红黑树的效率没有跳表高。
  • B+树 vs 跳表:B+树更适合作为数据库和文件系统中常用的索引结构之一,它的核心思想是通过可能少的 IO 定位到尽可能多的索引来获得查询数据。对于 Redis 这种内存数据库来说,它对这些并不感冒,因为 Redis 作为内存数据库它不可能存储大量的数据,所以对于索引不需要通过 B+树这种方式进行维护,只需按照概率进行随机维护即可,节约内存。而且使用跳表实现 zset 时相较前者来说更简单一些,在进行插入时只需通过索引将数据插入到链表中合适的位置再随机维护一定高度的索引即可,也不需要像 B+树那样插入时发现失衡时还需要对节点分裂与合并。

6.Redis持久化

  • RDB (Redis database,快照)
  • AOF (append-only file)
  • RDB & AOF

6.1 什么是RDB持久化

Redis 可以通过创建快照来获得存储在内存里面的数据在 某个时间点 上的副本。Redis 创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用。

6.1.1RDB创建快照会阻塞主线程吗?

Redis 提供了两个命令来生成 RDB 快照文件:

  • save : 同步保存操作,会阻塞 Redis 主线程;
  • bgsave : fork 出一个子进程,子进程执行,不会阻塞 Redis 主线程,默认选项。

6.2 什么是AOF持久化

与快照持久化相比,AOF 持久化的实时性更好。默认情况下 Redis 没有开启 AOF(append only file)方式的持久化(Redis 6.0 之后已经默认是开启了),可以通过 appendonly 参数开启:

appendonly yes

开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到 AOF 缓冲区 server.aof_buf 中,然后再写入到 AOF 文件中(此时还在系统内核缓存区未同步到磁盘),最后再根据持久化方式( fsync策略)的配置来决定何时将系统内核缓存区的数据同步到硬盘中的。只有同步到磁盘中才算持久化保存了,否则依然存在数据丢失的风险,比如说:系统内核缓存区的数据还未同步,磁盘机器就宕机了,那这部分数据就算丢失了。AOF 文件的保存位置和 RDB 文件的位置相同,都是通过 dir 参数设置的,默认的文件名是 appendonly.aof。

6.2.1 AOF持久化流程

AOF 持久化功能的实现可以简单分为 5 步:

    1. 命令追加(append):所有的写命令会追加到 AOF 缓冲区中。
    1. 文件写入(write):将 AOF 缓冲区的数据写入到 AOF 文件中。这一步需要调用write函数(系统调用),write将数据写入到了系统内核缓冲区之后直接返回了(延迟写)。注意!!!此时并没有同步到磁盘。
    1. 文件同步(fsync):AOF 缓冲区根据对应的持久化方式( fsync 策略)向硬盘做同步操作。这一步需要调用 fsync 函数(系统调用), fsync 针对单个文件操作,对其进行强制硬盘同步,fsync 将阻塞直到写入磁盘完成后返回,保证了数据持久化。
    1. 文件重写(rewrite):随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
    1. 重启加载(load):当 Redis 重启时,可以加载 AOF 文件进行数据恢复。

6.3 如何选择RDB和AOF

6.3.1 RDB比AOF优秀的地方

  • RDB 文件存储的内容是经过压缩的二进制数据, 保存着某个时间点的数据集,文件很小,适合做数据的备份,灾难恢复。AOF 文件存储的是每一次写命令,类似于 MySQL 的 binlog 日志,通常会比 RDB 文件大很多。当 AOF 变得太大时,Redis 能够在后台自动重写 AOF。新的 AOF 文件和原有的 AOF 文件所保存的数据库状态一样,但体积更小。不过, Redis 7.0 版本之前,如果在重写期间有写入命令,AOF 可能会使用大量内存,重写期间到达的所有写入命令都会写入磁盘两次。
  • 使用 RDB 文件恢复数据,直接解析还原数据即可,不需要一条一条地执行命令,速度非常快。而 AOF 则需要依次执行每个写命令,速度非常慢。也就是说,与 AOF 相比,恢复大数据集的时候,RDB 速度更快。

6.3.2 AOF比RDB优秀的地方

  • RDB 的数据安全性不如 AOF,没有办法实时或者秒级持久化数据。生成 RDB 文件的过程是比较繁重的, 虽然 BGSAVE 子进程写入 RDB 文件的工作不会阻塞主线程,但会对机器的 CPU 资源和内存资源产生影响,严重的情况下甚至会直接把 Redis 服务干宕机。AOF 支持秒级数据丢失(取决 fsync 策略,如果是 everysec,最多丢失 1 秒的数据),仅仅是追加命令到 AOF 文件,操作轻量。
  • RDB 文件是以特定的二进制格式保存的,并且在 Redis 版本演进中有多个版本的 RDB,所以存在老版本的 Redis 服务不兼容新版本的 RDB 格式的问题。
  • AOF 以一种易于理解和解析的格式包含所有操作的日志。你可以轻松地导出 AOF 文件进行分析,你也可以直接操作 AOF 文件来解决一些问题。比如,如果执行FLUSHALL命令意外地刷新了所有内容后,只要 AOF 文件没有被重写,删除最新命令并重启即可恢复之前的状态。

6.3.3 结论

  • Redis 保存的数据丢失一些也没什么影响的话,可以选择使用 RDB。
  • 不建议单独使用 AOF,因为时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。
  • 如果保存的数据要求安全性比较高的话,建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化。

7.Redis单线程模型

Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器(file event handler)。

  • 文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
  • 当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关 闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。

虽然文件事件处理器以单线程方式运行,但通过使用 I/O 多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部单线程设计的简单性。

7.1 既然是单线程,那怎么监听大量的客户端连接呢?

Redis 通过 IO 多路复用程序 来监听来自客户端的大量连接(或者说是监听多个 socket),它会将感兴趣的事件及类型(读、写)注册到内核中并监听每个事件是否发生。这样的好处非常明显:I/O 多路复用技术的使用让 Redis 不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗(和 NIO 中的 Selector 组件很像)。

8.Redis 6.0之后为什么引入了多线程?

Redis6.0 引入多线程主要是为了提高网络 IO 读写性能,因为这个算是 Redis 中的一个性能瓶颈(Redis 的瓶颈主要受限于内存和网络)。

虽然,Redis6.0 引入了多线程,但是 Redis 的多线程只是在网络数据的读写这类耗时操作上使用了,执行命令仍然是单线程顺序执行。因此,你也不需要担心线程安全问题。

Redis6.0 的多线程默认是禁用的,只使用主线程。如需开启需要设置 IO 线程数 > 1,需要修改 redis 配置文件 redis.conf:

io-threads 4 #设置1的话只会开启主线程,官网建议4核的机器建议设置为2或3个线程,8核的建议设置为6个线程

另外:

  • io-threads 的个数一旦设置,不能通过 config 动态设置。
  • 当设置 ssl 后,io-threads 将不工作。

开启多线程后,默认只会使用多线程进行 IO 写入 writes,即发送数据给客户端,如果需要开启多线程 IO 读取 reads,同样需要修改 redis 配置文件 redis.conf :

io-threads-do-reads yes

但是官网描述开启多线程读并不能有太大提升,因此一般情况下并不建议开启。

9.过期数据的删除策略?

如果假设你设置了一批 key 只能存活 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?
常用的过期数据的删除策略就两个(重要!自己造缓存轮子的时候需要格外考虑的东西):

    1. 惰性删除:只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
    1. 定期删除:每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,所以 Redis 采用的是 定期删除+惰性/懒汉式删除 。但是,仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里,然后就 Out of memory 了。怎么解决这个问题呢?答案就是:Redis 内存淘汰机制。

10.Redis内存淘汰机制?

    1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
    1. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。
    1. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
    1. allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
    1. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
    1. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

4.0 版本后增加以下两种:

    1. volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰。
    1. allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key。

11.大量key集中过期的问题

对于过期 key,Redis 采用的是 定期删除+惰性/懒汉式删除 策略。定期删除执行过程中,如果突然遇到大量过期 key 的话,客户端请求必须等待定期清理过期 key 任务线程执行完成,因为这个这个定期任务线程是在 Redis 主线程中执行的。这就导致客户端请求没办法被及时处理,响应速度会比较慢。如何解决呢?
下面是两种常见的方法:

  • 给 key 设置随机过期时间。开启 lazy-free(惰性删除/延迟释放) 。
  • lazy-free 特性是 Redis 4.0 开始引入的,指的是让 Redis 采用异步方式延迟释放 key 使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程。

个人建议不管是否开启 lazy-free,我们都尽量给 key 设置随机过期时间。

12. bigkey 大key问题

简单来说,如果一个 key 对应的 value 所占用的内存比较大,那这个 key 就可以看作是 bigkey。具体多大才算大呢?有一个不是特别精确的参考标准:

  • String 类型的 value 超过 1MB
  • 复合类型(List、Hash、Set、Sorted Set 等)的 value 包含的元素超过 5000 个(不过,对于复合类型的 value 来说,不一定包含的元素越多,占用的内存就越多)。

13. bigkey 是怎么产生的?有什么危害?

bigkey 通常是由于下面这些原因产生的:

  • 程序设计不当,比如直接使用 String 类型存储较大的文件对应的二进制数据。
  • 对于业务的数据规模考虑不周到,比如使用集合类型的时候没有考虑到数据量的快速增长。
  • 未及时清理垃圾数据,比如哈希中冗余了大量的无用键值对。

bigkey 除了会消耗更多的内存空间和带宽,还会对性能造成比较大的影响。大 key 还会造成阻塞问题。具体来说,主要体现在下面三个方面:

    1. 客户端超时阻塞:由于 Redis 执行命令是单线程处理,然后在操作大 key 时会比较耗时,那么就会阻塞 Redis,从客户端这一视角看,就是很久很久都没有响应。
    1. 网络阻塞:每次获取大 key 产生的网络流量较大,如果一个 key 的大小是 1 MB,每秒访问量为 1000,那么每秒会产生 1000MB 的流量,这对于普通千兆网卡的服务器来说是灾难性的。
    1. 工作线程阻塞:如果使用 del 删除大 key 时,会阻塞工作线程,这样就没办法处理后续的命令。大 key 造成的阻塞问题还会进一步影响到主从同步和集群扩容。
      综上,大 key 带来的潜在问题是非常多的,我们应该尽量避免 Redis 中存在 bigkey。

14. 缓存穿透

14.1 什么是缓存穿透?

缓存穿透说简单点就是大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中。这就导致这些请求直接到了数据库上,根本没有经过缓存这一层,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。

14.2 如何解决缓存穿透?

  • 加强数据校验
  • 缓存无效key
  • 布隆过滤器
  • 接口限流

15.缓存击穿

15.1 什么是缓存击穿?

缓存击穿中,请求的 key 对应的是 热点数据 ,该数据 存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期)。这就可能会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。

15.2 解决办法

    1. 设置热点数据永不过期或者过期时间比较长。
    1. 针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。
    1. 请求数据库写数据到缓存之前,先获取互斥锁,保证只有一个请求会落到数据库上,减少数据库的压力。

16. 缓存雪崩

16.1 什么是缓存雪崩

缓存雪崩描述的就是这样一个简单的场景:缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。 这就好比雪崩一样,摧枯拉朽之势,数据库的压力可想而知,可能直接就被这么多请求弄宕机了。

另外,缓存服务宕机也会导致缓存雪崩现象,导致所有的请求都落到了数据库上。

16.2 如何解决

16.2.1 针对Redis服务不可用情况

  • 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
  • 限流,避免同时处理大量的请求。
  • 多级缓存,例如本地缓存+Redis 缓存的组合,当 Redis 缓存出现问题时,还可以从本地缓存中获取到部分数据。

16.2.2 针对热点缓存失效情况

  • 设置不同的失效时间比如随机设置缓存的失效时间。
  • 缓存永不失效(不太推荐,实用性太差)。
  • 缓存预热,也就是在程序启动后或运行过程中,主动将热点数据加载到缓存中。

16.3 缓存预热如何实现?

常见的缓存预热方式有两种:

  • 使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。
  • 使用消息队列,比如 Kafka,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。

17.Redis sentinel 哨兵

17.1什么是 Sentinel?有什么用?

Redis Sentinel是一个高可用性解决方案,用于监控和管理Redis集群。Redis是一个流行的开源内存数据库,但是在单个Redis实例故障或宕机时,可能会导致应用程序中断或数据丢失。Redis Sentinel通过提供自动故障检测、故障转移和集群管理等功能,帮助确保Redis集群的高可用性和稳定性。

Redis Sentinel的主要功能包括:

    1. 监控:Sentinel通过定期向Redis实例发送心跳检查,以检测实例的健康状态。它可以监控主节点、从节点和其他Sentinel节点。
    1. 故障检测:当Sentinel检测到Redis实例故障或宕机时,它可以及时通知其他节点,并采取相应的故障处理措施。
    1. 自动故障转移:当主节点发生故障时,Sentinel能够自动将一个从节点升级为新的主节点,并将其他从节点重新配置为复制新的主节点。这样可以确保Redis集群在主节点故障时继续提供服务。
    1. 配置提供:Sentinel可以提供Redis集群的配置信息,包括哪些节点是主节点、从节点以及其他Sentinel节点的信息。
    1. 服务发现:应用程序可以通过向Sentinel节点请求获取可用的Redis主节点地址,从而实现Redis集群的服务发现。

通过使用Redis Sentinel,可以提高Redis集群的可用性和容错性,减少因为单点故障而导致的系统中断。它还简化了Redis集群的管理和维护工作,提供了一种可靠的方式来监控和自动处理Redis实例的故障。

17.2 Sentinel 如何检测节点是否下线?主观下线与客观下线的区别?

Redis Sentinel使用以下机制来检测节点是否下线:

    1. 心跳检测(Heartbeat Checks):每个Sentinel节点会定期向Redis节点发送PING命令,以检测节点的健康状态。如果节点正常运行,它将会回复PONG响应。如果一个Sentinel节点在一定时间内未收到节点的PONG响应,它会将该节点标记为主观下线。
    1. 故障检测(Failure Detection):当一个Sentinel节点将节点标记为主观下线后,它会向其他Sentinel节点发送信息,询问它们对该节点的状态进行验证。其他Sentinel节点也会进行类似的主观下线检测,并回复验证结果。通过Sentinel节点之间的协作,可以达成对节点故障的共识,进一步确认节点是否下线。
    1. Quorum(法定人数):在判断节点是否客观下线时,Redis Sentinel使用了Quorum的概念。Quorum是指在Redis Sentinel集群中,至少需要多少个Sentinel节点认为节点下线才能达成共识。通常情况下,Quorum的值为总Sentinel节点数的一半加一。只有当足够多的Sentinel节点将节点标记为主观下线,并达到Quorum要求时,该节点才会被认定为客观下线。

通过这些机制,Redis Sentinel能够检测节点的健康状态并判断其是否下线。这样可以及时发现故障节点,并采取相应的故障转移措施,确保Redis集群的高可用性。

  • 主观下线(Subjective Down):主观下线是由Sentinel节点自身发起的节点故障检测。每个Sentinel节点会定期向其他节点发送PING命令来检测节点的健康状态。如果一个Sentinel节点在一定时间内无法收到节点的PONG响应,它会将该节点标记为主观下线。主观下线只是一个Sentinel节点认为节点不可用的主观判断,并不是全局性的判定。
  • 客观下线(Objective Down):客观下线是由多个Sentinel节点共同协作来进行的节点故障检测。当一个Sentinel节点将一个节点标记为主观下线后,它会向其他Sentinel节点发送信息,询问它们对该节点的状态进行验证。其他Sentinel节点也会进行类似的主观下线检测,并回复验证结果。当足够多的Sentinel节点都将节点标记为主观下线时,该节点会被认定为客观下线。客观下线是全局性的判定,表示整个Redis Sentinel集群都认为该节点不可用。

主观下线和客观下线的区别在于判断节点是否下线的依据和范围。主观下线是单个Sentinel节点的主观判断,而客观下线是整个Redis Sentinel集群的共识。只有当一个节点被足够多的Sentinel节点标记为主观下线时,它才会被认定为客观下线。这种机制可以减少误判,增加对节点故障的可靠性判断。

17.3 Sentinel 是如何实现故障转移的?

Redis Sentinel通过以下步骤实现故障转移:

    1. 主观下线检测:当一个Sentinel节点检测到主节点(master)下线时,它会将主节点标记为主观下线。主观下线是Sentinel节点的主观判断,表示该节点认为主节点不可用。
    1. 共识确认:Sentinel节点会向其他Sentinel节点询问它们对主节点的状态进行验证。如果足够多的Sentinel节点(达到Quorum要求)都将主节点标记为主观下线,则达成共识,确认主节点的客观下线。
    1. 选举新的主节点:一旦主节点被确认为客观下线,Sentinel节点会开始选举新的主节点。选举过程中,Sentinel会考虑所有可选的从节点(slave)作为潜在的新主节点,并根据一定的策略(例如优先级、复制偏移量等)选择其中一个从节点晋升为新的主节点。
    1. 重新配置从节点:一旦新的主节点选举完成,Sentinel节点会将其他从节点重新配置为复制新的主节点。这样可以确保Redis集群在主节点故障时继续提供服务,并保持数据一致性。
    1. 更新客户端连接:Sentinel节点会将新的主节点信息广播给Redis客户端,以便客户端能够更新连接信息,并将请求发送到新的主节点。

通过这个故障转移过程,Redis Sentinel可以保证在主节点故障时自动选择新的主节点,并使Redis集群继续对外提供服务。这种故障转移机制可以提高Redis集群的可用性和容错性,减少因为主节点故障而导致的系统中断。

17.4 为什么建议部署多个 sentinel 节点(哨兵集群)?

建议部署多个Sentinel节点(哨兵集群)的主要原因是提高Redis集群的高可用性和容错性。以下是几个关键的原因:

  • 故障检测和自动故障转移:通过部署多个Sentinel节点,可以增加对主节点故障的检测准确性。每个Sentinel节点会定期进行心跳检测,并监控主节点的健康状态。当主节点发生故障时,Sentinel集群能够迅速检测到,并自动进行故障转移,选举新的主节点,从而避免主节点故障导致的服务中断。
  • 共识机制和多数投票:多个Sentinel节点之间使用共识机制来判断主节点的健康状态和故障情况。通过多数投票的方式,确保对主节点故障的判定达成一致。如果只有单个Sentinel节点,可能由于网络问题或单点故障导致判断失误,增加了误判的风险。
  • 高可用性决策:在进行故障转移时,多个Sentinel节点能够共同决策选择新的主节点。通过多个节点的共同协作,可以选择具有最高优先级和复制偏移量的从节点作为新的主节点,确保数据的一致性和可用性。
  • 服务发现和客户端重定向:多个Sentinel节点共同提供服务发现功能,客户端可以通过其中任意一个Sentinel节点获取主节点的信息。如果某个Sentinel节点发生故障,客户端仍然可以通过其他可用的Sentinel节点获取到主节点的地址,并进行连接。这样可以提高Redis集群在Sentinel节点故障时的容错性。

综上所述,部署多个Sentinel节点能够增加Redis集群的鲁棒性和可用性,提供故障检测和自动故障转移的功能,并确保在主节点故障时能够快速选举出新的主节点,保持数据一致性和服务的连续性。

17.5 Sentinel 如何选择出新的 master(选举机制)?

在Redis Sentinel的故障转移过程中,选择新的主节点的策略是基于以下因素进行评估和决策:

  • 从节点的优先级(slave priority):每个从节点都可以配置一个优先级,表示成为新主节点的候选顺序。优先级较高的从节点更有可能被选为新的主节点。通过配置从节点的优先级,可以对新主节点的选举顺序进行控制。
  • 从节点的复制偏移量(slave replication offset):复制偏移量是指从节点与主节点之间的复制进度,表示从节点复制的数据量。在选举新的主节点时,Sentinel会选择复制偏移量最大的从节点作为新主节点。这样可以确保新主节点具有最新的数据。
  • 从节点的健康状态:Sentinel会考虑从节点的健康状态,选择处于正常运行状态的从节点作为新主节点。如果某个从节点也出现故障,则不会被选为新的主节点。
  • 额外配置的判断条件:除了上述因素,还可以根据需要进行额外的配置和判断条件。例如,可以配置需要满足的最小从节点数量,或者设置只在特定的网络条件下进行故障转移等。

总体而言,Redis Sentinel会综合考虑从节点的优先级、复制偏移量和健康状态等因素,选择出一个合适的从节点作为新的主节点。这个选择过程旨在保证新的主节点具有数据的一致性和可靠性,并尽可能地提高整个Redis集群的可用性。

17.6 如何从 Sentinel 集群中选择出 Leader ?

17.7 Sentinel 可以防止脑裂吗?

Redis Sentinel在一定程度上可以帮助防止脑裂(Split-Brain)问题的发生,但并不能完全消除脑裂的可能性。脑裂是指在分布式系统中,由于网络分区或其他原因,导致集群中的节点无法正常通信,进而导致数据一致性和可用性的问题。

Redis Sentinel采用了共识机制和多数投票的方式来进行故障检测和故障转移的决策,这有助于减少脑裂的影响。当主节点发生故障时,Sentinel节点会进行共识确认,并选举出一个新的主节点。这个过程要求至少有一半加一(Quorum)的Sentinel节点都达成共识,确保选举结果的一致性。

然而,脑裂问题可能在以下情况下发生:

  • 网络分区:如果Redis Sentinel集群中的节点之间发生网络分区,导致部分节点无法与其他节点正常通信,就有可能出现脑裂。在这种情况下,分区中的节点可能会形成多个子集群,并分别选举出各自的主节点。
  • Sentinel节点故障:如果发生Sentinel节点的故障,可能导致选举过程中无法达成共识,进而引发脑裂。特别是当无法满足Quorum要求时,可能会导致选举结果不一致。

为了减少脑裂的风险,可以考虑以下策略:

  • 适量增加Sentinel节点:增加Sentinel节点的数量可以提高集群的容错性和可用性,减少脑裂的概率。
  • 网络架构设计:设计合理的网络架构,尽量避免网络分区的发生。使用可靠的网络设备和配置,确保节点之间的通信畅通。
  • 定期监控和维护:定期监控Sentinel节点和Redis节点的健康状态,及时发现并处理故障情况。

需要注意的是,脑裂是分布式系统中常见的问题,对于高可用性和数据一致性的要求较高的应用场景,可能需要考虑使用更复杂的解决方案,如分布式一致性协议(如Paxos、Raft)或使用专门的分布式数据库系统来处理脑裂问题。

18. Redis cluster

18.1 为什么需要 Redis Cluster?解决了什么问题?有什么优势?

Redis Cluster是Redis提供的分布式解决方案,用于解决单节点Redis的性能和容量限制,并提供高可用性和数据冗余。它解决了以下问题并带来了一些优势:

    1. 高可用性:Redis Cluster通过将数据分布在多个节点上,实现了数据的冗余存储和故障转移。当节点发生故障时,集群可以自动进行主从切换,保证服务的持续可用性。
    1. 扩展性:单节点Redis在处理大规模数据和高并发请求时存在性能和容量限制。Redis Cluster通过将数据分片存储在多个节点上,允许横向扩展,实现数据和负载的均衡分布。这样可以提高系统的整体性能和吞吐量。
    1. 自动分片:Redis Cluster使用哈希槽(Hash Slot)的概念,将数据按照一定规则分配到不同的节点上。这样每个节点只负责管理一部分数据,简化了数据分片和路由的操作。同时,当集群的节点数发生变化时,Redis Cluster可以自动重新分配哈希槽,实现数据的动态迁移和负载均衡。
    1. 故障转移和自动恢复:Redis Cluster具有自动故障检测和转移的能力。当主节点发生故障时,集群会自动选举出新的主节点,并将从节点升级为主节点。同时,Redis Cluster还支持从节点的自动同步和数据恢复。
  • 5.集群管理和监控:Redis Cluster提供了集群管理和监控工具,方便管理和监控节点的状态、数据分布和性能指标。这些工具可以帮助管理员更好地了解集群的运行状况,进行故障排查和性能优化。

总的来说,Redis Cluster解决了单节点Redis的性能和容量限制,提供了高可用性、扩展性和自动化管理的优势。它适用于需要处理大规模数据和高并发请求的应用场景,如缓存、会话存储和实时数据处理等

18.2 Redis Cluster 是如何分片的?

Redis Cluster使用哈希槽(Hash Slot)的方式进行数据分片。哈希槽是一个固定数量的槽位集合,通常为16384个槽位(0-16383)。每个槽位可以被分配给集群中的一个或多个节点。
数据分片的过程如下:

    1. 哈希函数计算:当客户端发送一个命令到Redis Cluster时,根据命令中指定的键(Key),Redis Cluster会使用哈希函数计算出一个哈希值。
    1. 哈希槽映射:根据哈希值,Redis Cluster会将数据分配到对应的哈希槽上。每个哈希槽都有一个唯一的编号,范围从0到16383。
    1. 路由到节点:每个Redis Cluster节点负责管理一部分哈希槽。当Redis Cluster将数据分配到哈希槽后,它会根据哈希槽与节点的映射关系,将命令路由到负责该哈希槽的节点。
    1. 数据迁移:当节点加入或离开Redis Cluster时,集群会自动进行数据迁移,以保持数据的均衡分布。数据迁移的过程中,Redis Cluster会将相关的哈希槽从一个节点移动到另一个节点,确保数据的一致性和负载均衡。

通过使用哈希槽进行数据分片,Redis Cluster可以实现数据在集群中的均衡存储和路由。每个节点只负责管理一部分哈希槽,从而避免了单节点Redis的性能和容量限制。同时,当集群的节点数量发生变化时,Redis Cluster可以自动进行哈希槽的重新分配,实现数据的动态迁移和负载均衡。这样可以有效地提高系统的扩展性和性能。

18.3 为什么 Redis Cluster 的哈希槽是 16384 个?

Redis Cluster选择16384个哈希槽的数量是出于权衡和设计考虑。
以下是一些理由:

    1. 均衡性:16384个哈希槽提供了足够的细粒度,使得数据在集群中能够均匀分布。如果哈希槽数量较少,可能导致数据在节点之间的分布不均衡,某些节点负载过重,而其他节点负载较轻。
    1. 可扩展性:16384个哈希槽提供了足够的扩展性,可以支持大规模的分布式集群。通过哈希槽的数量,Redis Cluster可以方便地进行数据迁移和负载均衡操作,以适应节点的动态变化。
    1. 简化路由:16384个哈希槽数量的选择也是为了简化路由的计算和管理。客户端只需要计算键的哈希值,并将其映射到对应的哈希槽,然后将命令路由到管理该哈希槽的节点。这样的设计使得路由操作相对简单高效。
    1. 兼容性:选择16384个哈希槽的数量是为了与之前的Redis版本保持兼容性。在Redis Cluster之前,Redis的主从复制(Replication)也使用了16384个槽位的概念。通过保持相同的哈希槽数量,可以更容易地迁移和兼容现有的Redis部署。

总的来说,选择16384个哈希槽数量是为了提供均衡性、可扩展性和简化路由的优势,同时与之前的Redis版本保持兼容性。这个数量经过实践和经验的验证,被认为是一个合理的折衷选择。

18.4如何确定给定 key 的应该分布到哪个哈希槽中?

确定给定键(key)应该分布到哪个哈希槽中,可以通过以下步骤进行:

    1. 计算键的哈希值:使用哈希函数(如CRC16、MD5等)对键进行哈希计算,生成一个哈希值。
    1. 映射到哈希槽:将哈希值与哈希槽的总数(例如,16384)取模,得到一个介于0和哈希槽总数之间的数字。这个数字就是对应的哈希槽编号。

例如,假设有一个键"mykey"需要分布到Redis Cluster的哈希槽中:

    1. 使用哈希函数对"mykey"进行哈希计算,得到哈希值。
    1. 将哈希值与哈希槽的总数(16384)取模,得到一个介于0和16383之间的数字,比如1234。
    1. 键"mykey"将被分配到哈希槽编号为1234的哈希槽中。

在Redis Cluster中,客户端会根据键的哈希值自动进行哈希槽的计算和路由。客户端可以通过使用Redis客户端库或者自定义的哈希函数来实现这个过程。对于大多数应用来说,这个过程是透明的,由Redis Cluster的客户端库来处理。客户端只需要指定键,而不需要关心具体的哈希槽计算过程。

18.5 Redis Cluster 支持重新分配哈希槽吗?

是的,Redis Cluster支持重新分配哈希槽。当集群的节点数量发生变化,例如节点的加入或离开,Redis Cluster可以自动进行哈希槽的重新分配,以实现数据的动态迁移和负载均衡。

哈希槽的重新分配过程如下:

    1. 节点变更检测:当节点加入或离开Redis Cluster时,集群会检测到节点的变化。
    1. 新节点接管哈希槽:如果有新节点加入集群,Redis Cluster会将一部分哈希槽从现有节点重新分配到新节点上。这样新节点就负责管理这些哈希槽所对应的数据。
    1. 数据迁移:在哈希槽重新分配期间,Redis Cluster会自动进行数据迁移。数据从旧的节点上的哈希槽移动到新的节点上的相应哈希槽。这确保了数据的一致性和均衡分布。
    1. 迁移完成:当数据迁移完成后,集群中的每个节点负责管理一部分哈希槽,数据得到了重新分配和负载均衡。

这种自动的哈希槽重新分配机制使得Redis Cluster能够适应节点的动态变化,实现数据的平衡分布和负载均衡。同时,这个过程对应用程序是透明的,应用程序无需手动干预,Redis Cluster会自动处理数据迁移和哈希槽的重新分配。

18.6 Redis Cluster 扩容缩容期间可以提供服务吗?

在Redis Cluster的扩容和缩容过程中,集群仍然可以提供服务,但可能会有一些短暂的影响和潜在的性能变化。

  • 在扩容期间,当新节点加入集群并接管一部分哈希槽时,数据迁移过程会发生。在数据迁移期间,如果客户端发送命令到正在迁移的哈希槽上,集群会自动将请求重定向到正确的节点。这意味着客户端可能会在迁移过程中经历一些请求的重定向和稍微增加的延迟,但整体上仍然可以继续提供服务。

  • 在缩容期间,当节点离开集群时,集群会将相应的哈希槽重新分配给其他节点,并进行数据迁移。在这个过程中,客户端的请求也会被重定向到正确的节点上。与扩容相似,客户端可能会经历一些请求重定向和轻微的延迟。

需要注意的是,数据迁移过程可能会对集群的整体性能产生一些影响。数据迁移可能会消耗网络带宽和节点资源,因此在迁移期间可能会出现一些性能波动。但一旦数据迁移完成,集群的性能应该恢复到正常水平,并且能够继续提供服务。

为了最小化影响,可以采取一些策略,如逐步扩容或缩容、控制迁移速率等。此外,合理的集群规划和节点配置也可以提高Redis Cluster在扩容和缩容期间的稳定性和性能表现。

总的来说,Redis Cluster在扩容和缩容期间可以继续提供服务,但可能会有一些短暂的影响和性能变化。这些影响通常是暂时的,一旦数据迁移完成,集群应该恢复到正常状态。

18.7 Redis Cluster 中的节点是怎么进行通信的?

在Redis Cluster中,节点之间通过节点间通信(Node-to-Node Communication)来进行协调和数据同步。节点间通信是基于Redis自定义的二进制协议实现的。

以下是节点间通信的基本原理:

    1. Gossip协议:Redis Cluster使用Gossip协议来进行节点之间的发现和状态信息传播。每个节点都与其他节点保持连接,并周期性地交换关于集群拓扑和节点状态的信息。这种信息交换使得每个节点都能了解到其他节点的存在和状态变化。
    1. 握手过程:当一个节点加入集群时,它会通过Gossip协议与其他节点进行握手,以获取集群的拓扑信息。握手过程包括节点之间的互相识别、集群拓扑的交换等。
    1. 请求重定向:当一个节点接收到一个请求,但该请求所对应的哈希槽并不在该节点上时,节点会通过Gossip协议获取哈希槽对应的节点信息,并将请求重定向到正确的节点。这样,请求就会被正确地处理。
    1. 节点间数据同步:当集群中的节点发生数据迁移、主节点切换等情况时,节点之间需要进行数据同步,以保证数据的一致性。Redis Cluster使用主从复制(Replication)机制来实现数据同步。其中,主节点负责将数据同步到从节点,确保从节点与主节点的数据保持一致。
    1. 心跳检测:节点之间会通过定期的心跳检测来监测其他节点的健康状态。如果一个节点长时间没有响应,其他节点会将其标记为故障节点,并进行故障转移等操作。

通过以上机制,Redis Cluster中的节点能够进行通信、协作和数据同步,以实现集群的高可用性和数据一致性。这些机制使得Redis Cluster能够自动处理节点间的协调和故障恢复,从而提供稳定可靠的服务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/448070.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

修改Android打包apk的名字和目录

app打包生成apk后通常需要进行备份,但是要区分好哪个apk是什么版本的、什么时候打包的,以方便以后区分使用。 最开始的想法是把版本号、创建时间这些加在apk文件名上即可,但是公司要求apk使用一个固定的名称,那我怎么保存版本号信…

OpenGL学习——19.模板测试

前情提要:本文代码源自Github上的学习文档“LearnOpenGL”,我仅在源码的基础上加上中文注释。本文章不以该学习文档做任何商业盈利活动,一切著作权归原作者所有,本文仅供学习交流,如有侵权,请联系我删除。L…

Vue+OpenLayers7入门到实战:OpenLayers鼠标移动事件使用,实现鼠标移动到点位上方后高亮显示点位要素

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7入门到实战 前言 本章介绍如何使用OpenLayers7在地图上监听鼠标移动事件,并简单实现鼠标移动到点位上方后高亮显示点位要素的功能,带领大家快速上手OpenLayers鼠标移动事件的应用。 二、依赖和使用 "ol": &quo…

趣味看图-Linux 文件系统的组成

/(根目录):根目录是Linux文件系统中的顶级目录。所有其他目录都是根目录的子目录,使其成为整个文件系统的父目录。 /bin:包含启动系统和执行基本操作所需的基本二进制可执行文件。这些对所有用户都可用。 /boot&…

利用yaml文件部署NacosXxl-job到阿里云的ACK

背景介绍 随着容器化的技术成熟落地,拥抱各种成熟的容器化集群平台是加速我们落地的必然之路,目前国内以阿里云、华为云、腾讯云为平台的供应商为主,国外则以AWS,Azure为主,让我们借助平台已有的优势进行快速落地提高…

G-LAB郭主任公开课:Docker容器,3月18日开课!

带你一起走进Linux的世界! 【G-LAB】 Linux最新技术—Docker容器 免费公开课即将开讲! 不容错过! 公开课课程为期两天,3月18日&3月19日晚20:00 分享主题: —3月18日 Docker概念、安装、架…

MySQL-QA-异常问题及解决方案(持续更新)

MySQL-Q&A(持续更新) 1.1 PID文件找不到 问题描述 错误详情: ERROR!The server quit without updating PID file (/usr/local/mysql/data/localhost.localdomain.pid) 解决方案 首先排查配置文件,一般路径为:/etc/my.cnf 检查…

centos安装hadoop启动问题解决方案

1、出现了问题localhost: ERROR: JAVA_HOME is not set and could not be found. *解决方案尝试: 修改hadoop-env.sh(在etc/hadoop) sudo gedit /usr/local/hadoop/etc/hadoop/hadoop-env.sh 将原本的JAVA_HOME 替换为绝对路径就可以了 #expo…

RK3588-hdmiin

1. HDMI-IN简介 HDMI IN功能可以通过桥接芯⽚的⽅式实现,将HDMI信号转换成MIPI信号接收RK3588芯⽚平台⾃带HDMI RX模块,可以直接接收HDMI信号,无需通过桥接芯⽚实现。在ArmSoM系列产品中,ArmSoM-W3支持HDMI-IN功能HDMI-IN功能框图…

3.10复试专业课日报【周末总结】

数据结构 考点一,考点二 操作系统 计算机网络 组成原理 1.什么是中断向量 2. 数据库 选择题80-100 1.数据库的逻辑模型(数据模型) 2.DCL,DML,DQL,DDL 3.数据库特点 算法 1.复习 对称二叉树,二叉树最大深度 2.只出现一…

Mybatis-plus学习之Lombok

何为Lombok Lombok 是一个 Java 库,旨在通过自动生成样板代码来简化 Java 类的编写。它通过使用注解来减少冗长和重复的代码,提高代码的可读性和开发效率。 优点与优势 使用 Lombok,你可以在 Java 类中添加各种注解,从而自动为…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《含海上风电制氢的综合能源系统分布鲁棒低碳优化运行》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Navicat连接数据库出现的问题(3.8)

Navicat使用教程——连接/新建数据库、SQL实现表的创建/数据插入、解决报错【2059-authentication plugin‘caching_sha2_password’……】_2059authentication plugin-CSDN博客

NTC 测试温度

NTC 测温应用电路汇总及温度读取软件设计 - 知乎 1.开尔文273.5就是0摄氏度 2.B一般厂家都会给 3.上面公式大概准 4.计算还是查表法,段与段之间近似直线

Net8 ABP VNext集成FreeSql、SqlSugar

ABP可以快速搭建开发架构,但是内置的是EFCore,国内中小企业使用FreeSql与SqlSugar还是较多,为新手提供使用提供参考 ABP、FreeSql、SqlSugar参考地址: ABP Framework | Open source web application framework for ASP.NET Core…

在win7中快速安装vue2

首先要求我们安装node.js 如果没有安装可以点击跳转 安装node 1.配置环境变量 其实安装完node,就自动在path里增加环境变量,但是为了以后的本地部署项目,我们需要找到node.js的安装根目录 1.1在当中新建"node_cache"缓存和&qu…

两会声音|中国石化人大代表:要突出战略性新兴产业、未来产业的位置

十四届全国人大二次会议即将闭幕,“新质生产力”首次写入政府工作报告,并出现在了重要位置。政府工作报告主要从推动产业链供应链优化升级、积极培育新兴产业和未来产业、深入推进数字经济创新发展等三个方面进行了阐述和规划。 全国两会期间&#xff0c…

使用Vite构建Vue3+TypeScript项目

1,新建项目前,确保电脑 已经安装Node.js,pnpm 在本地新建一个文件夹 ,在文件路径输入cmd 如下展示 2,执行如下指令搭建项目 filename,即搭建的项目名称。 pnpm create vitelatest filename 输入指令按回车之后如下…

29个社媒营销经典案例!外贸人速来学习!

今天给大家分享一些比较经典的外贸社媒营销案例,希望对大家有帮助! 01 创建重复的内容系列 如果你每天都在为决定要在社交媒体上发布什么内容而焦头烂额,那就创建一些你擅长的重复内容系列和主题。 例如,有人经常分享鼓舞人心的…