我对诸如刷新和写入磁盘以及同步到磁盘之类的术语感到困惑。有人能解释一下刷新和写入以及同步到磁盘之间的区别吗,特别是在 MySQL 环境中。
我过去认为它们是相同的操作,但是在阅读各种概念时我感到困惑。
例如。文档中说,对于rpl_semi_sync_source_wait_point变量,如果我将其设置为AFTER_SYNC,则源会先将事务写入 bin 日志和副本,然后将 binlog 同步到磁盘。
AFTER_SYNC (the default): The source writes each transaction to its binary log and the replica, and syncs the binary log to disk.
这句话本身就令人困惑。它先是说source writes each transaction to its binary log and the replica
,然后又说syncs the binary log to disk.
那么在这种情况下究竟发生了什么。在 MySQL 上下文中,刷新、同步和写入磁盘究竟是什么?问题不在于 sync_binlog 或 MySQL 中的任何其他参数。问题在于刷新、同步和写入,以及这些活动何时发生?
当我再次尝试阅读更多内容时,在以下链接中,它解释说,有一个 binlog 缓存、一个页面缓存和一个 fsync 操作。因此,如果我理解正确的话,当发生事务时,缓冲区会变脏,事务的内容将写入 binlog 缓存(在 MySQL 级别),这是每个会话的单独缓存,然后 binlog 缓存将写入页面缓存(在 Linux 级别),然后根据sync_binlog
值,将其刷新/写入/同步到磁盘上的文件。
https://betterprogramming.pub/understanding-mysqls-binlog-4ac8de4d20ee
这是一个复杂的话题,但让我们试着稍微讨论一下。当涉及到“常规”写入(插入、更新、删除)时,过程如下(为了清楚起见,我不会阐明所有细节,例如双写缓冲区等)。
应用程序执行一些查询。修改后的行作为脏页存储在缓冲池中
更改写入重做日志(InnoDB 重做日志)
如果启用了二进制日志,更改也会存储在二进制日志中
然后,根据
sync_binlog
设置(1),每次写入之后,在 COMMIT 发生之前,binlog 可能会同步(持久化、刷新)到磁盘。提交发生
取决于
innodb_flush_logs_at_trx_commit
重做日志:a. 在 COMMIT 时刷新(同步)到磁盘(1) b. 在 COMMIT 时写入磁盘但 1 秒后刷新(2) c. 写入磁盘并在 1 秒后刷新(0)
稍后,在某个时间点,InnoDB 缓冲池中的数据被写入表空间并最终保存在那里(清除缓冲池中的脏页)
现在,写入和刷新(同步)之间有什么区别?写入就是写入。MySQL 写入文件。然后它进入操作系统文件系统缓存并保留在内存中。因此,写入不是持久的。它们最终会持久(每个操作系统最终都会将其写入文件本身),但不会立即持久。这是更快的写入,因为它缓存在内存中。然后我们将数据同步到磁盘。在这种情况下,MySQL 将尝试强制将写入持久化在磁盘上。它如何做到这一点是在
innodb_flush_method
变量中定义的,在大多数 Linux 发行版上默认为 O_DIRECT + fsync()。在这种情况下,写入会绕过操作系统文件系统缓冲区并直接在磁盘驱动器上执行。或者至少 MySQL 是这么认为的。实际上,您还必须考虑操作系统、磁盘存储甚至磁盘驱动器本身的配置。如果您有 SAN 或某种 RAID 控制器,则刷新写入很可能不会保留在磁盘上,而是保留在 SAN 或 RAID 控制器缓存中。甚至磁盘本身也可能“伪造”刷新数据并将其存储在其写入缓冲区中。
就您的示例而言,如果您有,
sync_binlog=1
那么任何其他缓存都无关紧要。每次写入后都会保留 Binlog。如果您有,sync_binlog=N
那么 MySQL 可能会在将 N 次写入保留到磁盘之前将其缓存在 Binlog 缓存中。至于
rpl_semi_sync_source_wait_point
,它定义了源节点何时等待半同步副本的 ACK。在应用程序端,它如下所示:开始
执行查询
犯罪
区别在于第 3 点。如果是
AFTER_SYNC
,则 COMMIT 仅在副本确认数据存储在副本上后才执行,确保无论您在主服务器上使用什么连接读取数据,您都会看到相同的内容。如果是 ,则AFTER_COMMIT
COMMIT 将在数据仍在副本上持久保存时执行。这意味着如果您使用另一个连接连接到主服务器,您将看到已提交的数据,即使提交数据的客户端仍在副本上等待确认他们已收到数据。