Canal+Otter

Wesley13
• 阅读 561

数据库同步中间件Canal+Otter - 前日篇(2)

MySQL+InnoDB架构体系

Canal+Otter
MySQL体系前端接受连接,并提供多种API,连接池化可重用。这里连接可以理解为线程,来处理来自客户端的请求。后台存储引擎负责控制IO策略,内存缓冲和线程调度,以及会话事务管理。
我们这里分析在MySQL5.6以后的默认引擎InnoDB。

InnoDB引擎结构:

Canal+Otter

1. 内存:

innoDB 将数据库文件按页读取到内存,按照最少使用算法。来保留数据。修改数据时,先修改的是缓冲中的页(脏页),之后按照一定频率将脏页刷新到文件。
缓冲池缓存的数据页类型有:索引页,数据页,undo页,插入缓冲,自适应哈希索引,InnoDB存储的锁信息和数据字典信息等。
日志缓冲池将重做日志信息先放入这个缓冲区,然后按一定频率将其刷新到日志文件,因此我们只要保证每秒产生的事务量不超过这个缓冲大小即可。
**额外内存池:**innodb申请缓冲池(buffer pool),但每个缓冲池中的页缓冲有对应的缓冲控制对象(buffer control block),这些对象记录LRU、锁、等待等信息,这些对象的内存需要多额外内存池中申请;因此当buffer pool较大时,也需相应增大该值
**线程缓冲:**MySQL数据库支持线程缓存,在多线程连接模式下,如果连接断开后,将这个线程放入空闲线程缓冲区,在下次有连接到来时,先去缓冲池中查找是否有空闲线程,有则用之,无则创建。
查询缓冲:查询缓冲的作用就是当查询接收到一个和之前同样的查询,服务器将会从查询缓冲中检索结果,而不是再次分析和执行上次的查询。这样就大大提高了性能,节省时间。
插入缓冲:插入时检查缓冲中对应索引页是否存在,若不存在则载入,并写入。这样可以把几个在同一个缓冲页上的插入操作放入一次IO中

2.后台线程

2.1 io thread:

read thread:读线程,默认个数为4
write thread:写线程,默认个数为4
insert buffer thread:插入缓冲线程
log thread:日志线程

2.2 master thread:

  • 主循环:
    • 每秒一次的操作:日志缓冲刷新到磁盘,即使这个事务未提交(总是);合并插入缓冲(可能),会根据前一秒内的io次数判断,如果小于5次,可以执行合并插入缓冲;至多刷新100个脏页至磁盘(可能),通过判断脏页比例是否超过了innodb_max_dirty_pages_pct这个设置值来进行,未超过则不执行;无用户活动,切换到background loop(可能);
    • 每10秒一次的操作:刷新100个脏页到磁盘(可能),如果过去10秒磁盘io操作小于200次,则执行本操作;合并至多5个插入缓冲(总是);日志缓冲刷新到磁盘(总是);删除无用的undo页(总是);刷新100个或10个脏页到磁盘(总是),判断缓冲池脏页比例,超过70%则刷新100个脏页,比例小于10%则刷新10个脏页;产生一个检查点checkpoint(总是),注意此时并不是把所有脏页都刷新到了磁盘,只是将最老日志序列号的页写入磁盘;
  • 后台循环 background loop:
    • 删除无用的undo页(总是);
      合并20个插入缓冲(总是);
      跳回到主循环(总是);
      不断刷新100个页,直到符合条件(可能,跳转到flush loop中完成);
  • flush loop:由background loop跳转到此loop中完成刷新脏页的工作;当flush loop中无事可做时会切换到suspend loop;
  • suspend loop: 该loop将master thread挂起,等待事件发生;

MySQL binlog原理:

MySQL有四种log:

  • Error Log:记录 mysqld 的一些错误
  • General Query Log:一般查询日志,记录 mysqld 正在做的事情,比如客户端的连接和断开、来自客户端每条 Sql Statement 记录信息;如果你想准确知道客户端到底传了玩意儿给服务端,这个日志就非常管用了,不过它非常影响性能。
  • Slow Query Log:记录一些查询比较慢的 SQL 语句——这种日志非常常用,主要是给开发者调优用的
  • Binary Log:包含了一些事件,这些事件描述了数据库的改动,如建表、数据改动等。
    • 两个重要的用途——复制和恢复。比如主从表的复制,和备份恢复什么的。
      Canal+Otter
      由于innoDB处理更新是在脏页中,而且脏页是存在于内存中,如果断电,则会丢失。为了防止这个问题,引入了redo log:将每次的页面修改存入redo log中。由于写入redo log近似于顺序读写,相比于直接刷入磁盘的随机读写快了很多。每次写redo log都要更新文件头的两个checkpoint值,所以为近似顺序读写。由于master thread每秒都会将log缓存刷入,所以我们可以认为log的记录一定比数据库的更新一些。异常断电重启时,mysql会根据checkpoint检查redo log来做恢复。
      不管你将二进制日志文件记录的格式设为哪一种,其记录的都是关于一个事务的具体操作内容,而InnoDB存储引擎的重做日志文件记录的关于每个页的更改的物理情况。
      在一个AB复制环境下主库crash,然后进行crash recovery,此时如果binlog里面的的事务信息与redo log里面的信息不一致,那么就会出现主库利用redo log进行恢复后,然后binlog部分的内容复制到从库去,然后出现主从数据不一致状态。所以需要保证binlog与redo log两者事务一致性。
      所以,为保证一致性,记录二进制日志过程中:
  • 取得全局锁(为保证全局事务顺序一致性),然后写redo log
  • 如果成功,继续写binlog
  • 如果成功,最后在redo log加上commit
  • 以上任一失败都将回滚重做
  • 释放全局锁

Binlog文件:

  • 文件头
    • 四字节 Magic Number,用来识别是正常的binlog文件
  • 事件
    • 在文件头之后,跟随的是一个一个事件依次排列。每个事件都由一个事件头和事件体组成(事实上在 Binlog 事件中应该是有三个部分组成,header、post-header 和 payload,不过通常情况下我们把 post-header 和 payload 都归结为事件体,实际上这个 post-header 里面放的是一些定长的数据,只不过有时候我们不需要特别地关心。想要深入了解可以去查看 MySQL 的官方文档。)。
    • 事件头里面的内容包含了这个事件的类型(如新增、删除等)、事件执行时间以及是哪个服务器执行的事件等信息。
      • timestamp 4 bytes四字节的时间戳
      • type code 1 byte一字节的当前事件类型
      • server_id 4 bytes四字节的服务端ID
      • event_length 4 bytes四字节的当前事件长度描述
      • next_position 4 bytes四字节的下个事件位置
      • flags 2 bytes 标识(可以标识binlog是否正常关闭)
    • 第一个事件是一个格式描述事件,描述了这个 Binlog 文件格式的版本。接下去的一堆事件将会按照第一个事件描述符所描述的结构版本进行解读。最后一个事件是一个衔接事件,指定了下一个 Binlog 文件名

Binlog格式:

  • ROW:日志中会记录成每一行数据被修改的形式
    优点:在row模式下,bin-log中可以不记录执行的sql语句的上下文相关的信息,仅仅只需要记录那一条记录被修改了,修改成什么样了,所以row的日志内容会非常清楚的记录下每一行数据修改的细节,非常容易理解。而且不会出现某些特定情况下的存储过程和function,以及trigger的调用和出发无法被正确复制问题。
    缺点:在row模式下,所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容。
  • STATEMENT:每一条会修改数据的sql都会记录。
  • MiXED:在 Mixed 模式下,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式,也就是在 statement 和 row 之间选择一种。新版本中的 statment 还是和以前一样,仅仅记录执行的语句。而新版本的 MySQL 中对 row 模式也被做了优化,并不是所有的修改都会以 row 模式来记录,比如遇到表结构变更的时候就会以 statement 模式来记录,如果 SQL 语句确实就是 update 或者 delete 等修改数据的语句,那么还是会记录所有行的变更。
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这