flume 1.8.0 開發基礎

qcloud發表於2019-03-01

本文由雲+社群發表

作者:皮皮熊

概述

Apache Flume是一個用於高效地從大量異構資料來源收集、聚合、傳輸到一個集中式資料儲存的分散式、高可靠、高可用的系統。

Apache Flume是Apache基金會的頂級專案。現在有兩個程式碼版本線可以獲取:0.9.x和1.x。本文件對應的是1.x版本。

資料流模型

Event是流經flume agent的最小資料單元。一個Event(由Event介面實現)從source流向channel,再到sink。Event包含了一個payload(byte array)和可選的header(string attributes)。一個flume agent就是一個jvm下的程式:控制著Events從一個外部的源頭到一個外部的目的地。

Source消費著具有特殊格式的Events(這些Event傳遞到Source通過像Web server這樣外在的資料來源)。例如AvroSource可以被用於接收Avro的Events,從本客戶端或者其他執行中的flume客戶端。當一個Source接收到一個Event,它會把它插入到一個或者多個Channel裡。Channel會被動地儲存這些Event直到它們被一個Sink消費到。Flume中一種Channel是FileChannel,其使用檔案系統來作為後端儲存。Sink需要負責任地將一個Event從Channel中移除,並將其放入像hdfs一樣的外部儲存系統(例如HDFSEventSink),或者轉發到傳輸中下一個節點的source中。Source和Sink在agent中非同步地互動Channel中的Event。

可靠性

Event是儲存在Flume agent的Channel裡。Sink的責任就是傳輸Event到下一個agent或者最終的儲存系統(像hdfs)。Sink只有當Event寫入下一個agent的Channel 或者 儲存到最終的系統時才會從channel裡面刪掉Event。這就是Flume如何在單跳訊息傳輸中提供端到端的可靠性。Flume提供了一個事務性的方法來修復可靠傳輸中的Event。Source和Sink包含了Event的儲存和重試(通過由channel提供的事務)。

構建Flume

獲取原始碼

通過git

編譯/測試 Flume

Flume使用maven來build。你可以通過標準的maven命令列來編譯Flume。

  1. 僅編譯:mvn clean compile
  2. 編譯且執行單元測試:mvn clean test
  3. 執行獨立的測試:mvn clean test -Dtest=,,... -DfailIfNoTests=false
  4. 打包:mvn clean install
  5. 打包(忽略單元測試):mvn clean install -DskipTests

注意:Flume build需要在path中有Google Protocol Buffers編譯器。

更新Protocol Buffer版本

File channel依賴Protocol Buffer。當你想更新Protocol Buffer版本時,你需要如下更新使用到Protocol Buffer的data access類:

  1. 本機安裝你想要的PB版本
  2. 更新pom.xml中PB的版本
  3. 生成flume中新的PB data access類:cd flume-ng-channels/flume-file-channel; mvn -P compile-proto clean package -DskipTests
  4. 在所有生成檔案中加上Apache license(如果缺了的話)
  5. rebuild及測試Flume:cd ../..; mvn clean install

開發自定義部分

client

Client在Event產生時運轉,並將他們傳遞到Flume的agent。Client通常執行在應用消費資料的程式空間中。Flume目前支援Avro, log4j, syslog, 以及 Http POST (with a JSON body)方式從外部資料來源傳輸資料。同時ExecSource支援將本地程式的輸出作為Flume的輸入。

可能已有的方案是不夠的。本案例中你可以使用自定義的方法來向flume傳送資料。這裡有兩種方法來實現。第一:寫一個自定義的客戶端來和flume已有的source互動,像AvroSource 或者 SyslogTcpSource。此時Client需要將資料轉換成這些Source能理解的message。另外一個方案:寫一個自定義的Flume Source,通過IPC或者RPC,直接地和已有的client應用通訊(需要將client的資料轉換成Flume的Event)。注意這些儲存在flume agent channel中的事件,必須以Flume Event形式存在。

Client SDK

儘管Flume包含了一系列內建的,用於接收資料的方法(即Source),人們常常想直接地通過flume和自定義的程式進行通訊。Flume SDK 就是這樣一個lib,它可以通過RPC直接地連線到Flume,並且傳送到Flume的資料流。

RPC客戶端介面

一個RPC客戶端介面的實現,包含了支援Flume的RPC方法。使用者的程式可以簡單地呼叫Flume SDK客戶端的append(Event)或者appendBatch(List)介面來傳送資料,而不用考慮訊息互動的細節。使用者可以通過使用諸如SimpleEvent類,或者使用EventBuilder的 靜態helper方法withBody(),便捷地實現直接提供事件介面所需的事件ARG。

Transaction(事務)介面

Transaction介面是Flume可靠性的基礎。所有主要元件(即source,sink和channel)必須使用Flume Transaction。

Transaction在channel的實現中實現。每個source和sink連線到channel時必須要得到一個channnel的物件。Source使用channnelprocessor來管理transaction。sink明確地通過他們配置的channel來管理transaction。儲存一個事件(把他們放入channnel中)或者抽取一個事件(從channnel中取出)在一個啟用的transaction中完成。例如:

Channel ch = new MemoryChannel();
Transaction txn = ch.getTransaction();
txn.begin();
try {
  // This try clause includes whatever Channel operations you want to do

  Event eventToStage = EventBuilder.withBody("Hello Flume!",
                       Charset.forName("UTF-8"));
  ch.put(eventToStage);
  // Event takenEvent = ch.take();
  // ...
  txn.commit();
} catch (Throwable t) {
  txn.rollback();

  // Log exception, handle individual exceptions as needed

  // re-throw all Errors
  if (t instanceof Error) {
    throw (Error)t;
  }
} finally {
  txn.close();
}

在這裡,我們從channel獲取transaction。在begin()返回後,Transaction現在處於活動/開啟狀態,然後將Event放入Channel中。如果put成功,則提交併關閉Transaction。

Sink

Sink的目的就是從Channel中提取事件並將其轉發到傳輸中的下一個Flume Agent或將它們儲存在外部儲存庫中。根據Flume屬性檔案中的配置,接收器只與一個通道關聯。每個已配置的Sink都有一個SinkRunner例項,當Flume框架呼叫SinkRunner.start()時,會建立一個新執行緒來驅動Sink(使用SinkRunner.PollingRunner作為執行緒的Runnable),該執行緒管理Sink的生命週期。Sink需要實現start()和stop()方法作為LifecycleAware介面的一部分。

  • Sink.start()方法應初始化Sink並將其置於可將事件轉發到其下一個目標的狀態。
  • Sink.process()應該執行從Channel提取Event並轉發它的核心處理過程。
  • Sink.stop()方法應該進行必要的清理(例如釋放資源)。

Sink實現還需要實現Configurable介面來處理自己的配置設定。例如:

public class MySink extends AbstractSink implements Configurable {
  private String myProp;

  @Override
  public void configure(Context context) {
    String myProp = context.getString("myProp", "defaultValue");

    // Process the myProp value (e.g. validation)

    // Store myProp for later retrieval by process() method
    this.myProp = myProp;
  }

  @Override
  public void start() {
    // Initialize the connection to the external repository (e.g. HDFS) that
    // this Sink will forward Events to ..
  }

  @Override
  public void stop () {
    // Disconnect from the external respository and do any
    // additional cleanup (e.g. releasing resources or nulling-out
    // field values) ..
  }

  @Override
  public Status process() throws EventDeliveryException {
    Status status = null;

    // Start transaction
    Channel ch = getChannel();
    Transaction txn = ch.getTransaction();
    txn.begin();
    try {
      // This try clause includes whatever Channel operations you want to do

      Event event = ch.take();

      // Send the Event to the external repository.
      // storeSomeData(e);

      txn.commit();
      status = Status.READY;
    } catch (Throwable t) {
      txn.rollback();

      // Log exception, handle individual exceptions as needed

      status = Status.BACKOFF;

      // re-throw all Errors
      if (t instanceof Error) {
        throw (Error)t;
      }
    }
    return status;
  }
}

Source

Source的目的是從外部客戶端接收資料並將其儲存到已配置的Channels中。Source可以獲取其自己的ChannelProcessor的例項來處理在Channel本地事務中提交的序列事件。在exception的情況下,需要Channels傳播異常,則所有Channels將回滾其事務,但先前在其他Channel上處理的事件將保持提交。

與SinkRunner.PollingRunner Runnable類似,有一個PollingRunner Runnable,它在Flume框架呼叫PollableSourceRunner.start()時建立的執行緒上執行。每個配置的PollableSource都與自己執行PollingRunner的執行緒相關聯。該執行緒管理PollableSource的生命週期,例如啟動和停止。

  • PollableSource必須實現LifecycleAware介面中宣告的start()和stop()方法。
  • PollableSource的執行器呼叫Source的process()方法。 process()方法應檢查新資料並將其作為Flume事件儲存到Channel中。

注意,實際上有兩種型別的Source:已經提到過PollableSource,另一個是EventDrivenSource。與PollableSource不同,EventDrivenSource必須有自己的回撥機制,捕獲新資料並將其儲存到Channel中。EventDrivenSources並不像PollableSources那樣由它們自己的執行緒驅動。下面是一個自定義PollableSource的示例:

public class MySource extends AbstractSource implements Configurable, PollableSource {
  private String myProp;

  @Override
  public void configure(Context context) {
    String myProp = context.getString("myProp", "defaultValue");

    // Process the myProp value (e.g. validation, convert to another type, ...)

    // Store myProp for later retrieval by process() method
    this.myProp = myProp;
  }

  @Override
  public void start() {
    // Initialize the connection to the external client
  }

  @Override
  public void stop () {
    // Disconnect from external client and do any additional cleanup
    // (e.g. releasing resources or nulling-out field values) ..
  }

  @Override
  public Status process() throws EventDeliveryException {
    Status status = null;

    try {
      // This try clause includes whatever Channel/Event operations you want to do

      // Receive new data
      Event e = getSomeData();

      // Store the Event into this Source's associated Channel(s)
      getChannelProcessor().processEvent(e);

      status = Status.READY;
    } catch (Throwable t) {
      // Log exception, handle individual exceptions as needed

      status = Status.BACKOFF;

      // re-throw all Errors
      if (t instanceof Error) {
        throw (Error)t;
      }
    } finally {
      txn.close();
    }
    return status;
  }
}

參考自(Flume 1.8.0 Developer Guide)

flume 1.8.0 文件完整翻譯可見 https://blog.csdn.net/u013128262

此文已由騰訊雲+社群在各渠道釋出

獲取更多新鮮技術乾貨,可以關注我們騰訊雲技術社群-雲加社群官方號及知乎機構號

相關文章