关于“凌晨服务器告警!我被动把性能优化了2000%”这件事~
前言
大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心。
大早上被叫醒!
前几天周末,大早上的时候,太阳才刚出来,我突然被老大电话叫醒了,并通知我速速进入飞书会议,说是服务器发生了警报,出现了严重事故。
进到会议才发现是我们的后端有一个接口,让监控直接红色了。由于这一块代码我比较熟,所以老大让我紧急定位并处理一下这个严重的问题~
定位问题
所以本全干工程师就开始了后端接口的问题定位~
初步定位
首先说说这个接口的背景,这个接口是提供给用户用作导入用的,用户在做导入的时候,有可能导入的数据超级大,所以会不会是因为导入的数据量太大了,所以导致此接口直接崩掉呢?
但是老大查了日志后跟我说,这个用户在以前也导入过这么大的数据量,但是那时候都没啥问题的啊~
所以我觉得这应该不是用户行为造成的,而是什么新功能造成的这个BUG~于是我看了涉及到此接口的最近的提交,发现确实是有一个新功能在最近上线了,是涉及到 json-schema 的
简单认识 json-schema
什么是 json-schema 呢?给大家举个小例子,让大家简单认识一下吧,比如下方的三个属性
- name
- age
- cars
他们都有对应的数据类型,他们需要通过 json-schema 来寻找到自己对应的类型
// jsonschema
const schema = {
name: {
$ref: 1
},
age: {
$ref: 2
},
cars: {
$ref: 3
}
}
// jsonschema合集
const schemaDefination = {
1: {
type: 'string'
},
2: {
type: 'number'
},
3: {
$ref: 4
},
4: {
type: 'array'
}
}
// 得出结果
const result = build(schema, schemaDefination)
console.log(result)
// {
// name: 'string',
// age: 'number',
// cars: 'array'
// }
继续定位问题
回到这个 BUG 上,我继续定位。其实刚刚上面的例子是很简单的例子,但是其实在这个功能里,数据量和负责度远远没这么简单,我们刚刚看到的 schemaDefination 其实就是所有 jsonschema 的引用的结合
// 实际上可能有几百个
const schema1 = {
$ref: 1
}
const schema2 = {
$ref: 2
}
const schema3 = {
$ref: 3
}
const schemaDefination = gen(schema1, schema2, schema3)
console.log(schemaDefination)
// 实际上可能有几百个
// {
// 1: {
// type: 'string'
// },
// 2: {
// type: 'number'
// },
// 3: {
// type: 'array'
// }
// }
也就是一开始会先根据所有 schema 去生成一个引用的集合 schemaDefination,而这个集合可能有几百个,数据量挺大
最终定位
然后到最终的时候 schema 结合 schemaDefination 去生成结果,我感觉就是在这一步导致了 BUG
// 得出结果
// 可能要 build 几百次
const result1 = build(schema1, schemaDefination)
const result2 = build(schema2, schemaDefination)
const result3 = build(schema3, schemaDefination)
为什么我觉得是这一步出问题呢?我们刚刚说了 schemaDefination 是所有 schema 的引用集合,数据量很大,你每次 build 的时候 schema 传的是一个 schema,但是你 schemaDefination 传的是集合!!!
正常来说应该是传 schema 时只需要传对应的 schemaDefination 即可,比如
// 合理的
const result1 = build({
$ref: 1
}, {
1: {
type: 'string'
}
})
// 不合理的
const result1 = build({
$ref: 1
}, {
1: {
type: 'string'
},
2: {
type: 'number'
},
3: {
type: 'array'
}
})
而我们现在就是处于不合理的情况,于是我特地看了 build 这个函数的内部实现,发现有 对象序列化处理 的代码,想一下下面的模拟代码
const obj = { 几百个数据 }
while(i < 300) {
JSON.stringfy(obj)
i++
}
这样的代码会给服务器造成非常大的压力,甚至把接口给搞崩!!!
解决问题,性能提升几百倍!
上面其实我已经分析出问题所在了:传 schema 的时候不要传整个 Defination集合!,所以我们只需要传入所需的 defination, 那么性能是不是可以优化几百倍!!!
解决手段
所以我们只需要写一个函数,过滤出所需要的 defination 即可,例如
// 找出所有被 ref 的数据模型
const filter = (
schema,
schemaDefinitions,
) => {
// 进行过滤操作
}
// jsonschema
const schema = {
name: {
$ref: 1
}
}
// jsonschema合集
const schemaDefination = {
1: {
type: 'string'
},
2: {
type: 'number'
},
3: {
$ref: 4
},
4: {
type: 'array'
}
}
// 过滤
const defination = filter(schema, schemaDefination)
console.log(defination)
//{
// 1: {
// type: 'string'
// },
//}
所以只需要在 build 的时候传入过滤后的 defination 即可!
const result1 = build(schema1, filter(schema1, schemaDefination))
const result2 = build(schema2, filter(schema2, schemaDefination))
const result3 = build(schema3, filter(schema3, schemaDefination))
测试无误,继续睡觉!
然后拿到一份用户的数据,在测试环境测了一下,没有发生之前那个 BUG 了!合并代码!打包上线!继续睡觉!
结语 & 加学习群 & 摸鱼群
我是林三心
- 一个待过小型toG型外包公司、大型外包公司、小公司、潜力型创业公司、大公司的作死型前端选手;
- 一个偏前端的全干工程师;
- 一个不正经的掘金作者;
- 一个逗比的B站up主;
- 一个不帅的小红书博主;
- 一个喜欢打铁的篮球菜鸟;
- 一个喜欢历史的乏味少年;
- 一个喜欢rap的五音不全弱鸡
如果你想一起学习前端,一起摸鱼,一起研究简历优化,一起研究面试进步,一起交流历史音乐篮球rap,可以来俺的摸鱼学习群哈哈,点这个,有7000多名前端小伙伴在等着一起学习哦 --> 摸鱼沸点
来源:juejin.cn/post/7238973821801594935