Flink的Apache Kafka連接器

這個連接器提供了對由Apache Kafka提供的事件流的訪問。

Flink 提供了特殊的Kafka Connectors來從Kafka topic中讀取數據或者將數據寫入到Kafkatopic中,Flink的Kafka Consumer與Flink的檢查點機制相結合,提供exactly-once處理語義。為了做到這一點,Flink并不完全依賴于Kafka的consumer組的offset跟蹤,而是在自己的內部去跟蹤和檢查。

請根據你自己的使用情況和環境來選擇一個包和類名,對于大部分用戶,FlinkKafkaConsumer08(flink-connector-kafka的一部分)是最合適的。

Maven Dependency Supported since Consumer and Producer Class name Kafka version Notes
flink-connector-kafka-0.8_2.10 1.0.0 FlinkKafkaConsumer08 FlinkKafkaProducer08 0.8.x Uses the SimpleConsumer API of Kafka internally. Offsets are committed to ZK by Flink.
flink-connector-kafka-0.9_2.10 1.0.0 FlinkKafkaConsumer09 FlinkKafkaProducer09 0.9.x Uses the new Consumer API Kafka.
flink-connector-kafka-0.10_2.10 1.2.0 FlinkKafkaConsumer010 FlinkKafkaProducer010 0.10.x This connector supports Kafka messages with timestamps both for producing and consuming.

然后,在你的工程中導入connector

<dependency>
  <groupId>org.apache.flink</groupId>
  <artifactId>flink-connector-kafka-0.8_2.10</artifactId>
  <version>1.3.0</version>
</dependency>

注意,目前streaming的connectors還不是Flink二進制發布包的一部分,請參考此處來了解在集群執行中與它們連接在一起。

安裝Apache Kafka

·按照Kafka 的快速入門說明,來下載代碼和啟動服務(每次啟動一個應用前都需要啟動一個Zookeeper和一個kafka服務)
·如果Kafka和Zookeeper服務運行在一個遠程服務器上,那么config/server.properties中的advertised.host.name配置必須要設置成那臺服務器的IP地址。

Kafka Consumer

Flink的kafka consumer叫做FlinkKafkaConsumer08(對于Kafka 0.9.0.X來說是09 等),它提供了對一個或者多個Kafka topic的訪問。
FlinkKafkaConsumer08、09等的構造函數接收以下參數:
  1、topic名稱或者名稱列表
  2、反序列化來自kafka的數據的DeserializationSchema/KeyedDeserializationSchema
  3、Kafka consumer的一些配置,下面的配置是必需的:
     "bootstrap.servers"(以逗號分隔的Kafka brokers列表)
     "zookeeper.connect"(以逗號分隔的Zookeeper 服務器列表)
     "group.id"(consumer組的id)

例如:
Java 代碼:

Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "test");
DataStream<String> stream = env
  .addSource(new FlinkKafkaConsumer08<>("topic", new SimpleStringSchema(), properties));

Scala 代碼:

val properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "test");
stream = env
    .addSource(new FlinkKafkaConsumer08[String]("topic", new SimpleStringSchema(), properties))
    .print

當前FlinkKafkaConsumer的實現會建立一個到Kafka客戶端的連接來查詢topic的列表和分區。

為此,consumer需要能夠訪問到從提交Job任務的服務器到Flink服務器的consumer,如果你在客戶端遇到任何Kafka Consumer的問題,你都可以在客戶端日志中看到關于請求失敗的日志。(這段翻譯得不太好,待我查看完源碼后再重新翻譯)

反序列化模式 DeserializationSchema

Flink的Kafka Consumer需要知道如何將Kafka中的二進制轉換成Java或者Scala的對象,而DeserializationSchema則是允許用戶來指定這樣一個模式,T deserialize(byte[] message)方法被每個kafka消息調用,并傳入kafka的值。

AbstractDeserializationSchema開始是非常有用的,它描述了Java/Scala類型的產生到Flink的類型系統。用戶實現基本的DeserializationSchema的話,需要自己去實現getProducedType(...)方法。

為了獲取Kafka消息中的key和value,KeyedDeserializationSchema需要有下面這個反序列化方法 T deserialize(byte[] messageKey, byte[] message, String topic, int partition, long offset)
為了方便起見,Flink提供了下面的模式:
  1、TypeInformationSerializationSchema(以及TypeInformationKeyValueSerializationSchema) ,這個是以Flink的TypeInfoSchema為基礎創建的,如果數據的讀寫都是由Flink來做的話,這是非常有用的,這種Schema是高性能的Flink具體的替代其他通用序列化方法的方法。
  2、JsonDeserializationSchema(以及JSONKeyValueDeserializationSchema),它能夠將序列化的JSON轉換成ObjectNode對象,在這個對象中字段可以通過調用objectNode.get("field").as(Int/String/...)()來獲取。keyValue類型的ObjectNode包含一個"key"和一個包含所有字段的"value",同時還有可選的用來展示這些消息的offset/partition/topic的"metadata"字段。

當遇到損壞的消息,無法被序列化時,這里有兩個選擇,要么在deserialize(...)方法中拋出一個異常,這會導致作業失敗和重啟,要么返回一個null值,來允許Flink Kafka consumer默默地跳過這些錯誤消息。值得注意的是,由于consumer的容錯性(見下面的詳細部分),在處理損壞數據時失敗的Job會讓consumer再次嘗試反序列化損壞的消息。因此,如果反序列化任然失敗,那么consumer將陷入不斷的失敗重啟中。

Kafka Consumer 開始位置配置

Flink Kafka Consumer允許配置Kafka分區的開始位置是如何確定的。
例如:
Java 代碼:

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

FlinkKafkaConsumer08<String> myConsumer = new FlinkKafkaConsumer08<>(...);
myConsumer.setStartFromEarliest();     // start from the earliest record possible
myConsumer.setStartFromLatest();       // start from the latest record
myConsumer.setStartFromGroupOffsets(); // the default behaviour

DataStream<String> stream = env.addSource(myConsumer);
...

Scala 代碼:

val env = StreamExecutionEnvironment.getExecutionEnvironment()

val myConsumer = new FlinkKafkaConsumer08[String](...)
myConsumer.setStartFromEarliest()      // start from the earliest record possible
myConsumer.setStartFromLatest()        // start from the latest record
myConsumer.setStartFromGroupOffsets()  // the default behaviour

val stream = env.addSource(myConsumer)
...

所有版本的Flink Kafka Consumer都有下面的切確配置方法來配置開始位置。
  setStartFromGroupOffsets(默認的行為):從consumer 分組(在consumer中group.id的配置項)提交到Kafka broker(Kafka 0.8是Zookeeper)的偏移位置開始讀取分區。如果分區中沒有偏移位置,那么會采用auto.offset.reset的配置信息。
  setStartFromEarliest() /setStartFromLatest():從最早的或者最近的記錄開始,在這種模式下,在Kafka中commit的偏移位置將會被忽略并且不會再用作開始位置。

你也可以指定一個確切的偏移位置,Kafka Consumer必須從這個位置開始讀取每個分區的信息,代碼如下:
Java 代碼:

Map<KafkaTopicPartition, Long> specificStartOffsets = new HashMap<>();
specificStartOffsets.put(new KafkaTopicPartition("myTopic", 0), 23L);
specificStartOffsets.put(new KafkaTopicPartition("myTopic", 1), 31L);
specificStartOffsets.put(new KafkaTopicPartition("myTopic", 2), 43L);

myConsumer.setStartFromSpecificOffsets(specificStartOffsets);

Scala 代碼:

val specificStartOffsets = new java.util.HashMap[KafkaTopicPartition, java.lang.Long]()
specificStartOffsets.put(new KafkaTopicPartition("myTopic", 0), 23L)
specificStartOffsets.put(new KafkaTopicPartition("myTopic", 1), 31L)
specificStartOffsets.put(new KafkaTopicPartition("myTopic", 2), 43L)

myConsumer.setStartFromSpecificOffsets(specificStartOffsets)

上面的例子中配置了consumer從myTopic的分區0,1,2的指定偏移位置開始,這個偏移位置必須是讀取每個分區的下一個記錄。注意:如果consumer需要讀取的分區在給定的偏移信息的map中,沒有指定的偏移位置,那么將會在這個特定的分區中采用默認的分組偏移的行為(即采用setStartFromGroupOffsets())。

注意:這些開始位置配置方法并不會影響作業失敗自動重啟或者通過savepoint手動重啟的開始位置,在恢復中,每個Kafka分區的開始位置由保存在savepoint或者checkpoint中的偏移來決定的。

Kafka Consumers 和Fault Tolerance

Flink的checkpoint啟用之后,Flink Kafka Consumer將會從一個topic中消費記錄并以一致性的方式周期性地檢查所有Kafka偏移量以及其他操作的狀態。Flink將保存流程序到狀態的最新的checkpoint中,并重新從Kafka中讀取記錄,記錄從保存在checkpoint中的偏移位置開始讀取.

checkpoint的時間間隔定義了程序在發生故障時可以恢復多少.

為了使用容錯性的Kafka Consumer,拓撲結構的checkpoint需要在執行環境中啟用,代碼如下:
Java 代碼:

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(5000); // 每5000毫秒檢查一次

Scala 代碼:

val env = StreamExecutionEnvironment.getExecutionEnvironment()
env.enableCheckpointing(5000) // 每5000毫秒檢查一次

同時需要注意的是Flink只能在有足夠的slots時才會去重啟topology,所以如果topology由于TaskManager丟失而失敗時,任然需要有足夠的slot可用。Flink on YARN支持YARN container丟失自動重啟。

如果checkpoint不可用,那么Kafka Consumer將會周期性地將offset提交到Zookeeper中。

Kafka Consumer Offset提交行為配置

Flink Kafka Consumer允許配置offset提交回Kafka brokers(Kafka 0.8是寫回Zookeeper)的行為,注意Flink Kafka Consumer 并不依賴于這個提交的offset來進行容錯性保證,這個提交的offset僅僅作為監控consumer處理進度的一種手段。

配置offset提交行為的方式有多種,主要取決于Job的checkpoint機制是否啟動。
  1、checkpoint禁用:如果checkpoint禁用,Flink Kafka Consumer依賴于Kafka 客戶端內部的自動周期性offset提交能力。因此,為了啟用或者禁用offset提交,僅需在給定的Properties配置中設置enable.auto.commit(Kafka 0.8是auto.commit.enable)/auto.commit.interval.ms為適當的值即可。
  2、checkpoint啟用:如果checkpoint啟用,當checkpoint完成之后,Flink Kafka Consumer將會提交offset保存到checkpoint State中,這就保證了kafka broker中的committed offset與 checkpoint stata中的offset相一致。用戶可以在Consumer中調用setCommitOffsetsOnCheckpoints(boolean) 方法來選擇啟用或者禁用offset committing(默認情況下是啟用的)。注意,在這種情況下,配置在Properties中的自動周期性offset提交將會被完全忽略。

Kafka Consumer與Timestamp抽取器和Watermark發射器

在許多情況下,記錄的timestamp都是顯式或者隱式地嵌入在記錄本身中,此外,用戶可能想周期性地發射水印或者不規則地發射,例如:根據Kafka 流中包含當前事件時間的特殊記錄的水印。為此,Flink Kafka Consumer允許這些指定:AssignerWithPeriodicWatermarks 或者 AssignerWithPunctuatedWatermarks

你可以指定你自定義的timestamp抽取器或者watermark發射器如這里描述,或者使用一個預定義的,之后你就可以按照下面的方式將它們傳遞到你的consumer中:
Java 代碼:

Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "test");

FlinkKafkaConsumer08<String> myConsumer =
    new FlinkKafkaConsumer08<>("topic", new SimpleStringSchema(), properties);
myConsumer.assignTimestampsAndWatermarks(new CustomWatermarkEmitter());

DataStream<String> stream = env
    .addSource(myConsumer)
    .print();

Scala 代碼:

val properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "test");

val myConsumer = new FlinkKafkaConsumer08[String]("topic", new SimpleStringSchema(), properties);
myConsumer.assignTimestampsAndWatermarks(new CustomWatermarkEmitter());
stream = env
    .addSource(myConsumer)
    .print

在內部,一個分配器實例會被每個Kafka分區執行,當一個實例被指定,這個extractTimestamp(T element, long previousElementTimestamp)方法就會被調用來為記錄分配一個timestamp并且Watermark getCurrentWatermark()(周期性的)或者 Watermark checkAndGetNextWatermark(T lastElement, long extractedTimestamp)(不規則的)會被調用來決定新生成的watermark是否需要發射,跟哪兒timestamp一起發射。

Kafka Producer

Flink的Kafka Producer叫做FlinkKafkaProducer08(Kafka 0.9.x版本是FlinkKafkaProducer09),它允許寫流記錄到一個或者多個Kafka topic中。
例如:
Java 代碼 Kafka 0.8+:

DataStream<String> stream = ...;

FlinkKafkaProducer08<String> myProducer = new FlinkKafkaProducer08<String>(
        "localhost:9092",            // broker list
        "my-topic",                  // target topic
        new SimpleStringSchema());   // serialization schema

// the following is necessary for at-least-once delivery guarantee
myProducer.setLogFailuresOnly(false);   // "false" by default
myProducer.setFlushOnCheckpoint(true);  // "false" by default

stream.addSink(myProducer);

Java 代碼 Kafka 0.9+

DataStream<String> stream = ...;

FlinkKafkaProducer010Configuration myProducerConfig = FlinkKafkaProducer010.writeToKafkaWithTimestamps(
        stream,                     // input stream
        "my-topic",                 // target topic
        new SimpleStringSchema(),   // serialization schema
        properties);                // custom configuration for KafkaProducer (including broker list)

// the following is necessary for at-least-once delivery guarantee
myProducerConfig.setLogFailuresOnly(false);   // "false" by default
myProducerConfig.setFlushOnCheckpoint(true);  // "false" by default

Scala 代碼 Kafka 0.8+

val stream: DataStream[String] = ...

val myProducer = new FlinkKafkaProducer08[String](
        "localhost:9092",         // broker list
        "my-topic",               // target topic
        new SimpleStringSchema)   // serialization schema

// the following is necessary for at-least-once delivery guarantee
myProducer.setLogFailuresOnly(false)   // "false" by default
myProducer.setFlushOnCheckpoint(true)  // "false" by default

stream.addSink(myProducer)

Scala 代碼 0.9+

val stream: DataStream[String] = ...

val myProducerConfig = FlinkKafkaProducer010.writeToKafkaWithTimestamps(
        stream,                   // input stream
        "my-topic",               // target topic
        new SimpleStringSchema,   // serialization schema
        properties)               // custom configuration for KafkaProducer (including broker list)

// the following is necessary for at-least-once delivery guarantee
myProducerConfig.setLogFailuresOnly(false)   // "false" by default
myProducerConfig.setFlushOnCheckpoint(true)  // "false" by default

上面例子展示了創建一個Flink Kafka Producer來寫流數據到指定的Kafka topic的基本用法:
對于更高級的用法,這里有其他變換的構造函數來允許提供下面的功能:
  1、提供自定義的屬性:Producer允許為內部的KafkaProducer提供自定義的屬性配置,請參考Apache Kafka 文檔來了解如何配置Kafka Producer的詳細信息。
  2、自定義分區器:為了給記錄指定分區,你可以為構造函數提供一個FlinkKafkaPartitioner的實現,這個分區器將會被流中的每個記錄調用,來決定記錄要被發送到目標topic的哪個確切分區。
  3、高級的序列化模式:與consumer類似,Producer允許使用一個叫KeyedSerializationSchema的高級序列化模式,這個模式允許分開地序列化key和value。同時允許重寫目標topic,因此一個Producer可以發送數據到多個topic。

Kafka Producer和容錯性

在Flink checkpoint開啟的情況下,Flink Kafka Producer可以提供至少一次(at-least-once)的發送保證。
除了啟用Flink的checkpoint之外,你還需要是當地配置setLogFailuresOnly(boolean) 和setFlushOnCheckpoint(boolean)方法,如前面章節的例子所示:
  1、setLogFailuresOnly(boolean):啟用這個配置將允許producer記錄失敗日志而不是捕獲和拋出它們,這個本質上會認為記錄已經成功,即使記錄沒有寫入目標Kafka topic中,對于at-least-once模式來說,這個配置必須禁用。
  2、setFlushOnCheckpoint(boolean):啟用這個配置,Flink的checkpoint會等待在checkpoint成功之前被Kafka識別的時間內傳輸的記錄,這就保證了所有checkpoint之前的記錄都被寫入Kafka 中,在at-least-once模式下,這個配置必須啟用。

注意:默認情況下,重試次數設置為“0”,這也就意味著setLogFailuresOnly設置為false,producer失敗的話會立即報錯,包括leader的切換也會報錯。這個值默認情況下設置為0是為了避免重試導致重復的消息進入目標topic中。對于大多數頻繁切換broker的生產環境中,我們建議將重試次數設置為一個比較高的值。

注意:現在Kafka還沒有事務型的producer,所以Flink無法保證精確地(exactly-once)分發消息到一個Kafka topic中。

在Kafka 0.10中使用Kafka timestamp和 Flink的event time

Apache Kafka 0.10之后的版本中,Kafka的消息可以攜帶timestamp,指出了事件發生的時間(參考Apache Flink的event time)或者消息被寫入到Kafka broker的時間。
如果Flink的TimeCharacteristic設置為TimeCharacteristic.EventTime (StreamExecutionEnvironment.setStreamTimeCharacteristic(TimeCharacteristic.EventTime))的話,FlinkKafkaConsumer010會發射附有timestamp的記錄。Kafka consumer并不會發射watermark,為了發射watermark,原理如"Kafka Consumers and Timestamp Extraction/Watermark Emission"所述,使用assignTimestampsAndWatermarks方法。
當使用Kafka中的timestamp時,無需定義timestamp抽取器,extractTimestamp()方法中的previousElementTimestamp參數已經包含了Kafka消息所攜帶的timestamp。
一個Kafka consumer的timestamp抽取器如下所示:

public long extractTimestamp(Long element, long previousElementTimestamp) {
    return previousElementTimestamp;
}

如果setWriteTimestampToKafka(true)配置了的話,FlinkKafkaProducer010 會僅發射記錄的timestamp。

FlinkKafkaProducer010.FlinkKafkaProducer010Configuration config = FlinkKafkaProducer010.writeToKafkaWithTimestamps(streamWithTimestamps, topic, new SimpleStringSchema(), standardProps);
config.setWriteTimestampToKafka(true);

Kafka Connector 度量

Flink的Kafka Connector通過Flink的度量系統提供了一些度量指標來分析connector的行為,producer通過Flink的度量系統輸出所有支持的版本的Kafka內部度量指標。consumer則輸出所有的Kafka 0.9版本的度量指標,Kafka在它的文檔中列出了所有的度量指標。

除此之外,所有的consumer都會為每個分區暴露出current-offsets和committed-offsets,current-offsets指出了當前分區的偏移位置,這個指出了我們最近檢索并成功發射的元素的偏移位置,committed-offsets是最近提交的偏移位置。

Flink中的Kafka Consumer提交offsets到Zookeeper(Kafka 0.8)或者Kafka Broker中(Kafka 0.9+),如果checkpoint禁用的話。offset會周期性地提交。啟用checkpoint的話,一旦所有流topology中的操作已經聲明它們已經創建為它們的State創建了一個checkpoint,offset會提交。這些為用戶提供了提交offset到Zookeeper或者Broker的at-least-once語義。對于offsetcheckpoint到Flink,系統提供了精確的(exactly once)保證。

提交到ZK或者Broker中的offset可以被用來追蹤Kafka consumer的讀取進度,提交的offset與每個分區中最近的offset的差異叫做consumer lag,如果Flink topology從topic中消費數據的速度小于新數據添加的速度,那么lag會增加,consumer會落后。對于大多數生產發布我們建議監控這個度量來避免不斷增加的延遲。

啟用Kerberos認證(對于0.9及以上版本)

Flink為Kafka Connector認證到一個配置了Kerberos的Kafka集群提供了一流的支持,僅僅需要在flink-conf.yaml配置Flink來為Kafka啟用Kerberos認證即可,如下:
1、通過如下設置來配置Kerberos憑證:
security.kerberos.login.use-ticket-cache:默認情況下,這個是true并且Flink會由kinit管理的票據緩存中使用Kerberos憑證。注意,當在部署到YARN的Flink 的Kafka Connectors中,Kerberos認證使用票據緩存是不起作用的,這種情況在作業部署到Mesos中也會出現,因為使用票據緩存的認證在Mesos部署中還未支持。
security.kerberos.login.keytabsecurity.kerberos.login.principal:為了使用Kerberos keytabs, 請為這兩個配置設置一個值。
2、將KafkaClient追加到security.kerberos.login.contexts中:這會告訴Flink來為Kafka 認證所用的Kafka登錄場景提供配置的Kerberos憑證。

一旦基于Kerberos的Flink安全啟用,你就可以通過Flink Kafka Consumer或者Producer認證到Kafka中,在提供的屬性配置中引入下面兩個配置,這兩個配置會傳入到內部的Kafka 客戶端。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,785評論 18 139
  • Kafka入門經典教程-Kafka-about云開發 http://www.aboutyun.com/threa...
    葡萄喃喃囈語閱讀 10,853評論 4 54
  • ** 今天看了一下kafka官網,嘗試著在自己電腦上安裝和配置,然后學一下官方document。** Introd...
    RainChang閱讀 5,035評論 1 30
  • 本文轉載自http://dataunion.org/?p=9307 背景介紹Kafka簡介Kafka是一種分布式的...
    Bottle丶Fish閱讀 5,489評論 0 34
  • kafka的定義:是一個分布式消息系統,由LinkedIn使用Scala編寫,用作LinkedIn的活動流(Act...
    時待吾閱讀 5,346評論 1 15