一、背景
有一张mysql分表:student000_student999,每张分表存储了大概几千万的数据,需要手动进行归档,保留近一个月的数据,该怎么操作?
二、解决方案
(1)写定时任务去删除
@Schedule(集群可以用redis实现分布式锁,单机的话不需要)、xxl-job、ElasticJob都可以
(2)获取待删除数据的最小主键id、最大主键id
用主键去删除是为了控制mysql查询的扫描范围,效率更高
(3)根据主键id去删除,每次删除5000条,线程休眠1s
现有的mysql集群大部分都是主从结构,主写从读,就会涉及到主从延迟的问题,最好是控制主从同步的TPS,避免影响业务
三、核心代码块
//TODO 1.从库里查询出要删除的minId、maxId
//没有符合条件的数据直接结束
if (minId == 0 || maxId == 0) {
return;
}
AtomicLong atomicLong = new AtomicLong(minId);
//分批删除,每次删除5000条,休眠1s
while (atomicLong.get() <= maxId) {
//待删除的最小id,其实就是minId的值
long deleteRangeMinId = atomicLong.get();
//待删除的最大id,其实就是minId+5000的值
long deleteRangeMaxId = atomicLong.addAndGet(5000);
//最后一次删除的边界条件
if (deleteRangeMaxId >= maxId) {
//maxId也要删掉
long newMaxId = maxId + 1;
//TODO 2.deleteExecutor是自定义的多线程,防止单线程阻塞,影响删除效率,deleteData方法就是根据主键id左闭右开的删除
deleteExecutor.execute(() -> deleteData(deleteRangeMinId, newMaxId));
break;
}
deleteExecutor.execute(() -> deleteData(deleteRangeMinId, deleteRangeMaxId));
Thread.sleep(1000);
}
执行定时任务的时候,可以观察下mysql主从同步的监控,看下是否有延迟,如果有的话,可以把5000配置在动态中心Apollo或者Nacos,便于实时的更改。具体使用结合场景来。