MySQL主从复制简单来说就是用来保证主MySQL(Master)服务器和从MySQL(Slave)服务器的数据一致性的一种机制.当我恩向Master插入数据后,Slave会自动从Master把修改的数据同步过来(有一定的延迟),通过这种方式来保证数据的一致性,这就是所谓的主从复制.
MySQL的主从复制解决了数据库的读写分离,并很好的提升了读的性能.其图如下:
其主从复制的过程如下图所示:
当Master挂掉后,可以指定一台Slave充当Master继续保证服务运行,因为数据是一致性的(如果刚插入Master就挂掉,可能不一致,因为同步也需要时间).
2. 负载均衡读写分离其实也算是负载均衡的一种,一般都是有多台Slaver,所以可以将读操作指定到Slave服务器上(需要代码控制),然后再用负载均衡来选择哪台Slaver来提供服务,同时也可以吧一些大量计算的查询指定到某台Slaver,这样就不会影响Master的写入以及其他查询.
3. 数据备份一般我们都会做数据备份,可能是写定时任务,一些特殊行业可能还需要手动备份,有些行业要求备份和原数据不能在同一个地方,所以主从就能很好的解决这个问题,不仅备份及时,而且还可以多地备份,保证数据的安全.
4. 业务模块化可以一个业务模块读取一个Slaver,再针对不同的业务场景进行数据库的索引创建和根据业务选择MySQL存储引擎.
5. 高扩展(硬件扩展)主从复制支持2种扩展方式:
5.1 scale-up向上扩展或者纵向扩展,主要是提供比现在服务器更好性能的服务器,比如增加CPU和内存以及磁盘阵列等,因为有多台服务器,所以可扩展性比单台更大.
5.2 scale-out向外扩展或者横向扩展,是指增加服务器数量的扩展,这样主要能分散各个服务器的压力.
三. 主从复制的缺点 1. 成本增加无可厚非的是搭建主从肯定会增加成本,毕竟一台服务器和两台服务器的成本完全不同,另外由于主从必须要开启二进制日志,所以也会造成额外的性能消耗.
2. 数据延迟Slave从Master复制过来肯定是会有一定的数据延迟的,所以当刚插入就进行查询的,可能查询不出来,当然如果是插入者自己查询,那么可以直接从Master中查询出来.
3. 写入更慢主从复制主要是针对读远大于写或者对数据备份实时性要求较高的系统中,因为Master在写中需要更多操作,而且只有一台写入的Master(因为我目前只会配置一台写入Master,最多就是有从Master的Slaver,用来在Master挂掉后替换成Master,平时不对外进行服务),所以写入的压力并不能被分散.
四. MySQL主从复制的方式MySQL5.6开始主从复制有两种方式: 基于日志(binlog)、基于GTID(全局事务标示符).
五. MySQL主从复制原理MySQL要做到主从复制,其实依靠的是二进制日志,类似Oracle中的归档日志,即:假设主服务器叫Master,从服务器叫Slave.主从复制就是Slave跟着Master学,Master做什么,Slave就做什么.
那么Slave怎么同步Master的动作呢?现在Master有一个日志功能,把自己所做的增删改查的动作全都记录在日志中,Slave只需要拿到这份日志,照着日志上面的动作施加到自己身上就可以了,这样就实现了主从复制.具体实现如下图:
1️⃣. Master将数据改变记录到二进制日志(binary log)中,也就是配置文件log-bin指定的文件,这些记录叫做二进制日志事件(binary log events);
2️⃣. Slave通过I/O线程读取Master中的binary log events并写入到它的中继日志(relay log);
3️⃣. Slave重做中继日志中的事件,把中继日志中的事件信息一条一条的在本地执行一次,完成数据在本地的存储,从而实现将改变反映到它自己的数据(数据重放).
六. MySQL垂直分区如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力.经过垂直分区后的数据库架构图如下:
然而,尽管业务之间已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务相关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题,因此为何不试试水平分割呢?
七. MySQL水平分片(Sharding)将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可.原理图如下:
如何来确定某个用户所在的shard呢?可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shardid,再从对应shard中查询相关数据,如下图所示:
单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到.
2. 单库多表随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能.如果使用mysql,还有一个更严重的问题是,当需要添加一列的时候,mysql会锁表,期间所有的读写操作只能等待.
可以通过某种方式将user进行水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000+user_0001+…的数据刚好是一份完整的数据.
3. 多库多表随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑,这个时候可以再对数据库进行水平区分.
八. 分库分表规则设计表的时候需要确定此表按照什么样的规则进行分库分表.例如,当有新用户时,程序得确定将此用户信息添加到哪个表中.同理,当登录的时候我们得通过用户的账号找到数据库中对应的记录,所有的这些都需要按照某一规则进行.
1. 路由通过分库分表规则查找到对应的表和库的过程,如分库分表的规则是user_idmod4的方式,当用户新注册了一个账号,账号id的123,我们可以通过idmod4的方式确定此账号应该保存到User_0003表中.当用户123登录的时候,我们通过123mod4后确定记录在User_0003中.
2. 分库分表产生的问题,及注意事项: 2.1 分库分表维度的问题假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦.反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找到买人的交易记录比较麻烦.
所以常见的解决方式有:
-
a.通过扫表的方式解决,此方法基本不可能,效率太低了;
-
b.记录两份数据,一份按照用户纬度分表,一份按照商品维度分表;
-
c.通过搜索引擎解决,但如果实时性要求很高,又得关系到实时搜索.
联合查询基本不可能,因为关联的表有可能不在同一数据库中.
2.3 避免跨库事务避免在一个事务中修改db0中的表的时候同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响.
2.4 尽量把同一组数据放到同一DB服务器上例如将卖家a的商品和交易信息都放到db0中,当db1挂了的时候,卖家a相关的东西可以正常使用,也就是说避免数据库中的数据依赖另一数据库中的数据.
2.5 一主多备在实际的应用中,绝大部分情况都是读远大于写.Mysql提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在Master和Slave机器上进行,Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂Slave,通过此方式可以有效的提高DB集群的QPS.
所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重.
此外,可以看出Master是集群的瓶颈,当写操作过多,会严重影响到Master的稳定性,如果Master挂掉,整个集群都将不能正常工作.
所以:
-
a.当读压力很大的时候,可以考虑添加Slave机器的分式解决,但是当Slave机器达到一定的数量就得考虑分库了;
-
b.当写压力很大的时候,就必须得进行分库操作.