后台批量进程开发的总结

1       总述

入口

    • 数据库
    • 文件
    • Socket通信

 

触发条件

    • 时间
    • 轮询
    • 接口
    • 手工

         对于批量处理理论上要至少满足以下五个方面的考虑:

    • 事务性
    • 统计
    • 监控
    • 性能
    • 错单处理

2       批量使用场景

2.1     批量操作同单笔操作比较

单笔操作:

    • 一般是由客户端触发
    • 更加实时;
    • 开发相对比较简单
    • 当业务处理复杂时,操作会比较慢,造成用户体验太好;
    • 出错处理相对比较简单;

 

批量操作:

    •  一般是在服务端触发
    • 执行时间比较固定;或者在满足某些条件下触发;
    • 开发和维护难度较大
    • 比较合适处理大批量的数据;
    • 出错处理相对比较麻烦

        

2.2     结论

在满足性能的条件下优先考虑使用单笔操作的方式去解决问题;对于一些有时间要求的业务,可以考虑增加eff_date/exp_date来进行自动判断,从而避免增加后台进程。为了良好的用户体验,将单笔业务操作移到后台批量进程去处理并不是一个很好的方案。单笔流程较长时,可以考虑增加调度方法来解决,例如事件(或者消息)驱动的方法来构造整体的框架。

如果单笔业务不好做了,那我们就考虑用批量进程来处理,下面就这个问题展开思考。

3       如何设计

3.1     事务性

3.1.1     入口为数据库的事务性

对于入口为数据库,一般每条数据为一个记录,则对于记录设置一个flag,一个remark(考虑合适的长度)。

?  Flag

0:未处理

                   1:正在处理

                   2:处理成功

                   3:处理异常

4:处理失败

说明一下34的区别,处理失败是指不满足业务条件的处理,既可以认为是正确的也可以认为是错误的,根据业务来确认;而处理异常,则是指程序问题、接口问题、系统、硬件等非业务原因引起的错误,是需要后期重新处理的业务;

另外,如果对于业务失败比较关注,则可以将其展开,分成部分的业务错误,以满足后期灵活的业务处理;

?  Remark

                   用来记录处理失败的详细信息;每处理完一条,则进行commit

?  另外对于入参及关键参数,绝对不能去修改,如果业务需要则建议新增字段;

3.1.2     入口为文件的事务性

         入口为文件的批量操作,一般文件的每条记录为一笔操作,每条记录中的以定长或者特殊分隔符(例如“|”,“,”)进行分割。也可以使用标准的传输文件协议为如何,例如xml或者json的方式,这种方式带来一定的灵活性比较合适业务有变动的情况,但是同时会增加网络的流量。

         这种方式一般会有下载数据文件、数据文件解析、循环数据文件,单行业务处理,异常处理记录,异常工单处理这些操作。循环中要捕获单行处理的任何异常,防止因为一条记录的失败,导致处理整个文件的退出。

另外,要保证原始文件的完整性,不能对原始文件进行任何修改。处理完成后,将文件备份到一个单独的目录中。

        处理成功的记录,由于文件方式的统计不是很方便,一般采用下面两种方式来记录。

方式1:将结果数据记录到数据库表中,此种方式简单不再啰嗦叙述。

方式2:记录一个汇总文件和一个明细文件。汇总文件记录每个文件或者每次触发条件下,处理的文件、成功的数目,失败的数目、开始时间和结束时间。明细文件记录处理成功的行记录信息,以便于以后进行核对。明细文件中,每一行代表一个记录的执行结果,里面能唯一识别该记录的来源,例如可以以下面方式组织:执行时间|文件名称|行数|关键数据(例如号码、订单号、流水号等)|处理结果。

         处理失败的记录,同样可以以2中方式去组织,一种以数据库表的方式去组织,一种以文件方式组织,这里还是讲述文件的方式。这里组织2个文件,一个文件记录异常的处理记录及其错误原因;一个文件则是原始的数据,这样在处理完问题后,可以方便地进行重新处理。

3.2     统计

         对于入口为数据库的方式来讲,可以通过时间、flag过滤筛选;

         对于入口为文件的方式来讲,可以通过汇总文件进行统计;

3.3     监控

3.3.1     通用的监控

         对于常驻进程,则通过类似于ps –fe|grep $(PROGRAM_NAME)|grep –v grep|wc,计算数量来分析;以及进程的状态来进一步处理;

         对于处理时间很短的后台进程,则需要保证其与触发条件的一致性;

        

3.3.2     入口为数据库或者涉及数据库操作进程的监控

         准实时监控处理的记录所占的及时性、正确率,例如处理比率、异常处理的比重;

         或者操作记录的时间来监控(前提是能区分是前台在修改还是后台在修改);

3.3.3     入库为文件的事务性

                  监控备份文件的变化;

                   监控汇总文件的变化、成功处理、异常处理数据的变化;

 

 

3.4     性能

3.4.1     入口为数据库的性能

         以下情况适用于数据很大的情况,例如系统中的短信接口表处理。

如果数据量很大,则对数据库性能的影响会很大,特别是索引的建立不合适,会加剧这一问题;这也是数据表做接口表的缺点,当数据量非常巨大的时候,在分表、分区、分库都很难满足的情况下,则考虑采用其他方式。

         一般会有至少3个表,分表为正表、处理成功表、处理失败表,处理失败表又可以根据业务进行拆分。

         关于正表的处理有个处理策略问题,有点类似于系统调用策略。一般有先进先出、优先级争抢、超时处理等。索引的建立只满足于该策略即可,不建议再增加其他索引。因为正常来讲,数据在表中的时间会非常短暂。程序每次按照策略从表中取出数据,取出的同时从表中删除数据。

         处理成功表,是用来存放正确处理的记录,供后续查看使用;这个表建议以时间进行分表,毕竟绝大多数是成功的数据。

         错误处理表,是用来存放处理失败的记录,供后续处理使用;这里错误包括业务条件不满足等业务上的错误和非业务上的错误。

         处理成功表和处理错误表相对来讲是比较静态的表,索引可以根据业务需要查询需要去建立合适数目的索引。

 

如何防止进程(或线程)竞争

此类程序一般都是多个进程或者线程去处理的,这样的话就可能会有多个程序争到同一条记录,或者业务上有要求,同一个用户的数据必须按照顺序去执行。

解决方法:

方法1:例如如果启动10个进程的话(编号01….9),每个进程处理编号位数相同的记录,进程3处理订单号为xxxxxxx3的记录。

方法2:例如对用订单而言,一般用户的订单一定要先后顺序去执行,以满足业务上的限制;处理的时候,先做判断,将同一个用户的订单行构造成一个队列(可以是虚拟的),然后按照队列的方法去处理;

方法3:让其中一个线程专职做调度,让剩下的线程去干活;这个方法是最好的方法,如果系统策略变更,则只需要修改调用程序的流程即可,而不需要修改业务操作,做到了业务逻辑的透明性;但是相对而言开发难度更大些。

3.4.2           入口为文件方式的性能

文件方式性能问题并不大,更多的是其他角度处理相对困难。

3.5     错单处理

3.5.1     手工处理

对于入口为数据库表的方式,可以通过修改flag、将错误表数据导入正表去触发重新处理。

         对于入口为文件的方式,可以手工指定错误数据数据文件去执行。

3.5.2     自动处理

自动处理的范围比较有限,且需要对异常处理有很好的细化,例如对于数据库故障、网络终端等错误,可以自动触发重新处理。

后台批量进程开发的总结

上一篇:【java设计模式】之 建造者(Builder)模式


下一篇:Redis学习系列(一):Redis服务器端的配置与启动