{eval=Array;=+count(Array);}

问答专栏Q & A COLUMN

当数据库扼住系统性能咽喉,直接分库分表能解决吗?

icyfireicyfire 回答0 收藏1
收藏问题

5条回答

Jackwoo

Jackwoo

回答于2022-06-28 14:22

分库分表是比较靠后的优化手段,因为成本比较高。

遇到数据库瓶颈:

- 首先考虑sql优化,这是最简单的方法。对现有系统基本没有影响。

- 其次就是考虑数据库的读写分离,这也是相对简单的方法。在数据库层面进行配置,系统层面只需要调整一下获取数据库连接的逻辑。读数据时即可以获取主库连接,也可以获取从库连接。写数据时只获取主库连接。

- 再考虑增加缓存层。将数据缓存到缓存中,当再次访问时不再从数据库获取。一般缓存层对系统是透明的,基本对系统本身没有影响。但是引入缓存,也引入了相应的需要考虑的问题,比如雪崩,命中率,分布式缓存等

- 还有一种非技术手段,就是改需求。引起性能问题的原因是否是需求不合理?或者需求太复杂?是否可以简化需求?此方法对系统的影响也相对较小。

- 最后才考虑分库分表。优先分库,因为相对分表更简单。将对应的表移动到新库,调整系统获取数据库连接的逻辑。这里需要考虑要移动哪些表,在提高性能的前提下,首先尽量避免分布式事务。

- 最最后,考虑分表。分表的主要原因是单表数据量太大。分表又分纵切和横切。纵切就是按列切,比如用户表,常用信息为基本信息表,其它信息为详情表。横切就是按行切,比如一亿数据量的表切分为十张一千万的表。这里就涉及数据该存放到哪张表,或从哪张表里取。分表后又可以分库,来进一步优化。

- 如果涉及到分布式事务,又要考虑如何保证分布式事务。理论方面2pc,3pc,paxos,cap,base。对应的中间件的使用。

对系统的设计和优化不是人云亦云,需要根据实际的场景来进行处理。

评论0 赞同0
  •  加载中...
codecook

codecook

回答于2022-06-28 14:22

大部分的软件架构、组件或解决方案,都是在解决一些问题的同时,会带来另外的问题。

数据库的分库分表,又可以分为垂直拆分和水平拆分(可能大家常说的分库分表主要指的是后者):

  • 垂直拆分:这是一种比较常见的数据库设计方法,就是把一个字段比较多的大表,拆分成多个小表,特别是在现在分布式、微服务的架构下,可以把各个小表按照业务模型,划分到不同的数据库中,这样就可以利用多台数据库服务器的性能;但当被拆分出来小表的数据量不断增长,到了一个极限的时候,还是需要考虑水平拆分。

  • 水平拆分:将表中的数据,按照一定的规则分布到不同的数据库中,比如对主键进行Hash和取模操作后,按照结果把数据路由到对应的数据库上;水平分库分表,可以降低每张表的数据量,这也是现在大部分公司所使用的方法。

数据库扩容问题

上文中说到,水平拆分常用的手段是对主键进行Hash和取模操作后,按照结果把数据路由到对应的数据库上;但如果被拆分的子表,数据量也达到极限值以后,就要面对数据库扩容的问题,比如开始规划分成8个库,现在要扩到16个库;

路由规则发生变化:hash(id)%8 变成了 hash(id)%16,那么历史数据也就要面临迁移的问题;这种情况,要么做数据迁移,要么增加分表算法的复杂性,让算法可以兼容增加分表前后的数据路由。

复杂查询、关联查询、order by、group by等的问题

在单库时代,复杂的关联查询是很容易实现的,但是数据库被拆分后,数据被保存在了不同的数据库服务器上,那么夸库的join就成了很大的问题。通常解决方案有:

  • 如果是垂直拆分,那么可以考虑做一定程度的字段冗余,避免跨表关联;或者可以做数据同步,把需要的表同步到同一个库中,进行表关联;

  • 代码层面组装,也就是把两边的数据都拿出来,然后在代码里面关联组装;或者先获取主表数据,再把其余字段补齐;但是从实际情况来看,这个方案在大多数场景下,实现起来都比较困难;

  • 现在一个比较主流的做法,是引入ES或ES+HBase或solr+HBase,把部分字段的全量数据保存在同一个地方。


ID问题

在水平拆分的场景下,一单一张表被拆分成多张表部署在多个数据库中,那么就不能使用数据库自身的主键生成机制了;这时候就需要由我们自己来考虑主键生成策略:

  • 主键生成中心:可以利用数据库、Redis、MongoDB、zookeeper等组件实现,需要生产主键的时候,调用主键生成中心的接口;缺点也很明显,增加了网络开销,并且主键生成中心如果发生问题,后果会很严重。

  • UUID:本地生成,不需要第三方组件,生成比较简单,性能好;不过缺点也不少,长度长,不利于存储,并且没有排序,是个字符串,不利于查询。

  • 一些唯一性ID的生成算法:比如Snowflake、UidGenerator、Leaf等等。

事务问题

单库的时候,解决事务问题很简单,但是现在要保证跨库的事务问题,需要额外的成本;

这种场景下(性能要求高,一致性要求不是那么的高),大部分公司会放弃事务的【实时】一致性,只要在一定的时间内,事务【最终】一致即可。


我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。

评论0 赞同0
  •  加载中...
wupengyu

wupengyu

回答于2022-06-28 14:22

1.优化SQL加索引

2.业务是否可以垂直拆分,业务拆分了可以分库

3.业务单边数据量还是大,是否可以把一些字段独立出去,表垂直拆分。水平拆分表可以按时间,或者id的has值进行拆分

4.分库分表必然带来很多问题,比如关联查询,聚合等操作,可以尝试下NewSQL,业务不再关心分库分表操作了。国内开源实现有TiDB,可以了解下,NewSQL应该是未来的趋势。

可以关注我,后面分享一些存储方面的文章。


评论0 赞同0
  •  加载中...
junbaor

junbaor

回答于2022-06-28 14:22

不到万不得已,不要分库分表

数据库遇到瓶颈,应该首先考虑优化。sql服务器硬件优化,sql语句优化,索引优化,读写分离,缓存层。

如果都不行,那就只能考虑分库分表了,可以利用mycat,DBProxy等中间件。

一旦分库分表,就会引出分布式事物,应该尽量避免。关联查询,聚合统计等操作等地方也有坑,一定要注意!

个人建议:一般到了分库分表的地步,都是因为数据量到了一定级别,单台服务器无法承受。一般都是某几张表或者某个库数据量过大。与其费力分库分表,倒不如考虑一些新兴的数据库,例如HBase或者TiDB等newSQL甚至ES。如果这些大表,不涉及复杂,需要考虑事物的业务,完全可以顶上。


回答完毕,谢谢,希望对你有所帮助!!

本人专注互联网前沿动态,大数据,数据采集,数据处理,数据治理,望交流

评论0 赞同0
  •  加载中...
Riddler

Riddler

回答于2022-06-28 14:22

ucloud就是这么干的

评论0 赞同0
  •  加载中...

最新活动

您已邀请0人回答 查看邀请

我的邀请列表

  • 擅长该话题
  • 回答过该话题
  • 我关注的人
向帮助了您的网友说句感谢的话吧!
付费偷看金额在0.1-10元之间
<