读取hdfs上snappy压缩文件并发送kafka的两种方式速度测试

最近有一个需求,因为第一次做,踩了许多坑,故在此记录一下

需求背景:
现在hdfs上有一份snappy压缩的文件,要把这份文件中的数据读出来并发送给kafka

解决思路
平时我90%的时间都是在消费kafka,现在要写入kafka,我承认我第一反应是懵逼的;不过这并难不倒天资聪慧的我,我首先想到的就是用spark去读出数据后,直接发送给kafka;so easy~

问题记录
Ⅰ、解析json问题
我用spark很快的就写好了代码,大概如下:

val rdd = spark.read.schema(schema).format("json").load(s"/log/*.snappy").toJSON.repartition(120).rdd

因为原始数据是json结构的,所以我这里用了dataframe的一个toJSON方法,一切看上去都如此美妙,
但是随后消费端就抛出了异常,仔细查看后,我发现了这样的问题:
我希望得到的json:

> {
>     "code":200,
>     "createTime":"1593190799975",
>     "logId":"5715d85d-2b07-425e-97cb-607c2f731d46",
>     "logTime":1593190799972,
>     "recordData":{
>         "recordMsg":"success"
>    	}
>     }

但是通过我用toJSON方法得出来的josn是这样的:

{
    "logId":"5715d85d-2b07-425e-97cb-607c2f731d46",
    "logTime":1593190799972,
    "code":200,
    "createTime":"1593190799975",
    "environment":"prod",
    "recordData":"{"recordMsg":"success"}"
}

可以发现
用了toJSON方法确实解析了外层的json,但是json里的json就被解析成了字符串
所以面对这样的josn结构,我们必须要读出内层的json字符串,重新转换成json结构:

	val dataStr = JSON.parseObject(jsonStr)
    val dataJson = JSON.parseObject(dataStr.getString("recordData"))
    dataStr.put("recordData",dataJson)
    val json = dataStr.toJSONString

此问题得以解决

Ⅱ、spark读snappy分区问题
解决了问题Ⅰ,我以为就大功告成了,信心满满的告诉同事,问题已经搞定,我调了100个分区,三分钟就能把数据全部发过去。
结果现实再一次打击了我,我发现10分钟过去了,任务丝毫没有跑完的迹象,我打开webui一看,竟然只有2个task在跑?我明明设置了100个啊,后来通过查阅文档才知道:
snappy压缩文件是没办法多task并发去读的,也就是task数=你要读的文件下的snappy文件数
那这样的话,面对4g左右的snappy文件,都跑完要15~20min,这样也太慢了,必须要找新的方法了。

改进方案
既然这样,那我就考虑直接把snappy文件重定向到本地,用java写kafka的producer直接去生产消息
例如:

  KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(props);

    File file = new File("");
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new FileReader(file));
        String tempString = null;
        int line = 1;
        //一次读入一行,直到读入null为文件结束
        while ((tempString = reader.readLine()) != null) {
            ProducerRecord<String, String> data = new ProducerRecord<String, String>("", tempString);
                kafkaProducer.send(data);
                line++;
        }
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e1) {
            }
        }
    }
    kafkaProducer.close();

对比结果:
本次snappy文件大小为:4.67g
解压缩后为:12.8g
数据量总共:29553273条
用spark读并发送kafka:16min
用java producer单机(32核128g内存)运行:3min(此方法需把snappy重定向到本地转为log格式)
我们发现,因为spark不能指定多分区去读snappy文件,所以性能处理远不如java单机去跑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值