sqoop是大数据架构中常用的数据导入导出组件之一,只要简单的设置一些参数就可以将数据库的数据快速导入数据仓库中。
但在实际使用过程中,常常会碰到一些问题,导致从数据库导入到数据仓库发生数据丢失的问题,以下将发生数据丢失的情况分为三种类型:

一、工具使用者使用不善导致的

sqoop数据导入过程为:将mysql数据导入到hdfs文件路径,然后再从该hdfs文件路径load到hive表中。所以需要用户指定hdfs文件路径,如下的${TMP_DIR},此时一定要保证该路径的唯一性。

TMP_DIR=/user/datamining/sqoop_tmp_dir/${MYSQL_TABLE_NAME}_${RANDOM}/${HOUR}
hadoop fs -rm -r -f ${TMP_DIR}

sqoop import --connect jdbc:mysql://${APP_DBHOST}:${APP_DBPORT}/app?serverTimezone=Asia/Shanghai --username ${APP_DB_USER} --password ${APP_DB_PAW} \
        --table ${MYSQL_TABLE_NAME} --hive-import --map-column-java create_time=java.sql.Timestamp\
        --map-column-hive create_time=TIMESTAMP --hive-overwrite --hive-table ${HIVE_DB}.${HIVE_TABLE_NAME}  \
        --hive-drop-import-delims  --outdir ./java  --hive-partition-key hour --hive-partition-value $HOUR \
        --target-dir ${TMP_DIR}  --delete-target-dir

因为在实际的企业数仓中,每日的调度作业往往有上百个sqoop导数作业在同一时间执行,如果两个sqoop导数任务的hdfs路径冲突,数据丢失的情况是很容易发生的。

二、业务逻辑导致的

我们都知道sqoop可以实现mysql表的全量导入,也可以通过mysql表的id或者modify_time来实现增量导入。使用sqoop来做增量导入要慎用,因为这很大程度上都需要业务端的逻辑支持才行。
1、如果业务库mysql表id不是随时间顺序递增或者递减的就无法使用id来实现增量导入;
2、如果mysql表中的modify_time并没有在每次表记录变更的时候都进行更新,那使用modify_time来实现增量导入也会导致数据的丢失。一般在企业真实的生产环境下,业务mysql表记录被变更的入口有很多,哪个大神在写业务逻辑时忘记同时同时更新modify_time这种情况也很难控制,所以最好不要用modify_time来做增量导入
总结一下:
第一,能不用增量导入就不要用增量导入,全量导入不香吗?
第二,如果想实现业务库mysql表的增量导入数据仓库,建议不要使用mysql表本身的字段来实现,最好使用解析数据库的binlog来实现会更靠谱。市场上可用的工具有Canal,不过好像也会丢数据,自己研发一个数据导入的工具也是可以的。

三、原因未知

现象:源表总结近800万数据量,共计切割4个分片,每个分片均约200多万数据量,前面3个分片SQL均可在MySQL的慢查询日志中找到,但最后的一个分片SQL约200万的量,没有在慢查询日志中出现,同时该SQL只返回了1条数据,查询1秒完成;
说明:DBA确认MySQL时间点现场是正常的,主从无延迟。可确认SQL的确被MySQL服务端执行了,同时没有出现在慢查询,说明Sqoop读取到的返回值是正常的。至于为什么只接收了1条数据,现无法确定。
改进:为避免问题再次发生,旧的同步数据任务前后均要加上校验,校验失败后告警并重试,可避免该问题再次出现。详细配置方式后续再补充

四、总结和反思

数据源头丢数据这种事情,除非丢失的数据量很大,导致数仓中的下游表数据出现了很大的波动,不然是很难被发现的。
那在大数据的架构中,丢数据这样是否真的会产生很严重的后果呢?这也是我一直在思考的问题。大数据的优势在于数据量大,其结果所反应的是一种趋势上的东西,而不是需要像传统OLTP数据库那样严格的要求每一条记录的精准性。
如果企业把实际应当放在OLTP的数据需求放到了OLAP的数据仓库中来计算,并进一步要求一个OLAP系统去保证其数据精准性,本身就是一种工具选择的错误。
当然,无论是OLTP还是OLAP,既然是数据的处理计算框架,数据校验自然是不可忽视的。