草庐IT

MySQL四种日志binlog/redolog/relaylog/undolog

Java程序员进阶 2023-04-10 原文

优质博文:IT-BLOG-CN

一、binlog

binlog记录数据库表结构和表数据变更,比如update/delete/insert/truncate/create,它不会记录select。存储着每条变更的SQL语句和XID事务Id等等。binlog日志文件如下:

[root@192.168.10.11]# mysqlbinlog mysql-binlog.0000012
..........
# at 523
# 168654 20:22:43 server id 1 end_log_pos 843 Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=156521934/*!*/;
INSERT INTO student('name','age','sex') VALUES('ZZX',20,'1');  # 执行的SQL语句
/*!*/;
# at 669
#168654 20:22:45 server id 1 end_log_pos 876 Xid = 12              #执行的时间和事务ID

主要有两个作用:复制和恢复数据
【1】MySQL架构为了高可用性都是一主多从,从服务器需要与主服务器保持数据一致,这就是通过binlog进行复制;
【2】数据库的数据如果被误删,可以通过binlog数据进行恢复。

因为binlog记录了数据库表的逻辑变更,所以可以用binlog进行主从复制和恢复数据。

二、redo log

MySQL执行SQL修改语句时,肯定是先把这条记录查出来,然后再将这条进行进行修改。因为Mysql的基本存储结构是页,记录都存在页里边,所以MySQL是先把这条记录所在的页找到,然后把该页加载到内存中,将对应记录进行修改。现在就可能存在一个问题:如果在内存中把数据改了,还没来得及落磁盘,而此时的数据库挂了,导致这次修改丢失了怎么办?

如果每个请求都需要将数据立马同步到磁盘,那速度会很慢,MySQL可能也顶不住。所以MySQL引入了redo log,内存写完了,然后会写一份redo log,这份redo log记载着这次在某个页上做了什么修改

redo log的时候,也会有buffer,是先写buffer,再真正落到磁盘中的。至于从buffer什么时候落磁盘,会有配置供我们配置。

redo log也是需要写磁盘的,但它的好处就是顺序IO(我们都知道顺序IO比随机IO快非常多)。

所以,redo log的存在为了:当我们修改的时候,写完内存了,但数据还没真正写到磁盘的时候。此时我们的数据库挂了,我们可以根据redo log来对数据进行恢复。因为redo log是顺序IO,所以写入的速度很快,并且redo log记载的是物理变化(x页做了y修改),文件的体积很小,恢复速度很快。

三、binlog与redolog的区别

两个日志较为相似,这里总结下两者的主要区别:
【1】存储内容不同: binlog记载的是update/delete/insert这样的SQL语句,而redo log记载的是物理修改的内容(x页修改了y)。redo log记录的是数据的物理变化,binlog记录的是数据的逻辑变化。

【2】功能: redo log的作用是为持久化而生的。写完内存,如果数据库挂了,那我们可以通过redo log来恢复内存还没来得及刷到磁盘的数据,将redo log加载到内存里边,那内存就能恢复到挂掉之前的数据了。
binlog的作用是复制和恢复而生的。主从服务器需要保持数据的一致性,通过binlog来同步数据。如果整个数据库的数据都被删除了,binlog存储着所有的数据变更情况,那么可以通过binlog来对数据进行恢复。

如果整个数据库的数据都被删除了,那我可以用redo log的记录来恢复吗?
不能,因为功能的不同,redo log 存储的是物理数据的变更,如果我们内存的数据已经刷到了磁盘了,那redo log的数据就无效了。所以redo log不会存储着历史所有数据的变更,文件的内容会被覆盖的。

【3】写入细节不同: redo logMySQLInnoDB引擎所产生的。binlog无论MySQL任何引擎都会有的。
InnoDB是有事务的,事务的四大特性之一:持久性就是靠redo log来实现的(如果写入内存成功,但数据还没真正刷到磁盘,如果此时的数据库挂了,我们可以靠redo log来恢复内存的数据,这就实现了持久性)。

上面也提到,在修改的数据的时候,binlog会记载着变更的类容,redo log也会记载着变更的内容。(只不过一个存储的是物理变化,一个存储的是逻辑变化)。那他们的写入顺序是什么样的呢?

redo log事务开始的时候,就开始记录每次的变更信息,而binlog是在事务提交的时候才记录。

于是新有的问题又出现了:我写其中的某一个log,失败了,那会怎么办?现在我们的前提是先写redo log,再写binlog,我们来看看:
  ■ 如果写redo log失败了,那我们就认为这次事务有问题,回滚,不再写binlog
  ■ 如果写redo log成功了,写binlog,写binlog写一半了,但失败了怎么办?我们还是会对这次的事务回滚,将无效的binlog给删除(因为binlog会影响从库的数据,所以需要做删除操作)
  ■ 如果写redo logbinlog都成功了,那这次算是事务才会真正成功。

简单来说:MySQL需要保证redo logbinlog的数据是一致的,如果不一致,那就乱套了。
  ■ 如果redo log写失败了,而binlog写成功了。那假设内存的数据还没来得及落磁盘,机器就挂掉了。那主从服务器的数据就不一致了。(从服务器通过binlog得到最新的数据,而主服务器由于redo log没有记载,没法恢复数据)
  ■ 如果redo log写成功了,而binlog写失败了。那从服务器就拿不到最新的数据了。

MySQL通过两阶段提交来保证redo logbinlog的数据是一致的。

阶段1:InnoDB redo log写盘,InnoDB事务进入prepare状态
阶段2:binlog写盘,InooDB事务进入commit状态

每个事务binlog的末尾,会记录一个XID event,标志着事务是否提交成功,也就是说,恢复过程中,binlog最后一个XID event之后的内容都应该被purge

如果binlog没有正常关闭,mysql server可能crash过,我们需要调用MYSQL_BIN_LOG::recover:找到最后一个XID完成最后一次事务的两阶段提交InnoDB commit。因此,需要遍历binlog文件,找到最后一个合法event集合,并purge无效binlog

四、relay-log

从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后从服务器SQL线程会读取relay-log日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致

show variables like '%relay%';
 
#结果
+---------------------------+----------------------------------+
| Variable_name             | Value                            |
+---------------------------+----------------------------------+
| max_relay_log_size        | 0                                |
| relay_log                 | relay-mysql                      |
| relay_log_basename        | /var/lib/mysql/relay-mysql       |
| relay_log_index           | /var/lib/mysql/relay-mysql.index |
| relay_log_info_file       | relay-log.info                   |
| relay_log_info_repository | FILE                             |
| relay_log_purge           | ON                               |
| relay_log_recovery        | ON                               |
| relay_log_space_limit     | 0                                |
| sync_relay_log            | 10000                            |
| sync_relay_log_info       | 10000                            |
+---------------------------+----------------------------------+

max_relay_log_sizerelay log允许的最大值,如果该值为0,则默认值为max_binlog_size (1G)。如果不为0,则max_relay_log_size则为最大的relay_log文件大小;

relay_log: 定义relay_log的位置和名称,如果值为空,则默认位置在数据文件的目录;

relay_log_index:定义relay_log索引的位置和名称,记录有几个relay_log文件,默认为2

cat /var/lib/mysql/relay-mysql.index
 
#结果
./relay-mysql.000241
./relay-mysql.000242

relay_log_info_file:定义relay-log.info的位置和名称。relay-log.info记录master主库的binary_log的恢复位置和从库relay_log的位置;

[root@localhost ~]# cat /var/lib/mysql/relay-log.info
 
#结果
7
./relay-mysql.000242
19421766
mysql-bin.000094
34300252
0
0
1

relay_log_purge:是否自动清空中继日志,默认值为1(启用);

relay_log_recovery
slave从库宕机后,假如relay-log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay-log,并且重新从master上获取日志,这样就保证了relay-log的完整性。默认情况下该功能是关闭的,将relay_log_recovery的值设置为1时,可在slave从库上开启该功能,建议开启;

sync_relay_log:当设置为1时,slaveI/O线程每次接收到master发送过来的binlog日志都要写入系统缓冲区,然后刷入relay log中继日志里,这样是最安全的,因为在崩溃的时候,你最多会丢失一个事务,但会造成磁盘的大量I/O。当设置为0时,并不是马上就刷入中继日志里,而是由操作系统决定何时来写入,虽然安全性降低了,但减少了大量的磁盘I/O操作。这个值默认是0,可动态修改;

sync_relay_log_info:这个参数和sync_relay_log参数一样。

五、undo log

undo log主要有两个作用:回滚和多版本控制MVCC

在数据修改的时候,不仅记录了redo log,还记录undo log,如果因为某些原因导致事务失败或回滚了,可以用undo log进行回滚

undo log主要存储的也是逻辑日志,比如我们要insert一条数据了,那undo log会记录的一条对应的delete日志。我们要update一条记录时,它会记录一条对应相反的update记录。

这也应该容易理解,毕竟回滚嘛,跟需要修改的操作相反就好,这样就能达到回滚的目的。因为支持回滚操作,所以我们就能保证:“一个事务包含多个操作,这些操作要么全部执行,要么全都不执行”。【原子性】

因为undo log存储着修改之前的数据,相当于一个前版本,MVCC实现的是读写不阻塞,读的时候只要返回前一个版本的数据就行了。

有关MySQL四种日志binlog/redolog/relaylog/undolog的更多相关文章

  1. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  2. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  3. ruby - Sinatra 中的全局救援和日志记录异常 - 2

    如何在出现异常时指定全局救援,如果您将Sinatra用于API或应用程序,您将如何处理日志记录? 最佳答案 404可以在not_found方法的帮助下处理,例如:not_founddo'Sitedoesnotexist.'end500s可以通过调用带有block的错误方法来处理,例如:errordo"Applicationerror.Plstrylater."end错误的详细信息可以通过request.env中的sinatra.error访问,如下所示:errordo'Anerroroccured:'+request.env['si

  4. ruby - 如何使用 ruby​​ mysql2 执行事务 - 2

    我已经开始使用mysql2gem。我试图弄清楚一些基本的事情——其中之一是如何明确地执行事务(对于批处理操作,比如多个INSERT/UPDATE查询)。在旧的ruby-mysql中,这是我的方法:client=Mysql.real_connect(...)inserts=["INSERTINTO...","UPDATE..WHEREid=..",#etc]client.autocommit(false)inserts.eachdo|ins|beginclient.query(ins)rescue#handleerrorsorabortentirelyendendclient.commi

  5. ruby-on-rails - 使用 Ruby 标准 Logger 每天只创建一个日志 - 2

    我正在使用ruby​​标准记录器,我想要每天轮换一次,所以在我的代码中我有:Logger.new("#{$ROOT_PATH}/log/errors.log",'daily')它运行完美,但它创建了两个文件errors.log.20130217和errors.log.20130217.1。如何强制它每天只创建一个文件? 最佳答案 您的代码对于长时间运行的应用程序是正确的。发生的事情是您在给定的一天多次运行代码。第一次运行时,Ruby会创建一个日志文件“errors.log”。当日期改变时,Ruby将文件重命名为“errors.log

  6. ruby - Cucumber/Savon 省略或删除日志输出 - 2

    在运行Cucumber测试时,我得到(除了测试结果)大量调试/日志相关的输出形式:D,[2013-03-06T12:21:38.911829#49031]DEBUG--:SOAPrequest:D,[2013-03-06T12:21:38.911919#49031]DEBUG--:Pragma:no-cache,SOAPAction:"",Content-Type:text/xml;charset=UTF-8,Content-Length:1592W,[2013-03-06T12:21:38.912360#49031]WARN--:HTTPIexecutesHTTPPOSTusingt

  7. ruby-on-rails - faraday如何设置日志级别 - 2

    我最近将我的http客户端切换到faraday,一切都按预期工作。我有以下代码来创建连接:@connection=Faraday.new(:url=>base_url)do|faraday|faraday.useCustim::Middlewarefaraday.request:url_encoded#form-encodePOSTparamsfaraday.request:jsonfaraday.response:json,:content_type=>/\bjson$/faraday.response:loggerfaraday.adapterFaraday.default_ada

  8. 网站日志分析软件--让网站日志分析工作变得更简单 - 2

    网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.

  9. ruby-on-rails - 当我通过 rvm 使用 rails3 时,如何在 ubuntu 上安装 mysql2 gem? - 2

    我正在尝试绕过rails配置这个极其复杂的迷宫。到目前为止,我设法在ubuntu上设置了rvm(出于某种原因,ruby在ubuntu存储库中已经过时了)。我设法建立了一个Rails项目。我希望我的测试项目使用mysql而不是mysqlite。当我尝试“rakedb:migrate”时,出现错误:“!!!缺少mysql2gem。将其添加到您的Gemfile:gem'mysql2'”当我尝试“geminstallmysql”时,出现错误,告诉我需要为安装命令提供参数。但是,参数列表很大,我不知道该选择哪些。如何通过在ubuntu上运行的rvm和mysql获取rails3?谢谢。

  10. ruby - 如何更改 Sinatra 中的日志级别 - 2

    我正在使用此代码在我的Sinatra应用程序中启用日志记录:log_file=File.new('my_log_file.log',"a")$stdout.reopen(log_file)$stderr.reopen(log_file)$stdout.sync=true$stderr.sync=true实际的日志记录是使用:logger.debug("Startingcall.Params=#{params.inspect}")事实证明,只有INFO或更高级别的日志消息被记录,而DEBUG消息没有被记录。我正在寻找一种将日志级别设置为DEBUG的方法。 最佳

随机推荐