简介:一份聚焦金融行业核心业务系统云化升级的演示文稿,面向保险/金融IT架构师、云平台规划者及运维团队。内容以传统金融公司技术陈旧(JDK 1.4.2)、批处理性能差、扩展困难等真实痛点为切入,系统说明新一代核心系统的建设目标与云平台分层设计,涵盖公有云、私有云、混合云多部署模式及IaaS、PaaS、SaaS服务模式。PaaS层包括流程管理、规则管理、内容管理、用户管理、批处理平台等模块,并重点展示批处理平台基于ZooKeeper实现分布式并行计算、动态节点管理和故障自动转移的改造实例,也涉及多租户数据、性能与安全隔离设计。资源包共1个pptx文件,大小2.58MB,约含项目简介、云平台架构、实现实例、总结四类内容,已有91人学习浏览。通过这份讲解,读者能快速理解云架构在核心系统转型中的技术选型、改造方式与资源复用思路,对后续规划本企业系统上云有直接参考价值。
1. 上云不是换台虚拟机:把金融核心系统改造成云架构,值不值
这份资源讲的是一家中小型寿险公司(农行控股)怎么从 JDK 1.4.2、JSP+Servlet 的老系统,走到支撑未来十年业务的云架构。公司业务每年增长 50%,目标 1000 亿保费、2 万用户、1000 万客户,老系统却频繁宕机、批处理慢、新软件集不进来。典型传统金融机构的困境:资源有限、保守安全、遗留系统一大堆。方案没有选择推倒重来,而是在私有云为主的基础上,把 IaaS、PaaS 一层层落地,其中批处理平台被改造成支持多租户的 Batch PaaS,这个实例尤其有参考价值。适合正在做系统云化选型的架构师和开发负责人,也适合想知道批处理、多租户到底怎么落地的从业者。
2. 云平台选型与整体设计:既有资产不丢,PaaS 为核心
2.1 部署模式与服务模式:为什么私有云是主战场
先说部署模式。方案里明确写了三种:公有云、私有云、混合云,排在中间的是私有云,混合云写入远期规划。单独看这三个词不新鲜,但结合这家公司的情况,这个排序是经过考量的。传统金融公司不是不想用公有云,而是业务数据合规、核心账务不能放在第三方机房,这在保险行业尤其严格。私有云意味着把 VMware 这类虚拟化或容器底座装到自己机房,业务数据不出门;公有云放在外围系统或者弹性明显的场景;混合云则是最理想但复杂度最高的远期目标。
服务模式上,方案把 SaaS 放在上层、PaaS 放中间、IaaS 在下层,但真正花篇幅讲的是 PaaS。原因不难理解:IaaS 只是把物理机或虚拟机做成池子,解决了资源“能分”的问题,没有解决“应用上线快不快”的问题。对开发团队来说更痛的是权限、批处理、报表、规则这些通用能力被反复建设。所以这个项目把 PaaS 作为核心,列出了 10 个 PaaS 组件、3 个 IaaS 组件,SaaS 待规划。从投入角度说,IaaS 是基础购置成本,PaaS 才是提升生产力和上线速度的关键,SaaS 在金融保险领域还不成熟,先不做。
提示:云架构选型时不要先谈技术,先把部署边界、服务边界定了。私有云为主、公有云为辅、混合云远期,这是传统金融比较稳的路径。
2.2 PaaS 十大组件:哪些买、哪些自建、哪些外包
资源里给了一张很实在的清单。PaaS 层由这 10 个组件组成:流程管理 IBM BPM、规则管理 IBM ODM、内容管理 ECM、监控平台 MONITA、分布式事务管理 DTX、用户管理 UM、批处理平台 Batch、报表平台 Report、渠道接入平台 CIPS、产品工厂 PF。实施模式上分三类:商业产品购买、自主设计自建、外包开发。我按自己的理解重新归类一下:
| 组件 | 类别 | 状态 | 选型逻辑 |
|---|---|---|---|
| IBM BPM | 商业产品购买 | 完成 | 流程编排成熟,避免自研工作流引擎 |
| IBM ODM | 商业产品购买 | 完成 | 规则引擎标准能力强,保险规则变化多 |
| ECM/MONITA/DTX/UM/Report/CIPS | 自建 | 实施中 | 业务耦合深,需要贴身定制 |
| Batch 批处理 | 自建 | 完成 | 要深度接入虚拟化和 ZooKeeper,外购难满足 |
| PF 产品工厂 | 自建 | 完成 | 保险产品工厂必须按自身产品线建模 |
买与自建的边界就在这:成熟通用、团队没精力长期维护的东西优先买;业务规则、内部数据、要跟虚拟化深度打交道的场景优先自建。IBM BPM 和 ODM 放到现在看可能有点贵,但当年选它们确实能降低交付风险。还有一个实施模式是外包开发,方案里提到用了但没说是哪一块。以我的经验,外包适合页面和报表这类外围功能,核心批处理和多租户逻辑外包很难做明白。
2.3 一条反常识的约束:利用遗留系统、已购资产和现有人员知识
这套设计里最不“技术流”的反而是它的约束。方案三次强调:“充分利用遗留应用系统”“充分利用已购买软硬件资产”“充分利用现有人员的知识技能”。听起来像凑数,其实这三条决定了整个项目形态。
先说“充分利用遗留应用系统”。老系统是 JDK 1.4.2,JSP+Servlet,很多新软件集成不进来。但业务规则、账务计算、批处理逻辑这些代码里有大量验证过的算法和公式,推倒重写的风险远远大于保留。常见的做法是把遗留系统拆成服务,外层用新框架适配,内部业务逻辑尽量保留,而不是非要在新项目里复刻一遍。再说“已购软硬件资产”:VMware、Oracle 12C、Weblogic 12C,这些是已经花过钱的东西,新核心系统继续用,不搞无意义的换新。最后“现有人员能力”:团队熟悉的是老 Java、JSP、存储过程,让他们一步跨到微服务加容器,项目大概率会烂尾。方案设计了五个基本概念的学习曲线,就指向这个现实。
为什么要强调这三条?因为大量云化改造项目死在“推倒重来”上。自以为老系统一无是处,三个月后发现光迁移数据就干了半年,预算超了几倍。这个项目把“不能用新技术”也当成一种机会:不追求技术最前沿,只追求几年后还能维护。
再往下,方案提到保险行业最易变的五个要素:渠道、产品、规则、流程、销管基本法。云平台要做的是把这五类变化尽量用配置或平台手段承接,让 80% 的应用开发建立在基础模块之上。我看到实现路径是 6 个公共基础模块:用户权限、批处理、报表、内容、日志监控、事务管理。把这 6 块做成 PaaS,应用层就不用重复造轮子了,上线速度自然会快。
3. 实例拆解:批处理平台从分布式计算到 Batch PaaS 的改造路径
3.1 原批处理平台的三个硬伤
这个比传统 IT 系统的痛处更典型。原平台处理分红批处理、满期批处理这种大批量数据任务是全散弹式的:用户的批处理会自动分配到所有服务器执行,结果大家都在抢资源;数据库访问由批处理程序自行设定,程序里写死连接串,想连哪个库连哪个库;所有用户都能查看和管理所有的批处理实例,一点隔离都没有。三件事分别对应性能隔离缺失、数据隔离缺失、安全隔离缺失。
改造后的 Batch PaaS 目标很明确:
- 用户只能查看和管理自己的批处理,解决安全隔离
- 用户的批处理自动分配到自己的服务器执行,解决性能隔离
- 用户只能访问自己的数据库,解决数据隔离
- 支持虚拟机动态分配、数据库动态分配、中间件动态分配
其中后两项在建设范围内的完成度不同,这一点后面细说。
3.2 分布式并行计算模型:Job、Task、Executor、SharedResourceHolder
分布式批处理首先要有一套任务模型。资源里把一次并行计算任务叫 Job,Job 会被拆分成多份并行执行的 Task,每一份 Task 对应的执行逻辑叫 Executor。既要控制并发又要避免一处出错全盘重来,所以还有一个 SharedResourceHolder 负责共享资源,比如数据库连接池、缓存连接池、Spring 上下文这类所有 Task 都要用的东西。
整个批处理平台由 Distributor 负责调度拆分,Executor 做执行。员工学这套模型只需要掌握五个基本概念,实际开发时实现其中 3 个子类即可:继承 Job 实现拆分逻辑、实现 Executor 接口执行 Task、扩展 SharedResourceHolder 的公共资源初始化逻辑。
我按自己的工程习惯理解了一下,大概是这样的伪代码:
// 1. 定义一个分红批处理 Job public class DividendBatchJob extends AbstractJob { @Override protected List<Task> split(TaskContext ctx) { // 按主键区间拆成 128 份,每份一个 Task List<Task> tasks = new ArrayList<>(); Range range = ctx.getDataRange(); long step = range.getSize() / 128 + 1; for (long i = range.getStart(); i <= range.getEnd(); i += step) { tasks.add(new DividendTask(i, Math.min(i + step - 1, range.getEnd()))); } return tasks; } }这个示例里,split 是 Job 需要实现的核心方法,它不负责具体计算,只决定把任务切成多少片。数量怎么定?我一般不会直接写 128 死值,而是结合 Executor 所在节点数来定,每个节点分 4 到 8 个 Task 比较均衡;切太少并行度不够,切太多调度开销和重复连接数据库反而拖慢整体。
再看 Executor 和 SharedResourceHolder:
// 2. Executor:真正执行 Task 的逻辑 public class DividendTaskExecutor implements TaskExecutor { @Override public ExecuteResult execute(Task task, SharedResourceHolder resources) { DataSource ds = resources.getDataSource("core_db"); // 按 task 携带的区间范围执行对应的数据更新 SQL return ExecuteResult.success(); } } // 3. SharedResourceHolder:封装公共资源初始化 public class CoreSharedResourceHolder implements SharedResourceHolder { @Override public void initialize() { initDataSourcePool(); // 初始化主库连接池 initRedisCachePool(); // 初始化缓存连接池 initSpringContext(); // 初始化 Spring 容器 } }这一段是大多数开发真正要写的东西。SharedResourceHolder 要保证在某个节点上只被初始化一次,多租户环境还要根据租户选择不同的数据源。常见做法是节点启动时从 ZooKeeper 拉取租户与数据源的映射关系,再按映射初始化连接池。初始化失败执行器直接退出,不让任务在坏环境下反复重试。
3.3 无单点故障、动态节点增减与自动故障转移
资源里提到批处理平台具备三个运行期能力:无单点故障、支持节点动态增减、自动故障转移。这三个能力是分布式批处理和传统定时任务最大的区别。
无单点故障要求调度器不能挂,常见做法是多节点部署 Distributor,用 ZooKeeper 做选主。动态增减节点要求新节点能自动注册进集群,旧节点可以随时下线,不用改配置,批处理自动在存活节点上重新分配。自动故障转移则要能在任务执行到一半时,由调度器重新把未完成的 Task 指派给其他 Executor。
这三件事落在 ZooKeeper 上就是典型的临时节点和 Watcher 机制。我贴一个常见的注册脚本:
#!/bin/bash # 新节点启动后向 ZooKeeper 注册临时 znode IP=$(hostname -I | awk '{print $1}') ZK="zk1:2181,zk2:2181,zk3:2181" # 节点路径带上租户标签,方便按租户调度 NODE_PATH="/batchpaas/nodes/${TENANT_ID}_${IP}" # 创建临时节点,线程存活时节点存在,进程退出后节点自动消失 /opt/zookeeper/bin/zkCli.sh -server "$ZK" create -e "$NODE_PATH" "$IP"临时节点的含义是:进程活着,节点就在;进程一断,节点自动消失,调度器马上知道有 Executor 下线。新建节点后要再触发一次任务重分配,把新 Executor 纳入调度范围。注意这里我用的是 zkCli.sh 做演示,生产上应该用 Curator 之类的客户端封装。
3.4 为什么是 Java Only:平台约束也是一种保护
方案在批处理平台后面标注了“Java Only”,这既是约束也是策略。选型时如果团队技术栈是 Java,那就全部走 Java,道理很简单:二次开发基于合作厂商产品,厂商的 Executor 接口、SharedResourceHolder 都要给 Java 版本;团队本身也只熟悉 Java。如果要让批处理节点同时支持 Python 脚本,意味着节点要维护两套运行时,调度器要维护两种 Executor,运维排查问题时要叠加两种定位方式,复杂度直接翻倍。Java Only 不是为了排他,是把维护成本锁在可控范围内。
4. 多租户与动态分配:Batch PaaS 真正做成云的关键细节
4.1 多租户不是加字段:数据、性能、安全三层隔离
这个项目用了一整页讲多租户,而且反复强调“不只是加一个区分租户的字段”,它要解决的是三个隔离问题:
| 隔离类型 | 原系统问题 | 改造后方案 |
|---|---|---|
| 数据隔离 | 用户能访问别人的数据库 | 每个租户绑定自己的数据源,程序无权随意连接 |
| 性能隔离 | 批处理任务互相抢服务器 | 任务只调度到租户名下的节点池 |
| 安全隔离 | 用户能看到别人的批处理实例 | 所有查询和管理接口强制按当前租户过滤 |
数据隔离最简单也最容易做歪。很多团队实现方式是在业务表加一个 tenant_id 字段,查询时 where tenant_id=当前用户,这样一套库一套表确实能骗过多数人,但数据库层面根本没隔离:一个租户的烂 SQL 可能拖垮整个库。这个平台的方案更彻底:用户只能访问自己的数据库,也就是说批处理运行时能用的数据源与该租户绑定的库强相关。用户申请了哪个库,Executor 初始化时就用哪个数据源。这样隔离从连接池开始就分开了,数据库层面的互相影响也随之消失。
性能隔离的核心是调度策略。常见做法是给每个租户分配独立的计算节点组,任务调度时不走全局随便分,而是先找该租户名下的节点,再在这些节点上做并行拆分。这样某租户发起的重任务再重,也只影响自己名下的节点;分配出去的节点数量可以做成配额,避免一个租户占掉整个集群的多数资源。
安全隔离有更隐蔽的坑:批处理平台改造前,登录系统管理页面的用户能看到所有节点的 Job 列表,甚至能操作其他部门的批处理。改多租户时如果只改了数据库字段,界面上最容易漏掉的就是“我的批处理”和“所有批处理”的权限边界。所以资源里明确把“用户能够查看和管理自己的批处理”当作新系统能力写了出来,不做成全局列表。
4.2 动态分配流程:申请、审批、VMware 接口到授权回收
动态分配是批处理平台做得最像 PaaS 的部分。从设计看它的运行流程是这样的:
- 用户(租户)发起计算节点申请
- 虚拟化管理员审批
- 系统自动调用 VMware 接口按需创建虚拟机
- 批处理管理员授权给该用户使用
- 用户的 Job 即可使用这些计算节点跑批处理
这个流程看起来简单,但每一步都涉及一个角色和一个后台动作。没有配额管理就会有租户无限申请节点;审批和授权分开,是为了避免“能创建虚拟机的人”和“能调度到该节点的人”是同一拨人,产生越权风险。我一般会在这个流程里加一个关键动作:授权的同时把节点注册进 ZooKeeper,并标注租户属性,否则虚拟机能创建出来但批处理调度器根本不知道它存在。
补充一段模拟的接口调用逻辑:
# 创建虚拟机并注册到批处理平台 def create_compute_node(tenant_id, cpu, mem): vm_id = vmware.create_vm(vm_template="batch-executor-template", cpu=cpu, mem=mem, tenant=tenant_id) # 虚机启动后执行初始化脚本 vmware.wait_for_guest_ip(vm_id) exec_id = zk.register_node("/batchpaas/nodes/" + tenant_id + "_" + vm_id) # 给租户增加节点配额,才能被调度 um_service.grant_node(tenant_id, exec_id, expire_days=30) return vm_id这里有几个点要留意。vm_template 是预设好的 Executor 镜像,里面预装了 JDK 和 Executor 应用,新创建的节点起来后只要向 ZooKeeper 注册,再用租户的共享资源初始化逻辑启动连接池即可。grant_node 相当于把刚刚生成的节点和某个租户做绑定关系,即使物理上这个节点属于公共资源池,请求进来了也只能被该租户调度。expire_days 这种过期机制很关键,否则那些申请完不再用的资源永远收不回来。
这个代码是我基于常见做法写的,原资源没有给出具体接口名,但它能说明整条链路的落点。凡是没想清 VMware、ZooKeeper、用户管理三者衔接的项目,动态分配大多卡在“虚拟机创建好了但租户用不了”这一环。
4.3 未完成模块的诚实清单:数据库和中间件动态分配为什么难
资源里有一个细节我觉得比整篇吹捧都有价值——它明确标记出动态分配里哪几块没做完。原文写的是:虚拟机动态分配完成;数据库动态分配未完成;中间件动态分配未完成。这不是失败,反而是这套方案可信度高的地方。我也确实在不少项目里见过类似的收尾方式。
数据库动态分配难在哪?难点不在“创建一个数据库实例”,而在租户绑定。连接池要能在运行时动态创建、销毁和切换;数据迁移怎么办;新旧库切换的窗口怎么处理;运维时如何保证每个租户的连接池参数一致。中间件动态分配同理:Weblogic 集群、JVM 内存、Classloader 这些都是动态创建后要初始化状态的,比虚机难度又上一个台阶。
更重要的是业务风险。批处理跑出结果已经上线了,数据库动态分配意味着账务数据可能在新库旧库之间漂移,这直接触碰审计红线。稳妥的方案是把计算节点动态分配先落地,数据库和中间件维持相对静态的拓扑,等虚拟机资源池稳定运行半年后,再逐步推库层动态化。这个决策顺序其实是相当聪明的。
5. 踩坑与排查:批处理 PaaS 改造中值得记住的五个坑
5.1 多租户=加一个 tenant_id 字段?
现象:改造后的系统上线第一周,A 部门看到 B 部门的批处理实例,甚至能强行停止对方一个跑了一半的任务。 原因:表结构确实加了 tenant_id,但查询列表的 SQL 只对主表做了过滤,关联子表、缓存、以及管理端的全局列表全部露出了所有租户数据。本质是把多租户当成了查询过滤器,而不是数据访问边界。 解决:所有的数据库访问强制走数据访问层,由框架统一注入租户条件,不允许 SQL 手写租户判断;管理端列表的所有查询改为先过“我能看哪些租户”的权限判断,再做数据查询。从那以后,凡是要改数据层代码,都要做一次租户穿透测试。
5.2 动态创建的节点,租户却迟迟用不上
现象:虚拟机管理员的审批通过了,VMware 也创建了好几个 Executor 节点,但用户跑批处理时,调度器始终找不到这些新节点,任务还是排队。 原因:新节点启动后没有注册到 ZooKeeper 调度器;或者注册了,但节点路径上没带租户标识,调度器无法判断该节点该分给谁。 解决:把“创建 VM→启动初始化→注册节点→绑定租户→授权”拆成一个完整流水线,而不是让虚机管理员手动点创建再手动配。建议写成一个自动化脚本,在 VM 创建完成后立刻执行注册和授权步骤;ZooKeeper 节点路径用租户 ID 作为前缀。
5.3 ZooKeeper 集群脑裂导致同一个 Task 被执行两次
现象:某个节点网络闪断,故障转移把 Task 丢给另一个 Executor 执行,但最后发现原节点又恢复了,两个节点同时处理同一个 Task,分红批处理重复计算了两次。 原因:故障转移机制处理不严,旧节点没有强制停止,新节点已经开始执行,系统中也没有幂等控制。网络抖动触发的脑裂让两个节点都以为自己是任务的新归属者。 解决:执行前在 ZooKeeper 创建一个带租户和 JobID 的临时顺序节点,多个 Executor 竞争创建,只有一个能拿到锁;执行结果写入前再查一次全局的 job_execution_log 唯一键做幂等校验,重复提交的任务直接丢弃。
5.4 预设“管理节点不是瓶颈”,任务暴增时被打脸
现象:平台运行稳定时管理节点 CPU 长期在 5% 以下,于是团队认定管理节点不用扩容。业务高峰期任务数翻到几千个,管理节点 CPU 干到 90%,Job 提交超时,ZooKeeper 频繁报连接数超限。 原因:管理节点平时确实清闲,但它连接的是 ZooKeeper 和数据库,又承担调度决策,任务量上来后频繁的会话心跳和 Job 元数据读写会把资源吃满。单机部署更是加重了这个局面。 解决:管理节点按 2 主 2 备部署,把 Job 元数据从数据库挪到 Redis 分片;按租户做调度器分区,某一租户的任务爆炸不会影响整个集群的调度;对提交的任务做批量拉取而不是逐条走 ZooKeeper。
5.5 计算节点扩了,数据库被压垮
现象:给租户动态加了 20 个虚机,批处理确实跑得更快了,但过了两天数据库连接池满了,主库的锁等待飙高,其他在线业务也跟着变慢。 原因:计算节点扩容了,数据库还在原地。一个批处理节点默认初始化 20 个连接,20 个节点就多出 400 个连接,数据库连接池上限没跟着调;任务并发抬上去后数据库锁竞争加剧,又没有做资源上限管治。 解决:动态扩容永远把数据库连接池配额一起算,别只做计算节点扩容;给每个 Executor 限制最大连接数;单租户的总连接数也要做上限,防止一个租户把数据库拉垮。资源里说数据库动态分配未完成,其实真正的原因就在这——补上了计算节点能力,数据库管理能力没跟上,你还是没得到真正的弹性。
6. 验证与进阶:怎么证明这套 PaaS 真的撑得住
6.1 四个维度的验收框架
改造完成后,我一般会从四个维度去验证,不只看技术指标,还要看业务团队是不是真的愿意用。
| 维度 | 验证方法 | 核心指标 |
|---|---|---|
| 上线速度 | 拿一个新险种需求走完整链路 | 从需求到上线的时间对比 |
| 稳定性 | 连续跑 7 天批处理,观察故障转移 | Job 失败率、任务重试时长 |
| 隔离性 | 两个租户同时发起大量批处理 | 互相影响延迟、资源争抢情况 |
| 资源效率 | 动态节点申请到回收的完整周期 | 平均审批时长、节余资源比例 |
上线速度是最直观的。老系统加一个新险种,规则、批处理、报表、权限全要开发;新平台上产品工厂和规则引擎已经把大部分逻辑配置化,批处理只需要改 Executor 里的业务段,上线周期能压掉一多半。稳定性靠故障演练,我习惯每周主动杀掉一个 Executor 节点,观察调度器能不能在几分钟内把 Task 重新派出去,而不是等真故障来了再学。
隔离性验证最容易被忽略。真正要测的是两个租户同时提交大规模任务时,一方任务积压会不会让对方的核心分红批处理也跟着变慢。资源效率要关注授权回收:如果申请了一堆节点跑完就晾着,那动态分配就成了变相浪费。可以从 ZooKeeper 节点列表里查出 30 天以上没有任务调度的节点,强制回收,把资源退回公共池。
6.2 后续演进:从人工审批走向配额自助,再走向全链路自动化
这套云架构就目前的状态还留下两个明显的改进空间。一个是资源申请还是走审批流程,高峰期会变成瓶颈。远期可以把人工审批改成配额制:每租户有额定配比,不超过配额直接自取,超出配额走审批。另一个是全链路自动化,把虚机创建、节点注册、授权、数据源绑定、任务发布串成一条流水线,开发提交代码后自动完成部署和注册,这已经是云原生要解决的事,但脱离这批基础的地基谈云原生都是空话。
从那以后,我每次做完云平台改造,都会把“已完成/未完成”的清单挂在项目墙上,不遮掩半途而废的模块。未完成不是失败,可能只是决策顺序的一部分。希望这份拆解能帮到你,也祝你的批处理平台改造少踩几个坑。
本文还有配套的精品资源,点击获取