Wu_Candy

V1

2022/07/26阅读:16主题:默认主题

线上一个隐匿 Bug 的复盘

前言

之前负责的一个项目上线好久了,最近突然爆出一 Bug,最后评估影响范围将 Bug 升级成了故障,只因为影响的数据量有 10000 条左右,对业务方造成了一定的影响。

但因为不涉及到资金损失,Bug 修复后对数据进行修补,所以最终级别也是较低的。

今天和大家分享这个线上隐匿的 Bug,也好在工作的项目中得以借鉴哈~

需求背景

主题:民宿入住回访问卷

描述:

针对入住民宿的顾客,在离店后的当天或第二天内需要给顾客发送本次入住民宿的回访问卷,以此收集顾客入住体验的意见或建议

说明:

因为数据量较大,采用的是 Hive 库存储数据和逻辑加工

问题分析

1.业务逻辑

t2表:存储(昨日+今日此时)离店的顾客清单信息

t3表:存储已发送过回访问卷的顾客清单信息

出现 Bug 的核心业务逻辑如下:

所使用的等值关联字段为:

t2.id = t3.primary_id

t2表中过滤掉t3表中的数据,通过使用t2表作为主表left join子表t3表

然后判断t3.primary_id is null,说明是没有发送过的。

2.问题出现

t2.id字段类型为:string 类型

t3.primary_id字段类型为:bigint 类型

两个不同类型的字段进行等值关联时,当t3.primary_id实际值为超过 16 位的数值时则在 MapReduce 计算过程中将其字段类型由 bigint 类型转换为 double 类型,此时就出现了精度缺失的情况。

例如:

# 此处只是用来举例说明问题,不代表实际真实值
t2.id = 1000110000000000
t3.primary_id = 10001100000000009

如上例子,t3表中已有 primary_id = 10001100000000009的记录发送过回访问卷

此时t3.primary_id = 10001100000000009的值超过 16 位,将其转换成 double 类型时,将其值进行截断后再等值关联

则会出现将t3.primary_id = 1000110000000000(将末尾的9去掉)再与t2表中的id关联

正好关联上已有 primary_id = 10001100000000009的记录,所以认为此条记录不应该再发送回访问卷,直接被过滤掉了

而实际业务中这条记录并不在已发送回访问卷记录表中,只因为精度缺失导致不该关联上的两条记录再被截断后错误的关联上了

结果:导致应该发送回访问卷的顾客,没有被发送

解决方案

1.Bug 解决

当时线上出现这个 Bug 后第一时间的解决方案是: 将等值关联的字段进行类型转换,全部转换成 string 类型后再进行等值关联

使用cast函数进行类型转换,这样可以解决精度缺失的问题

2.漏掉数据处理

将等值关联处修改后的代码逻辑,按照影响的业务数据时间范围,重新执行一次,找出本应该发送回访问卷但因此 Bug 而未发送的顾客清单,发送一次回访问卷。

总结

通过前面的分析,可看出这个线上的 Bug 比较隐匿,如果对隐式转换规则不清楚,则很大可能会出现这方面的问题。

今天给大家分享这个隐式转换的 Bug,希望在今后的工作项目中有类似问题时可借鉴一二。

除了出现 Bug 后的补救措施,在以后的项目中我们能提前做些什么呢?

  1. 一旦出现等值关联,则需要考虑关联字段的字段类型是否一致;
  2. 定义表时,需要结合具体业务情况考虑可能出现的最大值的数据范围;
  3. 不能因为害怕出现此问题,在不加思索的情况下,只要等值关联就使用cast函数进行 string 类型的转换;

分类:

后端

标签:

大数据

作者介绍

Wu_Candy
V1