6-3 MySQL分库分表与集群管理

1. 为什么需要分库分表?

关系型数据库,表中管理的数据以行记录为单元。当一张表的数据达到上千万条时,随之带来的是更高的磁盘、IO、系统开销,更复杂的索引维护,以及性能上的瓶颈。而一台服务的资源终究是有限的,因此需要对数据库和表进行合理拆分,从而使其更好的提供数据服务。

分库分表的目的在于:减小数据库的负担,提高数据库的效率,缩短查询时间。另外,因为分库分表这种改造是可控的,底层还是基于数据库管理系统,因此整个数据库的运维体系以及相关基础设施都是可重用的。

分库概念:一个系统的多张数据表,存储到多个数据库实例中;

分表概念:对于一张多行(记录)多列(字段)的二维数据表,分两种分表操作:

  • (1) 垂直分表: 竖向切分,不同分表存储不同的字段,可以把不常用或者大容量、或者不同业务的字段拆分出去;
    优点:可以实现热数据和冷数据的分离,将不经常变化的数据和变动较大的数据分散再不同的库/表中。
    缺点:没有解决数据量大带来的性能损耗,读写压力依旧很大。
  • (2) 水平分表(复杂): 横向切分,按照特定分片算法,不同分表存储不同的记录。例如根据年份来拆分不同的数据库。每个数据库结构一致,但是数据得以拆分,每个子表记录数量得到降低,从而提升性能。
    优点:单库(表)的数据量得以减少,提高性能。提高了系统的稳定性和负载能力。切分出的表结构相同,应用程序只需要做子表的映射即可。
    缺点:数据分片在扩容时需要迁移。数据库维护成本增加。

2. 主从复制,读写分离

高并发业务服务器端,如果将对数据库的读和写都放在同一个数据库实例中,无疑是低效率的。因为读、写操作会涉及到锁的竞争,尤其是写操作,通常一个事务进行写操作时,其它并发的事务则会因为排他锁而阻塞。而在实际的业务作业中,对数据库的操作总是读多写少的,并且读的效率也高于写操作。因此,将数据库架构设计成主从集群,读写业务分离,对于高并发的数据访问是高效的解决方法。

主从架构除了带来支持高并发的优点,还使得MySQL数据库具有高可用的能力。主从架构中,若主服务器宕机,从服务器可以快速顶替,使得服务器具有高可用、容灾能力。

2.1 主从架构

图片说明

如图所示为3个节点的主从架构的基本示意图,3个MySQL集群中1个节点为主库(Master),2个节点为从节点(Slave):

  • 1.主库负责接收用户的写操作,并通过更新二进制日志BINLOG通知从库更新数据。
  • 2.从库主要负责用户的读操作(分担主服务器的读写压力),并且负责重放Master的写操作(即复制主库做的写操作),从而保证集群数据一致性、高可用、实现容灾能力。
  • 3.Proxy: sql语句代理,对读写操作请求的SQL指令进行路由,使得读写分离。
  • 4.Direct: 负载均衡组件, 对Mysql Proxy分发得读操作,按照一定得一致性哈希等算法进行分发至后端的从库。

2.2 MySQL数据复制过程解析(Replication)

MySQL的数据复制(Replication)过程是将一个MySQL实例中的数据复制到另一个MySQL实例中。

MySQL的复制(replication)是一个异步的复制,从一个MySQLinstace(Master)复制到另一个MySQLinstance(Slave)。Replication功能的出现能够非常方便将某一数据库中的数据复制到多台服务器中的数据里实例中,从而实现数据备份、主从热备、数据库集群等功能。且整个过程是异步进行的,复制的延时非常小,有效的提高了数据库的处理能力,提高了数据安全性等。

整个复制操作主要由三个进程完成的,其中两个进程在Slave服务器上(Sql进程和IO进程),另外一个进程在Master服务器(IO进程)上。

要实施复制,首先必须打开Master端的bin-log功能,整个复制过程实际上就是Slave从Master端获取该日志然后再在自己端完全顺序的执行日志中所记录的各种操作。复制的基本过程如下:

  • (1)Slave端的I/O进程与Master端的I/O进程建立连接,Slave请求监控bin-log日志,当发现bin-log日志发生变化后请求获取指定位置的bin-log文件的日志内容,
  • (2)Master接收到来自Slave的IO进程的请求后,通过负责复制的IO进程根据请求信息读取指定日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置;
  • (3)Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的某个位置开始往后的日志内容,请发给我”;
  • (4)Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行

2.3 MySQL主从复制模式

    1. 异步复制(Asynchronous replication),即主库(Master)在执行完客户端提交的事务后会立即将结果返给给客户端,主库(Master)并不关心从库(Slave)是否已经复制了本次的写操作。异步复制效率较高,因为主库不关心从库的操作。但缺点也较为明显,即主从的数据一致性无法保障,从而影响高可用和容灾能力。
    1. 全同步复制(Fully synchronous replication),即主库(Master)执行完一个事务后不会立即返回客户端执行结果,而是等待所有的从库都执行了该事务才返回给客户端。全同步复制能够保证主从的数据一致性,但缺点是主库完成一个事务的时间会被拉长,性能降低。
    1. 半同步复制(Semisynchronous replication),介于全同步复制与全异步复制之间的方式,主库(Master)只需要等待至少一个从库(Slave)收到主库执行的事务修改并复制动作的应答,而不需要等待所有从库给主库反馈。半同步复制能够很大程度上提高效率,同时保证主从的数据一致性。

2.4 bin-log记录方式

  • 1.基于SQL语句的复制(statement based replication),Master端将每一条会修改数据的SQL记录下来,Slave端在复制的时候会根据二进制文件重新执行相同的SQL。这种模式的优点是Master端不需要记录每一行数据的变化(只记录sql query的执行动作),二进制日志文件量小,IO成本低,速度快。缺点是从库需要执行主库相同的SQL,就需要额外的知道每条语句执行的上下文信息,以保证该相同的操作在Slave端执行时能够得到和Master同样的结果。且并非所有的SQL语句都能被复制,当SQL操作不确定或操作较为复杂时可能导致从库执行失败。
  • 2.基于行记录的复制(row based replication),该模式的主要流程是,MySQL二级制日志文件会将每一行数据修改都记录下来,然后在Slave端进行同样的修改。这种模式的优点是:日志文件不需要将SQL语句执行的上下文记录下来,只是记录哪一条数据修改了,修改成什么样子了。相较于基于SQL语句的复制,基于行记录的复制在任何情况都可以被复制,是相对安全可靠的复制方式。
    缺点是bin-log的存储成倍增加。例如:执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。这样就大增加了复制过程的IO成本,导致速度下降、性能下降。
  • 3.混合方式复制(mixed based replication), 该模式结合了之前两种模式的优点,规避了二者的缺点。在该模式下,MySQL会根据执行的每一条语句来区分记录日志文件的格式。举例说明,当涉及到复杂的存储过程时,采用Row Level,规避Statement Level存在的某些场景无法复制的问题;当涉及到Alter table等操作时,采用Statement Level来规避Row Level带来的日志量巨大的问题。

2.5 全局事务标识(Global Transaction Identifier —— GTID)

GTID是唯一的标识符,由UUID(MySQL server中的全局唯一标识) + 事务id组成,一个事务对应一个GTID。GTID自动添加到事务的头部,并写入到bin-log中。GTID使得追踪和复制事务变得简单,而且能从宕机中快速恢复,如果主库(Master)宕机了,那么从库(Slave)要有顶替成为主库(Master)的方法。同理,如果宕机的机器恢复了,那么要有回到集群的方法。

以2.1节图中的3节点MySQL集群为例,假如已有MySQL集群是A为Master,B和C为Slave。此时A宕机了,需要从B和C中重新选择一个Master。replication机制是异步或半同步复制,若复制模式为半同步复制,可以通过GTID快速选择与Master保持一致的Slave成为新的Master;若复制方式为异步复制,那么B和C中的数据不一定包含了全部的A的数据,且B和C的数据也有可能不一致。此时若选择B为新的Master,根据GTID可以追踪到B和C中已完成的事务,从而将C中已完成的且B中为完成的数据迁移到B中。

全部评论

相关推荐

面试官人很好,态度和蔼可亲,没答出来时也会引导你去思考。由于是晚上面的,导致我白天一天都有点紧张,面的时候状态也不是很好,正常可能面试官提问完应该思考几秒再答,而我就像抢答一样一口气把所有会的都说出来,这样就导致逻辑比较混乱,东一句西一句的。首先是自我介绍,先把会的技术大致讲一下,由于我八股背的多所以着重讲了一下,Java,go,jvm,MySQL,Redis,计网,操作系统这些,然后一小部分闲聊,然后先问了一下项目,面试官问我这个项目是否落实之类的,直接坦言说是写的练手的,包括之前也写过IM通讯,外卖之类的。然后面试官就把提问的重点放在了八股上。先问了Java:类加载器(答:3种+自定义类加载器、tomcat、原因+双亲委派+好处)JVM参数(答:xmx,xms,newsize这些,问我是如何设定的,我回答是把内存分一半给堆,再把堆分一半给新生代,这方面确实不太了解)然后问了一下并发相关的:线程池(答:线程池的7个参数(忘了线程工厂和阻塞时间了),3个重要参数,还有线程如何启用,为什么要设计最大线程数之类的,提到Java栈默认分配1MB运行时不可以更改)AQS(答:先讲clh是自旋锁+list,然后是AQS在这个基础上做的两个优化,然后举了一下reentrantlock根据state如何获取资源)CAS(答:使用三个字段,aba问题,然后将通常搭配自旋锁实现,面试官问通常会自旋多少次,这个不太了解,答的100,然后问100次大概多少秒,回答微秒级,然后面试官讲了一下怎么做资源可能没用完,意识到可能还需要进行阻塞操作)然后考虑一下Linux命令(top,ps,如何使用管道符过滤线程和使用Linux启动线程没答出来)然后问Redis:持久化机制(答:三种aof,rdb,混合,aof的三个参数刷盘策略,rdb以快照保存,使用bgsave会使用子线程来保存不会阻塞,而aof虽然会阻塞但是只在写完数据后追加一条命令,不会太影响,然后是他俩的优缺点,还有混合是怎么保存数据的)集群模式(答:三种,主从复制到缺点再到哨兵机制,正常使用三个哨兵互相监督,主节点挂了投票选主哨兵然后选主节点,然后额外讲一下脑裂的问题,主节点进行数据更新然后把命令写入aof来同步从节点,最后cluster集群,如何实现,使用16383个哈希槽(艹答成16384了),先根据哈希码取余,再根据节点数取余决定放在哪个节点上,然后问了一下我会怎么选集群模式,首先是cluster的问题,会让管道操作之类的失效,然后哨兵会导致整个集群结构变得复杂,使用小项目可能会考虑哨兵,大的考虑cluster,然后考了一下cluster如果一个节点挂了怎么办,根据节点数重新取余然后数据转移,面试官说这么转移比较慢,有没有别的办法,我隐约记得使用一个类似环形数组的方式,想不起来了)然后考了一下MySQL的b+树(这方面的知识点太多了,导致我什么都想讲逻辑就比较乱,讲了一下聚簇索引,树的叶子节点对应着一张页16KB,MySQL有一个区的概念,把这些页放在同一个区中,这样叶子节点的双向链表遍历时速度更快,然后b+树的扇出比较大(非常二,说成扇度之类的,面试官以为说的是扇区)这样层数就比较小,一行1kb数据的话3层可以放心2000w数据)其他的暂时想不起来了算法是lru,面试官问要不要提示,我说写个,然后写了10分钟左右,说大概写好了,但是面试官指出了2个小错误,第一个马上就改回来了,第二个一直没看出来(大脑这时候已经停止工作了)反问:问学习建议,说根据实际的项目进行深入,考虑应该怎么做,还问了一下组里面是做Java的吗?面试官说他是做go的,组里什么语言都有,语言影响不大,连忙补充了一句我对go的底层有深入源码的学习)结束。总体感觉答得不太好,没有太体现出深度,细节也不够全面。
下一个更好呗:佬,我投完云智一直没消息,多久约的一面啊
查看14道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务