如何分离冷热数据
分析
分离冷热数据的基本逻辑如下:
判断数据是冷是热。
将要分离的数据插入冷数据库中。
从热数据库中删除分离的数据。
这个逻辑看起来简单,而实际做方案时,需要考虑以下3点:
一致性:同时修改多个数据库,如何保证数据的一致性?
这里的一致性要求是指如何保证任何一步出错后数据最终还是一致的。任何一个程序都要考虑在运行过程中突然出错中断时,应该怎么办。 这里的解决方案为,保证每一步都可以重试且操作都有幂等性,具体逻辑分为4步:
在热数据库中给需要迁移的数据加标识:ColdFlag=WaittingForMove(实际处理中标识字段的值用数字就可以,这里是为了方便理解),从而将冷热数据标识的计算结果进行持久化,后面可以使用。
找出所有待迁移的数据(ColdFlag=WaittingForMove)。这一步是为了确保前面有些线程因为部分原因运行失败,出现有些待迁移的数据没有迁移的情况时,可以通过这个标识找到这些遗留在热数据库中的工单数据。
在冷数据库中保存一份数据,但在保存逻辑中需要加个判断来保证幂等性。通过幂等性来确保冷数据库中没有重复数据。
从热数据库中删除对应的数据。
数据量:假设数据量大,一次处理不完,该怎么办?是否需要使用批量处理?
在当前的业务场景中,假设每天做一次冷热分离,根据前面的估算,每天有10万的工单数据和几十万的工单历史记录数据要迁移,但是程序不可能一次性插入几十万条记录,因此考虑批量处理。
假设每次可以迁移1000条数据,批量处理的逻辑如下:
在热数据库中给需要的数据添加标识:ColdFlag=WaittingForMove。这个过程使用Update语句就可以完成,每次更新大概10万条记录。
找出前1000条待迁移的数据(ColdFlag=WaittingForMove)。
在冷数据库中保存一份数据。
从热数据库中删除对应的数据。
循环执行2 ~ 4。
并发性:假设数据量大到要分到多个地方并行处理,该怎么办?
在当前的业务场景中,已经有了3000万的数据,第一次运行冷热分离的逻辑时,这些数据如果通过单线程来迁移,一个晚上可能无法完成,会影响第二天的客服工作,所以要考虑并发,采用多个线程来迁移。
当采用多线程同时迁移冷热数据时,需要考虑以下方面:
如何启动多线程?
设置多个定时器,让每个定时器启动的时间间隔短一些,每个定时器启动一个线程。
线程池
任务分配:某线程宣布正在操作某个数据,其他线程不能操作它 因为是多线程并发迁移数据,所以要确保每个线程迁移的数据都是独立分开的,不能出现多个线程迁移同一条记录的情况。 关于这个逻辑,需要考虑3个特性:
确定待迁移数据的归属:通过在表中增加LockThread字段,根据该字段划分处理任务归属。
存在托底机制,当某线程宕掉,或者处理速度过慢时,需要保证分配进行处理的记录能够得到即时处理:通过在表中增加LockTime字段,表示记录归属某一线程的期限,对于超时的记录可以交由其他线程进行处理。 此时,存在一个副作用:如果记录正在被某一线程处理,只是处理速度较慢,超过了期限,此时可能会发生重复处理问题,因此需要保证在插入冷库的SQL语句是幂等的。可以通过
INSERT … ON DUPLICATE KEY UPDATE
来保证记录不重复。
最终的SQL语句大致如下(猜测):
上述逻辑,只可能出现ticket记录被重复插入冷库,不会出现遗漏的记录。而重复插入可以通过幂等性的insert语句保障不会出现重复记录。