11. SpringBoot 整合MySQL高可用数据库 (五)

94 阅读16分钟

📕 高可用集群的相关面试题

  1. MySQL主从复制的好处

    • 数据备份与故障转移:主从复制能够实现数据的异地备份,当数据库故障时,可以切换到从数据库,避免数据丢失。同时,从数据库可以作为主数据库的备份,实现故障转移。
    • 架构拓展:当业务量越来越大,I/O访问频率越来越高的时候,采用多库的存储可以降低I/O访问的频率,提高单个机器的I/O性能。
    • 读写分离:主从复制可以实现读写分离,使数据库能支持更大的并发。这有助于平衡负载,提高数据库的性能。
    • 服务器负载均衡:通过在主服务器和从服务器之间切分处理客户查询的负荷,可以实现服务器的负载均衡,这有助于提高数据库的整体性能。
    • 性能提升:一主多从的情况下,不同用户可以从不同的数据库读取数据,这有助于提高整体性能。
  2. MySQL主从复制的缺点

    • 数据一致性问题:MySQL主从复制是异步复制,从库的数据复制可能存在一定的延迟。这就导致了主从库之间的数据可能存在不一致的情况。例如:当主库更新了数据之后,从库还未复制完成,此时查询从库可能会得到旧数据,这就会影响到应用程序的准确性。
    • 单点故障问题:MySQL主从复制的主库是单点,如果主库宕机,从库就无法进行数据同步,这就会导致真个系统的不可用。此外,如果主库在复制过程中发生了故障,也会影响从库的数据同步。
    • 安全问题:MySQL主从复制中的数据传输是明文传输,如果数据被截获,就会导致数据泄露的风险。此外,在主从复制中,从库的权限较高,如果从库被攻击,就可能导致整个系统的安全问题。
    • 实时性差:主从复制需要一定时间来完成数据同步,因此无法保证数据实时性。
    • 复杂性高:主从复制需要配置和管理多个数据库服务器,增加了系统的复杂性。
    • 性能瓶颈:在大量写入操作时,主库可能会成为性能瓶颈。
    • 数据量大的话同步效率差:单表数据量过大时插入和更新因索引,磁盘IO等问题,性能会变的很差。
  3. MySQL主从同步复制原理

    1. slave端的IO线程连接上master端,并请求从指定binlog日志文件的指定位置pos节点位置(或者从最开始的日志)开始复制之后的日志内容
    2. master端在接收到来自slave端的IO线程请求后,通知负责复制线程的IO线程,根据slave端IO线程的请求信息,读取指定的binlog日志指定pos节点位置之后的日志信息,然后返回给slave端的IO线程,该返回信息除了binlog日志所包含的信息之外,还包括本次返回的信息在master端的binlog日志文件名以及在该binlog日志中的pos节点位置。
    3. slave端的IO线程在接收到master端IO返回的信息,将接收到的binlog日志内容依次写入到slave端的relaylog(mysql-relay-bin)文件的最末端,并将读取到的master端的binlog文件名和pos节点位置的记录到master-info(该文件开存在slave端)文件中,以便下一次读取的时候能够清楚的告诉master,我需要从binlog文件的哪个pos节点位置开始,请把此节点的日志内容发给我。
    4. slave端的SQL线程在检测到relaylog文件中新增内容后,会马上解析该log文件中的内容。然后还原成在master端真实执行的那些SQL语句,并在自身按顺序依次执行这些SQL语句。这样,实际上就是在master端和slave端执行了同样的SQL语句,所以master端和 slave端的数据是完全一样的。
  4. MySQL主从同步复制的方式?

    • 异步复制:MySQL默认的复制是异步的,主库在执行完客户端提交的事务后会立即将结果返回给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题:主库如果crash掉了,此时主库已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
    • 全同步复制:指当主库完一个事务,所有的从库都执行了该事务才返回的客户端。因为要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会受到严重的影响。
    • 半同步复制:介于异步复制和全同步复制之间,主库在执行完客户端提交的事务不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回到客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也早就了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间,所以半同步复制最好在低延时的网络中使用。
  5. MySQL主从同步延迟怎么处理?

    主从复制延迟的原因: 一个服务器开放N个链接给客户端来连接的,这样会有大并发的更新操作,但是从服务器的里面来读取binlog的线程仅有一个,当某个SQL在从服务器上执行的时间越长,或者由于某个SQL要进行锁表就行会导致主服务器的SQL大量积压,未被同步到从服务器里。这就导致了主从不一致,也就是主从延迟。

    主从复制延迟的解决办法:

    • 写操作后的读操作指定发给数据库主服务器。

      例如,账号注册完成后,登录时读取账号的读操作也发给数据库主服务器。这种方式和业务强绑定,对业务的侵入和影响较大,如果哪个新来的程序员不知道这样写代码,就会导致一个bug。

    • 关键业务读写操作全部使用主服务器,非关键业务使用读写分离

      例如,对于一个用户管理系统来说,注册 + 登录的业务读写操作全部访问主机,用户的介绍、爰好、等级等业务,可以采用读写分离,因为即使用户改了自己的自我介绍,在查询时却看到了自我介绍还是旧的,业务影响与不能登录相比就小很多,还可以忍受。

    • 网络优化

      • 使用高速网络连接
      • 优化网络带宽
      • 减少跨数据中心的复制
    • 优化事务

      • 将大事务拆分成多个小事务
      • 减少并发事务的数量
      • 使用InnoDB存储引擎
    • 优化数据库性能

      • 提升硬件性能
      • 使用缓存技术
    • 优化MySQL配置

      • 调整主从服务器时间,如果主从服务器之间的时间存在偏差,则可以通过调整时间来减少主从复制延迟。可以使用ntpdate命令来同步时间。
      • 修改binlog格式,在MySQL中,有三种binlog格式:STATEMENT、ROW和MIXED。可以通过修改binlog格式来减少主从复制延迟。
      • 调整binlog缓存大小,binlog缓存大小是指MySQL服务器用来缓存二进制日志的内存大小。如果binlog缓存大小过小,则可能会导致主从复制延迟。可以通过修改my.cnf文件来调整binlog缓存大小。
      • 调整复制线程数,复制线程是指用于复制二进制日志的MySQL线程。如果复制线程数量过少,则可能会导致主从复制延迟。可以通过修改my.cnf文件来调整复制线程数。
      • 使用半同步复制,半同步复制是一种MySQL复制模式,它可以提高主从复制的可靠性,并减少主从复制延迟。在半同步复制模式下,当从服务器收到主服务器发送的日志时,它会向主服务器发送一个确认消息,以确保数据已经正确地复制到从服务器上。
  6. MySQL如何进行分库分表?

    分库:

    1. 垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库。例如:用户数据、商品数据、订单数据。
    2. 垂直分库:水平分库:以字段为依据,按照一定策略,将一个库中的数据拆分到多个库中。

    分表:

    • 水平分表:以字段为依据,按照一定策略,将一个表中的数据拆分到多个表中。
    • 垂直分表:以字段为依据,按照字段的活跃性,将表中字段拆到不同的(主表和扩展表)中。
  7. MySQL水平分表有哪几种路由方式?

    什么是路由呢?就是数据应该放在哪一张表。

    水平方式主要有三种路由方式:

    • 范围路由:选取有序的数据列作为路由的条件,不同分段分散到不同的数据库表中。例如时间戳
    • Hash路由:选取某个列的值进行Hash运算,然后根据结果分散到不同的数据库表中。
    • 配置路由:配置路由就是路由表,用一张独立的表记录路由信息。
  8. MySQL不停机扩容如何实现?

    1. 在线双写,查询走老库

      • 建立好新的库表结构,数据写入旧库的同时也写入新库。
      • 数据迁移,使用数据迁移程序,将旧库中的历史数据迁移到新库。
      • 使用定时任务,新旧库的数据对比,把差异补齐。
    2. 在线双写,查询走新库

      • 完成了历史数据的同步和校验
      • 把对数据的读切换到新库
    3. 第三阶段:旧库下线

      • 旧库不在写入新的数据
      • 经过一段时间,确定旧库没有请求以后,就可以下线旧库
  9. MySQL分库分表存在的问题?

    • 事务的问题:使用关系型数据库,有很大一点在于它保证事务完整性。而分库之后单机事务用不上了,必须用分布式事务来解决。

    • 跨库JOIN问题:在一个库中的时候我们还可以利用 JOIN 来连表查询,而跨库了之后就无法使用 JOIN 了。

      此时的解决方案就是在业务代码中进行关联,也就是先把一个表的数据查出来,然后通过得到的结果再去查另一张表,然后利用代码来关联得到最终的结果。

      这种方式实现起来稍微比较复杂,不过也是可以接受的。

      还有可以适当的冗余一些字段。比如以前的表就存储一个关联 ID,但是业务时常要求返回对应的 Name 或者其他字段。这时候就可以把这些字段冗余到当前表中,来去除需要关联的操作。

      还有一种方式就是数据异构,通过binlog同步等方式,把需要跨库join的数据异构到ES等存储结构中,通过ES进行查询。

    • 跨节点的count、order by,group by 以及聚合函数问题:只能由业务代码来实现或者用中间件将各表中的数据汇总、排序、分页然后返回。

    • ID 问题:数据库表被切分后,不能再依赖数据库自身的主键生成机制,所以需要一些手段来保证全局主键唯一。还是自增,只不过自增步长设置一下。比如现在有三张表,步长设置为3,三张表 ID 初始值分别是1、2、3。这样第一张表的 ID 增长是 1、4、7。第二张表是2、5、8。第三张表是3、6、9,这样就不会重复了。

      UUID,这种最简单,但是不连续的主键插入会导致严重的页分裂,性能比较差。

      分布式 ID,比较出名的就是 Twitter 开源的 sonwflake 雪花算法。

  10. MySQL百万级别以上的数据如何删除?

    关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。

    所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。

    • 所以我们想要删除百万数据的时候可以先删除索引
- 然后删除其中无用数据
- 删除完成后重新创建索引创建索引也非常快
  1. MySQL百万千万级大表如何添加字段?

    当线上的数据库数据量到达几百万、上千万的时候,加一个字段就没那么简单,因为可能会长时间锁表。

    大表添加字段,通常有这些做法:

    • 通过中间表转换过去

      创建一个临时的新表,把旧表的结构完全复制过去,添加字段,再把旧表数据复制过去,删除旧表,新表命名为旧表的名称,这种方式可能回丢掉一些数据。

    • 用pt-online-schema-change

      pt-online-schema-change是percona公司开发的一个工具,它可以在线修改表结构,它的原理也是通过中间表。

    • 先在从库添加 再进行主从切换

      如果一张表数据量大且是热表(读写特别频繁),则可以考虑先在从库添加,再进行主从切换,切换后再将其他几个节点上添加字段。

  2. MySQL数据库CPU飙升的话,如何处理?

    排查过程:

    (1)使用 top 命令观察,确定是 mysqld 导致还是其他原因。

    (2)如果是 mysqld 导致的,show processlist,查看 session 情况,确定是不是有消耗资源的 sql 在运行。

    (3)找出消耗高的 sql,看看执行计划是否准确, 索引是否缺失,数据量是否太大。

    处理:

    (1)kill 掉这些线程 (同时观察 cpu 使用率是否下降),

    (2)进行相应的调整 (比如说加索引、改 sql、改内存参数)

    (3)重新跑这些 SQL。

    其他情况:

    也有可能是每个 sql 消耗资源并不多,但是突然之间,有大量的 session 连进来导致 cpu 飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等

  3. MySQL主从复制中的选举机制详解

    1.选举流程

    当主节点失效的时候,从节点会发起选举流程,选出一个新的从节点。选举流程如下:

    1. 从节点向其他从节点发选举请求,请求其他节点投票支持自己成为主节点。
    2. 其他从节点收到选举请求后,如果没有投票支持其他从节点,则投票支持请求发起节点成为主节点。
    3. 如果有多个节点投票支持同一个节点,则选举流程结束,该节点成为新的主节点。

    2.选举规则

    在MySQL主从复制中,选举规则如下:

    • 每个从节点只能投一票,不能重复投票。
    • 如果一个从节点已经投票支持了某个节点,则不能再投票支持其他节点。
    • 如果一个从节点在指定时间内没有收到其他从节点的选举请求,则该节点可以自己发起选举请求。
    • 如果多个从节点同时发起选举请求,则选举请求的优先级如下:优先级高的节点先成为主节点。
    • 如果多个从节点同时发起选举请求,但是优先级相同,则选举请求的顺序如下:先收到选举请求的节点先成为主节点。

    选举算法

    MySQL主从复制中的选举算法是基于Raft算法实现的。Raft算法是一种分布式一致性算法,用于保证分布式系统中的数据一致性。Raft算法将分布式系统中的节点分为三种角色:领导者、跟随者和候选者。在MySQL主从复制中,每个节点都可以成为领导者、跟随者或候选者,具体角色的切换取决于选举流程中的投票结果。

  4. 一主多从的单节点故障如何避免?

    采用多主多从集群模式,比如使用Galera Cluster。

    Galera Cluster是由Codership开发的MySQL多主集群,包含在MariaDB中,同时支持Percona xtradb、MySQL,是一个易于使用的高可用解决方案,在数据完整性、可扩展性及高性能方面都有可接受的表现。图1所示为一个三节点Galera 集群,三个MySQL实例是对等的,互为主从,这被称为多主(multi-master)架构。当客户端读写数据时,可连接任一MySQL实例。对于读操作,从每个节点读取到的数据都是相同的。对于写操作,当数据写入某一节点后,集群会将其同步到其它节点。这种架构不共享任何数据,是一种高冗余架构。

    Galera集群具有以下特点:

    • 多主架构:真正的多主多活群集,可随时对任何节点进行读写。
    • 同步复制:集群不同节点之间数据同步,某节点崩溃时没有数据丢失。
    • 数据一致:所有节点保持相同状态,节点之间无数据分歧。
    • 并行复制:重放支持多线程并行执行以获得更好的性能。
    • 故障转移:故障节点本身对集群的影响非常小,某节点出现问题时无需切换操作,因此不需要使用VIP,也不会中断服务。
    • 自动克隆:新增节点会自动拉取在线节点的数据,最终集群所有节点数据一致,而不需要手动备份恢复。
    • 应用透明:提供透明的客户端访问,不需要对应用程序进行更改。