Apache Phoenix Flume集成 -- JsonEventSerializer改进
背景
数据从kafka ingest到Phoenix。数据格式采取Json。数据链路:
api -> kafka -> Flume -> Phoenix
官方JsonEventSerializer的问题
- 
每个table column必须有json字段,如果某个字段json中没有,那么这条记录被丢弃;
例如table中有cola和colb两个列,但是json数据中只有{"cola":1},原生版本会将这个消息丢弃。 - 
数组的问题,json中的数组元素是没有类型的,例如一个小数字会被解析为java的int,如果我们的表中数组元素定义为BITINT,此时会有integer转long类型的exception。
 - 
timestamp不支持unix timestamp格式(long)
 - 
如果数据格式出错会有
SqlException异常抛出,此时会导致Flume sink循环拉取错误的消息并不停地尝试插入数据到Phoenix,但是一直失败,新的数据也无法插入。 
内部原理
- 读取flume的event body (String),利用
JsonObject解析,这里的处理会将json的每个字段强转为String类型; - 如果该json字段对应的table列类型是
isArrayType则将json值(数组)创建成Phoenix Array; - 如果不是数组,则直接将json的值转为对应的
Object upsertValue = pDataType.toObject(jsonValue); - 最后调用Phoenix jdbc API (
PrepareedStatement.excute())将数据插入到Phoenix,这里会有类型判断。 
解决:
- 为null字段调用setNull
 - 把json数组元素逐个转为table中元素的类型
 - 对timestamp类型特殊处理,判断数据格式是不是\d+,如果是,则强转
 
else if (pDataType == PTimestamp.INSTANCE) {
          if (value.matches("\\d+")) { // if it's  a Long value as time stamp
                  upsertValue = pDataType.toObject(Long.parseLong(value), PLong.INSTANCE);
          } else {
                  upsertValue = pDataType.toObject(value);
          }
  }
- 避免抛出
SqlException,只打印错误消息。 
代码修改参见:https://github.com/wlu-mstr/phoenix/tree/4.13-cdh5.11.2

                
            
        
浙公网安备 33010602011771号