提供一个周期性任务生成(Excel/CSV)、导出、上传、推送的平台
数据来源
- 配置界面直接配置
- webrm直接插入(webrm本身的界面就是大量的表格、其自身的特殊性)
表设计
任务生成
- task_excel_tpl 定义Excel的模板相关
- task_excel_tpl_job 定义Excel的导出周期 cycle_type、cycle_number
- task_excel_tpl_sheet 定义Excel的Sheet相关和Sql相关 sql_table 、sql_field_str、sql_filter
- task_excel_tpl_sheet_para 定义Sheet的字段相关 field_name、 field_cn_name、 field_style
任务导出
- task_excel_tpl_joblist
- task_excel_job_data
- task_excel_data_sheet
- task_excel_data_xml 定义了完整的sql
- task_excel_data_sheet_para
代码设计
public interface TimeStrategy {
public boolean apply(TaskExcelTplJob taskExcelTplJob);
}
public void createTask(TimeStrategy strategy) {
if (strategy.apply())
doCreateTask();
}
task_excel_tpl_joblist 是任务生成和任务导出的桥梁,任务导出线程监控task_excel_tpl_joblist 中记录的状态进行导出。createTask根据任务生成表的中的记录将需要生成的任务插入到对应的任务导出表中。
上传与推送
- task_excel_tpl_ftp 根据tplid定义了需要上传的ftpip、addr、user、pass、space
- task_excel_tpl_trans 根据tplid定义了需要推送的地址、接口、唯一标识的服务名
优化
前期优化 (刚开始实现时的优化)
- 读写分离,拉一个只读库出来供导出
- 多线程的FutureTask,但由于每一个导出文件的大小并不确定容易导致fullGc甚至是内存溢出,于是只能暂时将线程调小。后期改成了居于当前一共的导出数据来控制线程的数量,但也为后面的扩展留下了坑。
- 缓存,维护一个uploadSet/transportSet对tplid在set中的任务入队到对应的队列、减少查询次数
- sql,往往所有的优化都没有直接优化sql来的有效。在配置界面提供了sql测试功能,限制sql必须优化到固定时间才能进入任务生成,缓存枚举表,task_excel_tpl_sheet_para提供fieldKey字段,减少sql连表操作
后期优化(用了四五个月后由于以前报表转移过来、其他项目的报表也转移过来导致任务暴增)
- 服务拆分加机器,服务边界也很明显。生成、导出、上传、推送。但由于我们前期为了追求最大的导出速率采用了根据导出数据量控制线程数量,不同机器不适用又需要大幅度改回来。同时推送手段的多样性导致我们暂时并没有进行推送处理,只是将记录插入到对应的表中由任务发起者定期扫描表自行推送。
监控
暂时采用简单的监控方式 ,监控task_excel_tpl_joblist 中记录的状态,当某个状态超过一个阈值时告警上报。同时单个机器完成任务时在task_excel_tpl_joblist注册ip和端口用于排查具体机器的状况
拯救还是放弃
- 任务失败时前期采用的是失败后全部任务处理完成后尝试重新执行
- 毒丸任务 长时间执行不过的任务各个机器又尝试去执行导致整个down掉
- 建立舱壁 每台机在启动的时候向数据库中注册申请自身为对失败任务进行重试的机器,已存在则放弃
最重要的因素——人
- 前期给以了用户极大的自由度,包括定义Excel样式、列中文名称,但是用户都是懒惰的,导致样式都使用默认的、列中文名直接读数据库表字段注释,功能逐渐被废弃。
- 无论多大的任务,最终导出时间用户都选默认早上9点,导致真正紧急的任务得不到执行。
- 需要推送的任务插入到一个表中,但是多个项目共用表出现问题时没有准确的日志谁都自信的认为自己的代码是没有问题的。永远不要把表或数据暴露给不相干的人
未来
- 帮助任务发起方进行推送?传输协议的多样性、接口参数的不确定如何统一以及都揽到自己身上是否工作量过于庞大
- 强迫任务发起方提供某个接口,只是做一种间接推送,真正的推送仍由任务发起方自己去做?至少不应该依赖数据库进行集成吧,但是改造花费的时间是否值得
网友评论