不动产登记中心这种系统,平时没人觉得它有多重要,可一旦到了房产新政发布、学区划分调整、或者年底集中办证那几天,柜台前排起长队,后台的查询和写库压力一下子就上来了。这时候系统要是卡顿个几十秒,办事群众情绪立刻就能点燃整个大厅。更别说遇到系统升级、硬件更换、数据库迁移这种大动作,稍微没处理好,就是“停摆半天、全城抱怨”的事故。
我参与过某地不动产登记系统从传统架构向全栈国产化迁移的全过程,这里说的“全栈”,不是只在某个环节换一两个国产组件,而是从底层芯片、操作系统、数据库、中间件到上层应用框架,一整条技术链路的整体替换。这个项目最核心的目标就八个字:不停顿、不卡顿。今天把我们的设计思路、踩坑经历、还有最终落地的方案完整梳理一遍,希望能给正在做或者准备做国产化迁移的团队一些参考。
1. 项目整体设计与思路拆解
1.1 不动产登记系统的业务特点决定了技术方案
不动产登记系统和其他政务系统有个本质区别:它是强事务、高并发、长链条的业务系统。一笔普通的二手房转移登记,从受理、审核、登簿到缮证,涉及十几个环节,每个环节都要读写数据库,而且这些操作不能出错,错了就意味着产权归属可能出现法律风险。
更棘手的是它的并发特征。平时可能风平浪静,一天几千笔业务,但遇到政策窗口期(比如契税优惠即将截止、学区房政策调整),业务量会在几天内暴涨到平时的5到10倍。这种“平时平稳、峰时暴增”的曲线,对系统的弹性要求极高。
还有一个容易被忽略的点:不动产登记系统是7×12小时在线的政务服务系统,不像电商系统可以半夜停机维护。白天要保证业务办理不中断,晚上又往往留给数据备份和批处理任务。留给系统升级、迁移、重启的窗口时间非常有限,经常只有凌晨两三个小时。这就意味着,迁移方案的设计必须把“停机时间”压缩到极致。
1.2 国产化迁移不是简单的换件,而是整体重构
最开始我们接到任务时,团队内部的直觉是“这不就是把Oracle换成国产数据库、把Windows换成Linux、把x86换成ARM嘛”。但真正梳理完整个技术栈之后发现,事情远没有那么简单。
整个系统的技术栈是这样的:应用层是Java开发的,跑在WebLogic中间件上,数据库用的是Oracle RAC,操作系统是Windows Server,底层是x86服务器。要把这套东西全部换成国产化组件,意味着以下每一项都要变动:
- 芯片从x86换成鲲鹏或海光
- 操作系统从Windows Server换成麒麟或统信UOS
- 数据库从Oracle换成达梦或人大金仓
- 中间件从WebLogic换成东方通TongWeb或宝兰德
- 应用框架需要适配新的JDK版本和中间件规范
这五层同时变动,问题就来了:出了问题你根本不知道是哪一层惹的祸。所以我们在方案设计时立了一个基本原则——分层替换、逐层验证、最后再整体联调。
提示:全栈国产化迁移最容易犯的错就是“一步到位”。所有组件同时切换,出了问题连排查的入口都找不到。我们的经验是宁可慢一点,也要保证每一步的变更都是可控、可回退的。
1.3 为什么把“不停顿、不卡顿”作为第一目标
很多团队做迁移,关注的指标是“功能是否正常、数据是否一致”,但我们项目从立项开始,就把“不停顿、不卡顿”作为第一优先级来考核。原因很现实:
不停顿意味着系统在迁移过程中,尤其是切换数据库和中间件的窗口期,业务不能长时间中断。我们当时的目标是:核心服务切换的停机时间控制在30分钟以内,整个迁移周期内业务中断时间累计不超过2小时。
不卡顿意味着迁移之后,系统性能不能比原来差。我们设了三个硬指标:单笔查询响应时间不超过原来的1.2倍,核心登记业务的平均处理时长不超过原来的1.1倍,峰值并发能力不低于原来的80%。达不到这些指标,迁移就是失败的。
说实话,一开始我们觉得这些指标定得有点苛刻,毕竟底层芯片架构都换了,性能有波动是正常的。但后来发现,正是因为有这些硬性指标,才逼着我们在每一个环节都做了充分的性能优化,而不是简单地把系统搬过去能跑就行。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 全栈国产化技术选型解析
2.1 芯片与服务器选型
芯片是整条技术链路的基石。目前国内主流的服务器芯片主要是鲲鹏、海光和飞腾三家。我们最终选的是鲲鹏920系列,理由有三:
第一,鲲鹏的生态相对成熟,主流国产操作系统和数据库都有适配版本,踩坑的概率会低一些。第二,我们现有的Java应用是纯字节码运行,跨架构迁移的难度本来就比C/C++应用小,换到ARM架构上的成本可控。第三,鲲鹏在多核并发场景下的表现不错,而我们的业务系统正好是典型的OLTP高并发场景。
服务器配置上,我们按照“两地三中心”的思路,核心生产环境部署了8台鲲鹏920(64核/台),分成两个集群,分别跑应用和数据库。测试环境复用了4台,同时承担性能压测和联调任务。
2.2 操作系统与中间件选型
操作系统我们选了银河麒麟V10。选它没有太多悬念,主要原因是适配面广,无论是达梦还是人大金仓,都提供了基于麒麟的安装包和部署文档,省去了很多编译适配的麻烦。
中间件这块是重头戏。我们原来用的是WebLogic,换国产中间件时在东方通TongWeb和宝兰德之间犹豫了很久。最终选东方通,是因为它对Java EE规范的兼容度比较好,而且我们负载均衡、集群配置这些功能,在TongWeb上都有现成的管理界面。
但这里要提醒一句:不同中间件的类加载机制、JSP编译方式、session管理策略都有差异,换中间件不是换一个容器那么简单,应用的部署方式、配置文件格式、日志规范全部要跟着改。我们为此专门列了一个“中间件迁移适配清单”,逐项核对,才没有遗漏。
2.3 数据库选型与迁移策略
数据库是这次迁移中风险最高的环节。我们原来的数据量大概是:核心业务表70多张,总数据量接近4TB,最大的几张表(房产登记信息、权利人信息)都有上亿行。这么大规模的数据迁移,选任何一个国产数据库都意味着大量适配工作。
我们对比了达梦8和人大金仓V8,最终选了达梦。原因有两个:一是达梦对Oracle语法的兼容性做得比较好,我们的存储过程、触发器、包(Package)迁移过去,改动的代码量最少;二是达梦提供了完善的数据迁移工具DTS,可以基于Oracle的导出文件做批量导入,还支持增量同步,这对我们在迁移窗口内保持数据一致性非常关键。
选型定了之后,我们专门做了一次针对性的POC测试,把业务系统里最复杂的20条SQL、10个存储过程、5个触发器原样搬到达梦上跑了一遍,确认兼容性和性能都没有大问题,才正式启动迁移。这个过程不能省,等到生产环境再发现问题,代价就太大了。
3. 核心系统改造与性能优化实践
3.1 数据库迁移:最难啃的骨头
数据迁移是整个项目里耗时最长、坑最多的阶段。我们最终采用的策略是“全量+增量”两步走:
第一步,全量迁移。 利用周末的低峰期,通过达梦DTS工具把Oracle生产库的整体数据导出,再导入到达梦库里。4TB的数据量,导一次大概需要6到8个小时。这个阶段不需要停业务,但要注意导出期间Oracle库的I/O压力会明显上升,建议把导出任务安排在凌晨。
第二步,增量同步。 全量迁移完成之后,Oracle那边还在继续产生新数据。我们用了达梦的增量同步工具,基于Oracle的归档日志做解析,把新增数据实时同步到达梦库。这个阶段要密切监控同步延迟,理论上可以做到秒级,但实际跑起来经常会有几分钟的滞后。
第三步,切换。 选一个工作日的晚上,先停掉外围系统的写操作,等增量同步追平,然后修改应用的数据库连接配置,指向达梦库,整个切换过程我们控制在25分钟左右。切换完成后观察30分钟,确认业务正常,再把写操作打开。
这里有一个非常关键的细节:切换前一定要做“回退演练”。我们当时在测试环境模拟了切换后3小时发现严重问题的场景,验证了如何切回Oracle。虽然最终没有用上,但这个预案让整个团队在真正切换时心里有底。
3.2 SQL适配与优化:国产数据库的“脾气”要摸清楚
从Oracle迁移到达梦,最直接的感受就是:语法兼容性再好,也有一些细节不一样。我们总结了三个最常见的坑:
- 分页查询。Oracle用的是ROWNUM,达梦支持的是LIMIT语法。虽然达梦兼容ROWNUM,但大量使用ROWNUM的复杂查询,性能都一般,建议统一改造成LIMIT写法。
- 隐式类型转换。Oracle里字符串和数字之间可以做隐式转换,但达梦对这类操作比较敏感,容易导致索引失效。排查时发现我们有两张表的关联字段,一个是VARCHAR2,一个是NUMBER,在Oracle里跑了好几年没出问题,到达梦上直接全表扫描。
- 空值排序。Oracle里NULL默认排最后,达梦里NULL默认排最前,这个差异会直接影响列表查询的展示顺序。
SQL适配不是一次性工作。我们当时的做法是:迁移完成后,把生产环境的慢查询日志打开,持续观察了一周,把执行时间超过1秒的SQL全部捞出来,挨个分析执行计划,针对索引和写法做优化。这一轮优化下来,整体查询性能比刚迁移时提升了将近40%。
3.3 应用层改造:中间件切换的适配细节
应用层虽然是Java写的,跨架构迁移并不难,但中间件从WebLogic换到东方通TongWeb,还是有不少适配工作要做:
- JNDI数据源配置。原来WebLogic里配置的数据源,在TongWeb里要重新配置,而且配置项的名称和路径都不一样。
- Session共享方案。WebLogic集群里自带Session复制,TongWeb也支持,但配置方式和性能表现有差异。我们的业务对Session要求不高,最后直接改成了Redis存储Session,顺便解决了集群环境下Session不共享的老问题。
- 日志规范。TongWeb的日志和WebLogic格式不同,我们做了统一的日志采集适配,确保日志能正常接入原有的日志分析平台。
- 类加载冲突。这是最容易出的问题。应用里用了很多第三方库,有些库自带旧版本的类,和中间件自带的版本冲突,启动时报ClassNotFoundException或者NoSuchMethodError。解决方法是调整应用的ClassLoader策略,把应用依赖的库优先加载。
3.4 高性能架构设计:不卡顿的关键手段
应用和数据库都迁移完之后,开始做性能调优。我们主要做了三件事:
引入Redis缓存层。把不动产登记业务里的热点数据——比如房屋基本信息、权利人信息、常用字典项——全部缓存到Redis里。理论上,热点数据的缓存命中率做到85%以上,数据库的查询压力能下降一大截。我们实际跑下来,命中率稳定在88%左右,效果很明显。
优化数据库连接池。国产数据库在连接数比较高的时候,性能下降比Oracle明显。我们把连接池的最大连接数从原来的200调到了150,同时增加了等待队列的长度,配合Redis缓存降低数据库的并发请求数量,整体响应时间反而更稳定了。
读写分离。把不动产登记业务中的查询类请求(比如信息查询、进度查询、权属核验)路由到只读从库,写操作(登记、变更、注销)走主库。这个策略对“高峰查询压垮主库”的场景特别有效。
这套组合拳打完之后,我们的压测数据是这样的:单笔登记业务平均耗时从原来的1.8秒降到了1.4秒,查询类接口的P95响应时间稳定在800毫秒以内,达到了迁移前的水平。
4. 高可用保障与容量规划实战
4.1 系统架构的容灾设计
“不停顿”不是靠祈祷得来的,而是靠架构设计托底。我们的核心生产环境做了双集群部署:一个集群在市中心机房,另一个在郊区灾备机房,两个机房之间通过专线连接,数据库做主备同步。
正常情况下,所有业务流量都打到主集群。如果主集群出现故障(比如机房断电、网络中断、硬件损坏),通过全局负载均衡把流量切到备集群。这个切换过程我们做了预案和演练,目标是在15分钟内完成全量切换。之前说的那次数据库切换,实际上就是利用了这套容灾架构做的一次真实演练。
4.2 峰值流量预估与容量规划
容量规划这块,我们踩过不少坑,最大的教训是:不要用平均峰值来规划容量,要用极端峰值。
不动产登记的业务量分布很不均匀。我们统计过去三年的数据,正常情况下每天业务量大概3000笔,但“5·1”假期后、春节后、学区划分公布后,单日业务量能冲到1.5万到2万笔。而且高峰时段非常集中,上午9:30到11:00、下午2:00到4:00,这两个时段的请求量占了全天的60%以上。
我们的容量规划逻辑是这样的:以峰值时段每秒请求数(QPS)为基准,预留30%的缓冲空间,再乘以1.5的冗余系数,得出系统需要支撑的最大QPS。按照这个算法,业务系统需要支撑的峰值QPS大概是1200左右。基于这个指标,我们把应用服务器从原来的6台扩展到8台,数据库从单实例升级为一主两从,Redis集群从3个节点扩展到6个节点。
4.3 全链路压测:在真正的高峰来临前找到瓶颈
压测是整个项目中绝对不能跳过的一环。我们在迁移完成后、上线前,做了一轮全链路压测,用的是压测工具模拟真实业务请求,从网关到应用、到Redis、到数据库,全链路打满。
压测的结论让我们有点意外:瓶颈竟然不在数据库,而在网关层。我们原来的API网关用的是开源版本的Nginx,配置的worker进程数和连接数都比较保守,压到600 QPS的时候,网关的CPU使用率已经到80%了,再往上压就会丢请求。后来调整了Nginx的worker_processes、worker_connections参数,并且开启了HTTP keepalive,网关的支撑能力直接翻倍。
压测过程中还发现了一个“看起来是小问题、实际影响很大”的bug:有一张业务表的唯一索引在迁移时没有建上,导致并发高的时候出现了几条重复数据。虽然量不大,但处理起来特别麻烦。这个教训让我们养成了一个习惯:迁移完成后,所有索引、约束、触发器必须逐一核对,不能相信迁移工具的报告。
4.4 哨兵监控与快速恢复机制
高可用系统的另一个关键是:发现问题要快,定位问题要准。我们的监控体系分三层:
第一层是基础设施监控,用Prometheus采集CPU、内存、磁盘、网络等指标,重点盯数据库服务器的I/O等待和磁盘使用率。第二层是应用监控,用SkyWalking追踪每个请求的调用链,哪一层慢了、哪一层报错了,一目了然。第三层是业务监控,直接在关键业务节点埋点,统计每分钟的业务处理量、成功率、响应时间,设了阈值告警。
有了监控还不够,快速恢复机制同样重要。我们做了一套自动化的健康检查脚本,每30秒检查一次关键服务的存活状态。如果发现服务挂了,会自动拉起新的实例,同时发送告警到值班群。手动重启这种事,在现在的架构里基本不再需要了。
5. 迁移过程中的踩坑实录与排查技巧
5.1 数据库迁移中最容易忽略的“隐性坑”
迁移过程中,我们遇到过一个非常隐蔽的问题:某张核心业务表在Oracle里是分区表,按登记年份分了12个分区。DTS迁移完成后,自动建表逻辑生成了普通表,而不是分区表。业务跑起来的前两天一切正常,但第三天导入历史数据的时候,这张表直接被锁死了,应用层超时一片。
排查了很久才发现,不是达梦的问题,而是DTS工具在迁移DDL时把分区信息给丢了。从那以后,我们的操作规范里多了一条:迁移完成后,必须把原库的表结构(分区、索引、约束、序列)和新建库逐项核对一遍,不能只核对数据量对得上就认为迁移成功了。
5.2 国产操作系统上的“半兼容”问题
银河麒麟V10底层虽然是Linux内核,但我们在上面部署Java应用时还是遇到了一些“半兼容”问题。最典型的一个是:应用跑了一段时间后,突然报“Too many open files”,但系统层面的文件句柄数限制明明已经调过了。
后来发现,问题出在Tomcat的连接数配置上。默认配置下,Tomcat最大连接数是10000,但我们需要开更多。在Linux上只需要改ulimit就行,但麒麟系统有一个独立的配置文件来限制进程的句柄数。这个配置项藏得很深,不踩一次坑真的找不到。
另一个常见问题是字体。不动产登记系统要生成不动产证书的PDF,PDF模板上用了Windows字体(比如宋体、黑体)。麒麟系统上如果没有安装这些字体,生成的PDF就会乱码或者缺字。这个坑我们是在测试环境发现的,生产上线前在系统里补装了中文字体包,才算解决。
5.3 国产中间件的“活锁”与线程池调优
东方通TongWeb的线程池策略和WebLogic不太一样,默认配置下,最大线程数是200。我们的应用是IO密集型的,大量时间花在数据库查询和Redis访问上,线程数经常被打满,导致新的请求在队列里等待,整体响应时间急剧上升。
排查时发现,应用的线程池监控显示线程数长时间接近最大值,而且WAITING状态的线程占比很高。这说明线程都在等下游服务返回,属于典型的IO等待密集型场景。我们把最大线程数从200调到了400,同时把空闲线程回收时间从60秒降到30秒,问题就缓解了。
这里要提醒的是:线程数不是越大越好。调大线程池会带来更多上下文切换开销,如果到了CPU瓶颈,加线程反而会让性能更差。调优时一定要结合监控数据,观察线程状态和CPU使用率的变化,找到平衡点。
5.4 常见问题速查表
整理了一张我们在迁移过程中遇到的核心问题速查表,供大家参考:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 分页查询响应慢 | ROWNUM用法导致索引失效 | 改写为LIMIT语法,重建分页查询 |
| 定时任务不执行 | 中间件对定时任务线程托管方式不同 | 改用独立的定时任务调度框架,与Web容器解耦 |
| 乱码或PDF缺字 | 操作系统缺少中文字体包 | 安装fonts-chinese以及对应品牌字体 |
| 连接池报错无可用连接 | 连接泄漏或最大连接数过小 | 排查连接池配置,启用连接回收机制 |
| 接口响应时快时慢 | 慢SQL未优化,或缓存命中率低 | 开启慢查询日志,按执行计划逐条优化 |
| 高并发时出现重复数据 | 唯一索引未正确迁移 | 核对所有索引和约束,补齐缺失项 |
| 应用启动缓慢 | 类加载冲突或JVM参数不合理 | 调整ClassLoader策略,优化JVM堆内存配置 |
6. 项目上线后的运维保障与优化建议
6.1 上线切换的完整流程复盘
整个迁移项目从启动到正式上线,我们花了将近四个月,其中前两个月在做技术调研和选型认证,中间一个月在做代码适配和数据迁移,最后一个月做全链路压测和上线演练。真正对外发布的切换窗口,我们选在了某个周末的凌晨,切换过程分了三步:
第一步,凌晨1:00,停止所有外围系统的数据写入,通知各业务部门系统进入维护模式。第二步,1:30,完成数据库增量同步的最终追平,修改应用数据库连接配置,指向达梦。同步调整网关路由,把流量切换到新集群。第三步,2:00,在测试环境验证核心功能正常,开放部分窗口做灰度验证。凌晨4:00,确认无重大问题,全面开放业务。
整个切换过程实际只用了28分钟,远低于最初30分钟的目标。但切换到新环境之后,我们留了两个整天的观察期,期间安排专人盯监控,随时准备启动回退预案。好消息是最终没有用上。
6.2 运行一年后的实际表现
这个系统上线运行已经超过一年,从实际表现来看,当初设定的目标基本都达到了:
- 全年未发生一次计划外停机,系统可用性达到99.95%以上。
- 业务高峰期的平均响应时间保持在迁移前的水平,最忙时单日处理业务量超过16000笔,没有出现明显卡顿。
- 数据库CPU使用率高峰期维持在65%左右,还有可扩展的空间。
当然,这中间不是没有问题。上线早期出现过两次证书打印模板错乱的问题,排查下来都和字体包有关,这让我们意识到:国产化环境下的兼容性问题,往往不是技术架构的大问题,而是这种“细枝末节”最容易翻车。
6.3 给准备做全栈国产化团队的几点建议
根据这一年的项目经验,我总结了几点建议,供即将开始或正在做国产化迁移的团队参考:
第一,先把“为什么国产化”想清楚,再谈“怎么做”。如果只是被要求“替换国产组件”,没有明确业务目标,很容易做成“能跑就行”的搬迁,最后性能、稳定性都打个折扣。我们之所以能把性能做到不降反升,正是因为从立项开始就把“不停顿、不卡顿”立成了硬指标。
第二,一定要留足测试和压测的时间。我们最终的结果看起来顺利,但中间有将近一个月时间是在持续压测、调优、再压测中度过的。没有充分的压测数据,你根本不敢在真实的业务高峰来临前切换。
第三,做好团队的知识储备和心态建设。国产化组件的生态还在完善中,很多问题没有现成的答案,需要靠团队去查源码、翻文档、试配置。我们的经验是:遇到问题不要慌,先确认是不是兼容性问题,再确认是不是配置问题,最后才考虑是不是代码问题,按这个顺序排查,多数问题都能在半天内定位。
第四,永远准备一个回退方案。无论前期的测试做得多充分,生产环境总会有你意想不到的问题。回退方案不是“有没有”的事,而是必须“演练过”的事。我们团队每两周做一次回退演练,虽然花费了不少时间,但给了所有人底气。
这个项目做完之后,团队里最大的变化是:大家对待国产化组件的心态从“忐忑不安”变成了“习以为常”。说到底,技术栈的切换固然有阵痛,但只要方法论对路、准备工作充分,国产化系统完全可以做到和传统架构一样稳定,甚至在某些方面的表现还能更好。希望我们踩过的这些坑、总结出来的这些经验,能让大家在迁移路上少走一些弯路。
