当前位置: 首页 > 十万个为什么 > 为什么淘宝卡(作为数据库核心成员,如何让淘宝不卡顿?)

为什么淘宝卡(作为数据库核心成员,如何让淘宝不卡顿?)

时间:2024-05-04 08:45:35阅读:

为什么淘宝卡(作为数据库核心成员,如何让淘宝不卡顿?)

时间倒转穿越回2007年年底。

一 分析当前的现状。

1.1 现有业务背景。

1.2 当前的问题。

1.2。1 用户体验与反馈。

1.2。2 分析核心原因。

大量的用户在浏览商品,并不下单。这个人数和场景的比例有20:1。

说明:数据库模式事务,写操作会对表或者行加写锁,阻塞读操作。

业务数据集中在一张表里,如user表。一张表里数据破几千万。查询一条数据需要好几秒。

说明:一张表数据提升,必然会导致检索变慢, 这是必然事实。不论如何加索引或者优化都无法解决的。

所有表集中在一个库里,所有库集中在一个机器里。数据库集中在一台机器上,动不动就说硬盘不够了。

说明:所有业务共用一份物理机器资源。机器存在瓶颈:磁盘和CPU不够用且后期拓展性不佳。

1.2。3 总结问题。

20:1读写比例场景。单表单库数据量太大。小型机与单机场景,抗不住当前规模。

当前现状。

二 我要做什么?

如何满足未来有上亿用户的访问,甚至是同时访问,且用户体验好。

高筑墙,广积粮,积极做好准备。

提炼核心:。

提高数据库操作速度。同时能应对未来规模变化。

三 我能做什么?

为实现以上两大目标,我能做什么?

3.1 提高数据库操作速度,通用方法。

提炼常见的通用方法:。

sql优化。

排除语法问题,烂sql下推优化。

下推的目的:提前过滤数据 -> 减少网络传输、并行计算。

提前过滤数据小表驱动大表等。

建立索引。

查询频率高的热点字段区分度高的(DISTINCT column_name)/COUNT(),以主键为榜样长度小尽量能覆盖常用查询字段注意索引失效的场景。

分库分表。

垂直分库分表水平分库分表。

读写分离缓存的使用。

等等。

3.2 如何应对未来的持续变化?

必须支持动态扩容。必须走分布式化路线,百分百不动摇。

3.3 结合定位,分析自己能做的。

3.3。1 分析我们的架构定位。

大前提。

我们要做通用型框架,不参与业务。

从软件设计原则出发,开闭原则:对扩展开放,对修改关闭。

说明:大修改就意味着不稳定,因此:我们要做到尽可能少的修改原来的代码。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。

当前架构现状。

初始框架。

分析我们的架构定位。

同时jdbc是与底层数据库交互的Java数据库连接驱动程序,是基础能力,我们要使用它,而不是改造它。

结论:我得把TDDL安插于ibatis/jdbc之间,于是有了第一张架构图:。

TDDL的定位。

3.4 总结,我们能做什么?

结合我们的目标,通用方法,大前提以及架构定位,分析下我们能做和不能做的。

不能做的:。

索引,因为这个是设计阶段,强业务相关。与大前提冲突:我们不参与业务。

能做的:。

语法优化。

排除sql问题下推优化。

分表分库读写分离。

四 我们如何做?

4.1 语法优化。

为达到语法优化的目的,我们需要具备什么能力?

简单来说:。

我们需要认识这个别人提交给我的sql。我能拆解sql。优化与重组这个sql。

专业点来说:语义分析能力。

sql解析sql规则制定sql优化sql重组。

因此:我们需要设计一个sql解析器,sql优化器。

4.1。1 解析器。

解析器的核心是词法分析、语法语义分析,也就是说来了一条 select/update/insert/delete语句,你能认识它,而且你知道下一步该怎么处理,同时为后面的优化器打下基础。

核心:将sql解析为一棵语法树。

例:。

sql语法树:。

4.1。2 优化器。

核心:。

在sql解析成sql语法树后,使用sql优化规则(1。 语法优化 2。 下推优化), 通过对树进行左旋,右旋,删除子树来对语法树进行重构sql语法树。

将重构的语法树进行遍历得到优化后的sql。

语法优化。

函数提前计算。

判断永真/永假式。

合并范围。

类型处理。

下推优化。

Where条件下推。

说明:提前条件过滤,提前获取数据,减少后期计算/IO/网络成本。

JOIN中非join列的条件下推。

说明:提前过滤,减轻后期join计算成本,达到“小表驱动”的目的。

等值条件的推导。

说明:同理,提前过滤。

4.1。3 总结。

sql解析器。

负责将sql语句化为sql语法树。

sql优化器。

负责将sql语法树利用sql优化规则,重构sql语法树。

将sql语法树转化为sql语句。

4.2 分表分库。

单库单表的问题:。

几年前,业务简单,应用的数据比较少,表结构也不复杂。只有一个数据库,数据库中的表是一张完整的表。而到了今天,2007年了,业务复杂起来了,数据量爆增,单表数据破千万甚至上亿条,一条DML语句,死慢死慢的。这种情况下加索引已不再有显著的效果。

这个时候,数据库效率瓶颈不是靠加索引,sql优化能搞定的。

正确出路:分表分库,通过将表拆分,来降低单表数据量,进而提高数据库操作效率。

分表分为:。

垂直分表水平分表。

分库分为:。

垂直分库水平分库。

由于TDDL不参与业务,而垂直分库分表是强业务相关的,因此TDDL暂不参与垂直分库分表,只在水平分库分表方向上努力。

4.2。1 垂直分表。

垂直拆分是将一张表垂直拆成多个表。往往是把常用的列独立成一张主表。不常用的列以及特别长的列拆分成另一张拓展表。

简单垂直分表举例。

核心要素:。

冷热分离,把常用的列放在一个表,不常用的放在一个表。

大字段列独立存放,如描述信息。

关联关系的列紧密的放在一起。

它带来的提升是:。

为了避免IO争抢并减少锁表的几率,查看详情的用户与商品信息浏览互不影响。

充分发挥热门数据的操作效率,商品信息的操作的高效率不会被商品描述的低效率所拖累。

4.2。2 水平分表。

水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。

简单水平分表举例。

简单点的技巧:按照枚举类型区分。

作用总结:。

库内的水平分表,解决了单一表数据量过大的问题,分出来的小表中只包含一部分数据,从而使得单个表的数据量变小,提高检索性能。

避免IO争抢并减少锁表的几率。

4.2。3 垂直分库。

垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。

垂直分库。

作用总结:。

解决业务层面的耦合,业务清晰。

高并发场景下,垂直分库一定程度的提升IO、数据库连接数、降低单机硬件资源的瓶颈。

能对不同业务的数据进行分级管理、维护、监控、扩展等。

垂直分库通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。

4.2。4 水平分库(TDDL 核心)。

水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。

水平分库。

作用总结:。

解决了单库单表数据量过大的问题,理论上解决了高并发的性能瓶颈。

水平分库核心要解决的问题:。

如何知道数据在哪个库里?- 路由问题。

结果合并。

全局唯一主键ID。

分布式事务。

4.2。5 水平分库——问题解决。

自动路由算法。

例:。

其中拆分和寻找的算法:怎么知道对应哪个表?即自动路由算法。常见的有:固定哈希算法和一致性哈希算法。

a)固定哈希算法。

b)一致性哈希算法。

一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题。

一致性哈希算法的优势:。

极好的应对了服务器宕机的场景。

很好的支持后期服务器扩容。

在引入虚拟节点后:能很好的平衡各节点的数据分布。

由于一致性哈希算法的优势,此算法几乎是所有分布式场景下使用的方案,包括mysql的分布式、redis的分布式等。

结果合并。

升华:引入fork-Join,提升操作速度。

任务拆分多路并行操作结果合并。

全局唯一主键。

优势:简单高效。缺点:无法保证自增顺序。

例:。

表1新增一条数据,于是给表1分配1000个主键ID, 直到它用完。

同理,表2、表3在新增数据时,也给它们分配1000个主键ID。直到它用完。

当它们的1000个主键ID用完后,继续给它们分配1000个即可。

重复下去,可保证各库表上的主键不重叠,唯一。

这种产生全局唯一id的方式相当有效,保证基本的全局唯一特性和高性能的同时,可以对生成id的数据库分机架分机房部署达到容灾的目的。

4.2。6 分表分库总结。

架构师角度:。

优先考虑缓存降低对数据库的读操作。

再考虑读写分离,降低数据库写操作。

最后开始数据拆分,切分模式:首先垂直拆分、再次水平拆分。

首先考虑按照业务垂直拆分。

再考虑水平拆分:先分库(设置数据路由规则,把数据分配到不同的库中)。

最后再考虑分表,单表拆分到数据1000万以内。

个人开发角度:。

优先使用分表分库框架。优先考虑缓存降低对数据库的读操作。自己垂直分表。自己水平分表。

之所以先垂直拆分才水平拆分,是因为垂直拆分后数据业务清晰而且单一,更加方便指定水平的标准。

4.3 分布式化。

分布式化是大潮,是大规模服务器最后都要走的一步。

分布式数据库架构演变。

4.3。1 读写分离。

设计读写分离的数据库,有两大意义:。

主从只负责各自的写和读,极大程度的缓解X锁和S锁的竞争。

从库可配置myisam引擎,提升查询性能以及节约系统开销。

说明:myisam查询效率高于默认的innodb效率。参考:myisam和innodb的区别。

核心问题:。

数据的备份同步问题:参考4.4。3。

4.3。2 容灾。

主备倒换:提高可靠性 > 应对个别数据库宕机场景,尤其主库宕机。

主备倒换。

说明:DB2主库宕机后,自动将主库转为DB3。

核心问题:。

数据的备份同步问题:binlog 参考4.4。3。

检测数据库的在线状态:心跳机制。

4.3。3 数据备份与同步。

当只有单机或者一份数据时,一但数据库出问题,那么整体服务将不可用,而且更严重的是会造成数据损害丢失不可逆。

在读写分离与主备倒换的场景下,核心要解决的是多个数据库的数据同步与备份问题。

当前主流的是采用日志备份方式。

实现原理:binlog日志备份。

数据备份:bin-log同步。

说明:。

主库负责写操作,在数据变更时,会写入binlog,同时通知各从库。

从库收到通知后,IO线程会主动过来读取主库的binlog,并写入自己的log。

写完从库log后,通知sql线程,sql线程读取自己的日志,写入从库。

4.3。4 动态扩容。

动态扩容的意义在于:随着后期业务量增大,数据库个数可以通过增多的方式来应对,而相对的改造代价很小。

扩容前:。

扩容后:。

核心内容:。

在添加新库时。

注册机器与库。

路由算法调整:固定哈希算法-调整模数/一致性哈希算法天然支持扩容。

可选的权重调整。

修改权重,数据插入偏向于新库5。

在各库数量平衡时,触发修改回原来平衡的权重,以保证后续的均衡分配。

五 架构成型。

sql流向。

下图介绍sql从流入TDD到流入数据库,期间TDDL各模块对Sql的处理。

架构图。

下图介绍了TDDL三层的位置以及作用。

核心能力图。

TDDL 核心能力,核心组建示意图,其中标出了各模块核心要解决功能,核心算法等。

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文仅代表作者本人观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至120143424@qq.com举报,一经查实,本站将立刻删除。