最近在一家小公司实习,文章也没怎么更新。前两天参与了后台系统数据库冷热分离(一期)的工做,虽然只是参与了定时任务和接口的开发改造,但仍是想了解一下它的来龙去脉,毕竟做为一只咸鱼,就要有翻身以后再做咸鱼的觉悟,因而就有了这篇文章。html
先说一下背景吧,随着业务的发展,生产库中订单等数据已经有数千万,而相似订单详情、结算详情的数据则已通过亿,而且天天以 20w+ 的数据在增长,能够说对数据库的改造已是迫在眉睫了。前端
考虑到具体的业务须要,按照用户的习惯,通常在近期的订单、订单详情等数据,因为有待评价、售后等问题,访问会比较多,这些数据就称之为热数据;数据库
而对于较早时间的订单、订单详情等数据,通常都是已评价、已完成售后等状态,用户通常不会常常访问,这些数据就称之为冷数据。分布式
因此考虑是否可以进行冷热分离。对于须要常常查询的数据放在生产库中,例如一个月以内的数据;而那些查询很少的数据,例如一个月以前的数据,将其迁移到历史库中。这样既能够减轻生产库的压力,也能够保持数据的完整。性能
定好大体方案后,就要考虑如何对数据进行迁移了。因为数据量过大,迁移不可能一次并在短期内就完成。学习
对于之前的数据,考虑在凌晨分批次进行迁移。因为不一样时期的数据量不一样,定时任务很差实现,只能经过手动查询,可能刚开始是好几个月的数据一块儿迁移,到后面就是十几天的数据一块儿迁移。测试
这里经过人工去判断一段时间内的数据量,并进行迁移,主要就是为了保证迁移工做不能影响生产库的正常运行,另外也要让迁移次数较少,迁移工做尽早完成。设计
而对于之后的增量数据,则能够设置定时任务,每日凌晨自动执行,迁移一个月以前的数据。cdn
在迁移数据时,以订单为粒度进行迁移,其总体的逻辑主要分为如下几步:htm
在数据迁移后,另外一个问题就是如何读写了,通常会有以下几种方案。
对于读操做,一种方案是,每次在查询时,优先查询热库,只有当结果没有命中,或只有部分命中时,才去查询冷库。这里为了区分所有命中和部分命中,能够在热库中建立一个表,记录每次要求查询冷库时的查询条件、查询的结果数量等。在查询热库时,若是相同查询条件的查询结果数量一致,则本地查询结束,不然就要到冷库中进行查询。
另外一种方案,则能够经过前端配合实现,每次查询时,默认只查询最近一段时间内的数据,也就是主库内的数据。若是用户须要查询之前的数据时,再去冷库中查询就行了。这也是目前我司的实现方案。
而对于写操做,也有两种方案。
一种是每次在存储数据时,在热库中存储一份,在冷库历史表中一样存储一份。而后每日凌晨经过定时任务删除一段时间以前的数据,若是数据量较大的话,能够按照区间进行删除,防止影响生产库的正常运行。
另外一种方案,与之相似,只不过在写操做时,只是在热库中进行存储。将数据从热库迁移到冷库的操做,放在凌晨的定时任务中执行。
其实通常来讲,单表数据量在数千万时,数据的写入和查询效率就会受到影响。这时就应该考虑进行分表,例如水平分表、垂直分表。
分表
对于水平分表,也有多种分表的策略。
按照范围划分
按照范围划分,例如将表中的数据按照时间,每月或每一个季度一张表。
这种作法也有利有弊:
按照 Hash 切分
按照 Hash 切分,通常使用 Mod 2^n 将数据划分到不一样的表中。
mod 的值选择为 2^n,具体根据业务决定,目标就是为了在之后的扩展时能尽可能少迁移,甚至不迁移数据。
这种作法若是划分均匀,批量写入、查询等操做均摊到各个表中,对性能不会有太大影响。可是须要对 mod 的值仔细权衡,方便之后的扩展。
分库
分表很大程度上解决了单表写入和查询的效率,但对于数据库而言,其负载压力并无变化,对于分库也有相似于分表的不少策略,这里就再也不多说了。
分库分表虽然带来了很大的好处,但也有一些问题须要处理,除了读写设计外,还有分布式 id,分布式事务,动态扩容等问题等着咱们一个一个去挑战。活到老,学到老。