-
2021-08-22 10:13:12
在日常的工作中,关系型数据库本身比较容易成为系统的瓶颈点,虽然读写分离能分散数据库的读写压力,但并没有分散存储压力,当数据量达到千万甚至上亿时,单台数据库服务器的存储能力会成为系统的瓶颈,主要体现在以下几个方面:
- 数据量太大,读写的性能会下降,即使有索引,索引也会变得很大,性能同样会降下。
- 数据库文件会得很大,数据库备份和恢复需要耗时很长。
- 数据库文件越大,极端情况下丢失数据的风险越高。
因此,当流量越来越大时,且单机容量达到上限时,此时需要考虑对其进行切分,切分的目的就在于减少单机数据库的负担,将由多台数据库服务器一起来分担,缩短查询时间。
切分策略
数据切分分为两种方式,纵向切分和水平切分
- 纵向切分
常见有纵向分库纵向分表两种。
1). 纵向分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库,做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与“微服务治理”的做法相似,每个微服务使用单独的一个数据库。
2). 垂直分表是基于数据库中的列进行,某个表字段较多,可以新建一张扩展表,将不经常用或者字段长度较大的字段拆出到扩展表中。在字段很多的情况下,通过大表拆小表,更便于开发与维护,也能避免跨页问题,MYSQL底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的开销。另外,数据库以行为单位将数据加载到内存中,这样表中字段长度越短且访问频次较高,内存能加载更多的数据,命中率更高,减少磁盘IO,从而提升数据库的性能。
- 垂直切分的优点:
- 解决业务系统层面的耦合,业务清晰
- 与微服务的治理类似,也能对不同业务的数据进行分级管理,维护,监控,扩展等。
- 高并发场景下,垂直切分一定程度的提升IO,数据库连接数,单机硬件资源的瓶颈。
- 垂直切分的缺点
- 部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度。
- 分布式事处理复杂
- 依然存在单表数据量过大的问题。
- 水平切分
当一个应用难以再细粒度的垂直切分或切分后数据量行数依然巨大,存在单库读写,存储性能瓶颈,这时候需要进行水平切分。
水平切分为库内分表和分库分表,是根据表内数据内在的逻辑关系,将同一个表按不同的条件分散到多个数据库或多表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。
库内分表只解决单一表数据量过大的问题,但没有将表分布到不同机器的库上,因些对于减轻mysql的压力来说帮助不是很大,大家还是竞争同一个物理机的CPU、内存、网络IO,最好通过分库分表来解决。
- 水平切分优点
- 不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力。
- 应用端改造较小,不需要拆分业务模块。
- 水平切分缺点
- 跨分片的事务一致性难以保证
- 跨库的join关联查询性能较差
- 数据多次扩展维度和维护量极大。
#路由规则
水平切分后同一张表会出现在多个数据库或表中,每个库和表的内容不同,对于水平分表后分库后,如何知道哪条数据在哪个库里或表里,则需要路由算法进行计算,这个算法会引入一定的复杂性。
-
范围路由
选取有序的数据列,如时间戳作为路由的条件,不同分段分散到不同的数据库表中,以最常见的用户ID为例,路由算法可以按照1000000的范围大小进行分段,1 ~ 9999999放到数据库1的表中,10000000~199999999放到数据库2的表中,以此累推。
范围路由设计的复杂点主要体现在分段大小的选取上,分段太小会导致切分后子表数量过多增加维护复杂度,分段太大可能会导致单表依然存在性能问题,按一般大老们的经验,分段大小100W至2000W之间,具体需要根据业务选 取合适的分段大小。- 范围路由的优点
- 可以随着数据的增加平滑地扩充新的表或库,原有的数据不需要动。
- 单表大小可控
- 使用分片字段进行范围查找时,连续分片可快速定位查询,有效避免分片查询的问题。
- 热点数据成为性能瓶颈,连续分片可能存在数据热点,例如按时单字段分片,有些分片存储最近时间内的数据,可能会被频繁读写,而有些历史数据则很少被查询。
-
hash算法
选取某个列或几个列的值进行hash运算,然后根据hash的结果分散到不同的数据库表中,以用ID为例,假如我们一开始就规划10个数据库表,路由算法可以简单地用id % 10的值来表示数据所属的数据库编号,ID为985的用户放到编号为5的子表中。ID为10086编号放到编号为6的表中。
Hash路由设计的复杂点主要体现 在初始表数量的选取上,表数量太多维护比较麻烦,表数量太小又可能导致单表性能存在问题。而用Hash路由后,增加字表数量是非常麻烦的,所有数据都要重新分布。
Hash路由的优缺点与范围路由相反,Hash路由的优点是表分布比较均匀,缺点是扩容时很麻烦,所有数据均需要重新分布。配置路由就是路由表,用一张独立的表来记录路由信息。同样以用户ID为例,我们新增一张ROUTER表,这个表包含table_Id两列,根据user_id就可以查询对应的修改路由表就可以了。
配置路由设计简单,使用起来非常灵活,尤其是在扩充表的时候,只需要迁移指定的数据,然后修改路由表就可以了。
其缺点就是必须多查询一次,会影响整体性能,而且路由表本身如果太大,性能会成为瓶颈点,如果我们再将路由表分库分表,则又面临一个死循环。分库分表带来的问题
水平分表后,虽然物理上分散在多个表中,如果需要与其它表进行join查询,需要在业务代码或者数据库中间件中进行多次join查询,然后将结果合并。
水平分表后,某些场景下需要将这些表当作一个表来处理,那么count(*)显得没有那么容易 了。
分表后,数据分散到多个表中,排序操作无法在数据库中完成,只能由业务代码或数据中间件分别查询每个子表中的数据,然后汇总进行排序。
更多相关内容 -
数据库分库分表(sharding)系列
2021-01-31 02:10:20数据库分库分表(sharding)实施策略图解1.准备阶段对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系统业务逻辑和数据库schema.一个好的建议是绘制一张数据库ER图或领域模型图,以这类图为基础划分shard,... -
Mycat数据库分库分表
2018-10-28 12:22:43用户制作数据库的分库分表,Mycat软件压缩包,加压后即可使用 -
MyBatis实现Mysql数据库分库分表操作和总结(推荐)
2020-08-29 15:38:49主要介绍了MyBatis实现Mysql数据库分库分表操作和总结,需要的朋友可以参考下 -
数据库分库分表
2020-04-25 15:16:471、分库分表架构 关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维 度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重。...1、分库分表架构
关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维 度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重。此时就要考虑对其进行切分了,切分的目的就在于减少数据库的负担,缩短查询时间。
数据库分布式核心内容无非就是数据切分(Sharding),以及切分后对数据的定位、整合。数据切分就是将数据分散存储到多个数据库中,使得单一数据库中的数据量变小,通过扩充主机的数量缓解单一数据库的性能问题,从而达到提升数据库操作性能的目的。数据切分根据其切分类型,可以分为两种方式:垂直(纵向)切分和水平(横向)切分
1.1、垂直(纵向)切分
垂直切分常见有垂直分库和垂直分表两种。
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,每个微服务使用单独的一个数据库。如图:
垂直分表是基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,将不经常用或字段长度较大的字段拆分出去到扩展表中。在字段很多的情况下(例 如一个大表有100多个字段),通过"大表拆小表",更便于开发与维护,也能避免跨页问题,MySQL底层是通过数据页存储的,一条记录占用空间过大会导 致跨页,造成额外的性能开销。另外数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了 磁盘IO,从而提升了数据库性能。
垂直切分的优点:
- 解决业务系统层面的耦合,业务清晰
- 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
- 高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈
缺点:
- 部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度
- 分布式事务处理复杂
- 依然存在单表数据量过大的问题(需要水平切分)
1.2、水平(横向)切分
当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。
水平切分分为库内分表和分库分表,是根据表内数据内在的逻辑关系,将同一个表按不同的条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。如图所示:
库内分表只解决了单一表数据量过大的问题,但没有将表分布到不同机器的库上,因此对于减轻MySQL数据库的压力来说,帮助不是很大,大家还是竞争同一个物理机的CPU、内存、网络IO,最好通过分库分表来解决。
水平切分的优点:
- 不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力
- 应用端改造较小,不需要拆分业务模块
缺点:
- 跨分片的事务一致性难以保证
- 跨库的join关联查询性能较差
- 数据多次扩展难度和维护量极大
水平切分后同一张表会出现在多个数据库/表中,每个库/表的内容不同
2、什么时候考虑切分
2.1、能不切分尽量不要切分
并不是所有表都需要进行切分,主要还是看数据的增长速度。切分后会在某种程度上提升业务的复杂度,数据库除了承载数据的存储和查询外,协助业务更好的实现需求也是其重要工作之一。
不到万不得已不用轻易使用分库分表这个大招,避免"过度设计"和"过早优化"。分库分表之前,不要为分而分,先尽力去做力所能及的事情,例如:升级硬件、升级网络、读写分离、索引优化等等。当数据量达到单表的瓶颈时候,再考虑分库分表。
2.2、数据量过大,正常运维影响业务访问
这里说的运维,指:
1)对数据库备份,如果单表太大,备份时需要大量的磁盘IO和网络IO。例如1T的数据,网络传输占50MB时候,需要20000秒才能传输完毕,整个过程的风险都是比较高的
2)对一个很大的表进行DDL修改时,MySQL会锁住全表,这个时间会很长,这段时间业务不能访问此表,影响很大。如果使用pt- online-schema-change,使用过程中会创建触发器和影子表,也需要很长的时间。在此操作过程中,都算为风险时间。将数据表拆分,总量减 少,有助于降低这个风险。
3)大表会经常访问与更新,就更有可能出现锁等待。将数据切分,用空间换时间,变相降低访问压力
2.3、随着业务发展,需要对某些字段垂直拆分
2.4、数据量快速增长
随着业务的快速发展,单表中的数据量会持续增长,当性能接近瓶颈时,就需要考虑水平切分,做分库分表了。此时一定要选择合适的切分规则,提前预估好数据容量
2.5、安全性和可用性
鸡蛋不要放在一个篮子里。在业务层面上垂直切分,将不相关的业务的数据库分隔,因为每个业务的数据量、访问量都不同,不能因为一个业务把数 据库搞挂而牵连到其他业务。利用水平切分,当一个数据库出现问题时,不会影响到100%的用户,每个库只承担业务的一部分数据,这样整体的可用性就能提 高
3、切分策略
按照时间区间或ID区间来切分。
例如:按日期将不同月甚至是日的数据分散到不同的库中;将userId为1~9999的记录分到第一个库,10000~20000的分到第二个库,以此类推。
一般采用hash取模mod的切分方式,例如:将 Customer 表根据 cusno 字段切分到4个库中,余数为0的放到第一个库,余数为1的放到第二个库,以此类推
4、分库分表带来的问题
4.1、事务一致性问题
分布式事务
当更新内容同时分布在不同库中,不可避免会带来跨库事务问题。跨分片事务也是分布式事务,没有简单的方案,一般可使用"XA协议"和"两阶段提交"处理。
分布式事务能最大限度保证了数据库操作的原子性。但在提交事务时需要协调多个节点,推后了提交事务的时间点,延长了事务的执行时间。导致事务在访问共享资源时发生冲突或死锁的概率增高。随着数据库节点的增多,这种趋势会越来越严重,从而成为系统在数据库层面上水平扩展的枷锁。
最终一致性
对于那些性能要求很高,但对一致性要求不高的系统,往往不苛求系统的实时一致性,只要在允许的时间段内达到最终一致性即可,可采用事务补偿的方式。与事务在执行中发生错误后立即回滚的方式不同,事务补偿是一种事后检查补救的措施,一些常见的实现方法有:对数据进行对账检查,基于日志进行对比,定期同标准数据来源进行同步等等。事务补偿还要结合业务系统来考虑。
4.2、跨节点关联查询 join 问题
切分之前,系统中很多列表和详情页所需的数据可以通过sql join来完成。而切分之后,数据可能分布在不同的节点上,此时join带来的问题就比较麻烦了,考虑到性能,尽量避免使用join查询。
解决这个问题的一些方法:
1)全局表
全局表,也可看做是"数据字典表",就是系统中所有模块都可能依赖的一些表,为了避免跨库join查询,可以将这类表在每个数据库中都保存一份。这些数据通常很少会进行修改,所以也不担心一致性的问题。
2)字段冗余
一种典型的反范式设计,利用空间换时间,为了性能而避免join查询。例如:订单表保存userId时候,也将userName冗余保存一份,这样查询订单详情时就不需要再去查询"买家user表"了。
但这种方法适用场景也有限,比较适用于依赖字段比较少的情况。而冗余字段的数据一致性也较难保证,就像上面订单表的例子,买家修改了userName后,是否需要在历史订单中同步更新呢?这也要结合实际业务场景进行考虑。
3)数据组装
在系统层面,分两次查询,第一次查询的结果集中找出关联数据id,然后根据id发起第二次请求得到关联数据。最后将获得到的数据进行字段拼装。
4)ER分片
关系型数据库中,如果可以先确定表之间的关联关系,并将那些存在关联关系的表记录存放在同一个分片上,那么就能较好的避免跨分片join问题。在1:1或1:n的情况下,通常按照主表的ID主键切分。如下图所示:
这样一来,Data Node1上面的order订单表与orderdetail订单详情表就可以通过orderId进行局部的关联查询了,Data Node2上也一样。
4.3、跨节点分页、排序、函数问题
跨节点多库进行查询时,会出现limit分页、order by排序等问题。分页需要按照指定字段进行排序,当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片;当排序字段非分片字段时,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序,最终返回给用户。如图所示:
上图中只是取第一页的数据,对性能影响还不是很大。但是如果取得页数很大,情况则变得复杂很多,因为各分片节点中的数据可能是随机的,为了排序的准确性,需要将所有节点的前N页数据都排序好做合并,最后再进行整体的排序,这样的操作时很耗费CPU和内存资源的,所以页数越大,系统的性能也会越差。
在使用Max、Min、Sum、Count之类的函数进行计算的时候,也需要先在每个分片上执行相应的函数,然后将各个分片的结果集进行汇总和再次计算,最终将结果返回。如图所示:
4.4、全局主键避重问题
在分库分表环境中,由于表中数据同时存在不同数据库中,主键值平时使用的自增长将无用武之地,某个分区数据库自生成的ID无法保证全局唯一。因此需要单独设计全局主键,以避免跨库主键重复问题。有一些常见的主键生成策略:
1)UUID
UUID标准形式包含32个16进制数字,分为5段,形式为8-4-4-4-12的36个字符,例如:550e8400-e29b-41d4-a716-446655440000
UUID是主键是最简单的方案,本地生成,性能高,没有网络耗时。但缺点也很明显,由于UUID非常长,会占用大量的存储空间;另外,作为主键建立索引和基于索引进行查询时都会存在性能问题,在InnoDB下,UUID的无序性会引起数据位置频繁变动,导致分页。
2)结合数据库维护主键ID表
在数据库中建立 sequence 表:
CREATE TABLE `sequence` ( `id` bigint(20) unsigned NOT NULL auto_increment, `stub` char(1) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `stub` (`stub`) ) ENGINE=MyISAM;
stub字段设置为唯一索引,同一stub值在sequence表中只有一条记录,可以同时为多张表生成全局ID。sequence表的内容,如下所示:
+-------------------+------+ | id | stub | +-------------------+------+ | 72157623227190423 | a | +-------------------+------+
使用 MyISAM 存储引擎而不是 InnoDB,以获取更高的性能。MyISAM使用的是表级别的锁,对表的读写是串行的,所以不用担心在并发时两次读取同一个ID值。
当需要全局唯一的64位ID时,执行:
REPLACE INTO sequence (stub) VALUES ('a'); SELECT LAST_INSERT_ID();
这两条语句是Connection级别的,select last_insert_id() 必须与 replace into 在同一数据库连接下才能得到刚刚插入的新ID。
使用replace into代替insert into好处是避免了表行数过大,不需要另外定期清理。
此方案较为简单,但缺点也明显:存在单点问题,强依赖DB,当DB异常时,整个系统都不可用。配置主从可以增加可用性,但当主库挂了,主从切换时,数据一致性在特殊情况下难以保证。另外性能瓶颈限制在单台MySQL的读写性能。
flickr团队使用的一种主键生成策略,与上面的sequence表方案类似,但更好的解决了单点和性能瓶颈的问题。
这一方案的整体思想是:建立2个以上的全局ID生成的服务器,每个服务器上只部署一个数据库,每个库有一张sequence表用于记录当前全局ID。表中ID增长的步长是库的数量,起始值依次错开,这样能将ID的生成散列到各个数据库上。如下图所示:
由两个数据库服务器生成ID,设置不同的auto_increment值。第一台sequence的起始值为1,每次步长增长2,另一台的sequence起始值为2,每次步长增长也是2。结果第一台生成的ID都是奇数(1, 3, 5, 7 ...),第二台生成的ID都是偶数(2, 4, 6, 8 ...)。
这种方案将生成ID的压力均匀分布在两台机器上。同时提供了系统容错,第一台出现了错误,可以自动切换到第二台机器上获取ID。但有以下几个缺点:系统添加机器,水平扩展时较复杂;每次获取ID都要读写一次DB,DB的压力还是很大,只能靠堆机器来提升性能。
可以基于flickr的方案继续优化,使用批量的方式降低数据库的写压力,每次获取一段区间的ID号段,用完之后再去数据库获取,可以大大减轻数据库的压力。如下图所示:
还是使用两台DB保证可用性,数据库中只存储当前的最大ID。ID生成服务每次批量拉取6个ID,先将max_id修改为5,当应用访问ID生成服务时,就不需要访问数据库,从号段缓存中依次派发0~5的ID。当这些ID发完后,再将max_id修改为11,下次就能派发6~11的ID。于是,数据库的压力降低为原来的1/6。
3)Snowflake分布式自增ID算法
Twitter的snowflake算法解决了分布式系统生成全局ID的需求,生成64位的Long型数字,组成部分:
- 第一位未使用
- 接下来41位是毫秒级时间,41位的长度可以表示69年的时间
- 5位datacenterId,5位workerId。10位的长度最多支持部署1024个节点
- 最后12位是毫秒内的计数,12位的计数顺序号支持每个节点每毫秒产生4096个ID序列
这样的好处是:毫秒数在高位,生成的ID整体上按时间趋势递增;不依赖第三方系统,稳定性和效率较高,理论上QPS约为409.6w/s(1000*2^12),并且整个分布式系统内不会产生ID碰撞;可根据自身业务灵活分配bit位。
不足就在于:强依赖机器时钟,如果时钟回拨,则可能导致生成ID重复。
综上
结合数据库和snowflake的唯一ID方案,可以参考业界较为成熟的解法:Leaf——美团点评分布式ID生成系统,并考虑到了高可用、容灾、分布式下时钟等问题。
4.5、数据迁移、扩容问题
当业务高速发展,面临性能和存储的瓶颈时,才会考虑分片设计,此时就不可避免的需要考虑历史数据迁移的问题。一般做法是先读出历史数据,然后按指定的分片规则再将数据写入到各个分片节点中。此外还需要根据当前的数据量和QPS,以及业务发展的速度,进行容量规划,推算出大概需要多少分片(一般建议单个分片上的单表数据量不超过1000W)
如果采用数值范围分片,只需要添加节点就可以进行扩容了,不需要对分片数据迁移。如果采用的是数值取模分片,则考虑后期的扩容问题就相对比较麻烦。
5、常用的支持分库分表中间件:
- sharding-jdbc(当当)
- TSharding(蘑菇街)
- Atlas(奇虎360)
- Cobar(阿里巴巴)
- MyCAT(基于Cobar)
- Oceanus(58同城)
- Vitess(谷歌)
-
mysql数据库分库分表实践
2020-12-14 10:42:36一、背景 随着零售门店数量的增长,库存表,优惠劵表,消息表,订单表数据量不断的增多,目前一主(写)多从的MySQL 架构难于支撑公司业务的爆发式增长 二、调研 前期在于重点解决 MySQL 的单机...目前生产数据库架构 -
数据库分库分表策略的参考实现方案
2021-11-01 20:13:30对于数据库的扩展方案,主要包括:业务拆分、主从复制,数据库分库与分表。这篇文章主要讲述数据库分库与分表。 一、MySQL扩展方案具体的实现方式 (1)业务拆分 业务起步初始,为了加快应用上线和快速迭代,很多...目录
随着业务规模的不断扩大,需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。对于数据库的扩展方案,主要包括:业务拆分、主从复制,数据库分库与分表。这篇文章主要讲述数据库分库与分表。
一、MySQL扩展方案具体的实现方式
(1)业务拆分
业务起步初始,为了加快应用上线和快速迭代,很多应用都采用集中式的架构。随着业务系统的扩大,系统变得越来越复杂,越来越难以维护,开发效率变得越来越低,并且对资源的消耗也变得越来越大,通过硬件提高系统性能的方式带来的成本也越来越高。
因此,在选型初期,一个优良的架构设计是后期系统进行扩展的重要保障。
例如:电商平台,包含了用户、商品、评价、订单等几大模块,最简单的做法就是在一个数据库中分别创建users、shops、comment、order四张表。
但是,随着业务规模的增大、访问量的变大,我们不得不对业务进行拆分。对于每一个模块,都使用单独的数据库来进行存储。不同的业务访问不同的数据库,将原本对一个数据库的依赖拆分为对4个数据库的依赖。这样,系统就有4个数据库同时承担压力,吞吐量自然就提高了。
(2)主从复制
1、MySQL5.6 数据库主从(Master/Slave)同步安装与配置详解:
http://blog.csdn.net/xlgen157387/article/details/51331244
2、MySQL主从复制的常见拓扑、原理分析以及如何提高主从复制的效率总结:
http://blog.csdn.net/xlgen157387/article/details/52451613
3、使用mysqlreplicate命令快速搭建 Mysql 主从复制:
http://blog.csdn.net/xlgen157387/article/details/52452394
上述三篇文章,讲述了如何配置主从数据库,以及如何实现数据库的读写分离,这里不再赘述。有需要的同学,请自己点击查看。
下图是一张关于MySQL的Master和Slave之间数据同步的过程图。
该图主要讲述了MySQL主从复制的原理:首先,Slave从Master获取Binary log文件;然后,Slave在本地镜像地执行Binary日志中记录的操作。由于主从复制的过程是异步的,因此Slave和Master之间的数据有可能存在延迟的现象,其只能保证数据最终的一致性。
(3)数据库分库与分表
我们知道,无论机器配置多么好,每台机器都有自身的物理上限。所以,当我们的应用已经能触及或远远超出单台机器的某个上限的时候,我们惟有寻找别的机器的帮助,或者继续升级的我们的硬件,但常见的方案还是通过添加更多的机器来共同承担压力。
当我们的业务逻辑不断增长,我们的机器能不能通过线性增长就能满足需求?使用数据库的分库分表,能够立竿见影的提升系统的性能。关于为什么要使用数据库的分库分表,这里不再赘述,主要讲解具体的实现策略。
二、单库分表实现策略
关键字:用户ID、表容量
大部分数据库的设计和业务操作,基本都与用户ID相关。因此,用户ID作为贯穿整个系统的重要字段,是最常用的分库分表的路由策略因子。因此,使用用户ID,不仅可以方便查询,还可以将数据平均分配到不同的数据库中。(当然,还可以根据类别等进行分表操作,分表的路由策略有很多方式)
接着上述电商平台假设,订单表order存放用户的订单数据,sql脚本如下(只是为了演示,省略部分细节):
CREATE TABLE `order` ( `order_id` bigint(32) primary key auto_increment, `user_id` bigint(32), ... )
当数据量比较大的时候,对数据进行分表,首先要确定将数据平均分配到多少张表中,也就是:表容量。
这里假设单库有100张表进行存储,则我们在进行存储数据的时候,首先对用户ID进行取模操作,根据 user_id%100 获取对应的表进行存储和查询操作,示意图如下:
例如,
user_id = 101,
我们在获取值的时候,可以通过下边的sql语句:select * from order_1 where user_id= 101
其中,表名
order_1的后缀数值
是根据101%100
计算所得。在实际的开发中,如果我们使用MyBatis做持久层,MyBatis已经提供了很好地支持数据库分表的功能。例如,上述sql用MyBatis实现,应该是:
接口定义:
/** * 获取用户相关的订单详细信息 * @param tableNum 具体某一个表的编号 * @param userId 用户ID * @return 订单列表 */ public List<Order> getOrder(@Param("tableNum") int tableNum,@Param("userId") int userId);
xml配置映射文件:
<select id="getOrder" resultMap="BaseResultMap"> select * from order_${tableNum} where user_id = #{userId} </select>
其中${tableNum} 含义是直接让参数加入到sql中,这是MyBatis支持的特性。
注意:
另外,在实际的开发中,我们的用户ID更多的可能是通过UUID生成的。若是这样,我们可以首先对UUID进行hash,获取到整数值;然后,对该整数值进行取模操作。三、分库单表实现策略
单个数据库分表,能够解决“单表在数据量很大时查询数据的效率问题”,但是无法给数据库的并发操作带来效率上的提高。单库分表还是在一个数据库上进行操作,很容易受数据库IO性能的限制。
如何平均分配数据库的IO性能?显然,对数据进行分库存储,可以很好地解决单台数据库的性能问题。
分库策略与分表策略的实现相似,最简单的都是可以通过取模的方式进行路由。
还是上例,对用户ID进行取模操作,可以获取到某一个具体的数据库,同理,这种方式对关键字为:用户ID、库容量。
数据库路由的示意图如下:
上图中,库总数为100。
同样,如果用户ID为UUID,那么:首先对用户ID进行hash取值;然后,对hash结果值进行取模。
四、分库分表实现策略
上述的配置中,单库分表可以解决“单表海量数据的查询性能问题”,分库单表可以解决“单台数据库的并发访问压力问题”。
在实际应用中,我们既需要分库操作,也需要分表操作,以便同时扩展系统的并发处理能力和提升单表的查询性能,这就是分库分表。
分库分表的策略相对复杂一些,一种常见的路由策略如下:
1、中间变量 = user_id%(库数量*每个库的表数量);
2、库序号 = 取整(中间变量/每个库的表数量);
3、表序号 = 中间变量%每个库的表数量;
例如:数据库有256 个,每一个库中有1024个数据表,用户的user_id=262145,按照上述的路由策略,可得:
1、中间变量 = 262145%(256*1024)= 1;
2、库序号 = 取整(1/1024)= 0;
3、表序号 = 1%1024 = 1;
这样,对于user_id=262145,将被路由到第0个数据库的第1个表中。
示意图如下:
五、分库分表总结
分库分表策略有很多种,根据用户ID进行分库分表是比较简单的一种。对于其他分库分表方式,比如使用号段、使用hash进行路由等,有兴趣的同学可以自行查找学习。
如果用户的ID是通过UUID方式生成的,那么:首先,我们需要单独进行一次hash操作;然后,对hash结果进行取模。其实hash本身就是一种分库分表的策略,使用hash作为路由策略的时候,我们需要知道hash路由策略的优缺点,优点是:数据分布均匀;缺点是:数据迁移的时候麻烦,不能按照机器性能分摊数据。
通过分库分表操作,系统的数据查询性能和并发能力都得到了提高。但是,还有一些需要注意的点:
(1)原本单库的事务变成了分布式事务;
(2)由于记录被切分到不同的数据库和数据表中,难以进行多表关联查询;
(3)对数据进行查询时,必须指定路由字段。
(4)分库分表之后,如果我们需要对数据库进行进一步的扩容(或者路由策略变更),将变得非常不方便,需要重新进行数据迁移。
自己开发分库分表工具的工作量是巨大的,好在业界已经有了很多比较成熟的分库分表中间件,我们可以将更多的时间放在业务实现上。
业界常用分库分表工具:
-
sharding-jdbc(当当)
-
TSharding(蘑菇街)
-
Atlas(奇虎360)
-
Cobar(阿里巴巴)
-
MyCAT(基于Cobar)
-
Oceanus(58同城) Vitess(谷歌)
六、本文总结
通过本文,我们学到了如何进行数据库分库分表。那么,是不是就可以实现一个可扩展、高性能、高并发的网站?很显然,还不可以!一个大型网站使用到的技术远不止这些,这些只是其中最基础的一个环节,还有很多具体的细节我们没有掌握到,比如:数据库的集群控制、集群的负载均衡、灾难恢复、故障自动切换、事务管理等。因此,还有很多需要去学习和研究的地方。
-
-
阿里巴巴数据库分库分表的实践
2021-03-03 13:25:56业务数据从原来的单库单表模式变成了数据被拆分到多个数据库,甚至多个表中,如果在数据访问层做一下功能的封装和管控,所有分库分表的逻辑和数据的跨库操作都交给应用的开发人员来实现,则对开发人员的要求变得相对... -
一文读懂数据库分库分表
2022-04-15 12:05:07什么是分库分表以及为什么分库分表 如何分库分表 分库分表常见几种方式以及优缺点 如何选择分库分表的方式 数据库常见优化方案 对于后端程序员来说,绕不开数据库的使用与方案选型,那么随着业务规模的逐渐扩大...阅读此文你将了解:
- 什么是分库分表以及为什么分库分表
- 如何分库分表
- 分库分表常见几种方式以及优缺点
- 如何选择分库分表的方式
数据库常见优化方案
对于后端程序员来说,绕不开数据库的使用与方案选型,那么随着业务规模的逐渐扩大,其对于存储的使用上也需要随之进行升级和优化。
随着规模的扩大,数据库面临如下问题:
- 读压力:并发QPS、索引不合理、SQL语句不合理、锁粒度
- 写压力:并发QPS、事务、锁粒度
- 物理性能:磁盘瓶颈、CPU瓶颈、内存瓶颈、IO瓶颈
- 其他:宕机、网络异常
面对上述问题,常见的优化手段有:
索引优化、主从同步、缓存、分库分表每个技术手段都可以作为一个专题进行讲解,本文主要介绍分库分表的技术方案实现。
什么是分库分表?
对于阅读本文的读者来说,分库分表概念应该并不会陌生,其拆开来讲是分库和分表两个手段:
- 分表:将一个表中的数据按照某种规则分拆到多张表中,降低锁粒度以及索引树,提升数据查询效率。
- 分库:将一个数据库中的数据按照某种规则分拆到多个数据库中,以缓解单服务器的压力(CPU、内存、磁盘、IO)。
为什么分库分表?
- 性能角度:CPU、内存、磁盘、IO瓶颈
- 随着业务体量扩大,数据规模达到百万行,数据库索引树庞大,查询性能出现瓶颈。
- 用户并发流量规模扩大,由于单库(单服务器)物理性能限制也无法承载大流量。
- 可用性角度:单机故障率影响面
- 如果是单库,数据库宕机会导致100%服务不可用,N库则可以将影响面降低N倍。
分库分表带来的问题?
- 事务性问题
- 分库可能导致执行一次事务所需的数据分布在不同服务器上,数据库层面无法实现事务性操作,需要更上层业务引入分布式事务操作,难免会给业务带来一定复杂性,那么要想解决事务性问题一般有两种手段:
- 方案一:在进行分库分表方案设计过程中,从业务角度出发,尽可能保证一个事务所操作的表分布在一个库中,从而实现数据库层面的事务保证。
- 方案二:方式一无法实现的情况下,业务层引入分布式事务组件保证事务性,如事务性消息、TCC、Seata等分布式事务方式实现数据最终一致性。
- 分库可能导致执行一次事务所需的数据分布在不同服务器上,数据库层面无法实现事务性操作,需要更上层业务引入分布式事务操作,难免会给业务带来一定复杂性,那么要想解决事务性问题一般有两种手段:
- 主键(自增ID)唯一性问题
- 在数据库表设计时,经常会使用自增ID作为数据主键,这就导致后续在迁库迁表、或者分库分表操作时,会因为主键的变化或者主键不唯一产生冲突,要解决主键不唯一问题,有如下方案:
- 方案一:自增ID做主键时,设置自增步长,采用等差数列递增,避免各个库表的主键冲突。但是这个方案仍然无法解决迁库迁表、以及分库分表扩容导致主键ID变化问题
- 方案二:主键采用全局统一ID生成机制:如UUID、雪花算法、数据库号段等方式。
- 跨库多表join问题
- 首先来自大厂DBA的建议是,线上服务尽可能不要有表的join操作,join操作往往会给后续的分库分表操作带来各种问题,可能导致数据的死锁。可以采用多次查询业务层进行数据组装(需要考虑业务上多次查询的事务性的容忍度)
- 跨库聚合查询问题
-
分库分表会导致常规聚合查询操作,如group by,order by等变的异常复杂。需要复杂的业务代码才能实现上述业务逻辑,其常见操作方式有:
-
方案一:赛道赛马机制,每次从N个库表中查询出TOP N数据,然后在业务层代码中进行聚合合并操作。
假设: 以2库1表为例,每次分页查询N条数据。 第一次查询: ① 每个表中分别查询出N条数据: SELECT * FROM db1_table1 where $col > 0 order by $col LIMITT 0,N SELECT * FROM db2_table1 where $col > 0 order by $col LIMITT 0,N ② 业务层代码对上述两者做归并排序,假设最终取db1数据K1条,取db2数据K2条,则K1+K2 = N 此时的DB1 可以计算出OffSet为K1 ,DB2计算出Offset为K2 将获取的N条数据以及相应的Offset K1/K2返回给 端上。 第二次查询: ① 端上将上一次查询对应的数据库的Offset K1/K2 传到后端 ② 后端根据Offset构造查询语句查询分别查询出N条语句 SELECT * FROM db1_table1 where $col > 0 order by $col LIMITT $K1,N SELECT * FROM db2_table1 where $col > 0 order by $col LIMITT $K2,N ③ 再次使用归并排序,获取TOP N数据,将获取的N条数据以及相应的Offset K1/K2返回给 端上。 第三次查询: 依次类推.......
- 方案二:可以将经常使用到groupby,orderby字段存储到一个单一库表(可以是REDIS、ES、MYSQL)中,业务代码中先到单一表中根据查询条件查询出相应数据,然后根据查询到的主键ID,到分库分表中查询详情进行返回。2次查询操作难点会带来接口耗时的增加,以及极端情况下的数据不一致问题。
-
-
什么是好的分库分表方案?
- 满足业务场景需要:根据业务场景的不同选择不同分库分表方案:比如按照时间划分、按照用户ID划分、按照业务能力划分等
- 方案可持续性:
- 何为可持续性?其实就是:业务数据量级和流量量级未来进一步达到新的量级的时候,我们的分库分表方案可以持续灵活扩容处理。
- 最小化数据迁移: 扩容时一般涉及到历史数据迁移,其扩容后需要迁移的数据量越小其可持续性越强,理想的迁移前后的状态是(同库同表>同表不同库>同库不同表>不同库不同表)
- 数据偏斜:数据在库表中分配的均衡性,尽可能保证数据流量在各个库表中保持等量分配,避免热点数据对于单库造成压力。
- 最大数据偏斜率:(数据量最大样本 - 数据量最小样本)/ 数据量最小样本。一般来说,如果我们的最大数据偏斜率在5%以内是可以接受的。
如何分库分表
垂直拆分:
- 垂直拆表
- 即大表拆小表,将一张表中数据不同”字段“分拆到多张表中,比如商品库将商品基本信息、商品库存、卖家信息等分拆到不同库表中。
- 考虑因素有将不常用的,数据较大,长度较长(比如text类型字段)的拆分到“扩展表“,表和表之间通过”主键外键“进行关联。
- 好处:降低表数据规模,提升查询效率,也避免查询时数据量太大造成的“跨页”问题。
- 垂直拆库
- 垂直拆库则在垂直拆表的基础上,将一个系统中的不同业务场景进行拆分,比如订单表、用户表、商品表。
- 好处:降低单数据库服务的压力(物理存储、内存、IO等)、降低单机故障的影响面
水平拆分:
- 操作:将总体数据按照某种维度(时间、用户)等分拆到多个库中或者表中,典型特征不同的库和表结构完全一下,如订单按照(日期、用户ID、区域)分库分表。
- 水平拆表
- 将数据按照某种维度拆分为多张表,但是由于多张表还是从属于一个库,其降低锁粒度,一定程度提升查询性能,但是仍然会有IO性能瓶颈。
- 水平拆库
- 将数据按照某种维度分拆到多个库中,降低单机单库的压力,提升读写性能。
常见水平拆分手段
range分库分表
顾名思义,该方案根据数据范围划分数据的存放位置。
思路一:时间范围分库分表
举个最简单例子,我们可以把订单表按照年份为单位,每年的数据存放在单独的库(或者表)中。
时下非常流行的分布式数据库:TiDB数据库,针对TiKV中数据的打散,也是基于Range的方式进行,将不同范围内的[StartKey,EndKey)分配到不同的Region上。
缺点:
- 需要提前建库或表。
- 数据热点问题:当前时间的数据会集中落在某个库表。
- 分页查询问题:涉及到库表中间分界线查询较复杂。
例子: 交易系统流水表则是按照天级别分表。
hash分库分表
hash分表是使用最普遍的使用方式,其根据“主键”进行hash计算数据存储的库表索引。原理可能大家都懂,但有时拍脑袋决定的分库分表方案可能会导致严重问题。
思路一:独立hash
对于分库分表,最常规的一种思路是通过主键计算hash值,然后hash值分别对库数和表数进行取余操作获取到库索引和表索引。比如:电商订单表,按照用户ID分配到10库100表中。
const ( // DbCnt 库数量 DbCnt = 10 // TableCnt 表数量 TableCnt = 100 ) // GetTableIdx 根据用户 ID 获取分库分表索引 func GetTableIdx(userID int64) (int64, int64) { hash := hashCode(userID) return hash % DbCnt, hash % TableCnt }
上述是伪代码实现,大家可以先思考一下上述代码可能会产生什么问题?
比如1000? 1010?,1020库表索引是多少?
思考一下........
思考一下........
思考一下........
思考一下........
思考一下........
思考一下........
答:数据偏斜问题。
非互质关系导致的数据偏斜问题证明:
假设分库数分表数最大公约数为a,则分库数表示为 m*a , 分表数为 n*a (m,n为正整数) 某条数据的hash规则计算的值为H, 若某条数据在库D中,则H mod (m*a) == D 等价与 H=M*m*a+D (M为整数) 则表序号为 T = H % (n*a) = (M*m*a+D)%(n*a) 如果D==0 则T= [(M*m)%n]*a
思路二:统一hash
思路一中,由于库和表的hash计算中存在公共因子,导致数据偏斜问题,那么换种思考方式:10个库100张表,一共1000张表,那么从0到999排序,根据hash值对1000取余,得到[0,999]的索引,似乎就可以解决数据偏斜问题:
// GetTableIdx 根据用户 ID 获取分库分表索引 // 例子: 1123011 -> 1,1 func GetTableIdx(userID int64) (int64, int64) { hash := hashCode(userID) slot := DbCnt * TableCnt return hash % slot % DbCnt, hash % slot / DbCnt }
上面会带来的问题?
比如1123011号用户,扩容前是1库1表,扩容后是0库11表
扩展性问题证明。
某条数据的hash规则计算的值为H,分库数为D,分表数为T 扩容前: 分片序号K1 = H % (D*T),则H = M*DT + K1 ,且K1 一定是小于(D*T) D1 = K1 % D T1 = K1 / D 扩容后: 如果M为偶数,即M= 2*N K2 = H% (2DT) = (2NDT+K1)%(2DT) = K1%(2DT) ,K1 一定小于(2DT),所以K2=K1 D2 = K2%(2D) = K1 %(2D) T2 = K2/(2D) = K1 / (2D) 如果M为奇数,即M = 2*N+1 K2 = H%(2DT) = (2NDT +DT +K1)%(2DT) = (DT+K1)%(2DT) = DT + K1 D2 = K2 %(2D) = (DT+K1) % (2D) T2 = K2 /(2D) = (DT+K1) / (2D) 结论:扩容后库序号和表序号都变化
思路三:二次分片法
思路二中整体思路正确,只是最后计算库序号和表序号的时候,使用了库数量作为影响表序号的因子,导致扩容时表序号偏移而无法进行。事实上,我们只需要换种写法,就能得出一个比较大众化的分库分表方案。
func GetTableIdx(userId int64){ //①算Hash hash:=hashCode(userId) //②分片序号 slot:=hash%(DbCnt*TableCnt) //③重新修改二次求值方案 dbIdx:=slot/TableCnt tblIdx:=slot%TableCnt return dbIdx,tblIdx }
从上述代码中可以看出,其唯一不同是在计算库索引和表索引时,采用TableCnt作为基数(注:扩容操作时,一般采用库个数2倍扩容),这样在扩容时,表个数不变,则表索引不会变。
可以做简要的证明:
某条数据的hash规则计算的值为H,分库数为D,分表数为T 扩容前: 分片序号K1 = H % (D*T),则H = M*DT + K1 ,且K1 一定是小于(D*T) D1 = K1 / T T1 = K1 % T 扩容后: 如果M为偶数,即M= 2*N K2 = H% (2DT) = (2NDT+K1)%(2DT) = K1%(2DT) ,K1 一定小于(2DT),所以K2=K1 D2 = K2/T = K1 /T = D1 T2 = K2%T = K1 % T = T1 如果M为奇数,即M = 2*N+1 K2 = H%(2DT) = (2NDT +DT +K1)%(2DT) = (DT+K1)%(2DT) = DT + K1 D2 = K2 /T = (DT+K1) / T = D + K1/T = D + D1 T2 = K2 %T = (DT+K1) % T = K1 %T = T1 结论: M为偶数时,扩容前后库序号和表序号都不变 M为奇数时,扩容前后表序号不变,库序号会变化。
思路四:基因法
由思路二启发,我们发现案例一不合理的主要原因,就是因为库序号和表序号的计算逻辑中,有公约数这个因子在影响库表的独立性。那么我们是否可以换一种思路呢?我们使用相对独立的Hash值来计算库序号和表序号呢?
func GetTableIdx(userID int64)(int64,int64){ hash := hashCode(userID) return atoi(hash[0:4]) % DbCnt,atoi(hash[4:])%TableCnt }
这也是一种常用的方案,我们称为基因法,即使用原分片键中的某些基因(例如前四位)作为库的计算因子,而使用另外一些基因作为表的计算因子。
在使用基因法时,要主要计算hash值的片段保持充分的随机性,避免造成严重数据偏斜问题。
思路五:关系表冗余
按照索引的思想,可以通过分片的键和库表索引建立一张索引表,我们把这张索引表叫做“路由关系表”。每次查询操作,先去路由表中查询到数据所在的库表索引,然后再到库表中查询详细数据。同时,对于写入操作可以采用随机选择或者顺序选择一个库表进入写入。
那么由于路由关系表的存在,我们在数据扩容时,无需迁移历史数据。同时,我们可以为每个库表指定一个权限,通过权重的比例调整来调整每个库表的写入数据量。从而实现库表数据偏斜率调整。
此种方案的缺点是每次查询操作,需要先读取一次路由关系表,所以请求耗时可能会有一定增加。本身由于写索引表和写库表操作是不同库表写操作,需要引入分布式事务保证数据一致性,极端情况可能带来数据的不一致。
且索引表本身没有分库分表,自身可能会存在性能瓶颈,可以通过存储在redis进行优化处理。
思路六:分段索引关系表
思路五中,需要将全量数据存在到路由关系表中建立索引,再结合range分库分表方案思想,其实有些场景下完全没有必要全部数据建立索引,可以按照号段式建立区间索引,我们可以将分片键的区间对应库的关系通过关系表记录下来,每次查询操作,先去路由表中查询到数据所在的库表索引,然后再到库表中查询详细数据。
思路七:一致性Hash法
一致性Hash算法也是一种比较流行的集群数据分区算法,比如RedisCluster即是通过一致性Hash算法,使用16384个虚拟槽节点进行每个分片数据的管理。关于一致性Hash的具体原理这边不再重复描述,读者可以自行翻阅资料。
其思想和思路五有异曲同工之妙。
总结
本文从5W1H角度介绍了分库分表手段,其在解决如IO瓶颈、读写性能、物理存储瓶颈、内存瓶颈、单机故障影响面等问题的同时,也带来如事务性、主键冲突、跨库join、跨库聚合查询等问题。anyway,在综合业务场景考虑,正如缓存的使用一样,非必须使用分库分表,则不应过度设计采用分库分表方案。如数据库确实成为性能瓶颈时,在设计分库分表方案时也应充分考虑方案的扩展性。或者说可以考虑采用成熟热门的分布式数据库解决方案,如TiDB。
-
【sql】数据库分库分表设计方案(1)
2022-06-12 12:30:321.数据库分库分表设计(1) 2.数据库分库分表,实现分库分表后的分页查询,比如所有用户信息分页显示,用户表q_user_01–q_user_10淘宝的做法是拆分买家库和卖家库,也就是两个库:买家库、卖家库。买家库,按照用户... -
数据库分库分表实战
2021-12-11 11:30:15当单个数据库实例达到瓶颈,例如连接数过多,处理能力受限、存储容量不足、磁盘IO达到瓶颈、内存不足,都需要对数据库进行分库分表。 二垂直切分 数据库表按列拆分,拆分后,数据库从一个数据列多的表变成了多个... -
【数据库专题】一文搞懂数据库分库分表的原理
2022-07-06 11:25:29是一种数据分片技术,主要分为垂直拆分和水平拆分。垂直拆分的意思是,把部分字段及其值挪到其它表或者其它数据库实例中;水平拆分的意思是,把部分记录挪到其它表或者其它数据库实例中;单表的存储总是有上限的,... -
数据库分库分表可扩展及数据倾斜/热点问题(二)
2022-03-28 13:22:04数据库分库分表可扩展及数据倾斜/热点问题(二) 垂直&水平 分库分表 Range & Hash策略 “ 山前车 策略 数据库分库分表可扩展及数据倾斜/热点问题(二) “在高并发、业务数据规模庞大、数据库服务负载... -
水平分库分表的关键步骤以及可能遇到的问题
2021-01-29 21:17:15在之前的文章中,我介绍了分库分表的几种表现形式和玩法,也重点介绍了垂直分库所带来的问题和解决方法。本篇中,我们将继续聊聊水平分库分表的一些技巧。 关系型数据库本身比较容易成为系统性能瓶颈,单机存储容量... -
什么是数据库分库分表?
2019-08-14 14:11:40中大型项目中,一旦遇到数据量比较大,小伙伴应该都知道就应该对数据进行拆分了。有垂直和水平两种。我们也知道 mysql 单表存储量推荐是百万级,如果不进行处理,...当然也可以分库,再分表;把压力从数据库层级分开。 -
数据库分库分表及MySQL主从复制
2021-12-09 21:14:01一、为什么要分库分表 解决大数据存储时数据访问性能,具体来说就是解决超大容量问题和性能问题。 举例说明,订单表或用户表如果数据量达到上亿条记录,此时数据库的IO能力、处理能力就会出现一个瓶颈(MySQL官方... -
阿里巴巴数据库分库分表的实践.docx
2021-10-24 12:15:06阿里巴巴数据库分库分表的实践.docx -
如何做到数据库分库分表?
2022-06-08 16:56:55一、中大型项目中,一旦遇到数据量比较大,小伙伴应该都知道就应该对数据进行拆分了。有垂直和水平两种。垂直拆分比较简单,也就是本来一个数据库,数据量大之后,从业务...当然也可以分库,再分表;把压力从数据库层 -
数据库分库分表中间件实践
2018-11-09 21:53:58数据库分库分表中间件实践,降低单机负载 降低单点故障带来的影响 提高读写的性能 -
常用数据库分库分表技术介绍
2019-07-07 10:24:33今天主要讲讲,一个网站的分库分表是有哪些方法,不同纬度的做法有哪些。 首先,一个最简单的网站结构如下,一台服务器和一个数据库就能搭建一个完整的网站,用户通过Internet访问对应的域名,就能使用该网站提供的... -
数据库分库分表是什么,什么情况下需要用分库分表
2021-05-04 06:44:36为了保证数据库的查询效率,当数据达成一定量时建议进行分表操作1、oracle当oracle单表的数据量大于2000万行时,建议进行水平分拆。2、mysql当mysql单表的数据量大于1000万行时,建议进行水平分拆。单表容量到了1000... -
数据库分库分表存储分析思路
2021-11-04 22:53:51解决大数据量存储时,分表存储时常见问题及解决方案 -
数据库分库分表事务解决方案
2021-01-19 06:26:15另一方面,在分库分表以后还需要保证分库分表的和主库的事务一致性二、需要解决问题2.1 事务问题由于分库分表之后,新表在另外一个数据库中,如何保证主库和分库的事务性是必须要解决的问题。通过在主库中创建一个... -
从零开始SpringCloud Alibaba实战(71)——数据库分库分表
2021-09-08 19:16:34当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重。 此时就要考虑对其进行切分了,切分的目的就在于减少数据库的负担,缩短查询时间。 数据库分布式核心... -
一句话说明数据库分库分表分区及实用场景
2022-04-18 16:45:51像这种情况,一般小项目开发时用到的较少,所以实操经历真的很有限,只有像阿里、腾讯、华为等大厂有大业务量的项目上才会多用到这种,首先说实用场景,一般数据库表的数据量超过500万条,索引的效率会大幅下降,... -
数据库分库分表策略和分库分表后数据的查询
2019-08-30 17:50:17在日常的工作中,关系型数据库本身比较容易成为系统的瓶颈点,虽然读写分离能分散数据库的读写压力,但并没有分散存储压力,当数据量达到千万甚至上亿时,单台数据库服务器的存储能力会成为系统的瓶颈,主要体现在...