MySQL属于什么架构_MySQL整体架构是什么样?点开这里告诉你!

MySQL 在整体架构上分为 Server 层和存储引擎层。其中 Server 层,包括连接器、查询缓存、分析器、优化器、执行器等,存储过程、触发器、视图和内置函数都在这层实现。数据引擎层负责数据的存储和提取,如 InnoDB、MyISAM、Memory 等引擎。在客户端连接到 Server 层后,Server 会调用数据引擎提供的接口,进行数据的变更。

sgs_tc_news.php?req=ebTFhIqCfka-iMUBYjR5vQ44ryygXdMWXdBGce1uzME=

连接器

负责和客户端建立连接,获取用户权限以及维持和管理连接。

通过 show processlist; 来查询连接的状态。在用户建立连接后,即使管理员改变连接用户的权限,也不会影响到已连接的用户。默认连接时长为 8 小时,超过时间后将会被断开。

简单说下长连接:优势:在连接时间内,客户端一直使用同一连接,避免多次连接的资源消耗。劣势:在 MySQL 执行时,使用的内存被连接对象管理,由于长时间没有被释放,会导致系统内存溢出,被系统kill. 所以需要定期断开长连接,或执行大查询后,断开连接。MySQL 5.7 后,可以通过 mysql_rest_connection 初始化连接资源,不需要重连或者做权限验证。

查询缓存

当接受到查询请求时,会现在查询缓存中查询(key/value保存),是否执行过。没有的话,再走正常的执行流程。

但在实际情况下,查询缓存一般没有必要设置。因为在查询涉及到的表被更新时,缓存就会被清空。所以适用于静态表。在 MySQL8.0 后,查询缓存被废除。

分析器

1. 词法分析

如识别 select,表名,列名,判断其是否存在等。

2. 语法分析

判断语句是否符合 MySQL 语法。

优化器

确定索引的使用,join 表的连接顺序等,选择最优化的方案。

执行器

在具体执行语句前,会先进行权限的检查,通过后使用数据引擎提供的接口,进行查询。如果设置了慢查询,会在对应日志中看到 rows_examined 来表示扫描的行数。在一些场景下(索引),执行器调用一次,但在数据引擎中扫描了多行,所以引擎扫描的行数和 rows_examined 并不完全相同。

不预先检查权限的原因:如像触发器等情况,需要在执行器阶段才能确定权限,在优化器阶段无法验证。

MySQL 日志模块

如前面所说,MySQL 整体分为 Server 层和数据引擎层,而每层也对应了自己的日志文件。如果选用的是 InnoDB 引擎,对应的是 redo log 文件。Server 层则对应了 binlog 文件。至于为什么存在了两种日志系统,咱们往下看。

1. redo log

redo log 是 InnoDB 特有日志,为什么要引入 redo log 呢,想象这样一个场景,MySQL 为了保证持久性是需要把数据写入磁盘文件的。我们知道,在写入磁盘时,会进行文件的 IO,查找操作,如果每次更新操作都这样的话,整体的效率就会特别低,根本没法使用。

既然直接写入磁盘不行,解决方法就是先写进内存,在系统空闲时再更新到磁盘就可以了。但光更新内存不行,假如系统出现异常宕机和重启,内存中没有被写入磁盘的数据就会被丢掉,数据的一致性就出现问题了。这时 redo log 就发挥了作用,在更新操作发生时,InnoDb 会先写入 redo log 日志(记录了数据发生了怎么样的改变),然后更新内存,最后在适当的时间再写入磁盘。先写日志,在写磁盘的操作,就是常说到的 WAL (Write-Ahead- Logging)技术。

redo log 的出现,除了在效率上有了很大的改善,还保证了 MySQL 具有了 crash-safe 的能力,在发生异常情况下,不会丢失数据。

在具体实现上 redo log 的大小是固定的,可配置一组为 4 个文件,每个文件 1GB,更新时对四个文件进行循环写入。

sgs_tc_news.php?req=ebTFhIqCfka-iMUBYjR5vQ44ryygXdMWXdBGce1uzME=

write pos 记录当前写入的位置,写完就后移,当第写入第 4 个文件的末尾时,从第 0 号位置重新写入。

check point 表示当前可以擦除的位置,当数据更新到磁盘时,check point 就向后移动。

write pos 和 check point 之间的位置,就是可以记录更新操作的空间。当 write pos 追上 check point ,不在能执行新的操作,先让 check point 去写入一些数据。

可以将 innodb_flush_log_at_trx_commit 设置成 1,开启 redo log 持久化的能力。

2. binlog

binlog 则是 Server 层的日志,主要用于归档,在备份,主备同步,恢复数据时发挥作用,常见的日志格式有row, mixed, statement三种。

可以通过 sync_binlog=1 开启 binlog 写入磁盘。

这里对 binlog 和 redo 进行下区分:所有者不同,binlog 是 Server 层,所有引擎都可使用。redo log 是 InnoDB 特有的。

类型不同,binlog 是逻辑日志,记录的是语句的原始逻辑(比 statement)。redo log 是物理日志,记录某个数据页被做了怎样的修改。

数据写入的方式不同,binog 日志会一直追加,而 redo log 是循环写入。

功能不同,binlog 用于归档,而 redo log 用于保证 crash-safe

3. 两阶段提交

一条更新语句,在 InnoDB 引擎下的更新过程如下。在更新内存后,将写入 redolog 和写入 binlog 放在一起成为一个事务最后一起写入 redo log 和 binlog 的过程就是常说的两阶段提交。用于保证当有意外情况发生时,数据的一致性。

sgs_tc_news.php?req=ebTFhIqCfka-iMUBYjR5vQ44ryygXdMWXdBGce1uzME=

这里假设下,如果不采用两阶段提交会发生什么?先写 redo log 后写 binlog,设在写入 redo log 后,MySQL 发生异常重启,此时 binlog 没有写入。在重启后,由于 redolog 已经写入,此时数据库的内容是没有问题的。但此时,如果想要拿 binlog 进行备份或恢复,发现会少了最后一条的更新逻辑,导致数据不一致。先写 binlog 和 redo log. binlog 写入后,MySQL 异常重启,redo log 没有写入。此时重启后,发现 redo log 没有成功写入,任务这个事务无效,而此时 binlog 却多了一条更新语句,拿去恢复后自然数据也是不一致的。

再分析下两阶段提交的过程:在写 redo log prepare阶段奔溃,重启后,发现 redo log 没写入,发现此次事务。

如果在写 binlog 时奔溃,重启后,发现 binlog 未被写入,回滚操作

如果在写入 redo log 和 binlog 后崩溃,重启后,发现没提交,则进行 commit

总结

在文章开始部分,说明了 MySQL 的整体架构分为 Server 层和引擎层,并简要说明了一条语句的执行过程。接着 MySQL 在 5.5 后选用 InnoDB 作为默认的引擎,就是因为比原生的 MyISAM 多了事务以及 crash-safe 的能力。

而 crash-safe 就是由 redo log 实现的。与 redo log 类似的日志文件还有 binlog,是 Server 引擎的日志,用于归档和备份数据。

最后提到了,为了保证数据的一致性,将 redo log 和 binlog 放入相同的事务中,也就是常提到的两阶段提交操作。

PS:部分信息来源于网站,如有侵权请与我们联系删除

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
yog-log 是 Node Log 统计方案,是yog框架的log统计模块,支持中间件或者单独使用等方式,兼容ODP日志格式与配置。关于ODP的日志方案调研可查看此文档. 统计日志类型包括: server日志 access_log: web访问日志,按小时分日志 error_log: web错误日志,按小时分日志 访问日志统计方式为请求返还才触发。 应用日志 每个app有各自独立的日志,日志名为app的名称,例如demo.log和demo.log.wf。 可配置每个app是否使用独立的子目录存放自身日志,例如demo/demo.log。 可配置每个app是否按小时切分日志。 可配置每个app的日志级别。 对于不属于任何app的node.js程序,日志名为unknown.log。 快速开始 1 在yog的config.json中添加此配置   "yogLogger": {             "enabled": true,             "priority": 50,             "module": {                 "name": "yog-log",                 "arguments": [                     {                         "level" : 16, //线上一般填4,参见配置项说明                         "app": "app_name", //app名称,产品线或项目名称等                         "log_path": "path:./data/log"//日志存放地址                     }              ]       }  } 填写此配置之后yog-log就开始统计访问日志。 2 调用接口统计应用日志 router层统计日志 router层推荐使用emit方式触发log事件,避免在每个文件中都require yog-log try{     //do something }catch(e){     res.emit('log',{'stack':e,'errno':120,'msg' :'error happened!'}, 'warning'); //推荐方式     //or res.emit('log',{'stack':e});//日志等级不写默认为notice     //or res.emit('log','error!');//只写字符串不会解析错误堆栈 } model等没有res的地方 使用getLogger方法获取到日志模块实例,然后调用接口统计日志。 var YLogger = require('yog-log'); var logger = YLogger.getLogger();  //默认通过domain获取,单独使用请传递 configlogger.log('warning','msg'); //or logger.warning('msg'); 日志初始化配置项 配置项均有默认值,理论上不需要配置也能工作。推荐设置配置有:level、app、log_path 三项。 配置项 默认值 说明 app unknown app名称,推荐填写 format 见下 默认应用日志格式 format_wf 见下 默认的应用日志warning及fatal日志格式 level 16 log日志级别,高于此级别的日志不会输出 auto_rotate 1 是否自动切分 use_sub_dir 1 日志是否在二级目录打印,目录名为 APP_NAME log_path 插件安装地址/log 日志存放目录,注意需要设置 data_path 插件安装地址/data 格式数据存放的目录,可不用设置 is_omp 0 是否开启omp日志,如果不接入omp,建议置为2 debug 0 是否开启omp日志,如果不接入omp,建议置为2 默认`format`: %L: %t [%f:%N] errno[%E] logId[%l] uri[%U] user[%u] refer[%{referer}i] cookie[%{cookie}i] %S %M 默认的`format_wf `: %L: %{%m-%d %H:%M:%S}t %{app}x * %{pid}x [logid=%l filename=%f lineno=%N errno=%{err_no}x %{encoded_str_array}x errmsg=%{u_err_msg}x] 应用日志等级 日志等级 数据编号 统计说明 FATAL 1 打印FATAL WARNING 2 打印FATAL和WARNING NOTICE 4 打印FATAL、WARNING、NOTICE(线上程序正常运行时的配置) TRACE 8 打印FATAL、WARNING、NOTICE、TRACE(线上程序异常时使用该配置) DEBUG 16 打印FATAL、WARNING、NOTICE、TRACE、DEBUG(测试环境配 response.emit(name,obj,level) 在router层使用emit方式可以避免每个文件都引入logger和获取实例。参数说明: name :日志事件名称,固定为'log' obj: string或者object格式。如果是string,认为是错误消息。如果是object,请认为是详细信息。正确格式为{'stack':e,'msg':'msg','errno':'010'},分别代表错误堆栈、错误消息、错误码。错误消息如果不填将使用错误堆栈的消息。 level : 日志等级字符串,见上。不区分大小写,不写默认为notice 如下所示: res.emit('log',{'stack':e,'errno':120,'msg' :'error happened!'},'warning'); getLogger(config) 当框架接收请求时,yog-log会新建一个实例,并保存到domain中,确保单次请求流程中调用的getLogger获取到的是同一个实例。 如果单独使用log不经过请求, getLogger会新建一个实例,此时应当传递config配置参数。 log(level,obj) 提供统一的log方法打印日志。参数说明同response.emit。另外针对各个应用日志等级提供了相对应的方法。 请确保使用快捷方法时名称准确,否则程序将报错。 fatal   :  logger.fata(obj) warning : logger.warning(obj) notice : logger.notice(obj) trace : logger.trace(obj) debug : logger.debug(obj) 注意 : logger为通过getLogger获取到的日志模块实例 。 自定义错误消息 如果想在日志中填写自定义的日志字段用于追查错误,请在obj中加入custom对象,然后按照键值对应放在custom中。如下所示:  //router层  res.emit('log',{    'stack':e, //错误堆栈    'errno':120,  //错误码    'msg' :'error happened!',  //错误消息    'custom':{'key1' :'value1','key2':'value2'} //自定义消息  });   //其他地方  logger.log('warning', {    'stack':e, //错误堆栈    'errno':120,  //错误码    'msg' :'error happened!',  //错误消息    'custom':{'key1' :'value1','key2':'value2'} //自定义消息  }); 注意custom字段默认只会在warning和fatal日志中展现 生成的错误日志将会类似于下面的格式。其中可以看到custom字段已自动添加到日志中: WARNING: 07-03 16:44:55 yd * - [logid=868855481 filename=D:\fis\test\models\doc.js lineno=25 errno=120 key1=value1 key2=value2 errmsg=error happened!] Debug支持 处于debug模式下Log将在控制台输出错误日志,并根据错误日志类型显示不同的颜色,方便开发人员调试(debug模式下依旧会写日志到文件)。有两种方法开启debug模式: 开发时 :yog的config.json的yogLogger arguments添加参数debug : 1 即开启debug模式 线上 : 无论在线上还是线下都可以在url中添加query参数_node_debug=1 开启debug模式 日志格式配置 yog-log兼容ODP支持灵活的日志格式配置,以满足不同系统对日志的格式要求。如接入OMP时warning日志格式配置: %L: %{%m-%d %H:%M:%S}t %{app}x * %{pid}x [logid=%l filename=%f lineno=%N errno=%{err_no}x %{encoded_str_array}x errmsg=%{u_err_msg}x] 除非特殊情况,不建议随意修改日志格式配置。 格式配置方法如下: 字段 描述 %% 百分比字符串 %h name or address of remote-host %t 时间戳,支持自定义格式如%{%d/%b/%Y:%H:%M:%S %Z}t %i HTTP-header字段 %a 客户端IP %A server address %C 单个或全部cookie %D 请求消耗时间/ms %f 物理文件名称 %H 请求协议 %m 请求方法 %p 服务端端口 %q 请求query %U 请求URL %v HOSTNAME %V HTTP_HOST %L 当前日志等级 %N 错误发生行数 %E 错误码 %l LogID %M 错误消息 %x 内置的自定义数据,有pid、cookie、encoded_str_array等 测试说明 单元测试说明详见此文档 标签:yoglog
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值