迎接双11,深度剖析高并发数据库Sharding的道与术
Posted 架构之美
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迎接双11,深度剖析高并发数据库Sharding的道与术相关的知识,希望对你有一定的参考价值。
迎接双11,高并发数据库设计,文末有福利~~
01、为什么讨论分库分表之道?
在服务器后端技术人员的成长路线上,分片(Sharding)思想的理解和把握是绕不过去的门槛,而数据库分库分表可能是讲述拆分思想最好的教材,大部分后端技术人员都会在成长过程中遇到数据库分库分表的问题。
为什么讲道,因为道比术重要一万倍。技术浪潮一波一波在推动社会的前进,新的技术雨后春笋,简单且朴实的道理,更长久也更朴实且普适。正所谓有道无术术可求,有术无道止于术。
02、为什么需要数据库分库分表?
如何描述分库分表呢?可以这样定义分库分表,当业务的增长导致数据库瓶颈的时候,一种解决瓶颈的手段。
单机数据库很容易出瓶颈,包含性能、容量等。一方面是存在放大效应。比如:业务强要求所有的请求在100ms返回,这100ms分配到数据库,可能留的时间也就1-2ms,任何数据库的波动,会被放大10-20倍反应到上层服务;另一方面是存在单点问题,数据库保持了最新且最准确的状态,这个状态增长是随业务增长同步的,且业务的增长会导致业务的复杂性,复杂性最后反应到数据库的存储里代表的就是增量。数据库需要应对随业务增长指数上升的数据增量,且数据库系统本身通过单点性,来保持状态的准确性,很容易遇到单机的性能问题。
而分库分表就是大多数互联网公司遇到数据库瓶颈后,解决瓶颈的近乎行业标准手段。
03、数据库分库分表的本质到底是什么?
我们回顾数据库发展的历史,数据库是怎么发展起来的?它在先解决什么问题?为什么现在会有瓶颈的问题?
计算机的本质是满足可计算性的快速计算。而数据库系统的本质是,随着计算力扩大随之匹配的对数据的储存和管理能力。最早的编程是通过在纸带上打孔来完成计算步骤的编写,输出的也是纸带。数据库就是对一系列纸带的管理,还别说,那时候就有搜索的需求了。
1968年,IBM做出了第一现代意义上的数据库系统DBMS,除了没有SQL的支持,但是基本上已经是完善的现代数据库了,拥有现代数据库应有的存储、检索、状态一致等功能。
1970年后关系型数据库兴起,那时候搞关系型数据库的公司,就像现在专门做NewSQL的数据库那么的酷。Oracle 是关系型数据库最终的胜利者。如果去深挖这段历史,确实是IBM的员工在1974 年的时候提出了SQL的观点,但是在1979年,Oracle最终第一个做出了关系型数据库。
这时候的数据库,和我们现在接触的数据库已经基本一致了。我们简单概括一下数据库所提供的功能:存储、检索、管理。分别对应储存、索引、一致性的功能。数据库储存数据为文件,通过树的结构来提供索引,通过提供事务组的方式,来保证一致性。至于SQL,是用于管理数据的语言,用于扩展对数据的管理能力。
为什么现在会有数据库瓶颈的问题,在我看来就是,单机的到计算瓶颈了,计算的部分可以快速转向分布式、大规模的集群。而数据库存储做集群的方式很难。对于单机应用来说,数据库基本上没有瓶颈,对于互联网公司来说,流量在不停的拆分,保证单台机器的处理负载在可处理范围内,但是因为数据库本身是一个针对单机的系统,同时需要保证一致性状态,所以更容易到瓶颈。数据库系统原本就是一个支持索引、一致性和存储相对平衡的单机应用,一旦想要扩展分布,那就要做一些权衡。
在我看来,数据库分库分表就是拉伸存储,适度牺牲索引和一致性的一个折中方案。
04、如何拉伸储存?
拉伸储存,本质上就是通过减少需要计算的数据量,来换取计算速度的提升。所以拆分依据就是:如何让计算速度最快那就如何拆分。因此在实际企业业务中,贴子系统适合按日期分库分表、交易系统适合冷热数据分类、长期有效的商品系统适合按照Hash水平拆分。
分表解决的是:过大的数据表影响计算速度的问题,比如单表上亿,那么拆成十个表,必然会比一个表更快,用了一部分计算落表时间,来换取单表计算的时间。
分库更多解决的是机器局限的问题,单机容量有限,单机容量实际上是由机器硬件决定,比如网卡打满、CPU打满、机器磁盘写满等case,必须将计算分布到其他机器上解决。先拆分进程,随后将进程拆分到不同的机器上。
分库分表的核心是创建一个对业务透明的逻辑大表,隔离存储的负载度,进而实现在业务应用眼里的无限存储!
05、如何保障索引的高效性?
一定要理解,索引和存储是相关隔离的两件事,而对于数据库来说,强行提升了储存,而索引就是需要付出的代价。
当存储分布之后,单机的索引是无法满足对索引的要求,而SQL是对索引更上一层的封装,会有一定程度的限制,比如:分库分表最多能满足两个维度的拆分,Join表这种操作就变得异常困难。如何解决呢?方法就是,简单索引逻辑靠中间件构建虚拟索引,复杂索引靠其他方式构建外置索引。
所有的分库分表的中间件的工作,无非是在数据源和业务应用之间封装一层虚拟的满足基本需要的索引。业务应用发送请求到中间件,中间件起到一部分索引的作用,判定需要到哪个库,哪个表来执行,这其实就是单机数据库,选择表过程的外置。中间件还有一个作用是,对涉及逻辑表的部分,进行一部分SQL逻辑改写,来最终判定到某些部分执行。
对于更复杂的查询要求,应用方需要单独构建另外的索引,即把索引单独拆出来做成一个系统,来满足检索需要。作为代价来说,外置的索引会比内置的索引相对慢些,这是在系统架构上需要注意的地方。但是作为大原则,尽量把计算逻辑放置在索引外进行。
06、如何保障一致性?
分库分表还好的地方在于,数据最终存储是一份的,主从实际上是以主为准的,除了严格的时间窗口外,对一致性存储的调整不是很大。但是因为分库分表把需要操作的数据源分散了,操作的原子性在保障起来是有损耗了,核心问题就在于,如何保障跨数据库、跨进程、跨机器的操作原子性。
方法就是:外置保证一致性的方式。A、B、C 三个独立动作,想让他们保证一致,要么在最前面一致,要么在最后面一致,就是消除这三个动作的中间状态。
通过MQ实现的数据一致性,相当于把动作归结为最终状态,用户付了款,那我就保证一定得完成支付、发券等等相关动作,如果交易各种原因最终失败,需要保证用户的这笔交易进入一个最终退款的状态。
通过柔性分布式事务的方式来实现最终一致性,方式就是外置检查,某一动作失败时,往前回滚,不一定完全回滚数据状态,回滚到不影响发生其它业务逻辑的业务状态。比如下单、减库存,如果创建订单失败,那就需要释放库存,倒序回置状态。
07、数据库分库设计案例
对于交易系统来说,天然区分冷热数据,交易核心订单一旦超过三个月之后,不太可能会再有更改问题,另外一个问题是,交易强事务驱动,必须依靠事务,对一致性强要求,交易的读写实际上并不是特别的大。同时交易的访问量相比于社交流量是有数据量级差异的。
方案设计描述如下。交易维护一个热数据库,保留最近三个月的交易热数据,事务相关表尽量保留在这个数据库中,所有的交易的一致性需求必然会是热数据。冷库按时间分库,保留三个月之后的数据,随业务量扩展。在交易ID拼入日期因素,中间件判定ID是冷数据还是热数据,确定查询方案,如果不好判定,先查询热库再查询冷库。两者之间靠MQ完成数据传输,保证交易数据不会丢失。线上业务一般无复杂查询,中间件可以搞定,对于线下业务,有相关复杂数据的,走单独构建的Elasticsearch(ES)搜索引擎集群,来完成复杂检索。此设计基本可以满足大部分相关交易业务需求。
08、更多高并发案例讲解
可能很多同学还没有学够,不着急,推荐我联手58到家CTO沈剑老师,结合10多年一线大厂实践经验,打造的《3天挑战架构师级mysql海量数据设计与实践 》精品课带你快速掌握MySQL核心架构分库分表技术。
以上是关于迎接双11,深度剖析高并发数据库Sharding的道与术的主要内容,如果未能解决你的问题,请参考以下文章