likes
comments
collection
share

我是如何快速修复线上脏数据的

作者站长头像
站长
· 阅读数 6

背景

经常写代码的同学一定经历过“常在河边走,哪有不时鞋”的痛,上线的代码出现了bug后,最痛的往往不是修复这个bug,而是修复因为这个bug而造成的脏数据,如果这个脏数据是上线时间不长导致的bug还好,如果是长达几个礼拜几个月的脏数据,整个人都会疯掉,之前有同事还因为修复线上脏数据整晚通宵达旦。

修复线上数据长的原因

如果是简单的数据修复,跑一些SQL就行了,但是真实情况往往比较复杂,需要跑脚本跑代码去执行具体的逻辑,如果涉及到一些外部服务的数据回滚,还需要调用外部接口,因此,往往我们都是在沙箱环境部署修复的代码批量跑一下,如果发现有问题再修改部署再跑一下修复的代码。

而在反反复复跑修复代码和部署的过程中,会面临两个问题:

  1. 需要沙箱环境 : 尤其是依赖外部服务的情况,不断修改逻辑和部署花费大量时间。
  2. 需要触发你写的修复代码 : 往往是新写接口修复,要是修复过程中发现还需要修其他数据,还需要另写接口触发。

线上修数大法

如果有一种方式能将本地写完的代码快速热更新到沙箱服务器的内存里,然后直接触发这个代码,效率不就提升数十倍了吗?

说干就干,于是用上了我之前写的热部署插件HotSeconds,可以一键热部署代码到远程沙箱服务器,然后想到了“函数即服务”的模式,于是我在想,一定要写接口触发我的代码吗?我通过本地插件发送一个消息到远程,然后直接触发那个函数不就行了吗?

于是我在HotSeconds插件的基础上开发了一个远程执行函数的功能: 假设有个修复函数是这样的:

public static class FixDirtyData {  
    public String fixData(){  
        UserService userService = SpringBootMain.getApplicationContext().getBean(UserService.class);  
        User user = new User();  
        user.setEmail("111@qq.com");  
        user.setName("Tom");  
        user = userService.updateUser(100L, user);  
        return null == user?"fail":"sueccess";  
    }  
}

写完代码后,我直接通过插件热更新到远程服务器,然后在函数fixData上右键在远程执行这个函数:

我是如何快速修复线上脏数据的

触发后会在远程服务器执行这个函数,并将结果返回到本地控制台。

如果发现代码写的有问题,修改代码,然后一键化热部署到远程服务器,再次执行。

上面是基于写的静态无参数函数实现的,中间需要一些Spring容器或者bean的获取可以自己去维护。

丰富的远程执行函数功能

那么如果是有参数的函数怎么触发呢? 比如有一个函数是

public static String fixData(long id)

这样的函数,同样在函数上右键选择远程执行这个方法,会弹出参数输出框,输入参数即可,如果多个参数用,隔开。

我是如何快速修复线上脏数据的

看到这里或许有人想问,如果是对象形式的参数呢?这个时候输入就比较麻烦,右键选择生成无参调用函数

我是如何快速修复线上脏数据的

然后写调用目标函数的代码,写完热部署后执行这个新函数即可。

如果是非静态的函数是如何触发呢?

两种方案,一种方案就是用上面的无参调用有参的函数,具体是new一个对象还是从Spring中获取看具体需求。

另一种方法就是,在非静态函数上右键选择远程执行函数,这时会弹出这个类所有的对象,选择具体的对象后会触发调用此对象的函数。

快速导出数据

还是用这个远程执行函数功能,写完导出数据的逻辑,执行完后,会将代码返回到本地的控制台,这样对于一些复杂的导出数据也是非常方便的,如果返回结果是对象实体,会序列化成json返回到本地。

我是如何快速修复线上脏数据的

其他妙用

  • 远程执行函数的好处可太多了,有时我想不登录远程服务器查看最后几行日志?该怎么做呢?也是写一个函数,返回最后几行日志的字符串,这样本地控制台就能看到。

  • 有时我想让远程服务器直接gc一下,于是我打开了java.lang.System类,在gc()函数上远程执行这个函数,于是远程服务器就gc了。

更多的妙处都可以自己去挖掘,反正拥有了远程热部署+远程执行函数,几乎是为所欲为了。

查看远程字段值

有时我不禁在想,如何不在Debug的时候获取内存的一些数据值呢?

于是我又基于反射做了查看远程字段值的功能,直接在字段上右键->远程获取值

我是如何快速修复线上脏数据的

这样远程服务器的内存值,会返回到本地的控制台。

查看对象大小

在一个已经实例化的类上面,右键->选择所有对象实例

我是如何快速修复线上脏数据的

这样会展示内存中的所有对象实例和占用大小。

我是如何快速修复线上脏数据的

总结

基于远程热部署+远程执行函数+远程查看字段值,真的可以做到沙箱环境上纲上线无所不能,而且是事半功倍,当别人还在晚上不断写代码修复脏数据到第二天天明的时候,你已经在前一天晚上修完数据回去美美的睡上一觉了。

这个插件是我假期一时兴起开发的,有兴趣的朋友可以下载使用。

github.com/Liubsyy/Hot…