Redis多机数据库实现

news2024/11/23 12:36:01

Redis多机数据库实现

为《Redis设计与实现》笔记

复制

客户端可以使用SLAVEOF命令将指定服务器设置为该服务器的主服务器

127.0.0.1:12345> SLAVEOF 127.0.0.1 6379

127.0.0.1:6379将被设置为127.0.0.1:123456的主服务器

旧版复制功能的实现

Redis的复制功能分为同步(sync)和命令传播(command propagate)两个阶段

  • 同步:将从服务器的数据库状态更新至主服务器当前所处的状态
  • 命令传播:在主服务器的数据状态被修改,导致主服务器的数据状态出现不一致时,让主从服务器的数据重新回到一致状态

同步

从服务器对主服务器的同步操作通过向主服务器发送SYNC命令来完成,步骤如下:

  1. 从服务器向主服务器发送SYNC命令
  2. 主服务器执行BGSAVE命令,生成RDB文件,并用一个缓冲区记录现在开始执行的所有写命令
  3. 将生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件
  4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些命令,将自己的状态更新至主服务器数据库当前所处的状态

命令传播

同步完成后,客户端对主服务器执行了某些操作导致主从服务器的数据库出现不一致,此时主服务器会将自己执行的写命令发送给从服务器,使其恢复成同步状态

旧版复制功能的缺陷

旧版复制存在两种情况:

  • 初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务器和上次复制的主服务器不同
  • 断线后重复制:主从服务器因为网络原因而中断了复制,但从服务器通过自动重连重新连上了主服务器,并继续复制主服务器

在旧版复制中,断线重连后整个复制操作都需要重新执行,导致效率过低

新版复制功能的实现

Redis2.8开始,使用PSYNC命令代替SYNC来执行复制时的同步操作

PSYNC命令具有两种模式:

  • 完整同步:用于初次赋值情况,执行步骤和SYNC命令的执行一样,也是通过主服务器创建并发送RDB文件并发送缓冲区里的写命令给从服务器来进行同步
  • 部分重同步:用于短线后重复复制情况,当从服务器在断线后重连时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令即可恢复到主服务器当前所处的状态

部分重同步由以下三个部分构成:

  • 主服务器的复制偏移量和从服务器的复制偏移量
  • 主服务器的复制积压缓冲区
  • 服务器的运行ID

复制偏移量

主服务器每次向从服务器传播N个字节的数据时,就将自己的复制哦i按一辆值加上N,而从服务器接收到N个字节的数据时,也将自己的复制偏移量加上N。如果主从服务器处于一致状态,那么主从服务器地偏移量是相同的,反之则说明主从服务器为处于一致状态

复制积压缓冲区

复制偏移量能够判断主从服务器是否初一致状态,而复制积压缓冲区则是在从服务器断线重连时执行部分重同步时发挥作用

复制积压缓冲区为主服务器维护的固定长度的先进先出队列,其默认大小为1MB。当主服务器将写命令发送给从服务器时,同时将写命令加入到复制积压缓冲区中,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量。

当从服务器重新连上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量发送给主服务器,主服务器将根据该偏移量来决定进行那种同步方式:

  • 如果偏移量之后的数据任然存在于复制挤压缓冲区中,那么主服务器将对冲服务器执行部分重同步操作
  • 如果偏移量之后的数据已经不存在于复制积压缓冲区中,那么将执行完整同步操作

服务器运行ID

每个Redis服务器都拥有自己的而运行ID,其在服务器启动时自动生成,由40个随机的十六进制字符组成。当主从服务器进行初次复制时,主服务器将自己的运行ID发送给从服务器,并保存好自己的运行ID;当从服务器断连后重新连接,从服务器将告知主服务器之前保存的运行ID

  • 如果从服务为保存的运行ID和当前连接的主服务器的运行ID相同,则说明从服务器断连之前复制的就是当前连接的主服务器,那么将执行部分重同步操作
  • 如果如果从服务为保存的运行ID和当前连接的主服务器的运行ID不同,则说明从服务器断连之前复制的不是当前连接的主服务器,那么将执行完整的重同步操作

PSYNC 命令

PSYNC命令的调用方法有两种:

  • 如果从服务器一脸没有父之过任何主服务器,或之前执行过SLAVEOF no one命令,那么从服务器将在开始复制时向主服务器发送PSYNC ? -1命令,主动请求服务器进行完整重同步
  • 如果从服务器已经复制过某个主服务器,那么从服务器在开始复制时将向主服务器发送PSYNC <runid> <offset>命令,其中runid为运行ID,offset为偏移量

主服务器在接收到PSYNC命令后会有以下三种回答:

  • 如果要执行完整重同步,主服务器将返回+FULLRESYNC <runid> <offset>,从服务器将保存主服务器的运行ID,并将offset作为自己的初始化偏移量
  • 执行部分重同步时,主服务器将发送+CONTIMUE回复,这时从服务器只需要等待主服务器发送自己缺失的写命令即可
  • 如果Redis版本过低,不支持PSYNC,则发送-ERR回复,从服务器将发送SYNC命令执行旧的完整同步操作

复制的实现

1. 设置主服务器ip和端口

从服务器执行SLAVEOF <master_id> <master_port>命令时,从服务器保存有主服务器id和端口信息;SLAVEOF为一个异步命令,在设置完上述两个属性后,向客户端发送OK后再开始执行复制工作

struct redisServer {
    ...
    // 主服务器地址
    char *masterhost;
    // 主服务器端口
    char *masterport;
    ...
};

2. 建立套接字连接

在执行完SLAVEOF后,从服务器将根据上一步设置的IP和端口,向主服务器建立套接字连接;主服务器接收(accept)从服务器的连接后,为该套接字建立相应的客户端状态,将从服务器看作是连接主服务器的一个客户端来看待

3. 发送 PING 命令

连接建立完成后,从服务器将向主服务器发送PING命令,其有以下两个作用:
- 检查套接字的读写状态书否正常
- 检查主服务器是否能正常处理命令请求

主服务器接收到PING命令后会有三种情况

  • 主服务器返回PONG,表示网络连接正常,可以继续进行下面的步骤
  • 主服务器正常返回,但是从服务器未能在规定事件内接收到消息,此时从服务器将断开并重新连接主服务器
  • 出服务器向从服务器返回一个错误信息,表示此时主服务器暂时无法处理从服务器的命令请求,此时从服务器将断开并重新连接主服务器

4. 身份验证

从服务器接收到PONG回复后,如果从服务器设置了masterauth选项,则进行身份验证,此时从服务器向主服务器发送AUTH命令,命令的参数为masterauth的值

从服务器在进行身份验证阶段存在以下几种情况:

  • 主服务器没有设置requirepass选项,并且从服务器也没有设置masterauth选项,则跳过该阶段
  • 如果从服务器通过AUTH命令发送的密码和主机的requirepass选项相同,则进行下一步操作,否则返回invalid password错误
  • 如果主服务器设置了requirepass选项,但从服务器没有设置masterauth选项,那么主服务器将返回NOAUTH;相反地,从服务器设置了masterauth选项而主服务器未设置时返回no password is set

5. 发送端口信息

在进行完身份验证后,从服务器将执行REPLCONF listening-port <port-number>向主服务器发送从服务器的监听端口号,其记录在主服务器对从服务器的客户端中,起作用时在主服务器执行INFO replication命令时打印从服务器的端口号

typedef struct redisClient {
    ...
    // 从服务器的监听端口号
    int slave_listening_port;
} redisClient;

6. 同步

从服务器将向主服务器发送PSYNC命令,执行同步操作,将自己的数据更新志主服务器当前所处的状态

在同步操作执行之前,只有从服务器是主服务器的客户端,而在执行同步操作后,主服务器也会成为从服务器的客户端,只有主服务器成为了从服务器的客户端,才能向从服务器发送同步需要的写命令

7. 命令传播

同步完成后,主从服务器进入命令传播阶段,此时主服务器只要一直将自己执行的写命令发送给从服务器,而从服务器只要一直接收并执行主服务器发送来的写命令,就可以保持主从一致了

心跳检测

在命令椽笔阶段,默认从服务器每秒向主服务器发送命令REPLCONF ACK <replication_offset>,其中replication_offset为偏移量,其作用如下:

  • 检测主从服务器的连接状态:主从服务器通过发送可接收REPLOCONF ACK命令来检查两者之间的网络连接是否正常,如果主服务器超过以免没有收到从服务器发来的REPLOCONF ACK命令,那么主服务器就知道与从服务器的连接出现问题
  • 辅助实现min-slaves选项:Redis的min-slaves-to-writemin-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令,其表示当从服务器数量少于min-slaves-to-write或者min-slaves-to-write个从服务器的延迟都不小于min-slaves-max-lag时主服务器将拒绝执行写命令
  • 检测命令丢失:主服务器可以通过比对REPLCONF ACK发送过来的偏移量和自己记录的偏移量来判断从服务器是否存在命令丢失,如果存在,主服务器将根据复制积压缓冲区中保存的数据重新发送给从服务器

Sentinel

Sentinel(哨兵)是Redis的高可用性解决方案,其由一个或多个Sentinel梳理组成的Sentinel系统可以监视任意多个主服务器及其从服务器,并在被监视的主服务器进入下线状态时自动其中的某个从服务器升级为主服务器

Redis哨兵

以上图为例,当Server1下线时长超过用户设定的下线时长时,Sentinel系统就会对Server1执行故障转移操作:

  1. Sentinel系统会挑选Server1属下的一个从服务器,将其升级为新的主服务器
  2. Sentinel向所有Server1下的从服务器发送新的复制指令,让他们成为新的主服务器的从服务器,当所有的从服务器都开始复制新的主服务器时,故障转移操作执行完毕
  3. Sentinel继续监视以下线的Server1,当Server1重新上线时,将其设置为新的主服务器的从服务器

故障转移过程

启动并初始化Sentinel

使用以下命令启动Sentinel:

redis-sentinel /path/to/your/sentinel.conf

或者

redis-server /path/to/your/sentinel.conf --sentinel

当Sentinel启动时,执行以下步骤

  1. 初始化服务器:Sentinel本质是一个特殊Redis服务器,在初始化时不会加载持久化文件
  2. 将普通Redis服务器使用的代码替换成Sentinel专用代码:Sentinel使用sentinel.c/REDIS_SENTINEL_PORT常量作为服务器端口,其默认值为26479,并将普通Redis服务器的命令表redis.c/redisCommandTable替换为sentinel.c/sentinelcmds命令表,所以Sentinel不能执行Redis中如GET, SET等命令
  3. 初始化Sentinel状态:初始化一个sentinel.c/sentinelState结构作为Sentinel状态
struct sentinelState {
    // 当前纪元,用于故障转移
    uint64_t current_epoch;

    // 被该Sentinel监视的主服务器列表,键为主服务器名字,值为指向sentinelRedisInstance结构的指针
    dict *masters;

    // 是否进入了TILT模式
    int tilt;

    // 目前正在执行的脚本的数量
    int running_start_time;

    // 最后一次执行时间处理器的事件
    mstime_t previous_time;

    // 包含了所有需要执行的用户脚本的FIFO队列
    list *scripts_queue;
};
  1. 根据给定的配置文件,初始化Sentinel的监视主服务器列表:Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器的相关信息,其值为sentinel.c/sentinelRedisInstance结构:
typedef struct sentinelRedisInstance {
    // 标识值,记录了实例的类型及其状态,主服务器为SRI_MASTER,从服务器为SRI_SLAVE
    int flags;
    
    // 实例的名称,默认为 ip:port
    char *name;

    // 实例的运行ID
    char *runid;

    // 配置纪元,用于实现故障转移
    uint64_t config_epoch;

    //实例的地址
    sentinelAddr *addr;

    // 实例无响应多少毫秒后会被判断为主观下线
    mstime_t down_after_period;

    // 判断该实例为客观下线所需的支持投票数量
    int quorum;

    // 在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量
    int parallel_syncs;

    // 刷新故障迁移状态时的最大时限
    mstime_t failover_timeout;

    ...

} sentinelRedisInstance;
  1. 创建连向主服务器的网络连接,Sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关信息,Sentinel会创建两个联想主服务器的异步网络连接:
  • 命令连接,用于向主服务器发送命令并接收回复
  • 订阅连接,专门用于订阅主服务器的__sentinel__:hello频道

Sentinel建立两个连接是因为在Redis的发布于订阅功能中,被发送的信息都不会保存在Redis服务器中秒如果在信息发送时,想要接收信息的客户端不在线或下线,则信息会丢失,因此需要建立一个专门的连接来接收该频道的信息。此外,除了订阅频道外,Sentinel还需要向主服务器发送命令,所以除了订阅连接外还需要建立命令连接

获取主服务器信息

Sentinel默认十秒一次向主服务器发送INFO命令,并通过该命令来获取主服务器的当前信息,信息格式如下:

# Server
...
run_id: XXX
...
# Replication
role:master
...
slave0:ip=127.0.0.1,port=11111,state=online,offset=43,lag=0
slave1:ip=127.0.0.1,port=22222,state=online,offset=43,lag=0
slave2:ip=127.0.0.1,port=33333,state=online,offset=43,lag=0
...
# othersections
...

信息内容包括:

  • 主服务器本身的信息,包括服务器运行ID以及role域记录的服务器角色
  • 主服务器下所有的从服务器信息,包括IP地址和端口号等

Sentinel会根据该信息更新masters字典中的主服务器信息及sentinelRedisInstance结构中的slaves字典中的信息

获取从服务器的信息

当Sentinel发现主服务器由新的从服务器时,会对该从服务器建立相应的实例结构和命令连接于订阅连接,同样会每个十秒发送INFO命令,其回复内容如下:

# Server
...
run__id:XXX
...

# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
slave_repl_offset:11887
slave_priority:100

# Other sections
...

信息内容包括:

  • 从服务器的运行ID runID
  • 从服务器的角色 role
  • 主服务器的地址 master_host 和端口号 master_port
  • 主从服务器的连接状态 master_link_status
  • 从服务器的优先级 slabe_priority
  • 从服务器的复制偏移量 slave_repl_offset

根据这些信息,Sentinel会对从服务器的实例结构进行更新

向主服务器和从服务器发送信息

默认Sentinel会以两秒一次的间隔给所有监视的主从服务器发送命令:

PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

信息内容包括:

  • s_开头的参数为Sentinel本身的信息
    • s_ip:Sentinel的IP地址
    • s_port:Sentinel的端口号
    • s_runid:Sentinel的运行ID
    • s_epoch:Sentinel当前的配置纪元
  • m_开头的参数为主服务器信息;如果发送的Sentinel正在监视的是主服务器,那么这些参数就是主服务器的信息,如果是从服务器,那么这些参数就是该从服务器对应的主服务器信息
    • m_ip:主服务器的IP地址
    • m_port:主服务器的端口号
    • m_runid:主服务器的运行ID
    • m_epoch:主服务器当前的配置纪元

接收来自主服务器和从服务器的频道信息

当Sentinel和主从服务器建立起连接后,会通过订阅连接发送以下命令

SUBSCRIB __sentinel__:hello

对于监视同一个服务器的多个Sentinel来说,一个Sentinel发送的信息会被其他Sentinel接收到,这些信息用于更新其他entinel对发送信息的Sentinel的认知,也会被用于更新其他Sentinel对被监视服务器的认知

Sentinel向服务器发送信息

当一个Sentinel从__sentinel__:hello频道收到一条信息时,Sentinel会对该信息尽心分析,提取出信息中的Sentinel IP地址,Sentinel端口号和运行ID等八个参数,进行以下检查:

  • 如果信息中记录的Sentinel的运行ID和接收信息的Sentinel的运行ID相同,那么Sentinel则丢弃这条信息不做处理
  • 如果信息中记录的Sentinel的运行ID和接收信息的Sentinel的运行ID不同,则接收信息的Sentinel将根据信息中的各个参数,对相应主服务器的实例结构进行更新:
    • 更新sentinels字典:Sentinel为主服务器创建的实力结构中的sentinels字典保存了其他监视该主服务器的Sentinel的信息,当收到其他Sentinel发来的消息时,会对sentinels字典进行更新
    • 创建向其他Sentinel的命令连接,使用命令连接相连的各个Sentinel可以通过向其他Sentinel发送命令请求来进行命令交换

检测主观下线状态

默认情况下,Sentinel会以每秒一次的频率向所有创建了命令连接的主从服务器和Sentinel发送PING命令,通过其返回值来判断其是否在线,如果在down-after-milliseconds毫秒内连续向Sentinel发送无效回复,那么Sentinel就会判断该实例为主观下线状态,其flag属性将被设置为SRI_S_DOWN

检查客观下线状态

当一个主服务器被判断为主观下线后,为了确认这个主服务器是否真的下线了,Sentinel会像同样监视这个主服务器的其他Sentinel进行询问,如果收集到了足够多的已下线判断后,Sentinel就会将其判定为客观下线,如果为主服务器则进行故障转移操作

选取零头Sentinel

当一个主服务器被判断为客观下线时,监视这个下线主服务器的Sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel来执行故障转移操作,其规则如下:

  • 所有Sentinel都有被选为领头Sentinel的资格
  • 当进行选举时,无论是否选举成功,所有Sentinel的配置纪元(configuration epoch)都会自增一次
  • 在一个配置纪元里,所有Sentinel都有一次将某个Sentinel设置为局部Sentinel的机会,并且局部领头一旦设置,在这个配置纪元里就不再更改
  • 当一个源Sentinel向另一个目标Sentinel发送SENTINEL -s-master-down-by-addr命令,其返回值中的runid不是*而是是源Sentinel的运行ID时,表示源Sentinel为目标Sentinel的局部领头Sentinel
  • 目标Sentinel在接收到SENTINEL -s-master-down-by-addr命令后,其回复中的leader_runid参数和leader_epoch参数分别为目标Sentinel的局部头领Sentinel的运行ID和配置纪元
  • 源Sentinel收到目标Sentinel的回复后,检查Leader_runid参数是否和源Sentinel的运行ID是否一致,如果一致测目标Sentinel将源Sentinel设置为自己的局部领头Sentinel
  • 如果某个Sentinel被半数以上的Sentinel设置为了局部头领Sentinel,那么该Sentinel为领头Sentinel
  • 如果在规定时间内为选举出领头Sentinel,那么重新来一轮选举

故障转移

在选举出领头Sentinel后,领头Sentinel会对一下先的主服务器执行故障转移操作:

  1. 在以下线的主服务器的从服务器中选取一个从服务器,将其转换为主服务器,其挑选过程为:
    1. 删除类表中所有处于下线和短线状态的从服务器
    2. 删除列表中所有最近五秒内没有回复过领头Sentinel的INFO命令的从服务器
    3. 删除所有于一下先主服务器连接断开超过down-after-milliseconds * 10毫秒的从服务器
    4. 在剩余的从服务器中,根据优先级进行选择,如果具有多个最高优先级的从服务器,那么选择复制偏移量最大的,如果复制偏移量也相同,那么按照运行ID进行排序,选择运行ID最小的从服务器作为新的主服务器
  2. 让其他从服务器改为新的主服务器的从服务器
  3. 将已下线的主服务器设置为新的主服务器的从服务器

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

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

相关文章

扫地僧静态养站王站群:搜狗SEO站群收录养站效果

扫地僧静态养站王站群:Sogou搜狗SEO出站及收录效果,扫地僧静态站群采用了静态生成式的方式&#xff0c;只需要一个后台管理系统即可管理多个网站&#xff0c;大大提高了建站效率。建站大概45天左右&#xff0c;收录率百分之三十至百分之五十左右 如果对购买的域名进行把控&…

Spring系列文章1:Spring入门程序

一、什么是spring 一个java框架、java语言开发&#xff0c;轻量级、开源框架、在j2se、j2ee中都可以使用。它是一个管理对象的容器&#xff0c;Spring 容器不装文本&#xff0c;数字。装的是java对象。 核心技术&#xff1a;ioc、aop 官网地址 https://spring.io 项目列表…

汇编-外中断

我们知道, CPU在计算机系统中, 除了能够执行指令,进行运算以外,还应该能够对外部设备进行控制,接收它们的输入,向它们进行输出。也就是说, CPU除了有运算能力外, 还要有I/O(Input/Output, 输入/输出) 能力。比如, 我们按下键盘上的一个键, CPU最终要能够处理这个键。…

栈trace(kprobe)

最近在看CPU/GPU的调用&#xff0c;于是就有了&#xff1a; 与事件跟踪器类似&#xff0c;不需要通过 current_tracer 激活。相反&#xff0c;通过 /sys/kernel/tracing/kprobe_events 添加探测点&#xff0c;并通过 /sys/kernel/tracing/events/kprobes/<EVENT>/enable…

图片怎么转换成pdf格式?好方法必须分享

图片怎么转换成pdf格式&#xff1f;也许一些朋友会问&#xff0c;为什么要将图片转换成PDF文件呢&#xff1f;众所周知&#xff0c;PDF文件格式具有较高的安全性和兼容性&#xff0c;并且不容易编辑。因此&#xff0c;在打印时&#xff0c;将图片转换成PDF格式后再进行打印可以…

Ubuntu-22.04通过RDP协议连接远程桌面

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、RDP是什么&#xff1f;二、配置1.打开远程桌面功能2.验证服务3.防火墙配置4.测试效果 总结 前言 由于一些特殊需要&#xff0c;我需要通过远程桌面连接到U…

0017Java程序设计-spr农业过程化管理系统

摘 要目 录系统设计开发环境 摘 要 本农业过程化管理系统就是建立在充分利用现在完善科技技术这个理念基础之上&#xff0c;并使用IT技术进行对农业过程化的管理&#xff0c;从而保证种植户能种植出优质的农作物&#xff0c;可以实现农业过程化的在线管理&#xff0c;这样保证…

传输层-TCP 的安全机制和高效策略

可靠性&#xff1a; 之前我们在UDP中谈到了&#xff0c;UDP不可靠但是简单&#xff0c;TCP可靠但是也要做更多的工作&#xff0c;那这些工作具体是什么呢&#xff1f;接下来让我们详细了解一下。 确认应答机制&#xff08;ACK机制&#xff09; 序号&#xff1a;我们可以把TCP…

Qt配置使用MSVC编译器

Qt配置使用MSVC编译器_qt msvc-CSDN博客注意:Qt支持的MSVC就是2017和2015&#xff0c;所以vs也要下载2017&#xff0c;不要直接用最新的&#xff0c;安装路径都用默认的。程序运行失败时可以尝试windeployqt拷贝库文件到本地&#xff0c;然后有可能就能运行了。VS官网下载Visua…

SOLIDWORKS工程图自动零件序号的极致体验

在装配体工程图中零件序号的标注要求不能漏标、要和明细表项目相对应、位置适当并且要按序排列。 这些要求看似简单&#xff0c;但是却需要极大的精力去完成。当然在SOLIDWORKS中这些问题都被很好的解决了&#xff0c;这也是本次分享的内容。 自动序号标注 1) 在进行尺寸标注前…

内网父子项目pom依赖依赖导入出现

这是拉下来两个独立的项目&#xff0c;子项目依赖父项目 我就把父项目install maven仓库中 再加载子项目 在子项目中就出现了有父项目导入类的提示但无论如何也导入不了该类 最后找错 我把本地父项目 install在maven仓库中删了 让子项目自动加载 就根据pom配置加载到内网仓库…

初始化一个 vite + vue 项目

创建项目 首先使用以下命令创建一个vite项目 npm create vite然后根据提示命令 cd 到刚创建的项目目录下&#xff0c;使用npm install安装所需要的依赖包&#xff0c;再使用npm run dev即可启动项目 配置 vite.config.js 添加process.env配置&#xff0c;如果下面 vue-route…

a_bogus 音 算法还原大赏

a_bogus算法还原大赏 hello&#xff0c;大家好呀&#xff0c;我是你的好兄弟&#xff0c;[星云牛马]&#xff0c;花了几天时间算法还原了这个参数的加密过程&#xff0c;一起看看吧&#xff0c;记得加入我们的学习群&#xff1a;529528142 天才第一步&#xff0c;F12你会不&am…

jframe生成柱状图片+图片垂直合并+钉钉机器人推送

需求&#xff1a; 后端根据数据自动生成2个图片&#xff0c;然后把两张图片合并成一张图片&#xff0c;再发到钉钉群里&#xff0c;涉及到定时生成和推送&#xff0c;当时我们测试同事说他们写定时脚本放到服务器上&#xff0c;然后让我提供生成图片的方法和钉钉机器人的逻辑 天…

rhcsa5(日志、维护准确时间)

分析和存储日志 许多系统都以文本文件的方式记录事件日志&#xff0c;而这些文件保存在/var/log目录中。 在红帽中有systemd-journald和rsyslog服务管理日志进程。systemd-journald服务是操作系统事件日志架构的核心&#xff0c;包括内核、引导过程早期阶段的输出、守护进程启动…

第16章_多版本并发控制MVCC

1. 什么是MVCC MVCC &#xff08; Multiversion Concurrency Control &#xff09;&#xff0c;多版本并发控制。顾名思义&#xff0c; MVCC 是通过数据行的多个版本管理来实现数据库的 并发控制 。这项技术使得在 InnoDB 的事务隔离级别下执行 一致性读 操作有了保证。换…

计算机毕业设计 基于SSM的问卷调查管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

孙哥Spring源码第20集

第20集 refresh()-invokeBeanFactoryPostProcessor 四-处理Configuration下的Bean生成代理对象 【视频来源于&#xff1a;B站up主孙帅suns Spring源码视频】【微信号&#xff1a;suns45】 1、二行InvokeBeanFactoryPostProcessors的作用 registryProcessors&#xff1a;处理的…

c语言逻辑思维

c语言逻辑思维 1.如何问问题? 有甲、乙两人&#xff0c;其中&#xff0c;甲只说假话&#xff0c;而不说真话;乙则是只说真话&#xff0c;不说假话。但是&#xff0c;他们两个人在回答别人的问题时&#xff0c;只通过点头与摇头来表示&#xff0c;不讲话。有一天&#xff0c;一…

怎么压缩pdf文件大小?详细压缩步骤

怎么压缩pdf文件大小&#xff1f;在日常的工作和学习中&#xff0c;我们频繁地处理PDF文件。然而&#xff0c;有时候这些文件的大小可能会非常庞大&#xff0c;这给我们带来了一系列的问题。首先&#xff0c;它们占用了大量的存储空间&#xff0c;使得我们的设备变得拥挤不堪。…