性能优化之数据库篇4-高可用

从单机到集群

随着数据量增加,读写并发的增加,系统可用性要求的提升,单机MySQL存在着一些问题:

  • 容量有限,难以扩容
  • 读写压力、QPS过大,特别是分析类需求会影响到业务事务
  • 可用性不足,单点故障

主从复制

核心流程是:

  1. 主库将数据变更操作记录到Binlog日志文件中
  2. 从库读取主库中的Binlog日志文件信息写入到从库的Relay log中
  3. 从库读取中继日志信息在从库进行Replay,更新从库信息

binlog格式

  • Row

这个模式存的是哪条记录被修改,修改成什么样.缺点是日志内容大。

  • Statement

存的是sql语句,日志量少。缺点是一些函数、触发器同步可能有障碍。

  • Mixed

两种模式的结合,根据执行的sql语句来区分对待记录的日志形式。

查看binlog命令,进入mysql的bin目录下执行。

mysqlbinlog --no-defaults ../data/binlog.000116

修改binlog模式

  1. 先查看binlog格式

SHOW VARIABLES LIKE "%binlog_format%";

  1. 在线修改

set global binlog_format='MIXED';

  1. 使用配置修改

配置文件my.ini中加入

binlog_format="MIXED" #开启MIXED模式

修改后重启mysql服务

主从复制方案

  1. 异步复制

传统的主从复制,网络或机器故障,会导致数据不一致

  1. 半同步复制

所谓的半同步复制就是master每commit一个事务(简单来说就是做一个改变数据的操作),要确保slave接受主服务器的binlog日志文件并写入到自己的中继日志relay log里,然后会给master信号,告诉对方已经接收完毕,这样master才能把事务成功commit。

保证Source和Replica最终一致性

  1. 并行复制

MySQL从5.6版本开始追加了并行复制功能,目的就是为了改善复制延迟问题。在上面的同步中从库有两个线程IO Thread和SQL Thread,都是单线程模式工作的,因此有一定的延迟,我们可以采用多线程机制来减少主从同步的延迟。

在MySQL的5.6、5.7、8.0版本上,都是基于上述SQL Thread多线程思想,不断优化,减少复制延迟。

3.1 MySQ L5.6并行复制

MySQL 5.6版本的并行复制是基于库的,如果用户MySQL数据库是多个库,那么从库复制速度会有比较大的提高。相当于以前一个线程负责多个库,变成了有多个线程,一个线程负责一个库。

缺点:对只有单库的场景发挥不出优势。对有执行顺序的两个库的处理也是个问题(A库执行完,B库才能执行的情况)。

3.2 MySQL 5.7并行复制

MySQL 5.7是基于组提交的并行复制,MySQL5.7通过对事务进行分组,当事务提交时,它们将单个操作写入到二进制文件中。如果多个事务能同时提交成功,说明它们没有冲突,因此可以在slave上并行执行,在二进制日志中添加一个组提交信息进行标识。

MySQL 5.7的并行复制基于一个前提,即所有已经处于prepare阶段的事务,都是可以并行提交的。这些当然也可以在从库中并行提交,因为处理这个阶段的事务都是没有冲突的。在一个组里提交的事务,一定不会修改同一行。这是一种新的并行复制思路,完全摆脱了原来一直致力于为了防止冲突而做的分发算法,等待策略等复杂的而又效率低下的工作。InnoDB事务提交采用的是两阶段提交模式。一个阶段是prepare,另一个是commit。

为了兼容MySQL 5.6基于库的并行复制,5.7引入了新的变量slave-parallel-type,其可以配置的值有:DATABASE(默认值,基于库的并行复制方式)、LOGICAL_CLOCK(基于组提交的并行复制方式)。

那么如何知道事务是否在同一组中,生成的Binlog内容如何告诉Slave哪些事务是可以并行复制的?

在MySQL 5.7版本中,其设计方式是将组提交的信息存放在GTID中。为了避免用户没有开启GTID功能(gtid_mode=OFF),MySQL 5.7又引入了称之为Anonymous_Gtid的二进制日志event类型ANONYMOUS_GTID_LOG_EVENT。
通过mysqlbinlog工具分析binlog日志,就可以发现组提交的内部信息。


可以发现MySQL 5.7二进制日志较之原来的二进制日志内容多了last_committed和sequence_number,last_committed表示事务提交的时候,上次事务提交的编号,如果事务具有相同的last_committed,表示这些事务都在一组内,可以进行并行的回放。

3.3 MySQL 8.0 并行复制

MySQL 8.0是基于write-set的并行复制。MySQL会有一个集合变量来存储事务修改的记录信息,所有已经提交的事务所修改的主键值经过hash后都会与那个变量的集合进行对比,来判断该行是否与其冲突,并以此来确定依赖关系,没有冲突即可并行。这样的粒度就达到了row级别,并行速度会更快。

要开启enhanced multi-threaded slave其实很简单,只需根据如下设置:

slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
slave_pending_jobs_size_max = 2147483648
slave_preserve_commit_order=1
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

主从复制实战

异步复制

  1. 准备两个mysql实例
  2. 修改master的那个mysql实例的my.cnf配置文件,增加如下内容,并重启mysql
server-id=1
log-bin=mysql-bin
  1. 登入master的mysql,创建一个同步数据的用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';

GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
  1. 修改slave的那个mysql实例的my.cnf配置文件,增加如下内容,并重启mysql
server-id=2
log-bin=mysql-bin
  1. 登入master的mysql,执行
show master status;

记录下File和Position

  1. 登入slave的mysql,配置从库
change master to master_host='192.168.161.21', master_user='slave', master_password='123456', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos= 837, master_connect_retry=30;

master_log_file和master_log_pos就是上面记录下的File和Position。

执行完后继续执行下面的命令,开启主从复制

start slave
  1. 查看主从复制是否生效
show slave status \G;

两个都是YES,说明成功

  1. 测试,在主库上新建数据库,新建表,插入数据,然后查看从库的数据情况即可。

主从复制的局限性

  1. 主从延迟问题
  2. 应用端需要配合读写分离框架
  3. 不解决高可用的问题

主从延迟问题解决方案:

  • 计算延迟最大时间T,写入数据在时间T之内就读主库,在时间T后读从库
  • 先从从库读,读不到就去主库读取
  • 根据业务特点。对实时性要求高的读写都走主库,一些要求不高的业务才进行读写分离。

双主模式

很多企业刚开始都是使用MySQL主从模式,一主多从。但是单主如果发生单点故障,从库切换成主库还需要做改动。因此,如果是双主或者多主,就会增加MySQL入口,提升主库的可用性。因此随着业务的发展,数据库架构可以由主从模式演变为双主模式。双主模式是指两台服务器互为主从,任何一台服务器数据变更,都会通过复制应用到另外一方的数据库中。

使用双主双写还是双主单写?

建议大家使用双主单写,因为双主双写存在以下问题:

  • ID冲突

在A主库写入,当A数据未同步到B主库时,对B主库写入,如果采用自动递增容易发生ID主键的冲突。可以采用MySQL自身的增长步长来解决,例如A的主键为1,3,5,7...,B的主键为2,4,6,8...,但是对数据库运维、扩展都不友好。

  • 更新丢失

同一条记录在两个主库中进行更新,会发生前面覆盖后面的更新丢失。

随着业务发展,架构会从主从模式演变为双主模式,建议用双主单写,再引入高可用组件,例如Keepalived和MMM等工具,实现主库故障自动切换

读写分离

方案1:

基于Spring提供的路由数据源AbstractRoutingDataSource以及AOP

缺点:

  • 代码侵入性强
  • 同一个service中有“写完读”数据不一致问题

具体实现:https://www.cnblogs.com/cjsblog/p/9712457.html

方案2:

ShardingSphere-jdbc 的 Master-Slave 功能

缺点:

  • 对业务系统还是有侵入
  • 对已存在的旧系统改造不友好

具体操作:https://www.cnblogs.com/javammc/p/12470838.html

方案3:

使用MyCat/ShardingSphere-Proxy的Master-Slave功能

部署中间件,规则配置在中间件中,业务系统无侵入。

MySQL高可用

什么是高可用?

高可用代表着更少的不可服务的时间。一般互联网公司要求达到4个9,即一年不能服务的时间不超过52.6分钟

99.9 = 8760 * 0.1% = 8760 * 0.001 = 8.76小时

99.99 = 8760 * 0.0001 = 0.876小时 = 0.876 * 60 = 52.6分钟

数据库要实现高可用,需要做到

  1. 读写分离,提高读的处理能力
  2. 故障转移,灾难恢复

常见的一些策略有:

  • 多个实例不在一个主机上
  • 跨机房部署
  • 两地三中心容灾高可用方案

3.1 MySQL高可用方案

方案1:主从手动切换

如果主节点挂掉了,将某个从改为主。然后配置其他从节点。应用侧需要修改数据源配置。

缺点:

  1. 可能数据不一致
  2. 需要人工操作
  3. 代码和配置的侵入性

方案2:主从手动切换2

用LVS+Keepalived实现多个节点的探活+请求路由
,配置VIP或DNS实现应用侧配置不变更

缺点:

  • 也需要手工操作
  • 大量的配置和脚本定义

方案3:MHA

MHA(Master High Availability)目前在 MySQL 高可用方面是一个相对成熟的解决方案,它由日本 DeNA 公司的 youshimaton(现就职于 Facebook 公司)开发,是一套优秀的作为 MySQL 高可用性环境下故障切换和主从提升的高可用软件。

MHA由两部分组成:MHA Manager和MHA Node。MHA Manager会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master,然后将所有其他的slave重新指向新的master,整个故障转移过程对应用程序完全透明。

基于Perl语言开发,一般能在30S内实现主从切换。切换时通过SSh复制主节点的日志。

缺点:

  • 需要配置SSH信息
  • 至少3台机器

方案4:MGR

Mysql Group Replication(MGR)

MGR的特点:

  1. 高一致性:基于分布式协议Paxos实现组复制,保证数据一致性
  2. 高容错性:自动检测机制,只要不是大多数节点宕机都可以继续工作
  3. 高扩展性:节点的的增加与移除会自动更新组成员信息。新节点加入后,自动从其他节点通过增量数据,直到与其他节点数据一致
  4. 高灵活性:提高单主模式和多主模式,单主模式在主库宕机后自动选主,多主模式支持多节点写入。
    如果主节点挂掉,将自动选择某个从改为主。无需人工干预,基于组复制,保证数据一致性。

缺点:

  • 外部获得状态变更需要读取数据库
  • 外部需要使用LVS/VIP配置

方案5:Mysql Cluster

MySQL InnoDB Cluster是一个高可用的框架,它由下面这几个组件构成:

  1. MySQL Group Replication :提供DB的扩展、自动故障转移
  2. MySQL Router:轻量级中间件,提供应用程序负载均衡和应用连接的故障转移
  3. MySQL Shell:新的MySQL客户端,多种接口模式

方案6:orchestrator

一款MySQL高可用和复制拓扑管理工具,支持自动故障转移和手动主从切换等。通过Web界面操作可以更改Mysql实例的复制关系和部分配置信息,同时提供命令行和API接口,方便运维管理。

posted @ 2021-07-18 18:43  女友在高考  阅读(452)  评论(0编辑  收藏  举报