数据库程序员大数据 爬虫Python AI Sql

大表数据存储优化

2017-01-10  本文已影响845人  MavericksJi

小明是一位新鲜出炉的架构师,在业务方的施压下,为了将产品快速地迭代上线,他并没有对未来的业务量做出合理地估计,将网站服务端的数据存储方案设计成了mysql单库单表的模式,“反正大家也不太看好这个产品,单库单表足够了”,他对着开发兄弟们说,方案很快地就成功上线了。
  不知道从哪天开始,小明开始收到了系统响应耗时长的监控告警,并且告警数量在慢慢增多。小明是一名有”匠心“的架构师,他必须查明告警的根源。通过查询服务端及数据库日志,他发现系统中的每一条sql语句都耗时较长,根源就在于当初空空如也的数据表中现在已经有将近500w多条记录了,小明此时陷入了深思,作为架构师,他必须解决现有的系统问题。
  小明遇到地其实就是比较常见的”大表数据存储优化“问题,当数据库单表记录数过大时,增删改查性能都会急剧下降,我们可以参考以下步骤来优化:

一、单表优化

除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑、部署、运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的。而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量:

1.数据字段

减少数据表单行记录的存储大小,这里主要是从字段类型、字段数量等方面来考虑,常见的原则如下:

2. 索引

了解数据库索引原理与结构,有助于我们更好地为数据表建立索引,在同样地数据量下,提高数据查询地效率,可以从以下方面考虑如何通过索引来优化sql性能:

主键索引.jpeg 普通索引.jpeg
3.查询语句

改写不合理地查询语句,以得到更快地响应时间:

4.大表分区

分区表是由多个相关的底层表实现,这些底层表也是由句柄对象表示,所以我们也可以直接访问各个分区,存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎),分区表的索引只是在各个底层表上各自加上一个相同的索引,从存储引擎的角度来看,底层表和一个普通表没有任何不同,存储引擎也无须知道这是一个普通表还是一个分区表的一部分。在分区表上的操作按照下面的操作逻辑进行:

分区的优点是:

分区的限制和缺点:

下面是根据时间字段建立分区的一个例子:

CREATE TABLE sales ( id INT AUTO_INCREMENT, 
amount DOUBLE NOT NULL, 
order_day DATETIME NOT NULL, 
PRIMARY KEY(id, order_day)) ENGINE=Innodb 
PARTITION BY RANGE(YEAR(order_day)) 
( PARTITION p_2015 VALUES LESS THAN (2015), 
PARTITION p_2016 VALUES LESS THAN (2016), 
PARTITION p_2017 VALUES LESS THAN (2017), 
PARTITION p_catchall VALUES LESS THAN MAXVALUE);

分区适合的场景:

二、分库分表

当一张单表的数据量达到几千万,并且还有不断增长趋势,在系统的访问量达到一定规模的时候,一次数据库的访问操作可能就很慢了。分库分表的目的就是要缓解单库压力,降低访问数据库的响应时间。

1.拆分方式
垂直拆分.jpg 水平拆分.jpg

在今天大型的互联网站基本上都是基于SOA或者微服务架构设计的,从某种意义上讲,我们的网站系统是按照业务功能进行垂直拆分的,不同的业务系统负责管理不同的业务数据库。在同一个业务系统中,比如订单系统,当单库单表的数据量不断增长时,往往只需要考虑水平拆分。
  这里讲到地水平拆分其实和表分区有些类似,表分区是在单库下,在存储引擎层面实现的水平拆分。

水平拆分的优点:

缺点是:

针对上面水平拆分带来的问题,目前技术上也有一些可提供的解决方案,大家在系统改造的时候,可以进行参考。

事务问题:
解决事务问题目前有两种可行的方案:

跨节点Join的问题
  只要是进行切分,跨节点Join的问题是不可避免的。但是良好的设计和切分却可以减少此类情况的发生。解决这一问题的普遍做法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。

跨节点的count,order by,group by以及聚合函数问题
  这些是一类问题,因为它们都需要基于全部数据集合进行计算。多数的代理都不会自动处理合并工作。解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题。

2.解决方案

基于开源还是自研?
  小明这里遇到的难题还是比较简单的,就是将大表数据分散到多库多表上存储,使用场景比较简单,而且如果要自主研发的话,时间周期长、项目风险大,小明果断地选取了市面上比较流行的分库分表解决方案,而且他还自信地对兄弟们说,即使以后我们遇到了分库分表的大难题,我们到时再在现有开源组件上基于自身业务做定制扩展嘛!

方案选取

客户端架构举例.png

客户端架构优点是: 应用直连数据库,降低外围系统依赖所带来的宕机风险,集成成本低,无需额外运维的组件。

缺点是:限于只能在数据库访问层上做文章,扩展性一般,对于比较复杂的系统可能会力不从心,将分片逻辑的压力放在应用服务器上,造成额外风险。

代理架构举例.png

代理架构的优点是:

  1. 能够处理非常复杂的需求,不受数据库访问层原来实现的限制,扩展性强;
  2. 对于应用服务器透明且没有增加任何额外负载;

缺点是:

  1. 需部署和运维独立的代理中间件,成本高;
  2. 应用需经过代理来连接数据库,网络上多了一跳,性能有损失且有额外风险;

有关客户端架构(比如tddl,sharding-jdbc等)和代理架构(mycat,heisenberg等)的具体实现方案,大家可以到internet上自行搜索学习,这里就不在累赘了。

这不产品经理又来催了,赶紧优化上线吧,这次小明明确了自己的需求:解决系统大数据量存储的问题,而且解决方案要轻量、简单易用、不增加额外的部署,所以小明选择客户端架构的实现方式,很快项目就优化上线了,告警短信消失了!

上一篇 下一篇

猜你喜欢

热点阅读