背景
我们这边有一个系统,和大多数系统一样吧,涉及后台管理部分、后台管理相关服务、数据库,另外,由于该系统对app提供接口,还涉及app接口服务。这个系统,业务上归属于我们部门,但是目前在线上,是在另一个部门的服务器上运行(这个部门是由于前两年组织架构调整,从我们部门拆分出去成立的),运行也算平稳,但是,这个系统最近突然有个需求要做,新部门这边明确表示需求他们不做,他们不做,就我们做呗。但是,我们开发完,上线又去他们的服务器上上线,流程也比较麻烦,我们这边最后决定是把系统迁回到我们部门的服务器上运行。
这个系统整体迁移完成,大概两个月左右,还是比较麻烦的,大概包括:现状梳理、迁移方案评审、开发验证、测试方案评审、测试验证、运维上线方案评审、运维上线、业务上线。下面简单讲讲。
这个系统,在经过对线上链路的梳理后,也画了架构图,大体来说呢,类似下面这样:
大家可以看到,上图有的是红色,有的是绿色,这个图实际是最终我们这边部署完成后的架构图,对方部门那边得原始架构也差不多(我就偷懒不弄了),毕竟这次任务就是做迁移,相当于把系统涉及的各类组件,都在我们这边部署一遍。当然了,有些组件其实我们已经有了,如后台管理系统、内部路由服务,这两个服务只需要做一些变更就行了,不用新部署;另外的绿色部分组件,就是我们这边没有的,本次需要在我们这边新部署。另外,还有个APP测路由的组件(可以简单理解为业务网关,如spring gateway),这个组件,原本是把app侧的接口转发到对方业务部门的服务,现在是要改一下,转到我们这边的业务服务A来,这样呢,app侧是无感的。
后台管理部分
前端页面的迁移
这个后台管理系统,其实挺有意思,是传统的以前servlet war包部署的架构,不过servlet容器不是tomcat,是resin(以前我也没听过)。不过这个不重要,这个管理系统,是厂商做的,一般来说,厂商把系统卖给我们了,但我们后续想在这个管理系统里加一些菜单、页面、功能,怎么办呢?难道厂商来给我们开发吗,那是不可能的,因为厂商卖给我们的这套系统是没卖源码的,没法改。
那这个系统怎么支持加菜单、页面这些呢?
这个系统做了些功能,支持你新建菜单,点击菜单后一般会渲染一个前端页面对吧,那页面怎么来呢,它就还支持你创建一个前端页面:
页面内容由你自己定义,可以看到,下面就是一些前端标签,但这个标签怎么都带了个前缀啥的,这我也没仔细研究,自然是弄了个前端渲染的引擎,不然浏览器肯定不认识这个html:
然后呢,页面数据从哪里来呢,点击按钮后,又触发什么动作呢。这些都是可以自己定义的,比如上图我框出来的,这个form对应的加载数据的事件就是e_q_important_notice。
那这个事件其实就相当于我们现在的接口了,但是为了保证扩展性,这里支持好几种事件。
这里的bus接口就是类似于现在的rest接口,只是你要指定一个服务名和接口名。
如果是想直接查库,也是支持的,需要指定一个datasource的名字(后台配置了对应datasource的数据库连接信息,ip端口用户名密码啥的):
所以,靠这么一套框架,厂商,既卖了管理系统给我们,代码没泄露,且后续的业务开发还不需要他们投人力。该说不说,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端是可以访问的,那就需要去梳理这些乱七八糟的配置是怎么玩的,具体就不说了。
富文本编辑器xml转义问题
迁移过来的页面,涉及使用富文本编辑器,ueditor,支持写word这种。
最终呢,数据库里会把这个富文本存储起来:
结果测试同事发现,在app端展示的格式不对,后来一查,是数据库里对那些< 、>这种xml元素做了转义,存储在数据库的就是下面这种:
后来才定位到是后台管理系统的那个厂商框架搞的鬼。如果要想不进行xml转义,要把这些接口对应的字段配成白名单。
ueditor表格不展示边框问题
这个问题折腾了我够呛,就是说,在ueditor里表格有边框,但是app侧看就没有,如下:
刚开始以为是app有问题,后来把数据库里存的html拿出来渲染,一看也没有边框,那就是后端写进去就有问题了。
一开始也以为是后台管理系统的问题,后来通过查看接口参数、抓包等,也排除了,发现就是前端这个ueditor的问题。
但,有个很疑惑的点,目前,app里的展示的那些老的文章,都是有边框的;我们就不知道,老系统(线上正在运行的,对方部门的那个系统:customer)难道没问题,只有我们的复刻的employee-own有问题?
技术架构都是厂商那套,但独立运行了这么多年,有什么差异也很正常,我也找了好久的问题,对前端js进行了一阵子调试(就在页面上F12 debug,还是比较痛苦,前端异步又多,经常就不知道跳哪里去了),对比了两个系统的不少配置,我就感觉,老系统(customer那套)应该也有类似问题。
后来找对方部门的同事配合验证,检查了数据库里写进去的html,发现也是没边框的,所以认定在他们那边确实应该有类似问题。唯一的问题就是,不知道目前在使用这个功能的业务运营人员,到底是怎么绕过这个bug的,然后我们开始去想办法联系业务运营人员,但我们也不知道谁在使用这个功能,就发邮件让人梳理,收到邮件的人又怕漏了担责,就推事,过了好久才联系到使用这块的业务人员。
当时开会时,一听她说的办法,我就明白了,是uedirot提供了一个按钮,对着表格点右键,有一个隐蔽的按钮:设置表格边线可见。 参考:https://www.ymama.net/news/txtlist_i2124v.html
为啥我没发现这个功能呢,首先就是,我刚开始甚至不知道还能右键,一般web系统很少做这种右键操作;其次,这个右键呢,按钮很多,如果屏幕分辨率不高,就看不到(算是一个bug)
我之前的定位思路歪了,因为当时想着,表格要么是在ueditor里插入,要么word里弄好了贴过来。
ueditor里插入表格,我找到了解决方案,就是要改下js源码:- https://blog.csdn.net/qq_33769914/article/details/97612061
- 修改ueditor.all.js里面的 UE.commands['inserttable']函数
- 加上下面标红的样式:
-
复制代码
但从word里粘贴的话,边框就被ueditor的代码自动去掉了,这块的逻辑死活没弄清楚(个人前端能力不足)。
后来知道业务人员可以绕过后,也就没管了。
ueditor附件上传问题
这个问题是完成上线后才发现的,测试也没测到,刚上线的前几天也没遇到,因为当时业务不需要在ueditor里传附件。
用户说,这块会失败:
然后,其实直到业务反馈的时候,我们才知道,这个富文本编辑器,还能传附件呢。当时时间很紧急,对这块也不理解,运维同事也请假了,然后就协调业务同事先想办法绕过这个问题,比如不传附件。。
后来开始排查,让运维看下管理系统的日志,发现是报主机名无法解析:
这个域名竟然是文件服务器的地址,之前都不知道,管理系统所在的服务器,还会直接访问文件服务器的接口。
通过这个域名,我找到了配置这个地址的地方。然后运维侧,配置了hosts文件后,再试,发现又报:
是https请求时,证书有问题。由于当时急于恢复,让业务能不受影响,我提议改成http访问,我们试了下,http协议对应的端口是通的,那就太好了,不用申请开网络。改成http后,重启服务,这块就解决了。
后来我空余又看了下,这个https问题其实就是:因为后台管理系统是jdk1.7的,而jdk1.7信任的根证书库里,没有digicert global root g2,而文件服务器返回的根证书正好就是g2.
这块只需要把g2导入到根证书信任库中即可。
ueditor附件上传如何实现了自定义
当时我虽然猜测到了附件上传配置:上传url的地方,
但是代码没搞明白怎么走的,如下图这个报错的调用栈,这个FileService的包名就能看出来,是厂商这边的代码,而ueditor是百度出的,这个ueditor是如何被修改成调我们自己的文件服务器接口的呢?
我刚用阿里那个arthas工具,看了下百度那个类的情况(就是调用我们厂商代码的上一层):
发现这个类,竟然不是从jar包里加载的,而是从WEB-INFO/classes目录下加载的,而classes下,一般主要是些配置文件啊。
去看了下,发现下面真有class,甚至还有源码文件。我查看了源码文件后,发现就是这里面修改了百度原来的实现,改成了调我们自己的文件服务器。
为啥要放到WEB-INFO/classes下呢,因为要确保classloader加载这个类时,优先加载。
再一个就是,我之前还以为程序用到是另一处地方(存放ueditor前端js的地方)的ueditor-1.1.2.jar呢,没想到还是WEB-INF下的,看来还是不能乱猜:
而且,上图中的那几个ueditor框架中带的那几个jar包,都全拷贝到了WEB-INF/lib下,但有个包有点怪:
官方ueditor带的是json.jar,而我们这边,不知道为什么是:json-20160212.jar
不知道又是这帮哥们为啥这么弄,我就先不深究了。
两个包内容比了下,不一样,我也找到了这个20160212的包,这里记录下。
https://mvnrepository.com/artifact/org.json/json/20160212- <dependency>
- <groupId>org.json</groupId>
- json</artifactId>
- <version>20160212</version>
- </dependency>
复制代码 总结
这个事,主要是技术工作和各种沟通协调工作,前前后后两个月,弄完上线,也算是了了一个事,压力小了不少。技术上看着并不困难,就是把服务各种重新部署、已有的服务改一改就完了,但是,中间的任何一个细节漏了,就会导致出现各种问题,不过,细心点,基本还是都能解决,要相信:办法总比困难多,实在不行,还可以绕着走。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |