数据库内核月报 - 2015 / 09-MySQL · 备库优化 · relay fetch 备库优化

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介:

业务背景

MySQL 主备通过 binlog 实现数据同步的功能,主库将生成的 binlog 通过 binlog send 线程发送到备库,备库通过应用这些 binlog 来更新数据,实现主备数据一致,其应用 binlog 的读取操作与更新操作的堆栈分别如下。

读取操作:

#0  row_search_for_mysql
#1  0x0000000000c200c2 in ha_innobase::index_read
#2  0x0000000000c21c57 in ha_innobase::rnd_pos
#3  0x000000000090c5d3 in handler::rnd_pos_by_record
#4  0x0000000000a574c3 in Rows_log_event::find_row
#5  0x0000000000a589da in Delete_rows_log_event::do_exec_row
#6  0x0000000000a50dcc in Rows_log_event::do_apply_event
#7  0x00000000005d0bb8 in Log_event::apply_event
#8  0x00000000005b9782 in apply_event_and_update_pos
...

更新操作:

#0  row_update_for_mysql
#1  0x0000000000c1f466 in ha_innobase::delete_row
#2  0x000000000090b64a in handler::ha_delete_row
#3  0x0000000000a58a4b in Delete_rows_log_event::do_exec_row
#4  0x0000000000a50dcc in Rows_log_event::do_apply_event
#5  0x00000000005d0bb8 in Log_event::apply_event
#6  0x00000000005b9782 in apply_event_and_update_pos
...
  • 由堆栈可以看出,sql 线程首先将数据从磁盘加载到内存,然后调用引擎层的接口执行相应的操作,当iops 及 buffer pool 较小时,读磁盘需要较多的时间,容易造成主备延迟问题;
  • 当系统重启后,需要对系统进行预热,提高 buffer pool 的命中率,因此需要提供有效的方法来对系统进行预热;

综上,我们需要一种可以在 DML 操作之前将数据从磁盘加载到内存的功能,以实现数据库的快速操作。

解决方法

我们需要找到一种将数据加载到内存的方法,但又不对数据进行修改,需要满足以下的条件:

  • 在库上更新的数据应该在备库操作之前被加载到内存中;
  • 对于重启的mysqld实例,应该将启动之前所用的数据页加载到内存中;
  • 加载操作对数据本身不进行修改,类似于select 语句。

因此,我们可以在mysqld启动时启动额外的线程对 relay log 进行特殊处理,以达到数据加载的目的。

设计思路 & 使用方法

RDS MySQL 利用 relay log 来解决上述两个问题,当系统启动后,可以在后台开启一个独立于SQL thread之外的线程将 relay log 相关的数据从磁盘加载到内存中,从而使备库在查找数据的时候直接利用buffer pool,而不需要从磁盘中进行加载,同理,使用这种方法也可以解决系统预热的问题。

当启动后,如果发现延迟且 buffer pool 命中率较低时,可以启用 relay fetch thread, 具体语法为:

启动 relay_fetch_thread: start slave relay_fetch_thread;
停止 relay_fetch_thread: stop slave relay_fetch_thread;

relay fetch thread 读取relay log, 并将要执行的数据从磁盘上加载到内存中,所以只能对包含数据部分的 log_event 进行操作,对 Query_log_event,Write_rows_log_event 是无法进行预读的,前者是因为Query_log_event 只是SQL语句,不包含具体的数据信息;后者则是event中没有的数据,所以不需要进行加载,另外为了防止 buffer pool 中读取的 page 被 evict 出去,我们需要对两种情况进行分别处理:

  1. relay fetch thread 不能领先 sql thread 过多,如果领先过多的 relay log files,当 buffer pool 较小时,新加载进来的数据页会将老的数据页从内存中 evict 出去,对 sql thread 的命中率会有直接的影响;
  2. 当 sql thread 领先 relay fetch thread 时,此时 relay fetch thread 不需要将已执行完的 relay log 加载到内存,继续加载不仅会有命中率的问题,同时会造成 CPU 不必要的资源浪费。

因此,relay fetch thread 与 sql thread 应该相差的距离不太远,我们的策略是 relay fetch thread 与 sql thread 应该在同一个 relay log 上,具体策略如下:

  1. 如果 relay fetch thread 领先, 则当 relay fetch thread 读完一个文件后要等待 sql thread,直到 sql thread 应用完此relay log 再继续加载;
  2. 如果 sql thread 领先,则会通知 relay fetch thread 跳过当前执行的文件并用 sql thread 的位点来初始化自己将要执行的起点;

relay fetch thread 执行过程的伪码如下:

handle_slave_relay_fetch
{
   init_thd_and_rli();
   while (!relay_fetch_killed(eli))
   {
       ev= Log_event::read_log_event(&rli->relay_log_buf, 0, rli->relay_log.description_event_for_relay_fetch);
       if (ev == NULL) 
       { 
          deal with situations like hot_log, relay log purged, eof of relay log etc.
       }
       else
       {
             switch(ev->get_type_code())
             {
                case QUERY_EVENT:
                   deal with begin, commit 
                   break;

                case XID_EVENT:
                   deal with xid(commit)
                   break;

               case TABLE_MAP_EVENT:
                   init table info for rows log event
                   break;

               case UPDATE_ROWS_EVENT:
               case DELETE_ROWS_EVENT:
                  find_row();
                  break;

               case FORMAT_DESCRIPTION_EVENT:
                  init description_event_for_relay_fetch for reading binlog event;
               default:
                  break;
             }
             delete ev;
       }
   }
}

实现过程中注意的细节

  • 由于 relay fetch thread 在加载数据的过程中会对记录进行加锁,所以在遇到begin, commit 的事件时,需要释放在读取过程中获取的所有锁资源,否则有可能会引起 sql 线程锁超时错误;
  • 由于 relay fetch thread 的位点是使用 sql thread 的位点进行初始化的,所以需要处理 relay log 不是完整事务的情况;
  • 释放 relay fetch thread 在执行过程中使用到的内存,否则会有内存问题;
  • 在 relay fetch thread 执行的过程中需要特别注意 log_lock、run_lock 等锁问题,以避免备库的死锁;
  • 需要对 relay log 的purge进行特殊处理;
  • 如果是系统预热的功能,则需要对 relay fetch thread 与 sql thread 的领先策略进行调整。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2天前
|
SQL DataWorks 关系型数据库
阿里云 DataWorks 正式支持 SelectDB & Apache Doris 数据源,实现 MySQL 整库实时同步
阿里云数据库 SelectDB 版是阿里云与飞轮科技联合基于 Apache Doris 内核打造的现代化数据仓库,支持大规模实时数据上的极速查询分析。通过实时、统一、弹性、开放的核心能力,能够为企业提供高性价比、简单易用、安全稳定、低成本的实时大数据分析支持。SelectDB 具备世界领先的实时分析能力,能够实现秒级的数据实时导入与同步,在宽表、复杂多表关联、高并发点查等不同场景下,提供超越一众国际知名的同类产品的优秀性能,多次登顶 ClickBench 全球数据库分析性能排行榜。
|
1天前
|
SQL 缓存 监控
数据库优化
【10月更文挑战第29天】数据库优化
5 1
|
2天前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
10 1
|
4天前
|
XML Java 数据库连接
如何使用HikariCP连接池来优化数据库连接管理
在Java应用中,高效管理数据库连接是提升性能的关键。本文介绍了如何使用HikariCP连接池来优化数据库连接管理。通过引入依赖、配置参数和获取连接,你可以显著提高系统的响应速度和吞吐量。 示例代码展示了从配置到使用的完整流程,帮助你轻松上手。
18 3
|
1天前
|
关系型数据库 MySQL
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
17 5
|
3天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
16 0
|
4天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
22 0
|
20天前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
55 3
Mysql(4)—数据库索引
|
5天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
34 2
|
8天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
38 4

相关产品

  • 云数据库 RDS MySQL 版