Apache Flink實戰(一) - 初識Flink

了解Flink是什么,Flink應用程序運行的多樣化,對比業界常用的流處理框架,Flink的發展趨勢,Flink生態圈,Flink應用場景及Flink如何進行高效的Flink學習。

0 相關源碼

1 前言

1.1 功能

1.2 用戶

  • 國際


  • 國內


1.3 特點

◆ 結合Java、Scala兩種語言
◆ 從基礎到實戰
◆ 系統學習Flink的核心知識
◆ 快速完成從入門到上手企業開發的能力提升

1.4 安排

◆ 初識Flink
◆ 編程模型及核心概念
◆ DataSet API編程
◆ DataStream API編程
◆ Flink Table&SQL
◆ Window和Time操作
◆ Flink Connectors
◆ Flink部署及作業提交
◆ Flink監控及調優

  • 使用Flink自定義數據源讀取配置數據
  • 使用Flink完成實時數據清洗
  • 使用Flink完成實時結果統計
  • 統計結果可視化展示(Kibana)

1.5 收獲

◆ 系統入門Flink開發
◆ 掌握應用Java SE/Scala的Flink實現
◆理解Flink項目的開發流程
◆ 快速上手企業開發

1.6 環境

◆ Mac OS: 10.14.12
◆ Kafka: 1.1.1
◆ Hadoop : CDH ( 5.15.1)
◆ ES/Kibana : 6+
◆ FXIQ: IDEA
◆ Flink : 1.7

1.7 確保你已掌握

◆ 了解Linux常用基本命令的使用
◆ 熟悉Java SE或Scala的基本使用
◆ 熟悉Hadoop基礎應用

1.8 學習方法推薦

◆認真閱讀本教程!多思考、多動手!
◆合理利用網絡資源
◆善于提問:QQ群討論

2 教程大綱

◆ Flink概述
◆ Flink應用場景
◆ Flink Layer
◆ Flink發 展趨勢
◆ Flink應用程序運行方式多樣化
◆ 如何學習Flink
◆ Flink VS Storm VS Spark Streaming

Flink概述

Apache Flink是一個框架和分布式處理引擎,用于對無界和有界數據流進行狀態計算。 Flink設計為在所有常見的集群環境中運行,以內存速度和任何規模執行計算。

在這里,我們解釋Flink架構的重要方面。

架構

處理無界和有界數據

任何類型的數據都是作為事件流產生的。信用卡交易,傳感器測量,機器日志或網站或移動應用程序上的用戶交互,所有這些數據都作為流生成。

數據可以作為無界或有界流處理。

  • 無界流有一個開始但沒有定義的結束。它們不會在生成時終止并提供數據。必須連續處理無界流,即必須在攝取之后立即處理事件。無法等待所有輸入數據到達,因為輸入是無界的,并且在任何時間點都不會完成。處理無界數據通常要求以特定順序攝取事件,例如事件發生的順序,以便能夠推斷結果完整性。

  • 有界流具有定義的開始和結束??梢栽趫绦腥魏斡嬎阒巴ㄟ^攝取所有數據來處理有界流。處理有界流不需要有序攝取,因為可以始終對有界數據集進行排序。有界流的處理也稱為批處理

  • Apache Flink擅長處理無界和有界數據集。精確控制時間和狀態使Flink的運行時能夠在無界流上運行任何類型的應用程序。有界流由算法和數據結構內部處理,這些算法和數據結構專為固定大小的數據集而設計,從而產生出色的性能。

通過探索在Flink之上構建的用例來說服自己。

利用內存中性能

有狀態Flink應用程序針對本地狀態訪問進行了優化。任務狀態始終保留在內存中,如果狀態大小超過可用內存,則保存在訪問高效的磁盤上數據結構中。因此,任務通過訪問本地(通常是內存中)狀態來執行所有計算,從而產生非常低的處理延遲。 Flink通過定期和異步地將本地狀態檢查點到持久存儲來保證在出現故障時的一次狀態一致性。


應用

Apache Flink是一個用于對無界和有界數據流進行有狀態計算的框架。 Flink在不同的抽象級別提供多個API,并為常見用例提供專用庫。

在這里,我們介紹Flink易于使用和富有表現力的API和庫。

流媒體應用程序的構建塊

可以由流處理框架構建和執行的應用程序類型由框架控制流,狀態和時間的程度來定義。在下文中,我們描述了流處理應用程序的這些構建塊,并解釋了Flink處理它們的方法。

顯然,流是流處理的一個基本方面。但是,流可以具有不同的特征,這些特征會影響流的處理方式。 Flink是一個多功能的處理框架,可以處理任何類型的流。

  • 有界和無界流:流可以是無界的或有界的,即固定大小的數據集。 Flink具有處理無界流的復雜功能,但也有專門的運營商來有效地處理有界流。
  • 實時和記錄的流:所有數據都作為流生成。有兩種方法可以處理數據。在生成時實時處理它或將流持久保存到存儲系統,例如文件系統或對象存儲,并在以后處理它。 Flink應用程序可以處理記錄或實時流。

狀態

每個非平凡的流應用程序都是有狀態的,即,只有對各個事件應用轉換的應用程序不需要狀態。運行基本業務邏輯的任何應用程序都需要記住事件或中間結果,以便在以后的時間點訪問它們,例如在收到下一個事件時或在特定持續時間之后。


應用狀態是Flink的一等公民。您可以通過查看Flink在狀態處理環境中提供的所有功能來查看。

  • 多狀態基元:Flink為不同的數據結構提供狀態基元,例如原子值,列表或映射。開發人員可以根據函數的訪問模式選擇最有效的狀態原語。
  • 可插拔狀態后端:應用程序狀態由可插拔狀態后端管理和檢查點。 Flink具有不同的狀態后端,可以在內存或RocksDB中存儲狀態,RocksDB是一種高效的嵌入式磁盤數據存儲。也可以插入自定義狀態后端。
  • 完全一次的狀態一致性:Flink的檢查點和恢復算法可確保在發生故障時應用程序狀態的一致性。因此,故障是透明處理的,不會影響應用程序的正確性。
  • 非常大的狀態:由于其異步和增量檢查點算法,Flink能夠維持幾兆兆字節的應用程序狀態。
    可擴展的應用程序:Flink通過將狀態重新分配給更多或更少的工作人員來支持有狀態應用程序的擴展。

時間

時間是流應用程序的另一個重要組成部分大多數事件流都具有固有的時間語義,因為每個事件都是在特定時間點生成的。此外,許多常見的流計算基于時間,例如窗口聚合,會話化,模式檢測和基于時間的連接。流處理的一個重要方面是應用程序如何測量時間,即事件時間和處理時間的差異。

Flink提供了一組豐富的與時間相關的功能。

  • 事件時間模式:使用事件時間語義處理流的應用程序根據事件的時間戳計算結果。因此,無論是否處理記錄的或實時的事件,事件時間處理都允許準確和一致的結果。
  • 水印支持:Flink使用水印來推斷事件時間應用中的時間。水印也是一種靈活的機制,可以權衡結果的延遲和完整性。
  • 延遲數據處理:當使用水印在事件 - 時間模式下處理流時,可能會在所有相關事件到達之前完成計算。這類事件被稱為遲發事件。 Flink具有多個選項來處理延遲事件,例如通過側輸出重新路由它們以及更新以前完成的結果。
  • 處理時間模式:除了事件時間模式之外,Flink還支持處理時間語義,該處理時間語義執行由處理機器的掛鐘時間觸發的計算。處理時間模式適用于具有嚴格的低延遲要求的某些應用,這些要求可以容忍近似結果。

4 Layered APIs

Flink提供三層API。 每個API在簡潔性和表達性之間提供不同的權衡,并針對不同的用例。


我們簡要介紹每個API,討論其應用程序,并顯示代碼示例。

ProcessFunctions

ProcessFunctions是Flink提供的最具表現力的功能接口。 Flink提供ProcessFunction來處理來自窗口中分組的一個或兩個輸入流或事件的單個事件。 ProcessFunctions提供對時間和狀態的細粒度控制。 ProcessFunction可以任意修改其狀態并注冊將在未來觸發回調函數的定時器。因此,ProcessFunctions可以根據許多有狀態事件驅動的應用程序的需要實現復雜的每事件業務邏輯。

以下示例顯示了一個KeyedProcessFunction,它對KeyedStream進行操作并匹配START和END事件。收到START事件時,該函數會記住其狀態的時間戳,并在四小時內注冊一個計時器。如果在計時器觸發之前收到END事件,則該函數計算END和START事件之間的持續時間,清除狀態并返回該值。否則,計時器只會觸發并清除狀態。

/**
 * Matches keyed START and END events and computes the difference between 
 * both elements' timestamps. The first String field is the key attribute, 
 * the second String attribute marks START and END events.
 */
public static class StartEndDuration
    extends KeyedProcessFunction<String, Tuple2<String, String>, Tuple2<String, Long>> {

  private ValueState<Long> startTime;

  @Override
  public void open(Configuration conf) {
    // obtain state handle
    startTime = getRuntimeContext()
      .getState(new ValueStateDescriptor<Long>("startTime", Long.class));
  }

  /** Called for each processed event. */
  @Override
  public void processElement(
      Tuple2<String, String> in,
      Context ctx,
      Collector<Tuple2<String, Long>> out) throws Exception {

    switch (in.f1) {
      case "START":
        // set the start time if we receive a start event.
        startTime.update(ctx.timestamp());
        // register a timer in four hours from the start event.
        ctx.timerService()
          .registerEventTimeTimer(ctx.timestamp() + 4 * 60 * 60 * 1000);
        break;
      case "END":
        // emit the duration between start and end event
        Long sTime = startTime.value();
        if (sTime != null) {
          out.collect(Tuple2.of(in.f0, ctx.timestamp() - sTime));
          // clear the state
          startTime.clear();
        }
      default:
        // do nothing
    }
  }

  /** Called when a timer fires. */
  @Override
  public void onTimer(
      long timestamp,
      OnTimerContext ctx,
      Collector<Tuple2<String, Long>> out) {

    // Timeout interval exceeded. Cleaning up the state.
    startTime.clear();
  }
}

該示例說明了KeyedProcessFunction的表達能力,但也強調了它是一個相當冗長的接口。

DataStream API

DataStream API為許多常見的流處理操作提供原語,例如窗口化,一次記錄轉換以及通過查詢外部數據存儲來豐富事件。 DataStream API可用于Java和Scala,它基于函數,例如map(),reduce()和aggregate()。 可以通過擴展接口或Java或Scala lambda函數來定義函數。

以下示例顯示如何對點擊流進行會話并計算每個會話的點擊次數。

// a stream of website clicks
DataStream<Click> clicks = ...

DataStream<Tuple2<String, Long>> result = clicks
  // project clicks to userId and add a 1 for counting
  .map(
    // define function by implementing the MapFunction interface.
    new MapFunction<Click, Tuple2<String, Long>>() {
      @Override
      public Tuple2<String, Long> map(Click click) {
        return Tuple2.of(click.userId, 1L);
      }
    })
  // key by userId (field 0)
  .keyBy(0)
  // define session window with 30 minute gap
  .window(EventTimeSessionWindows.withGap(Time.minutes(30L)))
  // count clicks per session. Define function as lambda function.
  .reduce((a, b) -> Tuple2.of(a.f0, a.f1 + b.f1));

SQL & Table API

Flink具有兩個關系API,Table API和SQL。 這兩個API都是用于批處理和流處理的統一API,即,在無界的實時流或有界的記錄流上以相同的語義執行查詢,并產生相同的結果。 Table API和SQL利用Apache Calcite進行解析,驗證和查詢優化。 它們可以與DataStream和DataSet API無縫集成,并支持用戶定義的標量,聚合和表值函數。

Flink的關系API旨在簡化數據分析,數據流水線和ETL應用程序的定義。

以下示例顯示用于會話點擊流的SQL查詢,并計算每個會話的點擊次數。 這與DataStream API示例中的用例相同。

SELECT userId, COUNT(*)
FROM clicks
GROUP BY SESSION(clicktime, INTERVAL '30' MINUTE), userId

Flink具有幾個用于常見數據處理用例的庫。這些庫通常嵌入在API中,而不是完全獨立的。因此,他們可以從API的所有功能中受益,并與其他庫集成。

  • 復雜事件處理(CEP):模式檢測是事件流處理的一個非常常見的用例。 Flink的CEP庫提供了一個API來指定事件模式(想想正則表達式或狀態機)。 CEP庫與Flink的DataStream API集成,以便在DataStream上評估模式。 CEP庫的應用包括網絡入侵檢測,業務流程監控和欺詐檢測。

  • DataSet API:DataSet API是Flink用于批處理應用程序的核心API。 DataSet API的原語包括map,reduce,(外部)join,co-group和iterate。所有操作都由算法和數據結構支持,這些算法和數據結構對內存中的序列化數據進行操作,并在數據大小超過內存預算時溢出到磁盤。 Flink的DataSet API的數據處理算法受到傳統數據庫運算符的啟發,例如混合散列連接或外部合并排序。

  • Gelly:Gelly是一個可擴展的圖形處理和分析庫。 Gelly在DataSet API之上實現并與之集成。因此,它受益于其可擴展且強大的運營商。 Gelly具有內置算法,例如標簽傳播,三角形枚舉和頁面排名,但也提供了一種Graph API,可以簡化自定義圖算法的實現。

5 運行多樣化

5.1 隨處部署應用程序

Apache Flink是一個分布式系統,需要計算資源才能執行應用程序。
Flink與所有常見的集群資源管理器(如Hadoop YARN,Apache Mesos和Kubernetes)集成,但也可以設置為作為獨立集群運行。

Flink旨在很好地運作以前列出的每個資源管理器。
這是通過特定于資源管理器的部署模式實現的,這些模式允許Flink以其慣用方式與每個資源管理器進行交互。

部署Flink應用程序時,Flink會根據應用程序配置的并行性自動識別所需資源,并從資源管理器請求它們。
如果發生故障,Flink會通過請求新資源來替換發生故障的容器。提交或控制應用程序的所有通信都通過REST調用。
這簡化了Flink在許多環境中的集成。

5.2 以任何規模運行應用程序

Flink旨在以任何規模運行有狀態流應用程序。
應用程序并行化為數千個在集群中分布和同時執行的任務。因此,應用程序可以利用幾乎無限量的CPU,主內存,磁盤和網絡IO。而且,Flink很容易保持非常大的應用程序狀態。其異步和增量檢查點算法確保對處理延遲的影響最小,同時保證一次性狀態一致性。

用戶報告了在其生產環境中運行的Flink應用程序令人印象深刻的可擴展性數字,例如

  • 應用程序每天處理數萬億個事件,
  • 應用程序維護多個TB的狀態
  • 運行在數千個核心上的應用程序

6 業界流處理框架對比

7 Flink 使用案例

Apache Flink 功能強大,支持開發和運行多種不同種類的應用程序。它的主要特性包括:批流一體化、精密的狀態管理、事件時間支持以及精確一次的狀態一致性保障等。
Flink 不僅可以運行在包括 YARN、 Mesos、Kubernetes 在內的多種資源管理框架上,還支持在裸機集群上獨立部署。
在啟用高可用選項的情況下,它不存在單點失效問題。事實證明,Flink 已經可以擴展到數千核心,其狀態可以達到 TB 級別,且仍能保持高吞吐、低延遲的特性。世界各地有很多要求嚴苛的流處理應用都運行在 Flink 之上。

接下來我們將介紹 Flink 常見的幾類應用并給出相關實例鏈接。

  • [事件驅動型應用]
  • [數據分析應用]
  • [數據管道應用]

7.1 事件驅動型應用

7.1.1 什么是事件驅動型應用?

事件驅動型應用是一類具有狀態的應用,它從一個或多個事件流提取數據,并根據到來的事件觸發計算、狀態更新或其他外部動作。

事件驅動型應用是在計算存儲分離的傳統應用基礎上進化而來。在傳統架構中,應用需要讀寫遠程事務型數據庫。

相反,事件驅動型應用是基于狀態化流處理來完成。在該設計中,數據和計算不會分離,應用只需訪問本地(內存或磁盤)即可獲取數據。系統容錯性的實現依賴于定期向遠程持久化存儲寫入 checkpoint。

  • 傳統應用和事件驅動型應用架構的區別


7.1.2 事件驅動型應用的優勢?

事件驅動型應用無須查詢遠程數據庫,本地數據訪問使得它具有更高的吞吐和更低的延遲。而由于定期向遠程持久化存儲的 checkpoint 工作可以異步、增量式完成,因此對于正常事件處理的影響甚微。事件驅動型應用的優勢不僅限于本地數據訪問。傳統分層架構下,通常多個應用會共享同一個數據庫,因而任何對數據庫自身的更改(例如:由應用更新或服務擴容導致數據布局發生改變)都需要謹慎協調。反觀事件驅動型應用,由于只需考慮自身數據,因此在更改數據表示或服務擴容時所需的協調工作將大大減少。

7.1.3 Flink 如何支持事件驅動型應用?

事件驅動型應用會受制于底層流處理系統對時間和狀態的把控能力,Flink 諸多優秀特質都是圍繞這些方面來設計的。
它提供了一系列豐富的狀態操作原語,允許以精確一次的一致性語義合并海量規模(TB 級別)的狀態數據。
此外,Flink 還支持事件時間和自由度極高的定制化窗口邏輯,而且它內置的 ProcessFunction 支持細粒度時間控制,方便實現一些高級業務邏輯。
同時,Flink 還擁有一個復雜事件處理(CEP)類庫,可以用來檢測數據流中的模式。

Flink 中針對事件驅動應用的明星特性當屬 savepoint。Savepoint 是一個一致性的狀態映像,它可以用來初始化任意狀態兼容的應用。在完成一次 savepoint 后,即可放心對應用升級或擴容,還可以啟動多個版本的應用來完成 A/B 測試。

典型的事件驅動型應用實例

數據分析應用

什么是數據分析應用?

數據分析任務需要從原始數據中提取有價值的信息和指標。傳統的分析方式通常是利用批查詢,或將事件記錄下來并基于此有限數據集構建應用來完成。為了得到最新數據的分析結果,必須先將它們加入分析數據集并重新執行查詢或運行應用,隨后將結果寫入存儲系統或生成報告。

借助一些先進的流處理引擎,還可以實時地進行數據分析。和傳統模式下讀取有限數據集不同,流式查詢或應用會接入實時事件流,并隨著事件消費持續產生和更新結果。這些結果數據可能會寫入外部數據庫系統或以內部狀態的形式維護。儀表展示應用可以相應地從外部數據庫讀取數據或直接查詢應用的內部狀態。

如下圖所示,Apache Flink 同時支持流式及批量分析應用。

流式分析應用的優勢?

和批量分析相比,由于流式分析省掉了周期性的數據導入和查詢過程,因此從事件中獲取指標的延遲更低。不僅如此,批量查詢必須處理那些由定期導入和輸入有界性導致的人工數據邊界,而流式查詢則無須考慮該問題。

另一方面,流式分析會簡化應用抽象。批量查詢的流水線通常由多個獨立部件組成,需要周期性地調度提取數據和執行查詢。如此復雜的流水線操作起來并不容易,一旦某個組件出錯將會影響流水線的后續步驟。而流式分析應用整體運行在 Flink 之類的高端流處理系統之上,涵蓋了從數據接入到連續結果計算的所有步驟,因此可以依賴底層引擎提供的故障恢復機制。

Flink 如何支持數據分析類應用?

Flink 為持續流式分析和批量分析都提供了良好的支持。具體而言,它內置了一個符合 ANSI 標準的 SQL 接口,將批、流查詢的語義統一起來。無論是在記錄事件的靜態數據集上還是實時事件流上,相同 SQL 查詢都會得到一致的結果。同時 Flink 還支持豐富的用戶自定義函數,允許在 SQL 中執行定制化代碼。如果還需進一步定制邏輯,可以利用 Flink DataStream API 和 DataSet API 進行更低層次的控制。此外,Flink 的 Gelly 庫為基于批量數據集的大規模高性能圖分析提供了算法和構建模塊支持。

典型的數據分析應用實例

數據管道應用

什么是數據管道?

提取-轉換-加載(ETL)是一種在存儲系統之間進行數據轉換和遷移的常用方法。ETL 作業通常會周期性地觸發,將數據從事務型數據庫拷貝到分析型數據庫或數據倉庫。

數據管道和 ETL 作業的用途相似,都可以轉換、豐富數據,并將其從某個存儲系統移動到另一個。但數據管道是以持續流模式運行,而非周期性觸發。因此它支持從一個不斷生成數據的源頭讀取記錄,并將它們以低延遲移動到終點。例如:數據管道可以用來監控文件系統目錄中的新文件,并將其數據寫入事件日志;另一個應用可能會將事件流物化到數據庫或增量構建和優化查詢索引。

下圖描述了周期性 ETL 作業和持續數據管道的差異。

image

數據管道的優勢?

和周期性 ETL 作業相比,持續數據管道可以明顯降低將數據移動到目的端的延遲。此外,由于它能夠持續消費和發送數據,因此用途更廣,支持用例更多。

Flink 如何支持數據管道應用?

很多常見的數據轉換和增強操作可以利用 Flink 的 SQL 接口(或 Table API)及用戶自定義函數解決。如果數據管道有更高級的需求,可以選擇更通用的 DataStream API 來實現。Flink 為多種數據存儲系統(如:Kafka、Kinesis、Elasticsearch、JDBC數據庫系統等)內置了連接器。同時它還提供了文件系統的連續型數據源及數據匯,可用來監控目錄變化和以時間分區的方式寫入文件。

典型的數據管道應用實例

8 Flink發展趨勢

X 聯系我

  • 公眾號


  • Q群


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

推薦閱讀更多精彩內容

  • 架構 Apache Flink是一個框架和分布式處理引擎,用于對無界和有界數據流進行有狀態計算。Flink設計為在...
    盜夢者_56f2閱讀 37,838評論 0 6
  • 本文是先介紹 Flink,再說 Flink的過去和現在 一、Flink介紹 Flink是一款分布式的計算引擎,它可...
    生活的探路者閱讀 1,315評論 0 22
  • 每天手機占居了我們很多時間,我身邊很多人(包括我自己)每天都會看很多來自各種app或者朋友圈的文章、精彩段落或者別...
    major_arthur閱讀 525評論 0 0
  • 2016.11.12 光棍節的第二天,星期六,學校補課。 自從開學分班后,我就認識了更多的人,隔壁班的,隔樓班的,...
    罷欲閱讀 440評論 0 0
  • 大家好,我蘿卜和大家聊天,看著手機還有百分之20的電,想著每天寫百字文章 練練手 討論一下這個簡書的平臺 說...
    蘿卜小哥閱讀 109評論 1 2