由於工作原因,博客沒進行更新,不過文章的確寫了,就是太懶不想排版,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,這就需要自己來調研了