Redis第6讲——主从复制模式详解

news2024/9/21 12:27:23

Redis的读写性能很高,但在面对大规模数据和高发访问的挑战时,单节点的Redis可能无法满足需求,这就引出了Redis集群的概念。本节先介绍一下Redis高可用方案之一的主从复制模式,虽说现在基本不会用这种模式,但是无论是哨兵还是集群(cluster),都会使用到主从复制。

一、什么是主从复制

1.1 概述

Redis 的主从复制是一种 Redis 数据库服务器之间的数据同步机制。在主从复制中,一个Redis服务器作为主服务器(master),其余的Redis服务器作为从服务器(slave),主服务器会实时将数据更新同步到从服务器上,从而实现数据的备份和读写分离,当主服务器出现故障时,从服务器可以直接顶替主服务器继续提供读写服务。

  • Matser节点负责读和写操作。
  • Slave节点只能负责读操作。
  • 所有的Slave节点都会连接Master,并同步数据。
  • 也可以实现读写分离:Master只负责写,Slave只负责读。

1.2 开启主从复制

通常有以下三种方式:

  • 在slave服务器直接执行命令:slaveof <masterip> <masterport>

  • 在slave配置文件中加入:slaveof <masterip> <masterport>

# 主从复制。使用 slaveof 命令让一个 Redis 实例成为另一个 Redis 服务器的副本。关于 Redis 复制,
# 有几件事情需要立即了解。
# 1) Redis复制是异步的,但是您可以配置一个主节点,在没有至少连接到指定数量的从节点时停止接受入。
# 2) 如果复制链路在相对较短的时间内丢失,Redis 从节点可以与主节点执行部分重新同步。您可能需要根据
# 您的需求设置合理的复制积压大小(请参见本文件的后续部分)。
# 3) 复制是自动的,不需要用户干预。在网络分区后,从节点会自动尝试重新连接到主节点并与之重新同步。
# slaveof <masterip> <masterport>
  • 使用启动命令:--slaveof <masterip> <masterport>

ps:在Redis5.0之后,slaveof相关命令和配置已经被替换成replicaof <masterip> <masterport>。为了兼容旧版本,配置文件仍然支持slaveof,但命令就不支持了。

二、复制(重点)

2.1 同步(sync)和命令传播(command propagate)

Redis的复制功能主要分为同步(sync)命令传播(command propagate)两个操作。

  • 同步操作用于将slave服务器数据库状态更新至master服务器当前所处的数据库状态。

当客户端salve服务器发送SLAVEOF命令,要求salve服务器复制master服务器时,slave服务器首先需要执行同步操作,通过向master服务器发送SYNC命令(Redis 2.8版本之前)来完成:

  • slave服务器向master服务器发送SYNC命令。
  • 收到SYNC命令的master服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令
  • 当master服务器的BGSAVE命令执行完毕,master服务器会将BGSAVE命令生成的RDB文件发送给slave服务器,slave服务器接收并载入RDB文件,将自己的数据库状态更新至master服务器执行BGSAVE命令时的状态。
  • master将记录在缓冲区里的所有写命令发送给slave服务器,slave服务器执行这些写命令,至此,主从服务器数据库处于一致状态。
  • 命令传播操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。

在同步操作执行完毕后,主从服务器数据库将达到一致状态,但每当主服务器执行写命令时,它俩就会不一致。为了让主从服务器再次回到一致状态,master服务器需要对slave服务器执行命令传播操作:master服务器会将自己执行的写命令,也就是会造成数据库状态不一致的命令,发送给slave服务器执行,当slave服务器执行了相同的命令之后,主从服务器将再次回到一致状态。

读到这,相信大家有一个疑问,如果主从服务器之间断开连接了,那么在恢复连接后,主从服务器之间是如何同步数据的呢?这就分为完整和部分复制两种方式了,在redis 2.8版本之前和之后是有差异的,下面我们一起来看看。

2.2 Redis 2.8版本之前的旧版复制(SYNC)

在Redis中,slave服务器对master服务器的复制可分为以下两种:

  • 初次复制:slave服务器以前没有复制过任何master服务器,或者slave服务当前要复制的master服务器和上一次复制的master服务器不同。
  • 断线后重复制:处于命令传播阶段的主从服务器因为某种原因中断,又重新连接。

对于初次复制还好说,旧版复制能很好地完成工作,但对于断线后重复制这种情况,虽说旧版复制也能完成,但效率太低

假如现在主从服务器处于正常状态,它们之间存储了1000个key,在存第1001个key时,主从服务器断开了,master服务器继续执行写命令,当执行到第1500key时,slave服务器恰好重连上了,那么:

  • slave服务器会向master服务器发送SYNC命令。
  • master服务器接收到SYNC命令,执行BGSAVE命令,创建k1到k1500的RDB文件,并使用缓冲区记录接下来执行的所有写命令。
  • BGSAVE命令执行完毕,向slave服务器发送RDB文件。
  • slave服务器接收到RDB文件,载入。
  • 载入完毕,master服务器将缓冲区的写命令发送给slave服务器。
  • slave执行缓冲区中的写命令,主从服务器重新回到一致状态。

SYNC存在的问题:

我们从这就可以发现,实际slave并不需要重新发送一遍SYNC命令,再从头到尾把master服务器的写命令执行一遍(k1-k1500),这无疑是低效的,而是只需要执行断开连接后的写命令即可(k1001-k1500)。

执行SYNC命令是一个非常耗费资源的操作,每次执行SYNC命令,master服务器都需要执行以下操作:

  • master服务器需要执行BGSAVE命令来生成RDB文件,这个生成操作会耗费master服务器大量的CPU、内存和I/O资源。
  • master服务器需要将自己生成的RDB文件发送给slave服务器,这个发送操作会耗费主从服务器大量的网络资源(带宽和流量),并对master服务器响应命令请求的时间产生影响。
  • 接收到RDB文件的slave服务器需要载入matser服务器发来的RDB文件,并且在载入期间,slave服务器会因为阻塞而没办法处理命令请求。

2.3 Redis 2.8版本起的新版复制(PSYNC)

为了解决slave每次断线重连都需要全量同步的问题,Redis在2.8版本引入了PSYNC命令,PSYNC包含完整重同步和部分重同步两种模式:

  • 完整重同步:和SYNC命令基本一致。
  • 部分重同步:slave只需要接收和同步短线期间丢失的写命令即可,不需要进行完整重同步(上述例子,只需执行k1001-k1500的写命令即可)

2.4 部分重同步的实现

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

  • master服务器和slave服务器的的复制偏移量(offset)。
  • master服务器的复制挤压缓冲区(replication backlog buffer)。
  • 服务器的运行ID(run ID)。

下面我们分别介绍一下。

2.4.1 复制偏移量(offset)

执行主从复制的双方都会分别维护一个复制偏移量,master每次向slave传播N字节,自己的复制偏移量就会增加N;同理,slave接收N个字节,复制偏移量也会增加N。通过对比主从之间的复制偏移量就可以知道主从服务器之间的同步状态。

ps:主从服务器复制偏移量相等说明处于一致状态,否则不一致。

2.4.2 复制积压缓冲区(replication backlog buffer)

复制积压缓冲区是master维护的一个固定长度的FIFO队列,默认大小1MB。

当master进行命令传播时,不仅将写命令发给slave服务器,还会同时写进复制积压缓冲区,因此master的复制积压缓冲区会保存一部分最近传播的写命令,并且会为每个队列中的每个字节记录相应的复制偏移量。

当slave服务器重新连上master服务器时,slave服务器会通过PSYNC命令将自己的复制偏移量发送给master服务器,master服务器会根据这个复制偏移量来决定对slave服务器执行哪个模式的同步操作:

  • 如果偏移量之后的数据(即offset+1开始的数据)仍然存在复制积压缓冲区里,那么就进行部分重同步操作。
  • 反之,只能执行完整重同步操作。

ps:如果master服务器需要执行大量的写命令,又或者主从服务器断线时间比较长,那么这个队列的大小(1MB)或许不合适。如果队列的大小不合适,那么也就一位置PSYNC命令就不能发挥正常的作用,所以,正确估算复制积压缓冲区的大小很重要。可根据公式: 2*(主从服务器断线时长second)*(master服务器每秒产生的写命令数据量)来估算。

2.4.3 服务器运行ID

每个Redis server都会有自己的运行ID,由40个随机的十六进制字符组成

当slave初次复制master时,matser会将自己的运行ID发给slave进行保存,这样slave重连时再将这个运行ID发送给重连上的master:

  • 如果slave服务器保存的ID和当前master服务器的ID相同,那么master可以继续尝试执行部分重同步操作。
  • 反之说明salve服务器断线之前复制的master服务器并不是当前连接的master服务器,master服务器将会对slave服务器进行完整重同步操作。

2.4.4 PSYNC命令的实现

了解了上述三个概念后,我们接着介绍PSYNC命令,PSYNC命令的调用方式有两种:

  • 如果slave服务器以前没有复制过任何master服务器或之前执行过slave no one命令,那么slave服务器会向master服务器发送PSYNC ? -1 命令,主动请求完整重同步。
  • 反之,如果slave服务器已经复制过某个master服务器,那么slave服务器会向master服务器发送PSYNC <runnid> <offset>命令:runnid为上次master服务器的运行id,offset为slave服务器的复制偏移量;接收到这个命令的master服务器会通过这两个参数来决定用哪种同步操作。

接收到命令的master服务器会返回的回复以下三种之一:

  • +FULLRESYNC <runnid> <offset>:表示执行完整重同步:runnid为master服务器的运行ID,offset为master服务器的复制偏移量。
  • +CONTINUE:表示执行部分重同步操作。
  • -ERR:表示master服务器的版本低于Redis 2.8,识别不了PSYNC命令,slave将向master服务器发送SYNC命令,执行完整同步操作。

大致流程如下:

PSYNC存在的问题:

通过上面的流程,我们可以看到,如果要执行部分重同步需要满足两个条件:runnid和offset,一旦两者不能同步满足,则仍需要进行完整重同步,例如以下场景:

  • slave重启,保存的master runnid和offset丢失,则需要进行完整重同步。
  • redis发生故障需要切换,切换后的runnid发生了变化,也需要完整重同步。

而上述两个场景出现的概率还挺高的,这么一来好像PSYNC命令的作用似乎并不完善了,好在Redis在4.0版本针对这个问题又进行了优化,下面我们一起来看下。

2.5 Redis 4.0版本起的新版复制(PSYNC2)

为了解决PSYNC命令执行部分重同步过分依赖runnid和offset的问题,Redis在4.0版本对PSYNC命令进行了优化,我们通常称之为PSCYN2,主要有两个改动:

  • 引入两组replid和offset:

  • 第一组:replid和master_repl_offset(可以理解为原来的runnid和offset

    • 对于master,分别表示为复制ID和复制偏移量

    • 对于slave,表示正在同步的master的复制ID和自己的复制偏移量。

  • 第二组:replid2和second_repl_offset

    • 对于master和slave,都表示自己的上一个master的复制ID和复制偏移量。主要用于故障切换时支持部分重同步。

  • slave开启复制积压缓冲区:

salve开启复制积压缓冲区,主要用于故障切换后,当某个slave升级为master,该slave仍然可以通过复制积压缓冲区继续支持部分重同步。

以上是改动,下面我们看下它对PSYNC命令的优化:

  • slave重启问题优化:

该问题的主要原因是slave重启后runnid和offset丢失了,解决也很简单,就是在重启之前把这两个变量想办法存下来就行。

而Redis的做法是:在服务正常关闭前会调用rdbSaveInfoAuxFields函数把当前的复制ID(replid)和复制偏移量(offset)保存到RDB文件中,后续就可以从RDB文件中读取到这两个变量。

  • master故障切换后问题优化:

该问题的主要原因是master故障切换后runnid会发生改变,从而导致执行完整重同步。

Redis的做法是:

当节点从slave晋升为master后,会将原来自己保存的第一组复制ID和复制偏移量,移动到第二组复制ID和复制偏移量,然后将第一组复制ID重新生成一个新的,也就是属于自己的复制ID。

相当于,slave晋升为master后,replid保存了自己的复制ID,replid2保存了老master的复制ID。

这样一来,新的master就可以通过判断replid2来判断slave之前是否跟自己是从同一个master复制数据,如果是的话,则尝试使用部分重同步。

流程如下:

2.6 总结

从Redis2.*到现在,主从复制流程进行了逐步的优化:

  • Redis 2.8之前复制采用SYNC命令,无论是第一次还是断线重连,都采用完整重同步方式,效率很低。
  • Redis 2.8~Redis 4.0版本之间采用PSYNC命令,主要优化了断线重连后可以通过runid和offset使用部分重同步,效率提高,但存在slave重启和master故障切换问题导致执行完整重同步的问题。
  • Redis 4.0版本之后对PSYNC命令进行了优化——PSYNC2,主要优化了PSYNC在slave重启和master故障切换后执行完整重同步的问题。

三、复制功能实现的八个步骤

这里以Redis 2.8版本为例,主从复制的完整过程如下:

3.1 开启主从复制

开启主从复制的方式主要有以下三种:

  • 在slave服务器直接执行命令:slaveof <masterip> <masterport>
  • 在slave配置文件中加入:slaveof <masterip> <masterport>
  • 使用启动命令:--slaveof <masterip> <masterport>

3.2 设置主服务器的地址和端口

当slave服务器执行命令后,slave服务器首先要做的是将master服务器的IP地址和端口号保存到服务器状态的masterhostmasterport属性里:

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

在完成ip和port的设置后,slave会向发送slaveof命令的客户端返回OK,表示复制指令已被接收,实际的复制工作在OK返回之后才真正开始执行

3.3 建立套接字连接

3.2执行完之后,slave将根据设置的ip地址和端口,创建连向master服务器的套接字(socket)连接。如果连接成功,slave服务器将为这个套接字(socket)关联一个专门处理复制工作的文件事件处理器,这个处理器负责执行后续的复制工作,比如接收RDB文件和master服务器传播来的写命令。

3.4 发送PING命令

建立套接字连接后,slave会向master发送一个PING命令,用来检查套接字的读写状态是否正常,master能否正常处理命令请求:

  • 如果slave收到“PONG”回复,则表示master和slave之间连接正常。
  • 反之,如果没回复或是其它回复,表示 master 和 slave 之间的网络连接状态不佳或者 master 暂时没办法处理 slave 的命令请求,则 slave 进入 error 流程:slave 断开当前的连接,之后再进行重试。

3.5 身份验证

slave服务器接收到master服务器返回的“PONG”回复后,下一步要做的就是决定是否进行身份验证,如果需要认证,slave服务器会向master服务器发送一条AUTH <password>(slave自己设置的密码)命令:

  • 如果master和slave都没有设置密码,则无需验证。
  • 如果都设置了密码,并且密码相同,则验证成功。
  • 如果都设置了密码但密码都不同或master和slave一个设置了密码一个没设置都会返回错误。从而使slave服务器进入error流程:slave断开当前连接,之后再进行重试

3.6 发送端口信息

在身份验证后,slave服务器将执行REPLCONF listening-port <port-number>命令,向master服务器发送slave服务器的端口号,master服务器收到后会将该端口号记录到slave服务器所对应的客户端状态的slave_listening_port属性中:

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

ps:slave_listening_port属性目前唯一的作用就是在主服务器执行INFO replication命令时打印出从服务器的端口号。

3.7 同步

在这一步,slave服务器会向master服务器发送PSYNC命令,执行同步操作,并将自己和master服务器的数据库状态更新至一致状态。

3.8 命令传播

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

在命令传播阶段,slave默认会以每秒一次的频率,向master发送命令:REPLCONF ACK <reploff>,其中reploff是slave当前的复制偏移量。

发送REPLCONF ACK命令对于主从服务器有三个作用:

  • 检测master和slave的网络连接状态。
  • 汇报自己的复制偏移量,检测命令丢失,master会对比复制偏移量,如果发现slave的复制偏移量小于自己,则会向slave发送未同步的数据。
  • 辅助实现min-slaves配置,用于防止master在不安全的情况下执行写命令。

例如redis.conf文件配置表示,当延迟时间小于10秒的 slave 数量小于3个,则会拒绝执行写命令。而这边的延迟时间,就是以 slave 最近一次发送 ACK 时间和当前时间作对比。

# 如果主节点连接的从节点数量少于 N 个,并且延迟小于等于 M 秒,则主节点可以停止接受写入。
# 这 N 个从节点需要处于“在线”状态。
# 延迟秒数必须小于等于指定值,是从上次接收从节点发送的 ping 命令开始计算的,通常每秒发送一次。
# 该选项并不保证 N 个副本将接受写入,但会限制暴露丢失写入的时间窗口,以指定的秒数为界。
# 例如,要求至少有 3 个延迟小于等于 10 秒的从节点,请使用:
# min-slaves-to-write 3
# min-slaves-max-lag 10

四、优缺点

4.1 优点

  • 提高系统的可靠性和容灾能力:通过将主服务器的数据复制到从服务器上,实现数据的备份和容灾,主服务器宕机时可以快速切换到从服务器,确保系统的稳定运行。

  • 读写分离:主从复制可以实现读写分离,主服务器负责处理写操作,从服务器负责处理读操作,有效分担服务器负载,提升系统的性能和并发能力。

  • 横向扩展:可以通过增加从服务器来实现横向扩展,提升系统的并发处理能力和数据存储容量。

  • 降低网络延迟:从服务器可以随时接手主服务器的工作,降低网络传输延迟,提升数据访问速度。

4.2 缺点

  • 网络传输开销:主从复制需要在主从服务器之间进行数据同步,会产生一定的网络传输开销,特别是在数据量较大的情况下,可能影响系统的性能。

  • 数据一致性问题:在网络异常或配置错误的情况下,可能导致主从数据不一致的问题,需要进行额外的监控和维护。

  • 复制延迟:由于主从复制是异步的,存在一定程度的复制延迟,从服务器的数据可能不是实时同步的,可能会影响数据的时效性。

  • 故障转移不是自动的:在没有使用Sentinel或Redis Cluster的情况下,发生故障时需要手动进行故障转移。

End:希望对大家有所帮助,如果有纰漏或者更好的想法,请您一定不要吝啬你的赐教🙋。

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

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

相关文章

Web自动化测试平台开发---Automated_platform

一、项目简介 历时一个假期&#xff0c;Automated_platform 第一版完工&#xff0c;是一款基于po模式的自动化测试平台,采用后端技术为DjangoceleryRabbitMQmysql 配置mysql数据库&#xff0c;进行数据迁移后&#xff0c;运行项目后&#xff0c;即可成功访问http://127.0.0.1:8…

单调栈的理解

单调栈的理解 核心代码场景思考 完整代码 单调栈&#xff1a; 单调递增或 单调递减的栈 核心代码 while (!s.empty()&&s.peek()<nums[i]){s.pop(); } s.push(nums[i]);将要放入的元素&#xff0c;与栈内元素依个比较&#xff0c;小于的都出栈&#xff0c;最后将要…

List 集合遍历过程中删除元素避坑指南。

文章目录 1. 遍历2. 遍历过程中删除元素2.1 for 简单循环正向遍历方式2.2 for 简单循环反向遍历方式2.3 foreach 方式遍历删除2.4 Iterator的remove()方法2.5 <font color green> removeIf() &#xff08;推荐&#xff09;<green>2.6 Strem 方式 作为一名后端开发…

Executable and Linkable Format(ELF)

File layout ELF文件有两种视图。程序头表&#xff08;Program Header&#xff09;显示在运行时使用的段&#xff08;Segments&#xff09;&#xff0c;而节头表&#xff08;Section Header&#xff09;则列出了二进制文件的所有节&#xff08;Sections&#xff09;的集合。程…

SCT2633STER:4.5V-60V Vin,3A,高效降压DCDC转换器

•宽输入范围&#xff1a;4.5V-60V •高达3A的连续输出电流 •1.221V1%反馈参考电压 •集成220mΩ高压侧MOSFET •低静态电流为300uA •轻负载下的脉冲跳过模式&#xff08;PSM&#xff09; •最小接通时间100ns •内置12ms软启动时间 •简易内部补偿 •固定频率500KH…

使用Docker搭建一款实用的个人IT工具箱——It-Tools

作为程序员&#xff0c;在日常工作中&#xff0c;需要借助一些工具来提高我们工作效率&#xff0c;IT-Tools是为开发人员度身打造的一套便捷在线工具。它提供全面功能&#xff0c;使开发者能以更高效方式完成任务。经由IT-Tools&#xff0c;开发人员能轻松应对各类技术挑战&…

怎么抠图把把人物扣下来?简单快捷的抠图方法

相信很多新手小白在初入设计行业时&#xff0c;对于抠图怎么把人物扣下来都是一头雾水。抠图作为设计中常用的一种技术&#xff0c;能够帮助我们快速提取图片中的某个部分&#xff0c;进行合成或者修改。对于老手来说&#xff0c;抠图或许是再熟悉不过的操作&#xff0c;但对于…

WPF中如何设置自定义控件

1.圆角按钮的设置&#xff1a; 众所周知在WPF中自带有提示信息&#xff0c;当我问创建Button时&#xff0c;点击空格出现如下可选设置 带有小扳手&#x1f527;图标为相应的属性&#xff0c;如果Button有CornerRadius&#xff08;角半径&#xff09;属性就能够直接设置Button实…

Unity中URP实现水体(整理优化)

文章目录 前言一、优化水的深度1、我们把 水流动的方向 和 水深浅过渡值&#xff0c;整合到一个四维变量中2、修改 水体流动方向3、在片元着色器中&#xff0c;修改使用过渡变量 二、优化泡沫三、优化水下的扭曲1、修复原本扰动UV的计算 四、优化水面高光1、把高光强度、光滑度…

如何用ai智能写作?推荐5款优秀的AI写作神器

写作是件繁琐的事情&#xff0c;也是需要耗费精力和时间的&#xff0c;还好目前有了ai写作神器的出现&#xff0c;帮助我们解决了不少的写作难题。这些AI写作工具不仅可以帮助我们提高写作效率&#xff0c;还能够生成高质量的内容。在本文中&#xff0c;我将向你推荐5款优秀的A…

MATLAB中strel函数用法

目录 语法 说明 任意邻域形状 二维几何邻域形状 三维几何邻域形状 示例 创建正方形结构元素 创建线形结构元素 创建盘形结构元素 创建三维球形结构元素 参数说明 属性 strel函数的功能是形态学结构元素。 语法 SE strel(nhood) SE strel("diamond",r…

BUUCTF AWD-Test1

打开靶场是这个有些简陋的界面。 随便点点&#xff0c;找到这个东西。 看到ThinkPHP&#xff0c;思路瞬间清晰&#xff0c;老熟人了。这个就是ThinkPHP漏洞。根据版本我们去找一下poc。 /index.php/?sIndex/\think\View/display&content%22%3C?%3E%3C?php%20phpinfo();…

Git工具Clone项目报错:OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054

目录 问题现象&#xff1a; 解决方法&#xff1a; 问题现象&#xff1a; 今天在项目中使用git工具clone远程库的项目地址时&#xff0c;遇到了如下报错&#xff0c;导致无法克隆项目代码到本地&#xff1a; OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054 解决方法&#…

【从Python基础到深度学习】9.Python 语法基础

一、常量与变量 常量:程序中使用的具体的数、字符。在运行过程中&#xff0c;值无法更改 变量:表示一一个存储单元&#xff0c;其中存储的值可以修改 如&#xff1a;a5,b6 变量命名: 1、只能包含字母、数字、下划线 2、只能以字母、下划线开头 3、不要使用关键字作为变量名称 …

浅谈mysql mvcc

目录 前言 mvcc 是如何工作的&#xff1f; 数据的更新 前言 mvcc 与一个事物的隔离级别有关&#xff0c;未提交读永远读的是当前值&#xff0c;串行化是通过加锁实现&#xff0c;这两种隔离级别都与mvcc 没有任何关系。只要一提到mvcc应该想到的是读提交以及可重复读&#…

【YOLO系列】YOLOv9论文超详细解读(翻译 +学习笔记)

前言 时隔一年&#xff0c;YOLOv8还没捂热&#xff0c;YOLO系列最新版本——YOLOv9 终于闪亮登场&#xff01; YOLOv9的一作和v7一样。v4也有他。 他于2017年获得台湾省National Central University计算机科学与信息工程博士学位&#xff0c;现在就职于该省Academia Sinica的…

vue3+ts+vite使用mock数据

安装以下命令 npm i vite-plugin-mock --save-dev npm i mockjs --save-dev 在根路径下创建mock文件夹 mock\user.ts const menuList [{path: /system,component: Layout,name: system,meta: {title: 系统管理,icon: Setting,roles: [sys:manage]},children: [{path: /depar…

曾桂华:车载座舱音频体验探究与思考| 演讲嘉宾公布

智能车载音频 I 分论坛将于3月27日同期举办&#xff01; 我们正站在一个前所未有的科技革新的交汇点上&#xff0c;重塑我们出行体验的变革正在悄然发生。当人工智能的磅礴力量与车载音频相交融&#xff0c;智慧、便捷与未来的探索之旅正式扬帆起航。 在驾驶的旅途中&#xff0…

卷积神经网络基本概念补充

卷积&#xff08;convolution&#xff09;、通道&#xff08;channel&#xff09; 卷积核大小一般为奇数&#xff0c;有中心像素点&#xff0c;便于定位卷积核。 步长&#xff08;stride&#xff09;、填充&#xff08;padding&#xff09; 卷积核移动的步长&#xff08;stride…

【Qt学习】QLCDNumber的介绍与实例使用(倒计时功能)

文章目录 1. 介绍2. 实例 - QLCDNumber倒计时3. 资源文件 1. 介绍 QLCDNumber是Qt框架中用于显示数字的控件&#xff0c;它模拟了一个液晶数字显示屏。 在Designer界面中显示如下&#xff1a; 有以下 常用属性&#xff1a; 属性描述intValue获取或设置QLCDNumber显示的整数…