由于工作原因,博客没进行更新,不过文章的确写了,就是太懒不想排版,code21.cn可能不会更新了,服务器费用的确太贵
场景模拟
kafka实时json格式数据解析写入hive
了解Flume
Flume中最重要的概念就是agent,数据流向基本依靠这三个组件
•Source:用来消费(收集)数据源到Channel组件中 数据源
•Channel:中转临时存储,保存所有Source组件信息 数据管道
•Sink:从Channel中读取,读取成功后会删除Channel中的信息 水槽(向目的地发送数据)
官网http://flume.apache.org/FlumeUserGuide.html
从页面左侧Flume sources channels sinks 可以明显的看出flume支持的源管道,及沉入对象。
上面的业务需求则是要沉入hive,也可以看到flume sinks支持的hive sinks
看了一下官网之前的文档,hivesinks是在flume1.6之后才有的。1.5页面挂了不知道有没有
搜了一下网上关于kafka + flume + hive的 业务逻辑,相关资料比较少
Source
在这个业务中sources采用 kafak source,此项配置比较简单。
Channel
管道先暂时忽略。
Sink
在此业务中最重要的模块就是sink了,官网也有hive sink组件。
下面我们来看一下他的参数
Hive表结构
Hive连接设置
分区配置与表
相对应
字段设置
通过 串行化 \t 分割将数据 与fieldnames对应,完成入库
以上是基本的hive sink操作,可以看出配置的确是太简单了。
那么问题来了
我的数据是json数据[{“”:””},{“”:””},{“”:””},{“”:””}]
用普通的分割符貌似解析不出对应的字段,此时引入一个概念,flume 拦截器。
flume 拦截器
Flume过滤器的作用是,将source处的数据进行拦截处理,然后传入管道,在进行sink。
好了,我们来看一下flume的拦截器
JingxiInterceptor就忽略吧,我自己定义的
从源码中我们可以找到他有八种拦截器
我们对拦截器的大体做一个了解,此处从书上做个截图
看完是不是发现还是解决不了我们的问题
我的数据是json,没有json拦截器啊
Flume对我们提供了一个接口Interceptor
我们基于这个接口则可以开发拦截器。(自定义拦截器方法在下面)
通过拦截器我们可以得到我们想要的数据格式进行入库操作。
好了,此时我们入库操作已经完成了,但是回到业务上,我们的kafka源是来自不同设备的数据,多数据格式我们需要根据不同的数据入不同的库。
难道我们要开发多套flume agent吗
此种逻辑完全可以解决业务需求
但是问题来了 拦截器分别在三个不同的agent中
每次都要拦截,相当于一共处理了数据总量乘3的数据
那么这样的资源利用率简直太低了,还不如采用 sparkstreaming 去进行逻辑操作。
Flume又一个概念
Channel选择器
来看一下概念
此时我们可以通过配合拦截器,就能将不同的数据发到不同的管道进行sink增加了资源利用率
此时的业务逻辑就变成了下图:
以上的逻辑就完美解决了实际业务需求
同时flume 还有sink组概念,可以同时开启多个节点实现高可用,此处就不介绍了
自定义拦截器
我们看一下flume提供给我们的接口
public interface Interceptor {
/**
* Any initialization / startup needed by the Interceptor.
*/
public void initialize();
/**
* Interception of a single {@link Event}.
* @param event Event to be intercepted
* @return Original or modified event, or {@code null} if the Event
* is to be dropped (i.e. filtered out).
*/
public Event intercept(Event event);
/**
* Interception of a batch of {@linkplain Event events}.
* @param events Input list of events
* @return Output list of events. The size of output list MUST NOT BE GREATER
* than the size of the input list (i.e. transformation and removal ONLY).
* Also, this method MUST NOT return {@code null}. If all events are dropped,
* then an empty List is returned.
*/
public List<Event> intercept(List<Event> events);
/**
* Perform any closing / shutdown needed by the Interceptor.
*/
public void close();
/** Builder implementations MUST have a no-arg constructor */
public interface Builder extends Configurable {
public Interceptor build();
}
}
我们需要实现的方法就是这两个方法
public Event intercept(Event event);
public List<Event> intercept(List<Event> events);
Flume中数据是以事件的形式传递,而且数据结构也非常简单就是包括了 事件头,与事件体,以字节的形式进行传递
下面是我写的拦截器案例
package cn.code21.demo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.Charsets;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;
import java.util.List;
public class JingxiInterceptor implements Interceptor {
public void initialize() {
System.out.println("接收到数据开始拦截过滤··");
}
public Event intercept(Event event) {
// 接收到json格式数据开始解析,按照字段名称解析完成返回
String inputeBody = null;
String data1 = null;
byte[] outputBoday = null;
try {
inputeBody = new String(event.getBody(), Charsets.UTF_8);
JSONArray data = JSON.parseArray(inputeBody);
for (Object item : data) {
JSONObject itemObj = JSON.parseObject(item.toString());
String name = itemObj.getString("name");
String type = itemObj.getString("type");
String age = itemObj.getString("age");
data1 = new String(name + "\t" + type + "\t" + age);
}
outputBoday = data1.getBytes();
} catch (Exception e) {
System.out.println("输入数据" + event);
}
event.setBody(outputBoday);
return event;
}
public List<Event> intercept(List<Event> events) {
for (Event event : events) {
intercept(event);
}
return events;
}
public void close() {
System.out.println("过滤完成");
}
public static class Builder implements Interceptor.Builder {
public Interceptor build() {
return new JingxiInterceptor();
}
public void configure(Context context) {
// 此处可以获取conf中的参数
}
}
}
代码就不多做介绍了,需要注意的是,如果拦截器能够运行还需要实现一个接口Interceptor.Builder,作为入口
编写完程序就可以进行打包了(注意如果使用第三方依赖,打包的时候一定要将依赖一起打入)
将自己的拦截器 放入flume/lib 目录下,进行conf配置启动flume
效果图:
可以看到只有符合拦截器格式的数据才进行输出,此时就完全可以使用了。
资料参考
Flume官网http://flume.apache.org/FlumeUserGuide.html
《Flume 构建高可用、可扩展的海量日志采集系统》
附加
flume目前还是由于很多公司在使用作为公司的日志收集组件,但是由于flume是运行与JVM的,以及吞吐量并不是很理想,可能会有更优秀的组件来替代flume,这就需要自己来调研了
欢迎扫码进群,期待更优秀的你!