【NoSQL数据库】Redis学习笔记

news2024/11/13 22:41:06

 一、缓存穿透

         缓存穿透是先查Redis,发现缓存中没有数据,再查数据库。然而,如果查询的数据在数据库中也不存在,那么每次查询都会绕过缓存,直接落到数据库上。

解决方案一、缓存空数据

  • 查询Redis缓存:首先查询Redis缓存,看看请求的数据是否已经缓存。
  • 缓存未命中:如果Redis缓存中没有该数据,则查询数据库。
  • 数据库查询结果为空:如果数据库中也没有该数据(即数据不存在),则将这个空结果缓存起来,并设置一个较短的过期时间。
  • 返回结果:下一次查询相同的数据时,直接从缓存中返回空结果。

布隆过滤器是一种高效的概率数据结构,用于测试一个元素是否在一个集合中。它能够快速判断某个元素是否可能存在于集合中,但不能准确地确定元素一定存在。布隆过滤器通过牺牲一定的准确性来大幅度节省空间。

布隆过滤器的原理

  1. 哈希函数:布隆过滤器使用多个哈希函数将输入元素映射到一个位数组中的多个位置。
  2. 位数组:布隆过滤器维护一个固定大小的位数组,初始时所有位都为0。
  3. 添加元素:将一个元素添加到布隆过滤器时,通过多个哈希函数计算出多个哈希值,并将位数组中对应位置的值设为1。
  4. 查询元素:查询一个元素是否在布隆过滤器中时,使用相同的哈希函数计算出多个哈希值,并检查位数组中对应位置的值是否全部为1。如果全部为1,则说明该元素可能在集合中;如果有任何一个位置的值为0,则说明该元素肯定不在集合中。

使用布隆过滤器解决缓存穿透

布隆过滤器可以用于防止缓存穿透,因为它能够高效地判断某个查询是否对应数据库中不存在的数据。如果布隆过滤器判断某个元素肯定不存在,就可以直接返回空结果,而不必查询数据库和缓存。

二、缓存击穿

        给一个key设置过期时间,当缓存中的热点数据(即频繁被访问的数据)过期时,意味着缓存系统中存储的这部分数据不再有效,并且会被移除或者需要重新加载。此时,如果有大量请求同时访问这个数据,而缓存中没有有效的数据存在,那么这些请求将直接转发到后端数据库进行查询。由于这些数据是热点数据,访问频繁,所以瞬间的大量请求可能会给后端数据库带来很大的压力,甚至导致数据库负载过高,性能下降,甚至崩溃。这种情况被称为缓存击穿。

        解决方案一:互斥锁

背景问题

想象你是一家餐馆的老板,平时店里有一个公告板,上面写着每日特价菜的信息(类似于缓存)。大家都可以直接看公告板获取信息,而不需要每个人都来问你(类似于访问数据库)。

但有时候,公告板上的信息过期了(缓存失效),需要更新。这时,很多客人都同时来问你今天的特价菜是什么(大量并发请求访问数据库)。如果所有人都来问你,你就会忙不过来(数据库压力骤增)。

互斥锁解决方案

为了防止这种情况,你决定用一个办法来解决这个问题——你安排一个锁(锁机制)。

具体过程

  1. 检查公告板:每个客人来餐馆时,首先会看看公告板(检查缓存)。
  2. 尝试获取锁:如果公告板上的信息过期了(缓存失效),第一个发现的客人会去找你更新信息。但你设立了一条规则:每次只能有一个客人来问你特价菜是什么(获取锁)。
  3. 锁获取成功:如果某个客人第一个来问你特价菜(成功获取锁),你会告诉他特价菜是什么(查询数据库),并让他把新的信息写到公告板上(更新缓存)。然后你会解除限制(释放锁),让其他客人可以直接看公告板。
  4. 锁获取失败:如果另外的客人也发现公告板的信息过期了,但发现已经有一个客人去问你了(获取锁失败),他们不会再来打扰你,而是等一会儿再看公告板,看看新信息是否已经更新(等待并重试)。

import time
import redis

# 初始化 Redis 连接,类似于你有一个能记录锁状态的工具
redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)

def get_special_dish_with_lock(key, query_database, lock_timeout=10, cache_timeout=60):
    # 先看看公告板上有没有特价菜的信息
    data = redis_client.get(key)
    
    if data is not None:
        return data
    
    # 如果公告板上没有信息,第一个客人会去找你问特价菜,并设立一个锁
    lock_key = f"lock:{key}"
    if redis_client.setnx(lock_key, 1):
        redis_client.expire(lock_key, lock_timeout)  # 设置锁的过期时间,防止有人占着不放
    
        try:
            # 再次检查公告板,因为可能有其他人已经更新了
            data = redis_client.get(key)
            if data is None:
                # 如果公告板上还是没有信息,你告诉第一个客人特价菜是什么
                data = query_database()
                
                # 第一个客人把新信息写到公告板上
                redis_client.set(key, data, ex=cache_timeout)
        finally:
            # 解除锁,其他客人可以直接看公告板了
            redis_client.delete(lock_key)
    else:
        # 如果有其他客人已经去问你了,其他客人等一会儿再看公告板
        while not data:
            time.sleep(0.1)
            data = redis_client.get(key)
    
    return data

# 模拟数据库查询函数
def query_database():
    return "Today's Special Dish"

# 使用互斥锁获取特价菜信息
key = "special_dish"
special_dish = get_special_dish_with_lock(key, query_database)
print(special_dish)
 

更新缓存的过程

  1. 缓存失效检测:每当有请求到来时,首先检查缓存中是否有需要的数据以及数据是否有效(未过期)。
  2. 缓存失效:如果缓存中没有数据或者数据已过期,就需要从数据库中获取最新的数据。
  3. 查询数据库:从数据库中查询最新的数据。
  4. 将数据存入缓存:将从数据库中查询到的最新数据存入缓存,并设置一个新的过期时间。
  5. 响应请求:将最新的数据返回给请求方。

缓存过期解决方案

逻辑过期是一种缓存管理策略,通过在缓存数据中附带一个逻辑过期时间,而不是依赖缓存系统的物理过期机制。这样可以避免热点数据在过期瞬间引发的缓存击穿问题,同时确保数据的一致性和及时性更新。

逻辑过期的餐馆例子

背景

假设你是一家餐馆的老板,公告板上每天展示特价菜的信息。为了让信息保持最新,你决定采用逻辑过期的方式来管理特价菜的信息。

具体过程

  1. 公告板展示特价菜:公告板上写着当天的特价菜信息,并附带一个逻辑过期时间(比如某个时间之后,信息被认为过期)。
  2. 检查公告板:每个客人到来时,首先看看公告板上的特价菜信息。
  3. 判断逻辑过期:客人不仅看特价菜信息,还要检查逻辑过期时间。
    • 未过期:如果逻辑过期时间还没到,客人就直接获取信息。
    • 已过期:如果逻辑过期时间到了,客人仍然先拿到旧的信息,但同时通知你更新信息。
  4. 后台更新:你在后台更新特价菜信息并重新设置逻辑过期时间,过程中公告板上的旧信息仍然有效。
  5. 更新公告板:新信息准备好后,公告板上的特价菜信息和逻辑过期时间被更新。

优点

  • 防止缓存击穿:即使逻辑过期时间到了,旧的信息仍然可用,避免了大量请求同时打到数据库。
  • 数据更新及时:后台更新新数据,确保新数据在逻辑过期后能尽快生效。

import time
import redis
import json

# 初始化 Redis 连接
redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)

def get_data_with_logical_expiration(key, query_database, logic_expiry_time=60):
    # 先看看缓存中有没有数据
    cached_data = redis_client.get(key)
    
    if cached_data is not None:
        cached_data = json.loads(cached_data)
        data = cached_data["data"]
        expiry_time = cached_data["expiry_time"]
        
        # 检查逻辑过期时间
        if time.time() < expiry_time:
            return data
        else:
            # 逻辑过期,启动后台更新
            refresh_cache_async(key, query_database, logic_expiry_time)
            return data  # 返回旧的数据
    else:
        # 如果缓存中没有数据,查询数据库
        data = query_database()
        
        # 将数据和逻辑过期时间存入缓存
        expiry_time = time.time() + logic_expiry_time
        cached_data = {"data": data, "expiry_time": expiry_time}
        redis_client.set(key, json.dumps(cached_data))
        
        return data

def refresh_cache_async(key, query_database, logic_expiry_time):
    # 模拟异步更新缓存
    data = query_database()
    expiry_time = time.time() + logic_expiry_time
    cached_data = {"data": data, "expiry_time": expiry_time}
    redis_client.set(key, json.dumps(cached_data))

# 模拟数据库查询函数
def query_database():
    return "Today's Special Dish"

# 获取特价菜信息
key = "special_dish"
special_dish = get_data_with_logical_expiration(key, query_database)
print(special_dish)
 

三、缓存雪崩

        同一时间段内大量缓存key同时失效或者Redis服务器宕机,导致大量请求到达服务器,带来巨大压力。

解决方案:

        给不同key的剩余生存时间(该键距离过期还有多少秒)增加随机值。

集群模式(Cluster Mode)

什么是 Redis 集群模式?

Redis 集群模式是 Redis 提供的分布式架构,允许数据在多个 Redis 节点之间分布。集群模式通过数据分片将数据分布到多个 Redis 实例上,每个节点负责部分数据,并且集群模式提供了自动故障转移和负载均衡的能力。

解决雪崩问题的机制
  • 数据分片:由于数据分布在多个节点上,单个节点的故障不会导致整个集群的服务中断。缓存雪崩只会影响到某个分片的数据。
  • 高可用性:自动故障转移和数据备份使得集群能够继续提供服务,即使某些节点失效,也不会影响整个系统的正常运行。

哨兵模式(Sentinel Mode)

什么是 Redis 哨兵模式?

Redis 哨兵模式是 Redis 提供的一种高可用解决方案。哨兵模式通过监控主节点和从节点,自动处理故障转移(主节点失效时从节点升级为主节点)来提高 Redis 的可用性。

如何工作?
  1. 监控:哨兵进程监控主节点和从节点的状态,检测故障。
  2. 通知:当检测到主节点发生故障时,哨兵会发出通知。
  3. 故障转移:哨兵会自动将某个从节点升级为新的主节点,并更新系统中的配置。
  4. 配置提供:客户端可以通过哨兵获取当前的主节点信息,以便进行连接。
解决雪崩问题的机制
  • 自动故障转移:即使主节点失效,哨兵模式可以自动进行故障转移,确保服务持续可用,降低单点故障带来的影响。
  • 高可用性:主从复制和自动故障转移使得 Redis 哨兵模式能够保证数据的高可用性,从而降低因为主节点失效导致的雪崩效应。

双写一致性(Double Write Consistency)是指在系统中同时更新两个或更多存储介质(如数据库和缓存)时,确保这些存储介质中的数据保持一致的机制

        四、双写一致性

在使用Redis和主数据库实现双写一致性时,可以结合共享锁和排他锁来确保数据一致性。以下是一个详细的实现方案:

1. 架构概述

  • 主数据库:负责持久化存储数据,支持写操作。
  • Redis缓存:负责加速读操作,提高性能。

2. 锁机制

  • 共享锁(Shared Lock):用于读操作。
  • 排他锁(Exclusive Lock):用于写操作。

3. 实现步骤

读操作
  1. 请求获取共享锁。
  2. 从Redis缓存中读取数据。如果缓存中没有数据,则从主数据库中读取,并将数据写入Redis缓存。
  3. 释放共享锁。
写操作
  1. 请求获取排他锁。
  2. 写入主数据库。
  3. 将数据更新到Redis缓存中。
  4. 释放排他锁。

为什么这样可以保证数据一致性

  1. 读操作不干扰写操作

    • 读操作使用共享锁,多个读操作可以并发进行,但在读操作进行时,写操作被排除在外,避免了读到不一致的数据。
  2. 写操作独占资源

    • 写操作使用排他锁,确保在写操作进行时,没有其他读或写操作进行。这样可以确保写操作完成后,数据在主数据库和Redis缓存中是一致的。
  3. 缓存更新机制

    • 读操作会在缓存未命中时,从主数据库读取数据并更新缓存。写操作会在主数据库更新后,立即更新缓存。这确保了缓存中的数据始终与主数据库保持一致。

五、Redis持久化

Redis RDB 快照

Redis 使用 RDB(Redis Database)文件来实现快照功能。RDB 快照是将 Redis 内存中的所有数据在特定时间点保存到一个二进制文件中的过程。RDB 文件包含了 Redis 数据库中的所有键值对的快照,可以用于数据恢复。

RDB 快照的生成方式
  1. 自动生成

    • Redis 可以根据配置文件中的 save 选项定期生成 RDB 快照。例如,save 900 1 表示在 900 秒(15 分钟)内至少有一个写操作时触发快照,save 300 10 表示在 300 秒(5 分钟)内至少有 10 次写操作时触发快照。
  2. 手动生成

    • 可以通过命令 BGSAVESAVE 手动触发快照生成。BGSAVE 命令在后台生成快照,SAVE 命令在前台生成快照,阻塞 Redis 服务器的所有客户端请求。

持久化(Persistence)是指将数据存储在非易失性存储介质上,以便在系统重启或崩溃后数据仍然可以被恢复。

        bgsave命令

BGSAVE 命令

  • 创建子进程:当 Redis 执行 BGSAVE 命令时,主进程会创建一个子进程(fork),这个子进程负责生成 RDB 文件。主进程继续响应客户端请求,而子进程负责写入 RDB 文件。
  • 写入文件:子进程会将内存中的所有数据写入 RDB 文件。这个过程中,主进程不会阻塞,可以继续处理其他请求。

在 Redis 中,当需要生成 RDB(Redis Database)快照时,Redis 会使用一个子进程来处理 RDB 文件的生成,这样主进程可以继续响应客户端的请求而不被阻塞。下面是这一过程的详细解释:

子进程和主进程的角色

主进程

主进程是 Redis 的核心进程,它负责处理所有的客户端请求,如读写数据、执行命令、管理连接等。在 Redis 执行 BGSAVE 命令时,主进程的主要任务是:

  • 继续接受和处理来自客户端的请求。
  • 在子进程生成 RDB 文件期间,不会受到阻塞。
  • 确保系统的高可用性和响应能力,即使在生成快照的过程中。
子进程

当 Redis 执行 BGSAVE 命令时,主进程会创建一个子进程来处理 RDB 文件的生成。子进程负责:

  • 复制内存数据:子进程会在创建时复制主进程的内存数据。这意味着子进程会有一个内存中数据的副本,便于将这些数据写入 RDB 文件。
  • 写入 RDB 文件:子进程将内存中的数据以 RDB 格式写入到磁盘上的文件中。这个过程涉及将所有键值对序列化并压缩到一个二进制文件中。
  • 完成后终止:子进程在 RDB 文件写入完成后会退出,生成的 RDB 文件会保存在 Redis 配置文件中指定的位置。

生成 RDB 文件的过程

  1. 主进程发起快照

    • 当 Redis 执行 BGSAVE 命令时,主进程创建一个子进程。
  2. 子进程复制内存

    • 子进程会复制主进程的内存数据,但在这个阶段,主进程和子进程都使用相同的数据快照。这保证了在快照生成过程中,数据的一致性。
  3. 子进程生成 RDB 文件

    • 子进程将内存数据序列化、压缩并写入到 RDB 文件中。这个过程中,主进程可以继续处理客户端的请求。
  4. 子进程完成并退出

    • 一旦子进程完成 RDB 文件的生成,它会退出。生成的 RDB 文件会保存到磁盘上,供未来恢复使用。

为什么使用子进程

使用子进程的主要原因是:

  1. 避免主进程阻塞:生成 RDB 文件的过程可能需要一定的时间,特别是当数据量很大时。如果主进程直接生成快照,它会阻塞所有客户端请求,影响系统性能和响应能力。通过使用子进程,可以确保主进程继续处理客户端请求,而子进程在后台生成快照。

  2. 数据一致性:通过复制内存数据到子进程,子进程可以在一个一致的时间点生成 RDB 文件,避免了在快照生成过程中数据的变化影响快照的一致性。

  3. 系统可靠性:将数据写入磁盘的过程是一个相对耗时的操作。将其交给子进程处理,可以提高系统的整体可靠性和响应速度,避免对主进程的性能产生重大影响。

Redis 的 AOF(Append Only File)持久化机制是一种通过将所有写操作追加到日志文件中来实现数据持久化的方式。与 RDB(Redis Database)通过快照生成文件不同,AOF 记录的是所有写操作的日志,以便在 Redis 重启时可以通过重放这些操作来恢复数据。

AOF 的工作原理

1. 记录写操作

AOF 通过记录每次写操作(如 SETDELINCR 等)到日志文件中来实现持久化。Redis 会将这些操作以命令的形式追加到 AOF 文件末尾。

  • 命令格式:每条写操作都以特定的格式写入 AOF 文件。AOF 文件中的每一行代表 Redis 的一个写命令。

    例如,以下是一个典型的 AOF 文件内容:

*3
$3
SET
$4
key1
$6
value1
*3
$3
SET
$4
key2
$6
value2
*2
$3
DEL
$4
key1
 

Redis 会按顺序执行以下操作:

  • 执行 SET key1 value1:将键 key1 的值设置为 value1
  • 执行 SET key2 value2:将键 key2 的值设置为 value2
  • 执行 DEL key1:删除键 key1

通过这些操作,Redis 会恢复到 AOF 文件记录的状态,即只有 key2 存在,key1 已被删除。

未完待续。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前后端分离项目部署,vue--nagix发布部署,.net--API发布部署。

目录 Nginx免安装部署文件包准备一、vue前端部署1、修改http.js2、npm run build 编译项目3、解压Nginx免安装,修改nginx.conf二、.net后端发布部署1、编辑appsetting.json,配置跨域请求2、配置WebApi,点击发布3、配置文件发布到那个文件夹4、配置发布相关选项5、点击保存,…

中电金信:AI数据服务

01 方案简介 AI数据服务解决方案为泛娱乐、电子商务、交通出行等行业提供数据处理、数据分析、AI模型训练等服务&#xff0c;通过自主研发的IDSC自动化数据服务平台与客户业务流程无缝衔接&#xff0c;实现超低延时的实时数据处理支持。 02 应用场景 智能医疗&#xff1a; 通…

Ribbon负载均衡与内核原理

什么是Ribbon? 目前主流的负载方案分为两种&#xff1a; 集中式负载均衡&#xff0c;在消费者和服务提供方中间使用独立的代理方式进行负载&#xff0c;有硬件的&#xff08;比如F5&#xff09;&#xff0c;也有软件的&#xff08;Nginx&#xff09;客户端根据自己的请求做负…

transformers进行学习率调整lr_scheduler(warmup)

一、get_scheduler实现warmup 1、warmup基本思想 Warmup&#xff08;预热&#xff09;是深度学习训练中的一种技巧&#xff0c;旨在逐步增加学习率以稳定训练过程&#xff0c;特别是在训练的早期阶段。它主要用于防止在训练初期因学习率过大导致的模型参数剧烈波动或不稳定。…

力扣经典题目之->设计循环队列 的超详细讲解与实现

一&#xff1a;题目 二&#xff1a;思路讲解 前提&#xff1a; a&#xff1a;本文采取数组来实现队列去解决题目 b&#xff1a;开辟k1个空间&#xff0c;front指向队首&#xff0c;rear指向队尾的后一个&#xff0c;rear这样会更好的判空和判满 以下根据pop和push感受满和空…

python如何调用matlab python package库matlab转python安装包调用使用简单示例

说明(废话) 之前没有进行python调用过matlab&#xff0c;前面用matlab engine for python可以通过调用matlab的源码文件的形式可以调用工程&#xff0c;但是这又有一个问题&#xff0c;就是在运行的时候必须提供python和matlab的全部源码 该文章是通过matlab源码转python pack…

FPGA JTAG最小系统 EP2C5T144C8N

FPGA的文档没有相应的基础还真不容易看懂&#xff0c;下面是B站上对FPGA文档的解读(本文非对文档解读&#xff0c;只是为个人记录第三期&#xff1a;CycloneIV E最小系统板设计&#xff08;一&#xff09;从Datasheet上获取FPGA的基本参数_哔哩哔哩_bilibili 电源部份 核心电…

PlantUML 语法、图标和示例

基本语法 关键字 声明参与者的几个关键字 actor、boundary、control、entity、database、collections、participant 箭头样式 我们可以通过&#xff0c;修改箭头样式&#xff0c;来表达不一样的意思&#xff1a; 表示一条丢失的消息&#xff1a;末尾加 x让箭头只有上半部…

[UE 虚幻引擎] DTHmacSha 蓝图HMACSHA加密算法插件说明

本插件可以在虚幻引擎中使用蓝图对字符串和文件进行HMACSHA加密。 1.节点说明 HMACSHA一共有5种加密方式&#xff0c;分辨是 HMAC SHA-1&#xff0c; HMAC SHA-224&#xff0c;HMAC SHA-256&#xff0c;HMAC SHA-384&#xff0c;HMAC SHA-512。 本插件对每种加密方式提供3个节点…

C++初学者指南-6.函数对象--函数对象

C初学者指南-6.函数对象–函数对象 文章目录 C初学者指南-6.函数对象--函数对象函数对象示例&#xff1a;区间查询区间内的查找区间划分(分组) 指南标准库函数对象比较算术运算 函数对象 提供至少一个成员函数重载 operator() 的对象 class Multiplier {int m_; public:// cons…

MATLAB绘制方波、锯齿波、三角波、正弦波和余弦波、

一、引言 MATLAB是一种具有很强的数值计算和数据可视化软件&#xff0c;提供了许多内置函数来简化数学运算和图形的快速生成。在MATLAB中&#xff0c;你可以使用多种方法来快速绘制正弦波、方波和三角波。以下是一些基本的示例&#xff0c;展示了如何使用MATLAB的命令来实现正弦…

centos系统mysql主从复制(一主一从)

文章目录 mysql80主从复制&#xff08;一主一从&#xff09;一、环境二、服务器master1操作1.开启二进制日志2. 创建复制用户3. 服务器 slave1操作4. 在主数据库中添加数据 mysql80主从复制&#xff08;一主一从&#xff09; 一、环境 准备两台服务器&#xff0c;都进行以下操…

入门C语言Day15——关系条件逻辑操作符

今天来学习操作符中的一些内容&#xff0c;主要讲的是关系&条件&逻辑操作符 1.关系操作符 首先要来了解一下什么是关系操作符&#xff0c;关系操作符其实就是关系运算符&#xff0c;关系运算符又和关系表达式有关。 C语言中用于比较的表达式&#xff0c;就被称为 “关…

google、windows自带语音识别中英文等实时字幕使用

2、自带实时字幕 1&#xff09;google浏览器自带 实时字幕 设置里可以设置&#xff1a; 有视频声音播放会弹出黑色文本框 下载其他语言包-比如中文&#xff1a; 测试 2&#xff09;windows11 辅助功能 实时字幕 &#xff08;直接快捷键打开&#xff1a;Win Ctrl L&#…

openmv学习笔记(24电赛笔记)

#opemv代码烧录清除详解 openmv的代码脱离IDE运行程序&#xff0c;只需要在IDE中将代码烧录道flash里面&#xff0c;断开IDE连接&#xff0c;上电之后&#xff0c;会自动执行main.py中的程序&#xff0c;IDE烧录的时候&#xff0c;会默认将程序后缀保存为 .py文件。 ​​​​​…

go语言day16 runtime包 临界资源 sync包

深入理解Java虚拟机到底是什么_java虚拟机是什么-CSDN博客 Golang-100-Days/Day16-20(Go语言基础进阶)/day17_Go语言并发Goroutine.md at master rubyhan1314/Golang-100-Days GitHub runtime 类似jvm&#xff0c;runtime包也提供了垃圾回收功能。 并且jvm实现了对线程创建销…

自动化网络爬虫:如何它成为提升数据收集效率的终极武器?

摘要 本文深入探讨了自动化网络爬虫技术如何彻底改变数据收集领域的游戏规则&#xff0c;揭示其作为提升工作效率的终极工具的奥秘。通过分析其工作原理、优势及实际应用案例&#xff0c;我们向读者展示了如何利用这一强大工具加速业务决策过程&#xff0c;同时保持数据收集的…

vuepress搭建个人文档

vuepress搭建个人文档 文章目录 vuepress搭建个人文档前言一、VuePress了解二、vuepress-reco主题个人博客搭建三、vuepress博客部署四、vuepress后续补充 总结 vuepress搭建个人文档 所属目录&#xff1a;项目研究创建时间&#xff1a;2024/7/23作者&#xff1a;星云<Xing…

Java响应式编程库Reactor的介绍和基本使用

关于响应式编程的概念和介绍可以参考: 响应式编程(Reactive Programming)是什么? Java语言中,RxJava和Reactor是实现响应式编程的两个最流行的库,因为 Spring 5 及更高版本中,Reactor 是 Spring WebFlux 的底层实现框架,用于构建响应式 Web 应用,所以相比而言,Reactor…

【docker】部署证书过期监控系统mouday/domain-admin

证书过期了再去部署证书容易被骂&#xff0c;就找了一个开源的证书过期系统来部署一下 过程 官方文档&#xff1a;https://domain-admin.readthedocs.io/zh-cn/latest/manual/install.html#docker 直接下载镜像是超时的&#xff0c;切换一下文档推荐的镜像源 新建docker配置…