项目场景:
前段时间项目组出现了OOM现象,导致机器重启,部分业务受到影响,这里做一个复盘和总结
问题描述:
原因:由于pda这种扫码枪,扫到一个空的商品条码,而在前端和或者后端接口层都没有做这种为空校验,而查询数据库时用的是“OR”导致没有走索引,而对于商品信息全表扫描,那个商品表的数据量大约为2000w。而那个表是个宽表,大约有100个字段,这些数据加载到内存,达到内存设置的告警线,而导致机器重启。
APP 中接收数据代码:
func (o Object) ScanCode(ctx context.Context, code string) ([]*SKUList, *wmserror.WMSError) {
var skuList []*SKUList
db := getSKUDBInstance(ctx)
db = db.Where("sku_code = ? or upc_code1 = ? or upc_code2 = ? or partner_sku_code = ? or supplier_code = ?", code, code, code, code, code)
err := db.Find(&skuList).GetError()
if err != nil {
return nil, wmserror.NewError(constant.ErrDB, err.Error())
}
return skuList, nil
}
原因分析:
这里当扫到的商品码为空的情况下不会走到索引,会导致全表扫描,这表数据量太大,当这些数据全部加载到内存中后,数据撑爆了内存
解决方案:
底层每个调用数据库层做强校验,把这种空的数据直接不让其去占用网络链接,不去请求数据库。就可以解决。
func (o Object) ScanCode(ctx context.Context, code string) ([]*SKUList, *wmserror.WMSError) {
var skuList []*SKUList
if len(code) == 0 {
return skuList, nil
}
db := getSKUDBInstance(ctx)
db = db.Where("sku_code = ? or upc_code1 = ? or upc_code2 = ? or partner_sku_code = ? or supplier_code = ?", code, code, code, code, code)
err := db.Find(&skuList).GetError()
if err != nil {
return nil, wmserror.NewError(constant.ErrDB, err.Error())
}
return skuList, nil
}
思考:
在开发时我们要做防御性编程,如果你写的业务逻辑受到数据的影响很大,那么接口层一定要做强校验,这样才可以保证不会让数据继续流转下去,一定需要做强校验,带着怀疑的态度去编码,而不是相信别人的接口的态度去编码。