一个由硬链接引发的问题

问题背景

最近对于 Fastjson 的破绽又被爆进去了,作为修理工(哦不,业余的软件工程师),又到了咱们表演的时候了。

咱们有很多服务是用的老版本的有破绽的jar包,为了解决这个破绽问题,咱们决定来个移花接木,应用新版本的jar包间接把老版本的有破绽的jar版本间接笼罩掉。哎哎哎,要想程序搞得好,三十六计不可少。

问题景象

既然计划确定了,那就开始干,具体思路如下:

  • 从环境上找出老版本的jar包,而后备份到一个备份门路下,这里备份是为了反对回退的性能。
  • 而后把新版本的jar包拷贝到老版本jar包的门路下。
  • 重启所有的微服务是jar包失效。

代码的逻辑如下图所示:

for 老版本的jar包 in 所有老版本的jar包; do     备份老版本的jar包     将新版本的jar包拷贝笼罩老版本的jar包done

整体思路很简略,然而问题就出在这个备份下面。在理论的测试过程中,发现备份的目录下,jar包的版本大多数都变成新版本的jar包了,而不是老版本的jar包,如下图所示,在 /tmp/home/testuser 下的 fastjson-1.2.70.jar 这个包的 Hash 值实际上和 fastjson-1.2.83.jar 这个包的 Hash 值一样。

最开始始终认为是本人代码逻辑写的有问题,于是一遍一遍的查看。我先把新版本的jar包笼罩老版本的 jar 包这个逻辑去掉,而后计算备份门路下所有的 Hash 值,发现都是老版本的 jar 包,是没有问题的。

然而一旦我把笼罩老版本的 jar 包逻辑加上去,这个备份的 jar 包版本就变了,我反反复复搞了好几次后果都是一样的,真是让我百思不得其解。困扰程序员的两大难题之一在我脑海中产生了,它为啥就跑不起来呢?

既然看不出来,那就只能应用程序员的必杀器了,Debug 一把。我把每次循环执行笼罩操作后,备份目录的下的 jar 的 Hash 值都算了一下,后果发现在执行第二次循环的时候,备份目录的下的 jar 文件就曾经变成了新版本的jar包文件了。

察看到这个景象之后,我就开始思考为啥会呈现这种状况呢?第二个循环的逻辑明明和第一次的逻辑是一样的,为啥后果就变了呢?

当天搞了很久也没有找到起因是啥,脑壳都给我搞昏了。没方法,今天接着搞。第二天早上来,因为通过了一早晨的回血,思路又清晰起来了,感觉本人又行了。

这个时候我想起来,之前有人如同给我说过,咱们的jar包是做的硬链接的。这个让我想到了一个经典的面试题:Linux 的软链接和硬链接的区别是啥?区别是啥来着?嗯嗯……,想不起来了,书到用时方恨少啊,默默的流下了没有常识的泪水。

网上找了一些文章来看,又从电脑屏幕下把压着的《鸟哥的 Linux 私房菜》取出来温习一下。

而后登录到环境上,看了一下环境上老版本的 jar 包,发现的确是做的硬链接。为了演示这个状况,我在我本人的环境上复现了一下这种状况,如下图所示:

软链接和硬链接的区别能够参考网上的材料和书籍,我在这里就不细讲了。针对我以后遇到的这个问题,能够打个不失当的比喻:硬链接就如同你照镜子一样,你做了什么样的扭转,镜子外面的你也会做同样的扭转。如上图所示,当咱们扭转 /home/testuser 目录下的 fastjson-1.2.70.jar 这个文件的内容时,/home/admin 目录下的 fastjson-1.2.70.jar 文件的内容会变得和它一样。

晓得了这个个性,咱们再联合代码来剖析一下:

  • 已知条件:环境上有两个jar包文件: /home/testuser/fastjson-1.2.70.jar/home/admin/fastjson-1.2.70.jar 这两个jar包是硬链接关系
  • 推导:当咱们执行第一次for循环到将新版本的jar包拷贝笼罩老版本的jar包这个步骤时,会把其中一个门路下的jar包版本替换成新版本的jar包了,这个时候相当于/home/testuser/fastjson-1.2.70.jar/home/admin/fastjson-1.2.70.jar 这两个jar包都曾经变成新版本的jar包了;当第二次for循环到备份老版本的jar包时,这个时候备份的是实际上曾经是新版本的jar包了。这个就是为啥第二次当前备份的jar包版本都是新版本的起因了。
for 老版本的jar包 in 所有老版本的jar包; do     备份老版本的jar包     将新版本的jar包拷贝笼罩老版本的jar包done

解决办法

晓得起因了,咱们就思考下面的代码应该怎么改?很显然,备份和拷贝笼罩老版本的jar包这两个动作应该拆分到两个for循环中去实现才行,这样的备份这个for循环外面就会备份的是所有老版本的jar包。如上面的代码所示:

for 老版本的jar包 in 所有老版本的jar包; do     备份老版本的jar包donefor 老版本的jar包 in 所有老版本的jar包; do     将新版本的jar包拷贝笼罩老版本的jar包done

这个问题的解决次要是要了解硬链接的原理。说实话这个常识之前也看过很多遍,每次看的时候都感觉本人懂了,然而真正遇到问题的时候,才发现自己基本就没有懂。

通过这次问题的解决,我想我应该是对硬链接有了肯定的理解。其实在日常的工作中,很多的小问题背地其实都对应的一些知识点的,如果咱们可能把这些小问题搞清楚,其实对咱们真正了解和把握这个常识是有很大帮忙的。好了,明天就到这里了,敌人们,咱们下期再见!