文章插图
△图4.主节点生命周期
图5描述了主节点的生命周期,主节点收到出账指令后,优先做的是账户余额类表的数据备份,这个动作归因于我们月度任务的特殊性 , 月度任务产出的数据表在其他时间不会更新,即上个月出账结束后,账户余额类的相关表会在下一次出账完毕才更新 。
备份表的环节非常重要:
1.是可以在月度任务结束后做数据总额验证工作;
2.是可以用于兜底,一旦月度任务产出数据异常,也可回退到备份数据 , 重新启动任务 。
主节点任务的第二步则是确认出账任务的用户uid范围,我们系统为了既支持C端用户体系,也支持商家账号体系 , 重新设计了一套内部用户id,不论是用户账号还是商家账号的id均会唯一映射成一个内部uid,后文提到的该任务的uid均为内部uid 。内部uid为自增id,因此查询数据库,即可获取到最大uid和最小uid,也就确定了我们本次任务的uid范围 。在redis中设置两个key代表uid的最值 。至此 , 出账任务的前置准备工作就完成了 。主节点获取执行子任务配置的BNS,基于BNS解析出所有实例,发送子出账任务指令 , 子实例获取到指令后,启动N个线程执行任务,即假设有M个子实例,那最终就是M*N个线程同时执行任务 。从主节点的任务可看出,该任务无其特殊性,即主节点实际和从结点是平等关系,任何实例都可成为主,也可成为从,这就为调度任务进一步提高了灵活性 。
3.2.2 woker节点的任务流程

文章插图
△图5.从节点生命周期
图5以上述实例中的一个线程作为示例,详细描述了线程启动后 , 执行的子任务的过程 。首先获取目前的最大uid和最小uid,最大uid为主节点固定值,最小uid则是一个游标 。若最小uid已经大于最大uid,则代表所有uid已经处理完毕,线程结束 。若不满足上述条件 , 则继续执行任务,利用redis的incryBy指令 , 将最小uid向前移动N个数值,这N个uid就是本次子任务的执行范围 。拿到uid后 , 先将uid变为N条任务批量落入Job表,并设置初始化状态 。落库失败,引入报警机制 。落库成功后,按照出账模型,启动过滤规则 。所有被过滤的用户uid均批量写入job表,设置任务结束状态 , 并且标记过滤原因,便于后续运营查询 。过滤规则执行完毕,剩余uid十不存一,此时我们利用sql计算本月用户结算金额 。计算完毕,写入jobDB的临时产出表 , 设置job任务完结态,此时一轮子任务就执行完毕 。线程继续重复执行上述过程 , 直至所有线程均结束,代表出账任务执行完毕 。
3.2.3 出账确认任务
所有任务执行完毕后,主节点会收到出账任务确认指令 。

文章插图
△图6.出账确认任务
该任务的主要目的就是确认所有uid均执行完毕,无疏漏,具体如图6所示 。上文提到,子任务执行时,都是先置落库job表的 , 确认任务的第一步:扫描job表,看是否有非完结态的任务 , 若有,则启动子任务,重新执行这批数据 。确认任务第二步:获取job表中所有执行的uid数量和需要执行任务的uid数量,确认数量是否一致,若不一致,重新执行出账任务,任务基于uid和业务期间重入,已经被执行的任务会被跳过 。多次兜底策略执行完毕后,数据总量校验一致后,会将临时月度产出数据写入正式DB,清理临时数据 。之所以设置临时表:1.是为了数据校验工作,若数据校验异常,可快速清理该表,重新启动任务;2.若直接写入正式线上库 , 大量数据的并发写入会导致数据库的主从延迟,会影响其他线上实时业务场景 。后置写入实现了另类的『读写分离』 , 任务过程中仅读正式表,任务完毕临时表往正式表写入数据 。
04 总结
本文主要介绍了在构建结算系统过程中的几个技术重点和难点,而要维护整套系统的平稳运行 , 不仅有这些技术重点,也有看似微不足道但却环环相扣的细枝末节 , 保障每个环节不掉链子是运维工作的重要一环,后续我们将着力于提升运维效率,节省人力成本,向着运维自动化、智能化改造 。另外目前的技术方案取决于我们的数据量级,未来业务蓬勃发展,业务架构也会持续迭代 , 期待我们向着更加完备的架构前进 。
推荐阅读
- 福禄生活卡券小程序在哪里 福禄生活卡券 百度网盘
- 以马内利什么意思啊 以马内利百度百科
- 益禾堂奶茶加盟费多少 益禾堂奶茶加盟费多少百度
- 什么是抢帽子交易操纵 什么是抢帽子交易
- 账户已暂停非柜面交易什么意思 账户已暂停非柜面交易什么意思外地卡可在本地
- 梦到自己大哭预示着什么 梦见自己大哭什么意思?百度知道
- 超好听的女孩名字大全 超好听的女孩名字大全 百度文库
- 白醋对霉斑有作用吗 白醋对霉斑有作用吗百度百科
- 国家一级演员被抓!涉及权钱色交易,曾被评为“德艺双馨工作者”
- 白色桔梗花百度百科 白色桔梗花的花语是什么
