1 概述
杭州银行批量交易平台(HZBAT
)是我基于DC4C
自研的面向批量交易的技术平台。DC4C
是我在2015年完全独立自研的分布式批量计算框架。
目前HZBAT已用于综合积分系统(2015年投产)、ECIF
系统(2017年投产),以及在2018年加入同事潘平原一起改造优化后实施于杭州银行核心业务系统的日终批量交易平台,稳定运行至今。
2 分布式批量计算框架(DC4C)
2015年4月,我在开发爬虫项目需要平台化、配置化的并发调度框架,搜寻了开源社区以及阿里等大厂都没有对应的技术产品可用,遂自己将调度逻辑抽象出来,借鉴分布式设计思想,充分考虑集群高可用和敏捷伸缩,花了一个多月完全独立设计自研了一套分布式批量计算框架,取名为DC4C
。
DC4C
是一个中介代理模式、动态自治、高可用易伸缩的分布式批量计算框架,也是业界最早实现有向无环图任务调度引擎的分布式计算框架之一。
DC4C
内核完全用C编写,版本'1.5.5'时手工代码约一万行,此外大量代码使用我的开源工具DirectStruct
自动化技术生成,大幅减少了开发量,提高了开发效率,减轻了底层细节编码压力。
DC4C
不依赖其它任何第三方代码、库和系统,只依赖我开源的极速JSON解析库fasterjson
,已包含在DC4C源码内。
2.1. 体系架构
DC4C
体系架构包含基础平台架构、API包和任务调度引擎库。
2.1.1. 基础平台架构
architecture.png
DC4C
提供了一个分布式基础设施,包含负责中介的注册节点(rserver
)、负责业务逻辑处理的计算节点组(wserver
)、负责任务分派和调度的用户节点API(dc4c_user_api
),构建了分布式集群管理和批量任务分派调度管理体系。在任务分派API基础上又封装了调度引擎库,自研了有向无环图任务调度引擎(dc4c_tfc_dag_api
)。
DC4C
用户节点API包可用其它语言编写以适配使用者公司的技术栈,计算节点应用目前只支持装载可执行程序和动态库,可扩展改造支持其它执行模式。
2.1.1.1. 注册节点
注册节点为父子进程结构,父进程负责监控子进程异常时重启子进程,子进程负责接受计算节点的注册、状态变更、注销,接受用户节点API查询空闲计算节点信息,接口支持TCP
、HTTP
/HTML
两种方式。
注册节点最多可部署8套,提高计算节点注册信息的冗余性,保证系统高可用。
2.1.1.2. 计算节点
计算节点为三级进程结构,管理进程创建一组工作进程,并监控工作进程异常时重启工作进程,每个工作进程都有一个唯一的侦听网络地址(起始端口号+工作进程编号),每个工作进程再创建一个执行进程作为其关联进程。
工作进程负责向注册节点注册、状态变更、注销,负责接受用户节点的任务分派请求、联动下发任务程序、传递任务命令给执行进程、反馈任务结果。工作进程与注册节点保持长连接并周期性交换心跳。工作进程接收到任务时会检查比较用户节点的任务程序和本地的是否一致,如果不一致会联动发起下发任务程序请求,最后再传递任务给执行进程执行。工作进程管理同一时间只有一个任务正在执行,如果有额外的用户节点连接进来则立即响应告知。
执行进程负责接收任务命令行,装载、执行任务程序。
2.1.1.3. 用户节点
用户节点由用户进程组成,用户代码调用用户节点API包实现向注册节点查询空闲计算节点、向计算节点分派任务。
2.1.2. API包
2.1.2.1. 用户节点API包
用户节点API包供用户节点进程调用,负责查询计算集群中空闲节点、分派任务,并监督任务执行。
用户节点API包括单任务分派API集、批任务分派API集和多批任务分派API集。
用户节点API还提供了开始、结束、取消事件钩子,以便于在批量前后、任务前后自动触发用户自定义的代码逻辑,比如更新数据库中的任务状态。
2.1.2.2. 计算节点API包
计算节点API包用于计算节点执行进程与任务程序之间的信息交互。
2.1.3. 任务调度引擎库
任务调度引擎用于用户节点,是基于用户节点API包的再高层封装。
目前引擎库提供有有向无环图任务调度引擎。
2.1.3.1. 有向无环图任务调度引擎API
DAG.png
有向无环图是一种图结构,图中所有图节点都有前序、后序方向关系,且从开始图节点开始,期间经历分拆和合拢,最后汇合至结束图节点。有向无环图节点之间都是有向且不能构成环。
dag_task_engine.png
有向无环图任务调度引擎读取JSON配置文件填充中间数据结构,再构造有向无环图内部结构,然后按有向无环图节点前序后继关系,依次执行所有批量,每个批量由一组任务组成,批量内任务呈列表结构,从上到下执行。引擎还提供直接接收中间数据结构接口,以便于用户自行编写从自定义配置源(如数据库)到中间数据结构的逻辑。
有向无环图任务调度引擎内部做了众多执行优化,比如执行前处理会对每一条图节点链路计算评分,执行时根据评分均衡每条链路的优先权重,实现执行总时间最小化。
2.2. 重要流程
2.2.1. 计算节点注册流程
compute_node_registe_flow.png
计算节点管理进程创建一组工作进程,工作进程创建自己的关联执行进程后,与注册节点建立TCP长连接,附带服务器信息,发送注册请求。请求被接受后,周期性交换心跳。
worker_info_strategy.png
注册节点会把每一个计算节点工作进程的注册请求都缓存起来,挂接成三级链表“主机类型”(OS版本号位数)-“主机”(IP)-“工作进程”(PORT)。
当收到注销或者长连接断开就删除对应工作进程链表节点,如果工作进程链表为空则连带删除主机链表节点,如果主机链表为空则连带删除主机类型链表节点。
当收到用户节点API的查询空闲计算节点请求时,根据上送的主机类型条件,挑选若干个工作负载最轻的主机,选择若干个空闲的计算节点工作进程信息返回给用户节点,移动该工作进程链表节点到最后,以均衡负载。
2.2.2. 用户节点分派任务流程
user_node_dispatch_task_flow.png
用户节点用户应用要分派一个任务时,调用用户节点API。
API首先与注册节点建立TCP连接,附带服务器信息,发送查询请求到注册节点,注册节点根据筛选条件和负载策略返回指定数量的计算节点网络地址信息给用户节点API,然后API连接计算节点并发送执行任务请求,计算节点根据收到的任务程序散列值和本地的比较,如果一致则去执行,如果不一致则联动请求用户节点API下发任务程序,最后工作进程传递任务相关信息给执行进程执行。
工作进程把任务命令行传递给执行进程时,也向注册节点发送状态变更通知,把自己切换为忙碌状态。
执行进程结束执行后,传递结果给工作进程,工作进程把执行结果转交给用户节点,也向注册节点发送状态变更通知,把自己切换为空闲状态。
用户应用还能通过调用用户节点API分派一批或多批任务,并在超时时间内等待所有任务分派到计算节点执行完成返回,或发生错误后根据设置决定是否优雅中断。
2.2.3. 任务状态迁徙
可靠性是考验一个分布式系统架构设计的重要考量,DC4C架构中,一个任务在分派、传递、执行、响应的任何过程中都可能发生异常。
由于任务的接收执行和计算节点状态变更通知是异步的,有可能用户节点向注册节点拿到的计算节点状态与实际不符,所以用户节点连接分派任务给计算节点时,可能会收到该计算节点忙碌响应,用户节点API将迭代再次向注册节点查询。
task_status_migration.png
每个任务在系统间流转时都会有一个任务状态来跟踪之,当一个任务被选中分派前,其状态从INIT
转换为USER_EXECUTING
,发送给计算节点且接受任务时,其状态从USER_EXECUTING
转换为WSERVER_EXECUTING
,执行进程执行完传递回工作进程时,其状态从WSERVER_EXECUTING
转换为WSERVER_FINISHED
或WSERVER_FINISHED_WITH_ERROR
,响应回用户节点后,其状态转换为USER_FINISHED
或USER_FINISHED_WITH_ERROR
。
当任务执行中崩溃时,工作进程能在第一时间感知到,代异常结束的执行进程响应回用户节点,用户节点API修改状态为USER_FINISHED_WITH_DOUBT
。可疑状态需要人工介入查证。
当任务执行时间过长或陷入死循环,用户节点API会强行断开与计算节点的连接,修改状态为USER_FINISHED_WITH_DOUBT
。可疑状态需要人工介入查证。
任务状态在流转中,如果使用者设置了每个任务或每个批量的事件钩子,将获得调度中自定义处理状态的机会,比如更新数据库。
2.3. 高可用
2.3.1. 当注册节点崩溃
当注册节点子进程崩溃时,用户节点和计算节点立即侦测到与之连接异常,转而连接其它注册节点,因其它注册节点拥有相同的冗余计算节点注册信息,不影响用户节点和计算节点工作。注册节点父进程立即侦测到子进程崩溃后会重启该进程。
当注册节点父进程崩溃时,子进程也会结束,其它注册节点拥有冗余计算节点注册信息提供给集群提供服务。
2.3.2. 当注册节点僵死
当注册节点子进程僵死时,计算节点通过心跳发现异常,强制断开并转而连接其它注册节点,用户节点与之通讯超时,转而连接其它注册节点。注册节点父进程不会侦测到子进程异常,但该节点被孤立,所有错误日志指向该节点,便于手工定位和处置。
当注册节点父进程僵死时,不影响子进程工作。
2.3.3. 当计算节点崩溃
当计算节点工作进程崩溃时,注册节点立即侦测到与之连接异常,断开等待其重启后重连。用户节点立即侦测与之连接异常,如果设置了忽略错误选项,重新向注册节点查询其它空闲计算节点,分派任务,否则进入优雅结束流程,人工介入处理。计算节点管理进程立即侦测到工作进程崩溃,重启该进程。
当计算节点执行进程崩溃时,工作进程会发送可疑状态回用户节点,然后重启执行进程,在未重启完成前拒绝所有用户节点执行任务请求,因为集群允许注册节点里计算节点状态与真实计算节点状态不一致,且注册节点把查询过的计算节点信息移到链表最后面并一定时间内不允许再查询,该计算节点在未准备好执行进程前不会被高频骚扰。
当计算节点管理进程崩溃时,不影响其它进程工作。
2.3.4. 当计算节点僵死
当计算节点工作进程僵死时,注册节点通过心跳发现异常,强制断开并等待重连,用户节点与之通讯超时,如果设置了忽略错误选项,重新向注册节点查询其它空闲计算节点,分派任务,否则进入优雅结束流程,人工介入。计算节点管理进程不会侦测到子进程异常,但该节点被孤立,所有错误日志指向该节点,便于手工定位和处理。
当计算节点执行进程僵死时,用户节点首先会超时,如果设置了忽略错误选项,重新向注册节点查询其它空闲计算节点,分派任务,否则进入优雅结束流程,人工介入。
当计算节点管理进程僵死时,不影响其它进程工作。
2.3.5. 当用户节点崩溃
当用户节点用户程序进程崩溃时,计算节点工作立即侦测到当前执行任务的用户节点断开连接,但不影响执行进程处理,后续需要人工介入。
2.3.6. 当用户节点僵死
当用户节点用户程序进程僵死时,计算节点工作进程等待执行进程结束,发送执行完成响应给用户节点,然后等待其他用户节点任务。
2.4. 高可靠
DC4C基于任务状态实现高可靠能力。当调度侦测到系统或应用失败而引发优雅结束后,再次启动时会检查未决任务的状态:如果用户节点为中间状态但计算节点为结束状态,以计算节点修正用户节点状态;明确失败状态重置成初始状态以便重新执行;如果存在可疑状态,拒绝启动,等待人工介入查证后修正状态。
2.5. 敏捷伸缩
2.5.1. 热扩大集群
需要新增计算节点,只需在新加入主机或已有主机内,启动新计算节点组,查询日志和查询注册节点确认加入成功后,自然有用户节点会查询到并分派任务过来。
2.5.2. 热缩小集群
当需要删除计算节点时,只需向目标计算节点组的管理进程发送中止信号TERM
,管理进程转发信号给工作进程组,没有任务的工作-执行进程组立即结束,有任务执行的工作进程关闭网络服务,等待执行进程任务完成后再结束,整个缩小集群过程不影响正在处理的任务。
2.6. 功能和优势
对于应用开发人员,无需编写任何并发控制细节代码(如
fork
、wait
)就可轻松实现本地或集群的并发管理,以及本地风格(wait
子进程退出值status
)的执行反馈。计算节点用户应用本身就是可执行程序,便于本地调试。对于系统运维人员,随时根据当前系统负载热伸缩(扩大或减小)集群规模,而不影响系统的功能性,更无需应用开发人员参与。集群伸缩无需重启等影响当前正在处理的任务。没有配置文件,大大减少运维复杂度,实现高伸缩性。目前热伸缩只能手工触发。
通过网络连接心跳、父子进程监控、数据冗余、任务状态迁徙等实现架构高可靠高可用。
用户API包提供了单任务分派、批量任务分派、多批量任务分派等高层封装API,也提供了低层API供用户自己封装适应自己应用场景的任务分派器。用户API包也提供了同步、多路复用等分派模式,支持各种场景的用户代码结构。
实现了一个有向无环图任务调度引擎,是业界最早实现该数据结构任务调度引擎的分布式计算框架之一。
用户节点API和计算节点有自动检查应用版本和自动集群应用部署机制。
支持telnet或网页查询、管理集群状态。
3 杭州银行批量交易平台(HZBAT)
3.1. 与DC4C的关系
hzbat_and_dc4c.png
杭州银行批量交易平台HZBAT(下面简称HZBAT
)是基于分布式批量计算框架DC4C研发而成。
HZBAT
建立“阶段-批量-任务”三级调度模型,调DC4C
用有向无环图任务调度引擎API实现银行批量交易调度处理。
主控管理程序hzbat
调用DC4C
调度引擎库中的有向无环图调度引擎API,作为用户节点,向注册节点查询空闲计算节点信息,下发任务程序和分派任务给计算节点,计算节点执行进程装载、执行任务程序。
HZBAT
依靠DC4C
实现随时热伸缩集群而不影响正在处理的批量交易,无基础设施配置文件模式减轻了运维人员工作,通过连接心跳、进程监控、状态冗余(部署多注册节点)等实现高可靠高可用,基于有向无环图任务结构大大丰富批量任务并发配置的灵活度,整个框架自带交易程序自动更新机制。
3.2. “阶段”-“批量”-“任务”三级调度对象
HZBAT
基于DC4C
把调度对象分为“阶段”-“批量”-“任务”三级。
任务是最小执行单元,一个任务即一个执行命令行(有直接执行命令行和动态库加参数两种模式),即一个执行进程。在DC4C
有向无环图调度引擎中,任务被分发到DC4C
分布式集群(计算节点群组)中空闲的计算节点上,由该计算节点执行进程执行该命令行、监控执行过程、反馈执行结果(进程返回值)回用户节点(任务分发方)。
批量由一组任务构成,任务之间平等没有优先级,一般按任务列表顺序分派和执行。
计划即有向无环图批量集合,每个批量是该图上的一个节点,批量与批量之间有先后依赖关系,只有所有前序批量都执行完成后才能开启后继批量。
schedule_list.png
整个银行日终批量分为五个阶段:日终
、日切
、日结
、日初
、报表
,季末在日初后会有季度结息
阶段。出于管理需要,每个阶段手工触发。
batch_dag_in_schedule.png
task_list_in_batch.png
每个阶段由一棵有向无环图组成,每个图节点是一个批量,每个批量由组任务列表组成。
平台主控管理程序hzbat
从数据库中读取阶段信息、批量信息、批量前序后继关系信息、静态任务信息、批量过滤信息,填充中间数据结构,调用有向无环图调度引擎API,引擎调用DC4C用户节点API,控制执行阶段、批量和任务。当阶段开始结束时、批量开始结束时、任务开始结束时,编写回调函数挂接到调度引擎事件钩子中,实现回写更新状态、记录结果等功能。
主控管理程序hzbat
还支持单批量、单阶段、自动阶段组执行,便于本地化调试。
3.3. 静态任务和动态任务
预先配置在数据库任务表中的任务称为静态任务,每天不变的任务按静态任务预置。
每天都可能变化的任务称为动态任务,动态任务不配置在任务表中,在每个阶段开始时,会先执行所有批量的准备任务,准备任务读入业务数据,拆分并行维度,生成动态任务并登记到任务表中,然后再按有向无环图结构执行所有批量在任务表中的任务,包括静态任务。
3.4. 批量过滤
有些批量只有在特定的时间才能执行,hzbat
加入数据库批量过滤表,实现批量过滤机制。
目前过滤类型有每月指定日执行(含自适应月初月末)、按每年指定月日执行、按每周星期几执行三种类型。同一种类型可配置一个或多个值,如每月的10日、20日执行,如每周的周一、周三、周四执行。
3.5. 主要数据库表结构
db_schema.png
3.6. 最佳实践
在长期使用HZBAT
中,总结出一套最佳实践,指导平台配置管理员、架构师、开发工程师等使用者产生最优使用效果。
3.6.1. 基础设施规划
一般部署两个注册节点即可实现一定程度的高可用能力,如果有更高要求,可部署更多。
多数据中心可部署多套注册节点和计算节点,多活工作。唯有用户节点由用户保证主备机制。
当集群过大时,注册节点的连接和心跳压力较大,建议注册节点单独部署服务器。
3.6.2. 批量任务颗粒度
批量交易往往数量较少、运行时间较长,交易开发人员在规划批量交易时要注意任务的颗粒度不能太小,比如生成多币种报表,不能一个币种一个任务,时间就大量耗费在的调度中,最佳实践建议一般来说人民币按机构拆分任务,外币整合成一个任务,每个任务尽量耗时均等,总处理时间最小化。
3.6.3. 批量图结构设计
调度引擎按有向无环图结构执行阶段中的所有批量,规划图结构(即批量的前序后继关系)时尽量发散链路,不要设计过多的汇合节点,因为汇合节点会约束下级批量开始,影响系统资源充分利用,导致总时间增加。
3.6.4. 监控
阶段、批量、任务表中有开始日期时间和状态等信息,可与监控平台对接,结合历史信息进行基准分析,当某个任务执行时间过长时立即告警,人工介入核查。
4 最后
厉华,主手C,写过性能卓越方便快捷的开源日志库,比肩世界最快的JSON、XML、HTTP开源解析器,占用系统资源极小的开源日志采集器等,自研银行核心联机交易平台、批量交易平台、全组件化配置化的前置框架等,分布式系统实践者,容器技术专研者,目前在杭州银行信息技术部负责基础架构团队。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31562044/viewspace-2643039/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31562044/viewspace-2643039/