惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 三国梦回

spring boot 项目中oracle datasource设置schema spring cloud项目中,在bootstrap.yml中指定了active的profile,结果不生效 线上服务重启后,从nacos取不到配置了,怎么回事 nginx location没学好,把自己坑了一把 技术问题记录20260125 最近遇到的两个技术问题记录 linux服务器文件上传失败 线上遇到的redis和数据库数据未同步问题、redisson内部实现问题 复杂业务系统线上问题排查过程 nacos中配了一个数字,springboot取回来怎么变了 一个java空指针异常的解决过程 centos停服,迁移centos7.3系统到新搭建的openEuler 端口telnet不通排查过程 https证书中的subject alternative name字段作用及如何生成含该字段的证书 linux中如何判断一个rpm是手动安装还是通过yum安装的 对接服务升级后仅支持tls1.2,jdk1.7默认使用tls1.0,导致调用失败 网络抓包文件太大,如何切分 分页查询不加排序有问题,加了排序怎么还有问题 利用mybatis拦截器记录sql,辅助我们建立索引(二) 利用mybatis拦截器记录sql,辅助我们建立索引(一) sql server版本太老,java客户端连接失败问题定位
简单记录下最近2个月完成的线上系统迁移工作
三国梦回 · 2025-07-12 · via 博客园 - 三国梦回

背景

我们这边有一个系统,和大多数系统一样吧,涉及后台管理部分、后台管理相关服务、数据库,另外,由于该系统对app提供接口,还涉及app接口服务。这个系统,业务上归属于我们部门,但是目前在线上,是在另一个部门的服务器上运行(这个部门是由于前两年组织架构调整,从我们部门拆分出去成立的),运行也算平稳,但是,这个系统最近突然有个需求要做,新部门这边明确表示需求他们不做,他们不做,就我们做呗。但是,我们开发完,上线又去他们的服务器上上线,流程也比较麻烦,我们这边最后决定是把系统迁回到我们部门的服务器上运行。

这个系统整体迁移完成,大概两个月左右,还是比较麻烦的,大概包括:现状梳理、迁移方案评审、开发验证、测试方案评审、测试验证、运维上线方案评审、运维上线、业务上线。下面简单讲讲。

这个系统,在经过对线上链路的梳理后,也画了架构图,大体来说呢,类似下面这样:

image-20250712141425774

大家可以看到,上图有的是红色,有的是绿色,这个图实际是最终我们这边部署完成后的架构图,对方部门那边得原始架构也差不多(我就偷懒不弄了),毕竟这次任务就是做迁移,相当于把系统涉及的各类组件,都在我们这边部署一遍。当然了,有些组件其实我们已经有了,如后台管理系统、内部路由服务,这两个服务只需要做一些变更就行了,不用新部署;另外的绿色部分组件,就是我们这边没有的,本次需要在我们这边新部署。另外,还有个APP测路由的组件(可以简单理解为业务网关,如spring gateway),这个组件,原本是把app侧的接口转发到对方业务部门的服务,现在是要改一下,转到我们这边的业务服务A来,这样呢,app侧是无感的。

后台管理部分

前端页面的迁移

这个后台管理系统,其实挺有意思,是传统的以前servlet war包部署的架构,不过servlet容器不是tomcat,是resin(以前我也没听过)。不过这个不重要,这个管理系统,是厂商做的,一般来说,厂商把系统卖给我们了,但我们后续想在这个管理系统里加一些菜单、页面、功能,怎么办呢?难道厂商来给我们开发吗,那是不可能的,因为厂商卖给我们的这套系统是没卖源码的,没法改。

那这个系统怎么支持加菜单、页面这些呢?

这个系统做了些功能,支持你新建菜单,点击菜单后一般会渲染一个前端页面对吧,那页面怎么来呢,它就还支持你创建一个前端页面:

image-20250712143101216

页面内容由你自己定义,可以看到,下面就是一些前端标签,但这个标签怎么都带了个前缀啥的,这我也没仔细研究,自然是弄了个前端渲染的引擎,不然浏览器肯定不认识这个html:

image-20250712143321829

然后呢,页面数据从哪里来呢,点击按钮后,又触发什么动作呢。这些都是可以自己定义的,比如上图我框出来的,这个form对应的加载数据的事件就是e_q_important_notice。

那这个事件其实就相当于我们现在的接口了,但是为了保证扩展性,这里支持好几种事件。

image-20250712143654104

这里的bus接口就是类似于现在的rest接口,只是你要指定一个服务名和接口名。

image-20250712143806585

如果是想直接查库,也是支持的,需要指定一个datasource的名字(后台配置了对应datasource的数据库连接信息,ip端口用户名密码啥的):

image-20250712143902882

所以,靠这么一套框架,厂商,既卖了管理系统给我们,代码没泄露,且后续的业务开发还不需要他们投人力。该说不说,10几年搞的这套东西,还是不错的,虽然它不符合现在的时代了(开发页面很不舒服,效率低),但上面有太多的业务功能了,该维护还得维护着。

说回迁移,所以这次,前端的迁移还是比较简单,因为这些页面对应的html代码、事件啥的,都是存储在管理系统的数据库里的,而且页面上支持导出这些html代码、事件,我们只需要把他们在原系统导出,然后在我们这边的系统导入即可。

为什么我们这边可以直接导入呢,导入到哪里呢,因为那时候基于厂商这套框架,搞了2个后台管理系统,1个是给员工相关系统用的(employee),1个是给app那种面向客户的系统用的(customer),两个系统独立演化了好些年,已经大不相同(毕竟厂商不能预判到所有需求,所以之前的开发同事们,在各自负责系统上弄了各种骚操作,后面会提到)。

部门拆分后,当时两个系统都归他们,后来呢,为了部门切割干净,我们把给员工用的那个系统(employee)复刻了一套(假设为employee-own),这次要迁移的功能的前端页面,其实是在customer那一套上面的,也就是从customer导出,然后在employee-own中导入。

数据库迁移

这块其实还是有点麻烦,我们做完迁移方案评审后,接下来就是验证方案的可行性。我先在开发环境做验证,尽量确保各种坑都能踩到。但我们这边的开发环境、测试环境,都没有这个库,然后对方部门呢,由于这个业务也是好几年没需求了,他们的开发、测试环境的库,和目前的线上环境也是差异很大。

为了保证在开发、测试环境的迁移步骤和生产一样,我们就直接是申请从线上数据库整库dump,数据量大概30-40个g左右吧,但问题是里面有不少敏感数据,然后就又发邮件给各路领导,申请导出脱敏的线上库,然后在开发、测试环境进行恢复。

至于线上的话,其实更麻烦一点,因为我们这个库的部分表,是从上游通过数据仓库同步来的,也就是我们依赖人家;另外呢,我们这边产生的一些数据,又需要通过数仓同步给下游,另一些人依赖我们,生产上的迁移,就会涉及到这些同步链路的切换,主要是协调沟通、确保万无一失为主。另外,我们这边,数据库是dba们负责,数据仓库是另外的小组负责,而数仓同步时,需要确保源库、目标库的网络畅通、且需要分配对应的数据库账号(要有对应的权限)。

内部路由服务迁移

这个就比较简单,原部门的路由服务和我们用的路由服务,都是厂商的同一套技术,路由,我们一般就是改下目标服务的ip端口就行了。

业务服务迁移

业务服务,我们这边也是厂商搞的一套,大家简单理解为spring后台接口服务即可。主要就是把原来的服务从对方部门的服务器上dump一份出来,在我们这边服务器上拷贝,然后改改配置,比如数据库配置改一下。

当然,厂商喜欢搞license这一套,dump出来后,在我们机器上发现就运行不了了,说license不对,然后这个玩意都过保了,厂商都不维护了。后来才从一个哥们那边拿到不需要license的版本。

遇到的各种问题

其实整体来看,把这些各种服务弄起来倒是不难,难在各种细节。

确保迁移后文件上传路径不变

在后台管理系统中上传图片等,具体上传到什么地方,都是靠各种配置。然后前端上传时,去查询这些配置。如下,接口就是会返回上传的接口路径、上传的相对路径等。

这里有一个点就是,上传完成后,我们会拿到一个文件的相对路径,存储到数据库中。app侧要展示这些文件时,是查到后端返回的相对路径再去拼接成绝对路径。

在app端不改动的情况下,我们必须确保,迁移后的文件上传路径,在app端是可以访问的,那就需要去梳理这些乱七八糟的配置是怎么玩的,具体就不说了。

image-20250712151859444

富文本编辑器xml转义问题

迁移过来的页面,涉及使用富文本编辑器,ueditor,支持写word这种。

image-20250712152445398

最终呢,数据库里会把这个富文本存储起来:

image-20250712152527158

结果测试同事发现,在app端展示的格式不对,后来一查,是数据库里对那些< 、>这种xml元素做了转义,存储在数据库的就是下面这种:

image-20250712152917661

后来才定位到是后台管理系统的那个厂商框架搞的鬼。如果要想不进行xml转义,要把这些接口对应的字段配成白名单。

image-20250712153320276

ueditor表格不展示边框问题

这个问题折腾了我够呛,就是说,在ueditor里表格有边框,但是app侧看就没有,如下:

image-20250712153542914

刚开始以为是app有问题,后来把数据库里存的html拿出来渲染,一看也没有边框,那就是后端写进去就有问题了。

一开始也以为是后台管理系统的问题,后来通过查看接口参数、抓包等,也排除了,发现就是前端这个ueditor的问题。

但,有个很疑惑的点,目前,app里的展示的那些老的文章,都是有边框的;我们就不知道,老系统(线上正在运行的,对方部门的那个系统:customer)难道没问题,只有我们的复刻的employee-own有问题?

技术架构都是厂商那套,但独立运行了这么多年,有什么差异也很正常,我也找了好久的问题,对前端js进行了一阵子调试(就在页面上F12 debug,还是比较痛苦,前端异步又多,经常就不知道跳哪里去了),对比了两个系统的不少配置,我就感觉,老系统(customer那套)应该也有类似问题。

后来找对方部门的同事配合验证,检查了数据库里写进去的html,发现也是没边框的,所以认定在他们那边确实应该有类似问题。唯一的问题就是,不知道目前在使用这个功能的业务运营人员,到底是怎么绕过这个bug的,然后我们开始去想办法联系业务运营人员,但我们也不知道谁在使用这个功能,就发邮件让人梳理,收到邮件的人又怕漏了担责,就推事,过了好久才联系到使用这块的业务人员。

当时开会时,一听她说的办法,我就明白了,是uedirot提供了一个按钮,对着表格点右键,有一个隐蔽的按钮:设置表格边线可见。 参考:https://www.ymama.net/news/txtlist_i2124v.html

为啥我没发现这个功能呢,首先就是,我刚开始甚至不知道还能右键,一般web系统很少做这种右键操作;其次,这个右键呢,按钮很多,如果屏幕分辨率不高,就看不到(算是一个bug)

image-20250712155026451

我之前的定位思路歪了,因为当时想着,表格要么是在ueditor里插入,要么word里弄好了贴过来。

ueditor里插入表格,我找到了解决方案,就是要改下js源码:

https://blog.csdn.net/qq_33769914/article/details/97612061
修改ueditor.all.js里面的 UE.commands['inserttable']函数

加上下面标红的样式:

style="border:1px solid #ddd;" 

style="border-collapse:collapse;"

image-20250712155316669

但从word里粘贴的话,边框就被ueditor的代码自动去掉了,这块的逻辑死活没弄清楚(个人前端能力不足)。

后来知道业务人员可以绕过后,也就没管了。

ueditor附件上传问题

这个问题是完成上线后才发现的,测试也没测到,刚上线的前几天也没遇到,因为当时业务不需要在ueditor里传附件。

image-20250712155600520

用户说,这块会失败:

image-20250712155641366

然后,其实直到业务反馈的时候,我们才知道,这个富文本编辑器,还能传附件呢。当时时间很紧急,对这块也不理解,运维同事也请假了,然后就协调业务同事先想办法绕过这个问题,比如不传附件。。

后来开始排查,让运维看下管理系统的日志,发现是报主机名无法解析:

image-20250712155804030

这个域名竟然是文件服务器的地址,之前都不知道,管理系统所在的服务器,还会直接访问文件服务器的接口。

通过这个域名,我找到了配置这个地址的地方。然后运维侧,配置了hosts文件后,再试,发现又报:

image-20250712160055301

是https请求时,证书有问题。由于当时急于恢复,让业务能不受影响,我提议改成http访问,我们试了下,http协议对应的端口是通的,那就太好了,不用申请开网络。改成http后,重启服务,这块就解决了。

后来我空余又看了下,这个https问题其实就是:因为后台管理系统是jdk1.7的,而jdk1.7信任的根证书库里,没有digicert global root g2,而文件服务器返回的根证书正好就是g2.

image-20250712160653638

这块只需要把g2导入到根证书信任库中即可。

ueditor附件上传如何实现了自定义

当时我虽然猜测到了附件上传配置:上传url的地方,

image-20250712160910220

但是代码没搞明白怎么走的,如下图这个报错的调用栈,这个FileService的包名就能看出来,是厂商这边的代码,而ueditor是百度出的,这个ueditor是如何被修改成调我们自己的文件服务器接口的呢?

image-20250712161009524

我刚用阿里那个arthas工具,看了下百度那个类的情况(就是调用我们厂商代码的上一层):

image-20250712161324377

发现这个类,竟然不是从jar包里加载的,而是从WEB-INFO/classes目录下加载的,而classes下,一般主要是些配置文件啊。

去看了下,发现下面真有class,甚至还有源码文件。我查看了源码文件后,发现就是这里面修改了百度原来的实现,改成了调我们自己的文件服务器。

image-20250712161557361

为啥要放到WEB-INFO/classes下呢,因为要确保classloader加载这个类时,优先加载。

image-20250712162018541

再一个就是,我之前还以为程序用到是另一处地方(存放ueditor前端js的地方)的ueditor-1.1.2.jar呢,没想到还是WEB-INF下的,看来还是不能乱猜:

image-20250712162232546

而且,上图中的那几个ueditor框架中带的那几个jar包,都全拷贝到了WEB-INF/lib下,但有个包有点怪:

官方ueditor带的是json.jar,而我们这边,不知道为什么是:json-20160212.jar

image-20250712162549196

不知道又是这帮哥们为啥这么弄,我就先不深究了。

两个包内容比了下,不一样,我也找到了这个20160212的包,这里记录下。

https://mvnrepository.com/artifact/org.json/json/20160212

<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20160212</version>
</dependency>

总结

这个事,主要是技术工作和各种沟通协调工作,前前后后两个月,弄完上线,也算是了了一个事,压力小了不少。技术上看着并不困难,就是把服务各种重新部署、已有的服务改一改就完了,但是,中间的任何一个细节漏了,就会导致出现各种问题,不过,细心点,基本还是都能解决,要相信:办法总比困难多,实在不行,还可以绕着走。