PDF批量打包下载
需求
产品要求每个税盘每月支持最大1万张PDF的打包下载
思路
每月1号定时往pdf_batch表插入一条记录(也可以做成用户实时筛选的模式);
另外每10秒启动一次轮询任务,遍历下载PDF到特定磁盘路径(batchId/diskName/storeId/xxx.pdf)下。
借助shell打包磁盘目录,删除磁盘文件夹,上传oss成功后,再删除zip包。
对于失败的PDF,要把错误原因打包到zip包中。
异常PDF前端会给用户展示,并提供补充的入口。
注:该功能为次要功能,由于大量占用带宽和CPU(压缩),所以不能放到核心系统,应该放到非核心系统(eg: 运营系统)。
表设计
pdf_batch(批次表):
id, diskId, month, type, status, total_size, ip, begin_time, end_time,
save_point, err_msg, zip_path, priority, retry_times, create_time, update_time
索引:
uni_key1(diskId, month)
key2(status, ip, priority, create_time)
说明:
type:1-正常的PDF下载,2-异常的PDF补充下载
status:1-待处理,2-处理中(会重试),3-处理成功,4-异常中断(会重试),5-永久中断(不重试)
pdf_batch_err(每个批次内部的PDF异常列表):
pdf_batch_id, invoice_id, pdf_path, err_msg
核心点
高性能高可用
多台机器同时跑:防止单点故障,并提高性能
每台机器最多有2个线程参与:防止该功能影响运营项目其他业务
pdf_batch表会记录ip,限制每个ip最多只有2个status=2的任务:如果没有ip限制,总体限制4个status=2的任务的话,一旦某台机器宕机,就会让剩余机器压力倍增,排队慢慢处理才是正道;而且也容易导致每台机器的处理线程数不均匀。
磁盘删除和淘汰策略
每个任务执行后,都会对dir和zip做删除。
中断(异常中断/永久中断)的任务,dir不删除。
每个batch任务执行前,都有diskFree监测,如果空间小于10G(两个任务同时跑最多占2G,留足余量防止意外):1. 会list当前目录下所有的batchId文件夹和zip包,如果有处理成功但删除失败的文件(夹),做二次删除;2. 如果有的dir=batchId当前执行的ip不是本机,说明任务被其他机器抢走,放心的做本地删除;3. 如果都是status=2/4/5的临时文件,则淘汰最早的文件夹,并对本机ip执行的batch任务savePoint做重置。
自动重试
status=2的场景:重启、宕机、网络分区、网络特别慢(oss下载超级慢) => 本机重试
status=4的场景:一般是数据不一致导致(disk数据丢失=>重试没用),打包异常(权限/磁盘满了/打包超时=>其他机器可以重试),oss上传失败(可以重试),打包前后校验失败(可以重试),文件创建/删除失败等(其他机器可以重试)
注:多个线程同时下载同一个文件,到本地相同的位置,是不会报错的,文件会不断被覆盖。所以不用担心网络慢导致超时后,两个线程同时下载文件会有冲突而抛异常。场景联想:A线程下载pdfX后更新savePoint=1001,然后B线程下载pdfX后更新savePoint=1001,正常场景是OK的
pageQuery和savePoint
每次对PDF的查询都是page(100),每成功下载一个PDF,都去更新一次savePoint。
pdf数量+err数量=totalSize
保证:打包后zip包中PDF的数量 + pdf_batch_err的数量 = totalSize
err.txt打包到税盘同级目录,展示给用户每个失败PDF的错误原因。
打包前后校验
检验dir在打包前后的修改时间
PDF数量
目录大小
问题
机器重启(短暂):任务线程会中断,status一直为2,只能等待超时
宕机(时间可能很长):任务线程会中断,status一直为2,只能等待超时
网络长时间分区(机器和DB不通):任务线程不中断,但连接数据库报错,status一直为2。
线程异常:前置大量校验,try-catch捕获 => status变为4/5 [什么错误可以重试,什么错误没必要重试:可以预先想一批,发到线上不断观察和完善]。
执行流程
10s定时任务启动时,查询"status=2 and ip=自己"的记录list;
如果有超时,报警并对它做重试:重试时,从savePoint开始;
没有超时,则判断有几条记录,如果大于等于2,则任务结束;如果小于2,则当前线程加入;
展望
针对特定status=4的场景做重试:可能本机重试,也可能交给其他机器重试
每次更新savePoint时,如果已下载数量超过10,计算平均速率,预估剩余执行时间,如果特别慢,则本机任务stop,交由其他机器尝试执行。
发票抽取
描述:将用户税盘和本地数据库的发票抽取到业务系统。
实现:
1.客户端进程会定时(5min)解析发票数据(几M ~ 几十M的小包),上传oss,oss监控meta.json文件触发postObject事件,然后产生MNS消息;
2.独立的抽取项目会订阅MNS消息队列,基于本地数据库做数据校验、过滤、格式转换等操作,然后将最终的发票数据发送给开票系统;
3.开票系统做发票落库和展示。
数据迁移
第一阶段:
只写老库
只读老库
第二阶段:
主写老库,次写新库. 新库异常走补偿重试.
只读老库
第三阶段:
主写老库,次写新库,同上阶段
只读新库(当然也可以走灰度慢慢放量至读新库)
第四阶段:
在上述流程稳定一段时间后.
主写新库,次写老库,写老库异常走补偿 (此步可一步到位,直接主写新库,不写老库)
只读新库