本文主要介绍“如何理解数据库子表,读写分离”。在日常操作中,相信很多人对于如何理解数据库子表、读写分离都有疑惑。边肖查阅了各种资料,整理出简单易用的操作方法,希望能帮你解答“如何理解数据库子表,读写分离”的疑惑!接下来,请和边肖一起学习!
00-1010当不使用子数据库和子表时,系统的性能瓶颈主要体现在:
面对高并发场景,为了避免Mysql崩溃(性能一般的MySql服务器建议读写并发低于2000/s),消息队列只能用来削峰。
受独立限制。数据库的磁盘容量很紧张。
数据库中单个表的数据量太大,sql运行越来越慢。
子数据库和子表正是为了解决这些问题,提高数据库读写的并发性,大大增加磁盘容量,减少单个表的数据量,提高查询效率。
00-101010
一、为什么要用分库分表
垂直拆分是指根据表格的字段进行拆分,其实很常见。有时是在数据库设计时完成的,属于数据库设计范式,如订单表、订单付款表、商品表。
水平分割表结构,数据分割。例如,原始的t_order表变成t_order_0、t_order_1和t_order_3。
00-1010垂直拆分是指根据不同的业务将原有的大型图书馆拆分成不同的图书馆(微服务一般都是这样设计的,即专用图书馆是专用的)。
服务的水平拆分对应多个库,每个库都有相同的业务表。例如,库1有一个t_order表,库2也有一个t_order表。系统通过数据库中间件或中间层操作t_order表,子数据库操作对业务代码透明。
因此,我们通常在提到子库和子表时,一般指的是水平拆分。
00-1010侧重于MyCat和sharding-jdbc。
两者之间的比较:
MyCat:基于中间件的形式,提供读写分离、子数据库和子表的功能。只是很久没更新了。我用的是1.6版本,不支持逻辑表的子数据库和子表同时存在。
Sharding-jdbc:基于jar包的中间层,提供读写分离、子库和子表的功能。社区更活跃。强大的支持。
二、垂直拆分和水平拆分
哈希除法方法,根据一个键来哈希模数,然后分发给一个表或库。优点是每个表的压力可以平均分担,缺点是容量扩展时会出现数据迁移问题。
按范围或时间分布的Range方法,例如,按键的值间隔或创建时间分布,其优点是易于扩展,但缺点是会导致数据热点问题。从子表来看,没关系。如果是子库,会导致一个库节点压力过大,节点间负载不均。
在这里,我认为最好的划分方法是哈希划分和范围划分。因为平衡负载对库很重要,动态扩展表也很重要。
00-1010
以表的维度来说:
方案非常简单,即在停机维护时,将旧的数据库数据直接分发到需要由基于数据库中间件的后台临时程序迁移的数据库中。
这种方案的主要缺点是肯定会有几个小时的停机时间。如果做不到,第二天还要继续做,开发者会慌。
00-1010主要步骤:
修改系统中所有库的代码,同时编写旧库和数据库中间件(包括添加、更新和删除操作)。
然后,在后台,使用工具将旧数据库之前的旧数据库数据迁移到新的数据库中间件。注意比较修改时间。如果id相同,根据修改时间决定是否覆盖。
使用后台工具对数据进行一次比较,看看它们是否完全相同。如果它们不同,后台工具将用于另一次迁移。(为了避免某些数据由于网络问题或业务错误而无法成功迁移),此过程通常需要几天时间。
这个循环重复几次,当数据正好是
以库的维度来说:
在有子数据库和子表的情况下,如何在已经有子数据库和子表的基础上进一步增加子数据库和子表,提高系统效率,是一个比较麻烦的问题。特别是对于基于哈希分片的服务器,再一次,只能关闭服务器,然后根据新的规则将所有数据插入到不同的库和表中。为了避免这个问题,我们可以在第一次把库分成表的时候,把库分成更小的部分,避免第二次扩展。例如:
一开始,图书馆分为32个图书馆。刚开始的时候业务量没那么大。可以在同一台机器上放多个库,然后按照2-4-8-16-32展开。例如,在开始时,两台机器可以满足数据库的读写并发。这
时一台服务器上有16个库,后来不够了,就扩容为4台机器,每台机器8个库。。。依次类推,这样做的好处是只需要迁移需要迁移的库,并且是按照整个库进行迁移,不需要重新进行分发,同时分库分表的分片机制也不用修改,只需要修改其数据源就行了。
对于分表来说,也可以分的多一些,推荐分为32张表。
以上,分为了32个库32张表,总共数据量可以达到32 * 32 = 1024张表,按每张表500万正常的容量来算,可以容纳约50亿数据,足以满足大部分过扩容需求。
另外这种方案推荐扩容方案为2-4-8-16-32倍数进行扩容,深层原因是32是这些数的公倍数,按照约数进行扩容更容易让每个机器负载的库都一样。
需要注意的是如果按照同一分片键进行同样的分片策略分库分表,会导致数据只会达到某库的某表比如1库的1表,2库的2表,(因为库和表的数量也是一样)所以分库我们可以按32取模策略,分表的话我们可以按整除之后的余数再对32取模进行分表。
七、全局id的生成策略
几种生成id的方式对比:
-
通过数据库自增
往公用的一张表(这张表是自增主键)插入一条数据,获取id的返回值,用这个id再去插入中间件当中去。oracle可以通过自增序列。
缺点:不适合并发高的场景,毕竟不管是自增序列还是采取自增键的方式来生成,会并发竞争写锁,效率太低。
-
UUID
缺点:uuid太长了,不规则
-
时间戳
一般联合其他业务字段拼接作为一个Id,如时间戳+用户id+业务含义编码
缺点:并发高容易重复
-
雪花算法
原理:前面1位为定值0+41位为时间戳+5位机房id+5位为机器id+12位为序号,唯一需要保证同步的地方是生成一个序号,锁粒度较低。另外这个算法可用于分布式环境中。最大的优点是不需要依赖任何中间件,核心原理是用5位机房id,5位机器id标志了唯一一台机器,所以不需要分布式锁去保证不同机器生成id的同步性,只需要在当前机器保证生成的序号不一样就行了。
-
redis中间件生成
原理:利用redis单线程工作线程属性去维护一个自增变量。
八、读写分离
为什么要读写分离
-
理论上来说读写请求不要超过2000/s,如果加了缓存之后,到数据库请求还是超过2000以上考虑读写分离
-
使得读请求可以在不同机器并发,用了读写分离之后可以通过动态扩展读服务器增加读效率,这与redis中的主从架构读写分离、copyOnWrite机制的并发容器、以及数据库MVCC机制有点相识,都是通过读请求的数据备份增加读写并发效率。
-
适用于业务场景中,读请求大于写请求的情况,读写分离使得系统能够更多的容纳读请求并发。
读写分离的实现方式
一般来说是基于mysql自带的主从复制功能。mysql主从复制的流程图如下:
总结mysql的主从复制过程大体是主库有一个进程专门是将将记录的Binlog日志发送到从库,从库有一个io线程(5.6.x之后IO线程可以多线程写入relay日志)将收到的数据写入relay日志当中,另外还有一个SQL进程专门读取relay日志,根据relay日志重做命令(5.7版本之后,从可以并行读取relay log重放命令(按库并行,每个库一个线程))。
主从同步的三种模式:
-
异步模式(mysql async-mode)
异步模式如下图所示,这种模式下,主节点不会主动push bin log到从节点,这样有可能导致failover的情况下,也许从节点没有即时地将最新的bin log同步到本地。
-
半同步模式(mysql semi-sync)
这种模式下主节点只需要接收到其中一台从节点的返回信息,就会commit;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性,确保了事务提交后,binlog至少传输到了一个从节点上,不能保证从节点将此事务更新到db中。性能上会有一定的降低,响应时间会变长。如下图所示:
-
同步模式(mysql semi-sync)
全同步模式是指主节点和从节点全部执行了commit并确认才会向客户端返回成功。
读写分离场景下主从延迟可能导致的问题
在代码中插入之后,又查询这样的操作是不可靠,可能导致插入之后,查出来的时候还没有同步到从库,所以查出来为null。如何应对这种情况了?其实并不能从根本上解决这种情况的方案。只能一定程度通过降低主从延迟来尽量避免。
降低主从延迟的方法有:
-
拆主库,降低主库并发,降低主库并发,此时主从延迟可以忽略不计,但并不能保证一定不会出现上述情况。
-
打开并行复制-但这个效果一般不大,因为写入数据可能只针对某个库并发高,而mysql的并行粒度并不小,是以库为粒度的。
但这并不能根本性解决这个问题,其实面对这种情况最好的处理方式是:
-
重写代码,插入之后不要更新
-
如果确实是存在先插入,立马就能查询到,然后立马执行一些操作,那么可以对这个查询设置直连主库(通过中间件可以办到)
到此,关于“怎么理解数据库的分库分表、读写分离问题”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/97028.html