数据质量监控
数据质量监控用于检测数据仓库的数据量,数据范围等是否在正常范围内,是否出现了异常的数据,如果出现异常的数据需要告警,并提醒开发人员。主要目标是产生可靠的数据,提升数据在使用中的价值。
数据质量评价指标
数据质量的目标是改善,如何评估改善的结果呢,通常包括以下内容。
评价标准 | 描述 | 监控项 |
---|---|---|
唯一性 | 指主键保持唯一 | 字段唯一性检查 |
完整性 | 主要包括记录缺失和字段值缺失等方面 | 字段枚举值检查 字段记录数检查 |
精确性 | 数据生成的正确性,数据在整个链路流转的正确性 | 波动阈值检查 |
合法性 | 主要包括格式、类型、阈值的合法性 | 字段日期格式检查 字段长度检查 字段值域检查 |
时效性 | 主要包括数据处理的时效性 | 批处理是否按时完成 |
上边的描述不直观,如下记忆常用的5个评价标准。
id列:重复值、空值,其他相关列:值域检查,行:数据总量同比、环比增长。
功能分块
数据统计模块:使用shell脚本,统计数据仓库中的指标,然后插入mysql数据库
可视化模块:使用superset读取myslq数据库,可视化告警结果。
告警模块:使用python读取mysql的数据,判断是否需要告警,并发送邮件。
调度模块:使用azkaban监控数仓清洗任务状态,如果有新的清洗任务,就执行 数据统计模块 和 告警模块,检测数据质量。
数据统计模块
列一个表,确定要统计那些表的那些评价指标,例如统计order表的id是否空值,id是否重复等。
参数解析
# 在每个脚本头部加入,便于解析参数
while getopts "t:d:c:s:x:l:" arg; do
case $arg in
# 要处理的表名
t)
TABLE=$OPTARG
;;
# 日期
d)
DT=$OPTARG
;;
# 要计算空值的列名
c)
COL=$OPTARG
;;
# 空值指标下限
s)
MIN=$OPTARG
;;
# 空值指标上限
x)
MAX=$OPTARG
;;
# 告警级别
l)
LEVEL=$OPTARG
;;
?)
echo "unkonw argument"
exit 1
;;
esac
done
空值检查
vim null_id.sh
# 空值个数
RESULT=$($HIVE_ENGINE -e "set hive.cli.print.header=false;select count(1) from $HIVE_DB.$TABLE where dt='$DT' and $COL is null;")
#结果插入MySQL
mysql -h"$mysql_host" -u"$mysql_user" -p"$mysql_passwd" \
-e"INSERT INTO $mysql_DB.$mysql_tbl VALUES('$DT', '$TABLE', '$COL', $RESULT, $MIN, $MAX, $LEVEL)
ON DUPLICATE KEY UPDATE \`value\`=$RESULT, value_min=$MIN, value_max=$MAX, notification_level=$LEVEL;"
重复值检查
vim duplicate.sh
#重复id检查脚本,使用hive -e执行sql语句查询有多少值发生了重复,先使用having过滤出所有发生重复的行记录,再统计共有多少重复记录。
RESULT=$($HIVE_ENGINE -e "set hive.cli.print.header=false;select count(1) from (select $COL from $HIVE_DB.$TABLE where dt='$DT' group by $COL having count($COL)>1) t1;")
# 然后使用mysql -e 执行mysql语句,插入统计结果到mysql。
# 包括监控的database,table,col,日期,统计结果,最小值,最大值,警告等级。
mysql -h"$mysql_host" -u"$mysql_user" -p"$mysql_passwd" \
-e"INSERT INTO $mysql_DB.$mysql_tbl VALUES('$DT', '$TABLE', '$COL', $RESULT, $MIN, $MAX, $LEVEL)
ON DUPLICATE KEY UPDATE \`value\`=$RESULT, value_min=$MIN, value_max=$MAX, notification_level=$LEVEL;"
值域检查
vim range.sh
# 查询不在规定值域的值的个数
RESULT=$($HIVE_ENGINE -e "set hive.cli.print.header=false;select count(1) from $HIVE_DB.$TABLE where dt='$DT' and $COL not between $RANGE_MIN and $RANGE_MAX;")
# 将结果写入MySQL
mysql -h"$mysql_host" -u"$mysql_user" -p"$mysql_passwd" \
-e"INSERT INTO $mysql_DB.$mysql_tbl VALUES('$DT', '$TABLE', '$COL', $RESULT, $RANGE_MIN, $RANGE_MAX, $MIN, $MAX, $LEVEL)
ON DUPLICATE KEY UPDATE \`value\`=$RESULT, range_min=$RANGE_MIN, range_max=$RANGE_MAX, value_min=$MIN, value_max=$MAX, notification_level=$LEVEL;"
数据量环比检查脚本
vim day_on_day.sh
# 昨日数据量
YESTERDAY=$($HIVE_ENGINE -e "set hive.cli.print.header=false; select count(1) from $HIVE_DB.$TABLE where dt=date_add('$DT',-1);")
# 今日数据量
TODAY=$($HIVE_ENGINE -e "set hive.cli.print.header=false;select count(1) from $HIVE_DB.$TABLE where dt='$DT';")
# 计算环比增长值
if [ "$YESTERDAY" -ne 0 ]; then
RESULT=$(awk "BEGIN{print ($TODAY-$YESTERDAY)/$YESTERDAY*100}")
else
RESULT=10000
fi
# 将结果写入MySQL表格
mysql -h"$mysql_host" -u"$mysql_user" -p"$mysql_passwd" \
-e"INSERT INTO $mysql_DB.$mysql_tbl VALUES('$DT', '$TABLE', $RESULT, $MIN, $MAX, $LEVEL)
ON DUPLICATE KEY UPDATE \`value\`=$RESULT, value_min=$MIN, value_max=$MAX, notification_level=$LEVEL;"
数据量同比检查脚本
同比是指当前日期,与上一周期的这一天相比变化了多少。环比是指当前周期内,今天比昨天变化了多少。
vim week_on_week.sh
# 上周数据量
LASTWEEK=$($HIVE_ENGINE -e "set hive.cli.print.header=false;select count(1) from $HIVE_DB.$TABLE where dt=date_add('$DT',-7);")
# 本周数据量
THISWEEK=$($HIVE_ENGINE -e "set hive.cli.print.header=false;select count(1) from $HIVE_DB.$TABLE where dt='$DT';")
# 计算增长
if [ $LASTWEEK -ne 0 ]; then
RESULT=$(awk "BEGIN{print ($THISWEEK-$LASTWEEK)/$LASTWEEK*100}")
else
RESULT=10000
fi
# 将结果写入MySQL
mysql -h"$mysql_host" -u"$mysql_user" -p"$mysql_passwd" \
-e"INSERT INTO $mysql_DB.$mysql_tbl VALUES('$DT', '$TABLE', $RESULT, $MIN, $MAX, $LEVEL)
ON DUPLICATE KEY UPDATE \`value\`=$RESULT, value_min=$MIN, value_max=$MAX, notification_level=$LEVEL;"
编写好检查shell脚本后,对需要的表执行shell即可,如下表示检查表ods_order_info的环比数据
一般来说,ods层是源数据,需要检查环比数据量,同比数据量,值域范围等。dwd和dim层是经过清洗的数据,需要保证某些列值的唯一性和非空。
#检查表 ods_order_info 数据量日环比增长
#参数: -t 表名
# -d 日期
# -s 环比增长下限
# -x 环比增长上限
# -l 告警级别
bash day_on_day.sh -t ods_order_info -d "$DT" -s -10 -x 10 -l 1
告警模块
读取mysql并判断是否发送
读取mysql数据如果大于告警级别,则调用邮件发送警告信息。
告警邮件发送
首先需要注册一个126邮箱,然后在设置中开启smtp服务。
编写代码,调用smtp发送邮件。
def mail_alert(line):
"""
使用电子邮件的方式发送告警信息
:param line: 一个等待通知的异常记录,{'notification_level': 1, 'value_min': 0, 'value': 7, 'col': u'id', 'tbl': u'dim_user_info', 'dt': datetime.date(2021, 7, 16), 'value_max': 5}
"""
# smtp协议发送邮件的必要设置
mail_host = "smtp.126.com"
mail_user = "********@126.com"
mail_pass = "********"
# 告警内容
message = ["".join(["表格", str(line["tbl"]), "数据异常."]),
"".join(
[
"指标", str(line["norm"]), "值为", str(line["value"]),
", 应为", str(line["value_min"]), "-", str(line["value_max"]),
", 参考信息:" + str(line["col"]) if line.get("col") else ""
]
)
]
# 告警邮件,发件人
sender = mail_user
# 告警邮件,收件人
receivers = [mail_user]
# 将邮件内容转为html格式
mail_content = MIMEText("".join(["<html>", "<br>".join(message), "</html>"]), "html", "utf-8")
mail_content["from"] = sender
mail_content["to"] = receivers[0]
mail_content["Subject"] = Header(message[0], "utf-8")
# 使用smtplib发送邮件
smtp = smtplib.SMTP_SSL(mail_host)
smtp.connect(mail_host, port=465)
smtp.login(mail_user, mail_pass)
content_as_string = mail_content.as_string()
smtp.sendmail(sender, receivers, content_as_string)
可视化模块
由于统计数据已经存入了mysql,所以可以借助superset可视化数据质量监控的结果,查看统计数据,如饼状图,柱状图等。
整体调度
流程为 统计模块(数仓各层),告警模块
nodes:
- name: check_ods
type: command
config:
command: /usr/bin/bash check_ods.py $(dt)
- name: check_dwd
type: command
config:
command: /usr/bin/bash check_dwd.py $(dt)
- name: check_dim
type: command
config:
command: /usr/bin/bash check_dim.py $(dt)
- name: check_notification
type: command
dependsOn:
- check_ods
- check_dwd
- check_dim
config:
command: /usr/bin/python3 check_notification.py $(dt)