持久化存储-MySql拓展

先说一个概念

ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability).
这是可靠数据库所应具备的几个特性.

一、MySql拓展

1、业务拆分

随着网站的业务不断发展单个库访问量越来越大,因此不得不对系统业务进行拆分。每一块业务都使用单独的数据库来进行存储,前端不同的业务访问不同的数据库,这样原本依赖单库的服务,变成几个库同时承担压力,吞吐能力自然就提高了。
业务拆分不仅提高了系统的可拓展性,也带来了开发工作效率的提升。原来一次简单修改,工程启动和部署都可能需要很长时间。随着系统的拆分,单个系统复杂度降低,减轻了应用多个分支带来的分支合并冲突解决的麻烦,不仅大大提高了开发测试的效率,同时也提高了系统的稳定性。

2、复制策略

架构变化的同时,业务也在不断的发展,可能很快就会发现,随着访问量的不断增加,拆分后的某个库的压力越来越大,马上就要达到性能瓶颈,数据库架构不得不再次进行变更。这时可以使用Mysql的replication(复制)策略来对系统进程拓展。
通过数据库的复制策略,可以将一台MySql数据库服务器中的数据复制到其他MySql数据库服务器上。当各台数据库服务器上都包含相同的数据时,前端的应用通过访问MySql集群中的任意一台服务器,都能够读取到相同的数据,这样单独一台数据库服务器所承担的负载就会大大降低,从而提高整个系统的承载能力,达到系统拓展的目的。

2.1 Master-Slave


这里写图片描述

如图所示,要实现数据库的复制,需要开启Master服务器端的Binary Log,数据复制的过程实际上就是Slave从Master获取Binary Log,然后再在本地镜像的执行日志中记录操作。
由于复制的过程是异步的,因此Master和Slave之间的数据可能会出现延迟现象,此时只能保证数据最终的一致性。

MySql的复制可以基于一条语句(statement level),也可以基于一条记录(row level)。
通过row level的复制,可以不记录Sql语句相关联的上下文信息,只需记录数据变更的内容即可。但由于每行的变更都会被记录,这样可能会产生很多的日志内容。

使用statement level则只记录修改数据的Sql语句,减少了Binary log的日志量,解决了I/O成本。但是为了保证Sql能够在Slave上正确的执行,他还需要记录Sql执行的上下文信息,以保证所有语句在Slave端执行时能够得到在Master端执行的相同结果。


这里写图片描述

如图,在实际的应用场景中,MySQL的Master与Slave之间的复制架构有可能是这样的。
前端服务器通过Master来执行数据的写入操作,数据的更新通过Binary log同步到Slave集群,而对于数据的读取请求,则交由Slave来处理。这样Slave集群可以分担数据库的读压力,并且读写分离还保障了数据能够达到最终一致性。

一般而言,大多数网站的读操作要比写操作更为密集。

如果读的压力较大,可以通过增加Slave来进行系统的拓展,因此,Master-Slave的架构能够显著的减轻前面所提到的单库读的压力。

Master-Slave复制架构存在一个问题,即所谓的单点故障。当Master宕机时,系统将无法进行写入,但是在某些特定的场景下,也可能需要Master停机,以便进行系统维护、优化或者升级。
同样道理,Master的停机将会导致整个系统都无法写入,直到Master恢复,大部分情况下显然是难以接受的。

2.2 Master-Master

为了尽可能的降低系统停止写入的时间,最佳的方案就是采用Dual-Master架构,即Maste-Master架构。


这里写图片描述

所谓的Dual-Master,实际上就是两台MySQL服务器互相将对方作为自己的Master,自己作为对方的Slave,这样任何一台服务器上的数据变更,都会通过MySQL的复制机制同步到另一台服务器。

由于MySQL在记录Binary log时,记录了当前的server-id,server-id在我们配置MySQL时就已经设置好了。一旦有了server-id,MySQL就能够很容易的判断最初的写入是在那台服务器上发生的,MySQL不会将复制所产生的变更记录到Binary Log,这样就避免了服务器间数据的循环复制。

当然,我们搭建Dual-Master架构,并不是让两台Master都提供写入服务,因为这样会导致一些数据写入时数据不一致的问题。例如:假入Master A和Master B几乎同时对一条数据进行了更新,对Master A的更新比对Master B的稍微快一点点,当对Master A的更新最终同步到Master B时, 老版本的数据会把版本更新的数据覆盖,而且不会抛出异常,从而导致数据不一致的现象发生。

在通常情况下,我们只开启一台Master的写入,另一台Master仅仅Stand By或者作为读库开放,这样可以避免数据写入的冲突,防止数据不一致的情况发生。

2.3 分表

对于大型的互联网应用来说,数据库单表的记录行数可能达到千万级甚至亿级,并且数据库面临着极高的并发访问。采用Master-Slave复制模式的架构,仅仅只是对数据的读进行了拓展,而对于数据库的写操作,仍然集中在了Master上。而且单个Master所挂载的Slave也不可能无限多,Slave数量受到了Master的能力和负载的影响。

因此,要对数据库的吞吐能力进行进一步的拓展,以满足高并发访问和海量数据存储的需求。
对于访问极为频繁且数据量相当庞大的单表来说,首先要做的就是减少单表的记录条数,以便减少查询所需要的时间,提高数据库的吞吐,这就是所谓的分表。

在分表之前,首先要考虑的是分表的策略,使得数据能够较为均衡的分布到多张表中并且不影响正常额查询。

对于互联网企业来说,大部分数据都是和用户关联的,因此,用户id是最常用的分表字段。
举例:


这里写图片描述

假设有一张记录用户购买信息的订单表order,由于order表记录的数据太多,将被拆分成256张表。拆分的记录根据user_id%256取得对应的表进行村春,前台应用则根据对应的user_id%256,找到对应订单存储的表进行访问。

2.4 分库
分表能够解决单表数据量过大带来的查询效率下降的问题,但是却无法给数据库的并发处理能力带来质的提升。面对高并发的读写操作,当数据库Master无法承载写操作压力时,不管如何拓展Slave,此时都没有意义。
因此,我们需要换一种思路,对数据库进行拆分,从而提高数据库的写入能力,这就是所谓的分库。


这里写图片描述

2.5 分库分表

有时数据库可能既面临高并发的访问,又要面临海量数据的存储,这是就需要对数据库即进行分表,也进行分库操作,以便同时提高系统的高并发处理能力,以及提升单表的查询能力,这就是所谓的分库分表。

分库分表的策略比单独分库和单独分表策略更为复杂。

数据库经过业务拆分以及分库分表之后,虽然查询性能和并发处理能力提高了,但是也会带来一系列的问题,如原本跨表的事务变成了分布式事务;记录被拆分到不同的库不同的表中,也无法进行多表关联查询。

猜你喜欢

转载自blog.csdn.net/zyhlwzy/article/details/80569038