Flume模擬場景各組件詳解

由於工作原因,博客沒進行更新,不過文章的確寫了,就是太懶不想排版,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連接設置
Sink類型設置 a1.sinks.k1.type = hive  表示hivesinka1.sinks.k1.hive.metastore = thrift://127.0.0.1:9083a1.sinks.k1.hive.database = logsdba1.sinks.k1.hive.table = weblogsa1.sinks.k1.hive.partition = asia,%{country},%y-%m-%d-%H-%M //分區配置
分區配置與表
partitioned by (continent string, country string, time string)
相對應

字段設置
a1.sinks.k1.serializer = DELIMITEDa1.sinks.k1.serializer.delimiter = "\t"a1.sinks.k1.serializer.serdeSeparator = '\t'a1.sinks.k1.serializer.fieldnames =id,msg
通過 串行化 \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,這就需要自己來調研了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章