MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MySQL主从复制在高可用性中的应用与优化

2024-04-087.3k 阅读

MySQL 主从复制基础原理

MySQL 的主从复制是一种数据同步机制,它允许将一个 MySQL 数据库服务器(主服务器)的数据复制到一个或多个其他 MySQL 数据库服务器(从服务器)。这种机制基于二进制日志(binary log)来实现。

主服务器工作原理

主服务器在执行写操作(如 INSERT、UPDATE、DELETE 等)时,会将这些操作记录到二进制日志(也称为 binlog)中。二进制日志以事件(event)的形式记录,每个事件代表一个数据库操作。例如,当执行一个 INSERT INTO users (name, age) VALUES ('John', 30) 的语句时,主服务器会将这个插入操作记录为一个事件写入 binlog。

从服务器工作原理

从服务器通过两个线程来实现与主服务器的数据同步:I/O 线程和 SQL 线程。

I/O 线程:从服务器的 I/O 线程连接到主服务器,请求主服务器发送二进制日志中的事件。主服务器会有一个 log dump 线程专门为从服务器的 I/O 线程提供 binlog 事件。I/O 线程接收到这些事件后,将其写入到从服务器的中继日志(relay log)中。

SQL 线程:从服务器的 SQL 线程负责读取中继日志中的事件,并在从服务器上按照顺序执行这些事件,从而使从服务器的数据与主服务器保持一致。

主从复制的配置步骤

主服务器配置

  1. 修改配置文件:编辑 MySQL 的配置文件(通常是 my.cnfmy.ini),在 [mysqld] 部分添加或修改以下配置:
log-bin=mysql-bin
server-id=1
  • log-bin=mysql-bin 表示开启二进制日志,并指定日志文件名为 mysql-bin
  • server-id=1 是主服务器的唯一标识,不同服务器的 server-id 必须不同。
  1. 重启 MySQL 服务:修改配置文件后,重启 MySQL 服务使配置生效。
sudo systemctl restart mysql
  1. 创建复制用户:登录到 MySQL 主服务器,创建一个用于从服务器连接的复制用户,并授予 REPLICATION SLAVE 权限。
CREATE USER'replication_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO'replication_user'@'%';
FLUSH PRIVILEGES;

这里 replication_user 是复制用户,% 表示允许任何 IP 地址的从服务器连接,password 是该用户的密码。

  1. 获取主服务器状态:执行以下命令获取主服务器的二进制日志文件名和位置:
SHOW MASTER STATUS;

输出结果类似如下:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |     154   |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

记录下 FilePosition 的值,后续从服务器配置会用到。

从服务器配置

  1. 修改配置文件:同样编辑 MySQL 配置文件,在 [mysqld] 部分添加或修改以下配置:
server-id=2

这里 server-id=2 是从服务器的唯一标识,需与主服务器不同。

  1. 重启 MySQL 服务:修改后重启 MySQL 服务。
sudo systemctl restart mysql
  1. 配置主服务器信息:登录到 MySQL 从服务器,执行以下命令配置主服务器的连接信息:
CHANGE MASTER TO
    MASTER_HOST='主服务器IP',
    MASTER_USER='replication_user',
    MASTER_PASSWORD='password',
    MASTER_LOG_FILE='mysql-bin.000003',
    MASTER_LOG_POS=154;

这里 主服务器IP 是主服务器的实际 IP 地址,MASTER_LOG_FILEMASTER_LOG_POS 是前面在主服务器上获取的值。

  1. 启动从服务器:执行以下命令启动从服务器的复制功能:
START SLAVE;
  1. 检查从服务器状态:执行以下命令检查从服务器的状态:
SHOW SLAVE STATUS \G;

重点关注 Slave_IO_RunningSlave_SQL_Running 这两个参数,它们都应该为 Yes,表示 I/O 线程和 SQL 线程都在正常运行。同时,Seconds_Behind_Master 表示从服务器落后主服务器的时间,理想情况下应该为 0 或非常小的值。

MySQL 主从复制在高可用性中的应用

读写分离

在高并发应用场景中,读操作往往远远多于写操作。通过主从复制实现读写分离,可以将读操作分摊到多个从服务器上,减轻主服务器的负载。

例如,在一个电商网站中,商品展示页面的查询操作(读操作)非常频繁,而订单提交等写操作相对较少。可以将商品查询请求发送到从服务器,订单提交等写请求发送到主服务器。

在应用程序层面,可以使用数据库连接池来实现读写分离。以 Java 应用为例,使用 HikariCP 连接池结合 MyBatis 框架,可以通过自定义数据源来实现读写分离。

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.example.demo.mapper.read", sqlSessionFactoryRef = "readSqlSessionFactory")
@EnableTransactionManagement
public class ReadDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.read")
    public HikariConfig readHikariConfig() {
        return new HikariConfig();
    }

    @Bean
    public DataSource readDataSource() {
        return new HikariDataSource(readHikariConfig());
    }

    @Bean
    public SqlSessionFactory readSqlSessionFactory(@Qualifier("readDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean
    public PlatformTransactionManager readTransactionManager(@Qualifier("readDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

上述代码配置了一个用于读操作的数据源,在实际应用中可以类似地配置写数据源,并在业务代码中根据操作类型选择不同的数据源。

故障转移

在高可用性架构中,主服务器可能会因为硬件故障、软件错误或网络问题等原因而不可用。通过主从复制,可以实现故障转移,确保系统的持续运行。

当主服务器发生故障时,需要将其中一个从服务器提升为新的主服务器。这可以通过手动操作或使用自动化工具如 MHA(Master High Availability)来实现。

手动故障转移步骤

  1. 停止从服务器:在所有从服务器上执行 STOP SLAVE; 命令。
  2. 选择新主服务器:从多个从服务器中选择一个作为新的主服务器。
  3. 配置新主服务器:在新主服务器上执行 RESET MASTER; 命令,这将清除其现有的二进制日志并创建新的日志文件。
  4. 配置其他从服务器:在其他从服务器上,使用 CHANGE MASTER TO 命令重新配置主服务器为新提升的主服务器。

自动化工具如 MHA 可以简化故障转移的过程。MHA 由 Manager 节点和 Node 节点组成,Manager 节点监控主服务器和从服务器的状态,当检测到主服务器故障时,自动选择一个从服务器提升为新主服务器,并重新配置其他从服务器。

MySQL 主从复制的优化策略

网络优化

主从服务器之间的网络延迟会影响数据同步的速度,从而影响主从复制的性能。

  1. 使用高速网络:确保主从服务器之间使用高速、低延迟的网络连接,如 10Gbps 或更高带宽的网络。
  2. 优化网络拓扑:减少网络中的中间设备(如路由器、交换机)数量,优化网络拓扑结构,降低网络延迟。
  3. 配置合理的网络参数:在操作系统层面,可以调整网络参数如 TCP 缓冲区大小等,以提高网络传输效率。例如,在 Linux 系统中,可以通过修改 /etc/sysctl.conf 文件来调整 net.core.rmem_maxnet.core.wmem_max 等参数。

服务器性能优化

  1. 硬件优化

    • CPU:确保主从服务器有足够的 CPU 资源。对于高并发的读写操作,多核 CPU 可以更好地处理复制相关的线程。
    • 内存:合理分配内存,确保 MySQL 有足够的内存用于缓存数据和日志。可以通过调整 innodb_buffer_pool_size 参数来优化 InnoDB 存储引擎的缓存大小。一般建议将 innodb_buffer_pool_size 设置为服务器物理内存的 60% - 80%。
    • 磁盘:使用高速磁盘,如 SSD。SSD 的随机读写性能远高于传统机械硬盘,可以显著提高二进制日志和中继日志的读写速度。
  2. MySQL 参数优化

    • sync_binlog:该参数控制二进制日志的同步方式。默认值为 1,表示每次写操作都将二进制日志同步到磁盘,这虽然保证了数据的安全性,但会降低性能。可以将其设置为 0 或大于 1 的值,但这样会在系统崩溃时丢失部分未同步的二进制日志。
    • innodb_flush_log_at_trx_commit:这个参数控制 InnoDB 存储引擎日志的刷新策略。取值为 0 时,日志每秒刷新到磁盘一次;取值为 1 时,每次事务提交时刷新日志到磁盘;取值为 2 时,每次事务提交时将日志写入文件系统缓存,但每秒才真正刷新到磁盘。默认值为 1,为了提高性能,可以将其设置为 2,但这会在系统崩溃时丢失一秒内的事务数据。

复制拓扑优化

  1. 一主多从拓扑:在一主多从拓扑结构中,如果从服务器数量过多,可能会导致主服务器的负载过高。可以采用分级复制的方式,即部分从服务器直接连接到主服务器,而其他从服务器连接到这些从服务器,形成一个树形结构。这样可以减轻主服务器的负载,提高复制性能。

  2. 双活或多活拓扑:在双活或多活拓扑结构中,多个主服务器同时提供读写服务,并且相互之间进行数据同步。这种拓扑结构可以提高系统的可用性和性能,但实现起来较为复杂,需要解决数据冲突等问题。例如,可以使用 Galera Cluster 等工具来实现 MySQL 的多活拓扑。

处理主从复制中的常见问题

主从延迟

主从延迟是指从服务器的数据落后于主服务器的数据。常见原因及解决方法如下:

  1. 网络延迟:如前面提到的,网络延迟会导致从服务器接收主服务器的二进制日志事件变慢。通过优化网络可以解决此问题。
  2. 主服务器负载过高:主服务器忙于处理大量的写操作,导致生成二进制日志的速度过快,从服务器来不及同步。可以通过优化主服务器的性能,或者将部分写操作分摊到其他服务器(如使用分库分表)来解决。
  3. 从服务器性能问题:从服务器的硬件性能不足或 MySQL 参数配置不合理,导致执行中继日志事件的速度慢。可以通过升级硬件或优化 MySQL 参数来提高从服务器的性能。

数据不一致

在主从复制过程中,可能会出现数据不一致的情况。常见原因及解决方法如下:

  1. 主从服务器版本差异:不同版本的 MySQL 可能在复制功能上存在差异,导致数据不一致。确保主从服务器使用相同版本的 MySQL。
  2. 存储引擎差异:如果主从服务器使用不同的存储引擎,可能会因为存储引擎的特性不同而导致数据不一致。统一主从服务器的存储引擎,推荐使用 InnoDB 存储引擎。
  3. 手动操作差异:在主从复制过程中,如果在主服务器和从服务器上同时进行手动数据操作,可能会导致数据不一致。避免在从服务器上进行写操作,所有写操作都在主服务器上执行。

监控与维护主从复制

监控主从复制状态

  1. 使用 SHOW SLAVE STATUS 命令:如前面所述,通过 SHOW SLAVE STATUS \G; 命令可以获取从服务器的详细状态信息,包括 I/O 线程和 SQL 线程的运行状态、主从延迟时间等。可以定期执行此命令来监控从服务器的状态。
  2. 使用 MySQL Enterprise Monitor:MySQL Enterprise Monitor 是 MySQL 官方提供的监控工具,可以实时监控主从复制的状态、服务器性能等指标。它提供了直观的图形化界面,方便管理员进行监控和管理。

定期备份与恢复

  1. 备份策略:定期对主从服务器进行数据备份,以防止数据丢失。可以使用 mysqldump 工具进行逻辑备份,或者使用 XtraBackup 工具进行物理备份。对于主服务器,建议在低峰期进行备份,以减少对业务的影响。
  2. 恢复策略:在发生数据丢失或故障时,根据备份数据进行恢复。如果是主服务器故障,在恢复主服务器后,需要重新配置从服务器与主服务器的复制关系。

通过合理配置、优化和监控 MySQL 主从复制,可以有效地提高系统的高可用性和性能,满足不同业务场景的需求。在实际应用中,需要根据具体的业务需求和系统架构,选择合适的优化策略和工具,确保主从复制的稳定运行。