Storm 折騰雜記

Date: Nov 17-24, 2017

1. 目的

  • 積累Storm為主的流式大數據處理平臺對實時數據處理的相關技術
  • 積累快捷的Storm部署、開發方式,例如Python和Java。

2. 閱讀資料

  1. Apache Storm官網Tutorial
  2. 阿里巴巴JStorm文檔
  3. intsmaze's blog
  4. Java 基礎 Serializable 的使用
  5. Java 高級 Serializable 序列化的源碼分析
  6. ITindex Storm 系列

3. 閱讀筆記

3.1 Apache Storm官網

3.1.1 Storm主要結構概覽

Storm主要結構

如上圖所示,Storm是一個流數據處理平臺。它與Hadoop相近,采用Map-Reduce的計算框架,區別在于Hadoop的worker在完成工作后被釋放,而Storm的worker在完成工作后進入等待狀態——等待“上級”分配下一個任務。

Storm的本質是定義一個計算的過程,類似于設計中的數據流圖,即先定義數據處理的流程,再分模塊實現數據處理的細節,結果由末端的節點返回或輸出。

Storm的核心是Clojure編寫、提供Java開發接口,核心離工業解主流編程語言(JavaC/C++)相對遙遠,阿里巴巴的工程師團隊用Java重寫了Storm的核心,即為JStorm

3.2 阿里巴巴JStorm

3.2.1 JStorm定位

JStorm 是一個分布式實時計算引擎。

JStorm 是一個類似Hadoop MapReduce的系統, 用戶按照指定的接口實現一個任務,然后將這個任務遞交給JStorm系統,JStorm將這個任務跑起來,并且按7 * 24小時運行起來,一旦中間一個Worker 發生意外故障, 調度器立即分配一個新的Worker替換這個失效的Worker。

因此,從應用的角度,JStorm應用是一種遵守某種編程規范的分布式應用。從系統角度, JStorm是一套類似MapReduce的調度系統。 從數據的角度,JStorm是一套基于流水線的消息處理機制。

JStorm Hadoop
角色 Nimubs JobTracker
Supervisor TaskTracker
Worker Child
應用名稱 Topology Job
編程接口 Spout/Bolt Mapper/Reducer
“設計模式” 資本主義 恐怖主義

3.2.2 優點

在Storm和JStorm出現以前,市面上出現很多實時計算引擎,但自Storm和JStorm出現后,基本上可以說一統江湖: 究其優點:

  • 開發非常迅速:接口簡單,容易上手,只要遵守Topology、Spout和Bolt的編程規范即可開發出一個擴展性極好的應用,底層RPC、Worker之間冗余,數據分流之類的動作完全不用考慮
  • 擴展性極好:當一級處理單元速度,直接配置一下并發數,即可線性擴展性能
  • 健壯強:當Worker失效或機器出現故障時, 自動分配新的Worker替換失效Worker
  • 數據準確性:可以采用Ack機制,保證數據不丟失。 如果對精度有更多一步要求,采用事務機制,保證數據準確。
  • 實時性高: JStorm 的設計偏向單行記錄,因此,在時延較同類產品更低

3.2.3 應用場景

JStorm處理數據的方式是基于消息的流水線處理, 因此特別適合無狀態計算,也就是計算單元的依賴的數據全部在接受的消息中可以找到, 并且最好一個數據流不依賴另外一個數據流。

因此,常常用于:

  • 日志分析,從日志中分析出特定的數據,并將分析的結果存入外部存儲器如數據庫。目前,主流日志分析技術就使用JStorm或Storm
  • 管道系統, 將一個數據從一個系統傳輸到另外一個系統, 比如將數據庫同步到Hadoop
  • 消息轉化器, 將接受到的消息按照某種格式進行轉化,存儲到另外一個系統如消息中間件
  • 統計分析器, 從日志或消息中,提煉出某個字段,然后做count或sum計算,最后將統計值存入外部存儲器。中間處理過程可能更復雜。
  • 實時推薦系統, 將推薦算法運行在jstorm中,達到秒級的推薦效果

3.2.4 基本概念

[站外圖片上傳中...(image-96ea41-1511406796108)]

  • Spout (中文意為水龍頭)即數據的來源、出水口,來源可以是Kafka、DB、HBase、HDFS等。
  • Bolt(中文意為插銷)即數據流向過程中的關鍵點、數據流處理點。
  • Topology(中文意為拓撲結構)即上述圖中所示的數據處理流程形成的數據流網絡結構。

3.2.5 組件接口

  • Spout組件接口:nextTuple 拉取下一條消息,執行時JStorm框架回不停調用該接口從數據源拉取數據發往Bolt。
  • Bolt組件接口:execute 執行處理邏輯

3.2.6 調度和執行

對于一個Topology,JStorm調度一個/多個Worker (每個Worker對應操作系統的進程),分布到集群的一臺或多臺機器上并行執行。

在一個Worker (進程) 中,分為多個Task (線程),每個線程對應于Spout/Bolt的實現。

工作流程

  1. 根據業務設計Topology
  2. 根據業務流程實現Spout的 nextTuple 接口中的數據輸入
  3. 根據業務細節實現Bolt的 execute 接口中的處理邏輯
  4. 提交Topology開始執行
3.2.6.1 提交Topology時的參數
總Worker數目
if #worker <= 10 then
    _topology_master 以Task形式存在,不獨占Worker
else
    _topology_master 以Task形式存在,獨占Worker
end
每個component的并行度

并行度(parallelism) 代表有多少個Task線程來執行這個Spout/Bolt。

同一個Component中的Task id一定是連續的。

每個Component之間的關系

聲明Spout和Bolt之間的對應關系,JStorm使用均勻調度算法,奇偶不同數目的Spout/Bolt會存在某個進程只有Spout或只有Bolt的情形。若topology運行過程中掛掉,JStorm會不斷嘗試重啟進程。

3.2.7 消息通信

  1. Spout發消息

  2. JStorm 計算消息目標 Task Id列表

       if Task_id 在本進程 then
         直接將消息放入目標Task執行隊列
       else
         netty跨進程發送至目標Task中
       end
    

3.2.8 實時計算結果輸出

JStorm的Spout或Bolt中會有一個定時往外部存儲寫計算結果的邏輯,將數據按照業務需求被實時或近似實時地輸出。

3.2.9 小結

JStorm是阿里巴巴平臺的產品,相對來說適用于大量數據集群的情況,目前我現有的資源很難使用。因此,選擇Python系的streamparser進行閱讀。

3.3 折騰Storm平臺部署

3.3.1 部署storm平臺

  • 下載[Java 8/9][1]、maven、zookeeper、storm、[lein][2]的release并依次安裝。(以上庫除lein外為storm運行所必須,由于服務器在國外,下載時間較長)

  • 將 JDK、maven、zookeeper、storm 等拷貝至/opt 目錄下,在~/.bash_profile中將相應目錄加入PATH:

    export JAVA_HOME="/opt/jdk8"
    export MAVEN_HOME="/opt/maven"
    export ZOO_KEEPER_HOME="/opt/zookeeper"
    export STORM_HOME="/opt/storm"
    PATH=$STORM_HOME/bin:$ZOO_KEEPER_HOME/bin:$MAVEN_HOME/bin:JAVA_HOME/bin:$PATH
    export PATH
    

    ?- 進入/opt/zookeeper/conf目錄,編輯zoo.cfg配置文件,如下:

    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/var/zookeeper # 注意需要對該目錄有寫權限
    clientPort=2181
    
  • 進入/opt/storm/conf目錄,編輯storm.yaml配置文件,如下:

    storm.zookeeper.servers: # 注意此處有空格
      - "10.211.55.37"  # 填入配置機器的IP,若為集群則在下一行以同樣格式列出
      # - "other server ip"
      
    # 此處為Nimbus服務器地址,單機運行時無效,系統自動使用本地hostname,[原因待求證]
    # nimbus.seeds:["host1","host2","host3"] 
    
    storm.local.dir: "/var/storm" # 需要保證該目錄有寫權限,此處使用root賬戶所以不考慮。
    
    # 設置supervisor slots
    supervisor.slots.ports: # 注意此處有空格
      - 6700
      - 6701
      - 6702
      - 6702
    # 此處在storm 1.1.1版的配置模板文件中未提及,但配置后在集群中能看到,[原因待求證]
    

    ?

  • 啟動zookeeper集群

    bin/zkServer.sh start
    

?

  • 在[Master服務器][3]上啟動storm nimbus服務

    bin/storm nimbus >> /dev/null &
    
  • 在[Worker服務器][3]上啟動storm supervisor服務

    bin/storm supervisor >> /dev/null &
    
  • 在[Master服務器][3]上啟動storm UI工具

    bin/storm ui &
    
  • 在[Master服務器][3]上采用jps查看服務的啟動情況,若顯示config_value則表示服務正在初始化;若顯示nimbussupervisorcorejpsQuorumPeerMain則說明初始化完畢,打開瀏覽器輸入http://server_host:8080即可進入Storm UI查看相關信息。

[1] Java8/9 推薦安裝Oracle官網下載的完整版JDK,因為后續的 lein 需要完整的JDK。解壓JDK之后配置系統變量即可。(本次Linux機器采用 Java 8)

[2] lein全稱為leiningen,是自動化管理Clojure腳本的工具,類似于Cargo。lein目前的腳本下載會出現證書不匹配的問題,解決方案為export HTTP_CLIENT="wget --no-check-certificate -O"。而且,上述設置后,下載release依舊很慢、需要代理,可以直接wget下載對應的release,放到~/.lein/self-installs/leiningen-2.5.3-standalone.jar即可,參考這里lein是一個可執行腳本,需要放到/usr/bin或者/usr/local/bin下面,然后命令行中運行./leinlein repl完成安裝。

[3] 本地測試則僅僅在本機即可

3.3.2 案例工程 WordCount

主要參照《Get Started with Storm》一書,網上有中文版,此處參照為英文原版。

3.3.2.1 前提準備
  1. maven編譯工具,建立pom.xml來聲明該工程的編譯結構,包括注明編譯需要的maven版本、編譯所需的storm依賴庫在線地址、以及依賴的storm版本。

      <repositories>
            <!-- Repository where we can found the storm dependencies  -->
            <repository>
                <id>clojars.org</id>
                <url>http://clojars.org/repo</url>
            </repository>
      </repositories>
    
3.3.2.2 編寫對應代碼文件
1. 建立文件結構

建立對應的文件結構src/main/java/{spouts,bolts}/src/main/resources等,其中resources文件夾要存放相應的資源文件。

2. 編寫spouts實例
package spouts;
import ....;

public class WordReader implements IRichSpout {
    private .....;
     public void ack(Object msgId) {...;}
     public void fail(Object msgId) {...;}
     public void nextTuple() {...;}
  // first method called in ANY spout    
  public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {...;}
     public void close() {}
     public void declareOutputFields(OutputFieldsDeclarer declarer) {...;}
}
3. 編寫bolts實例
package bolts;
import ...;

public class WordNormalizer implements IRichBolt {
    private ...;
     public void cleanup(){}
     public void execute(Tuple input) {...;}
     public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {...;}
     public void declareOutputFields(OutputFieldsDeclarer declarer) {...;}
}
4. 編寫topology結構
import ...;

public class TopologyMain {
    public static void main(String[] args) throws InterruptedException {
        // Topology definition
         TopologyBuilder builder = new TopologyBuilder();
         builder.setSpout();
         builder.setBolt().shuffleGrouping();
         builder.setBolt().fieldGrouping();
         // Configuration
         Config conf = new Config();
         conf.put("xxx", args[0]);
         conf.setDebug(false);
         // Topology run
         conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 1);
         LocalCluster cluster = new LocalCluster();
         cluster.submitTopology("xxxx",conf, builder.createTopology());
         Thread.sleep(1000); // sleep to reduce server load
         cluster.shutdown();
    }
}
5. 使用mvm帶好相應參數運行
mvn clean install # maven會自動下載相關的包
cd target # 注意目錄下有 `pom.xml` 中標識的輸出的jar包
storm jar output-jar.jar path.to.your.topology # LocalCluster 執行,然后關閉
storm jar output-jar.jar path.to.your.topology name-of-storm # 提交jar至storm集群,循環執行,可在UI中查看

3.4 運行Storm例子程序的問題記錄

3.4.1 存在問題以及解答記錄

1. 程序中的collector是指的什么?

collector是用來追蹤處理邏輯上每個emit的數據是否在下游bolt中被成功處理。collector是與storm通信的工具,反饋每個任務的處理情況。

2. 程序中collector最后emitValue(…)是什么結構?

官方文檔解釋:A convenience class for making tuple values using new Values("field1", 2, 3) syntax.

Value是構建Tuple的一個元組類,該類實現了Serializable, Cloneable, Iterable<Object>, Collection<Object>, List<Object>, RandomAccess等接口,與Bolt中的execute接口相對應:public void execute(Tuple input, BasicOutputCollector collector)

3. Storm中的Ack/Fail機制中對fail情形的處理?

為了保證數據能正確的被處理, 對于spout產生的每一個tuple, storm都會進行跟蹤。

這里面涉及到ack/fail的處理,如果一個tuple處理成功是指這個Tuple以及這個Tuple產生的所有Tuple都被成功處理, 會調用spout的ack方法;

如果失敗是指這個Tuple或這個Tuple產生的所有Tuple中的某一個tuple處理失敗, 則會調用spout的fail方法;

在處理tuple的每一個bolt都會通過OutputCollector來告知storm, 當前bolt處理是否成功。

另外需要注意的,當spout觸發fail動作時,不會自動重發失敗的tuple,需要我們在spout中重新獲取發送失敗數據,手動重新再發送一次

4. Storm中的Ack原理

Storm中有個特殊的task名叫acker,他們負責跟蹤spout發出的每一個Tuple的Tuple樹(因為一個tuple通過spout發出了,經過每一個bolt處理后,會生成一個新的tuple發送出去)。當acker(框架自啟動的task)發現一個Tuple樹已經處理完成了,它會發送一個消息給產生這個Tuple的那個task。
Acker的跟蹤算法是Storm的主要突破之一,對任意大的一個Tuple樹,它只需要恒定的20字節就可以進行跟蹤。
Acker跟蹤算法的原理:acker對于每個spout-tuple保存一個ack-val的校驗值,它的初始值是0,然后每發射一個Tuple或Ack一個Tuple時,這個Tuple的id就要跟這個校驗值異或一下,并且把得到的值更新為ack-val的新值。那么假設每個發射出去的Tuple都被ack了,那么最后ack-val的值就一定是0。Acker就根據ack-val是否為0來判斷是否完全處理,如果為0則認為已完全處理。

要實現ack機制:

  • spout發射tuple的時候指定messageId
  • spout要重寫BaseRichSpout的fail和ack方法
  • spout對發射的tuple進行緩存(否則spout的fail方法收到acker發來的messsageId,spout也無法獲取到發送失敗的數據進行重發),看看系統提供的接口,只有msgId這個參數,這里的設計不合理,其實在系統里是有cache整個msg的,只給用戶一個messageid,用戶如何取得原來的msg貌似需要自己cache,然后用這個msgId去查詢,太坑爹了
  • spout根據messageId對于ack的tuple則從緩存隊列中刪除,對于fail的tuple可以選擇重發。
  • 設置acker數至少大于0;Config.setNumAckers(conf, ackerParal);

Storm的Bolt有BasicBoltRichBolt:
  在BasicBolt中,BasicOutputCollector在emit數據的時候,會自動和輸入的tuple相關聯,而在execute方法結束的時候那個輸入tuple會被自動ack
  使用RichBolt需要在emit數據的時候,顯式指定該數據的源tuple要加上第二個參數anchor tuple,以保持tracker鏈路,即collector.emit(oldTuple, newTuple);并且需要在execute執行成功后調用OutputCollector.ack(tuple),當失敗處理時,執行OutputCollector.fail(tuple)

由一個tuple產生一個新的tuple稱為:anchoring,你發射一個tuple的同時也就完成了一次anchoring。

ack機制即,spout發送的每一條消息,在規定的時間內,spout收到Acker的ack響應,即認為該tuple被后續bolt成功處理;在規定的時間內(默認是30秒),沒有收到Acker的ack響應tuple,就觸發fail動作,即認為該tuple處理失敗,timeout時間可以通過Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS來設定;或者收到Acker發送的fail響應tuple,也認為失敗,觸發fail動作

注意,如果繼承BaseBasicBolt那么程序拋出異常,程序直接異常停止了,不會讓spout進行重發。

5. Fail注意點小結
  • 若某個task節點處理的tuple一直失敗,會導致spout節點存儲的tuple數據越來越多,直至內存溢出
  • 在某個tuple的眾多子tuple中,若某一個子tuple處理fail,但是其他子tuple仍會執行。即當所有子tuple都執行數據存儲操作,其中一個子tuple出現fail,即使整個處理是fail,但是成功的子tuple仍會執行而不會滾。
  • Tuple的追蹤只要是spout開始,可以在任意層次bolt停止追蹤并作出應答。acker的數量可以通過Acker task組件來設置。
  • 一個Topology并不需要太多acker,除非storm吞吐量不正常。
  • 若不需要保證可靠性,即不追蹤tuple樹的執行情況,則系統里的消息數量會減少一半。
  • 關閉消息可靠性的三種方法:
    • config.Topology_ACKERS=0
    • Spout發送消息時不指定消息的msgId
    • emit方法中不指定輸入消息
6. Anchoring 錨定概念

拓撲是一個消息(Tuple)沿著一個或多個分支的樹節點,每個節點將ack(tuple)或者fail(tuple),這樣當消息失敗時Storm就會知道,并通知Spout重發消息。因為一個Storm拓撲運行在一個高度并發的環境中,跟蹤原始Spout示例的最好辦法是在消息Tuple中包含一個原始Spout的引用,這種行為(技術)被稱為Anchoring(錨定)

錨點發生的語句在collector.emit(tuple, new Values(word))中,傳遞元組(emit方法)使Storm能夠跟蹤原始Spout。collector.ack(tuple)collector.fail(tuple)告訴Spout知道每個消息的處理結果。當消息樹上的每個消息已經被處理,Storm認為來自Spout的元組被完全處理。當消息樹在一個可配置的超時內處理失敗,一個元組被認為是失敗的。處理的每一個元組必須是確認或者失敗,Storm會使用內存來追蹤每個元組,如果不對每個元組進行確認/失敗,最終會耗盡內存

為了簡化編碼,Storm為Bolt提供了一個IBasicBolt接口,它會在調用execute()方法之后正確調用ack()方法,BaseBasicBolt類是該接口的一個實現,用來實現自動確認。

7. Storm組件與編程時遇到的概念
名稱 解釋
Nimbus 負責資源分配和任務調度,Nimbus分配任務到Zookeeper指定目錄。
Supervisor 去Zookeeper指定目錄接受Nimbusf分配的任務,啟停自己的Worker進程。
Worker 運行具體處理組件邏輯的進程(process),Worker的任務分為Spout和Bolt兩種。
Task Worker啟動相應的物理線程(Executor),Worker執行的每一個Spout/Bolt線程成為一個Task,0.8版本后Spout/Bolt的Task可能共享一個Executor。
Topology 拓撲,Storm集群,即定義的數據流處理的DAG。
Spout Storm集群的數據源
Bolt Storm任務的處理邏輯單元,在集群多個機器上并發執行。
Tuple 消息元組,Spout、Bolt用來與Storm集群通信、反饋任務處理成功與否的載體。恒定為20Bit。
Stream groupings 數據流的分組策略,分7種,常見為shuffleGrouping()fieldsGrouping()
Executor Worker啟動的實際物理線程,一般一個Executor執行一個Task,但也能執行多個Task。
Configuration Topology的配置
8. 序列化與反序列化

由于博客上特別提到了Java虛擬機序列化的性能極其辣雞,所以在此記錄。

把對象轉換為字節序列的過程稱為對象的序列化;把字節序列恢復為對象的過程稱為對象的反序列化。

對象的序列化主要有兩種用途:

  • 把對象的字節序列永久地保存到硬盤上,通常存放在一個文件中;

  • 在網絡上傳送對象的字節序列。

在很多應用中,需要對某些對象進行序列化,讓它們離開內存空間,入住物理硬盤,以便長期保存。比如最常見的是Web服務器中的Session對象,當有 10萬用戶并發訪問,就有可能出現10萬個Session對象,內存可能吃不消,于是Web容器就會把一些seesion先序列化到硬盤中,等要用了,再把保存在硬盤中的對象還原到內存中。

當兩個進程在進行遠程通信時,彼此可以發送各種類型的數據。無論是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方需要把這個Java對象轉換為字節序列,才能在網絡上傳送;接收方則需要把字節序列再恢復為Java對象。

在Java/Storm中,可以理解為toString()函數的自定義實現。注意使用transient 修飾的對象無法序列化

9. declareOutputFields() 函數的具體作用

該Spout代碼里面最核心的部分有兩個:

  • collector.emit()方法發射tuple。我們不用自己實現tuple,我們只需要定義tuplevalue,Storm會幫我們生成tupleValues對象接受變長參數。Tuple中以List存放ValuesListIndex按照new Values(obj1, obj2,…)的參數的index,例如我們emit(new Values("v1", "v2")), 那么Tuple的屬性即為:{ [ "v1" ], [ "V2" ] }
  • declarer.declare方法用來給我們發射的value在整個Stream中定義一個別名。可以理解為key該值必須在整個topology定義中唯一

3.5 Windows 平臺部署本地測試環境的注意事項

3.5.1 所需安裝包

  • Java SE Development Kit 8/9,安裝到非C:\Program Files\目錄下,否則storm將無法啟動。
  • Apache-maven,解壓到本地目錄,推薦非系統盤
  • Zookeeper,解壓到本地目錄,推薦非系統盤
  • Storm,解壓到本地目錄,推薦非系統盤

3.5.2 環境變量配置

  • JAVA_HOME: path\to\your\jdk-file
  • Path: path\to\your-storm\bin;path\to\your-zookeeper\bin;path\to\your-maven\bin;%JAVA_HOME%\bin

3.5.3 配置文件設定

  • 配置zoo.cfg,參照3.1
  • 配置storm.yaml,參照3.1,注意storm.local.dirs中的目錄使用\\來表示\

3.5.6 啟動集群

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

推薦閱讀更多精彩內容

  • 目錄 場景假設 調優步驟和方法 Storm 的部分特性 Storm 并行度 Storm 消息機制 Storm UI...
    mtide閱讀 17,173評論 30 60
  • 這是一個JStorm使用教程,不包含環境搭建教程,直接在公司現有集群上跑任務,關于JStorm集群環境搭建,后續研...
    Coselding閱讀 6,386評論 1 9
  • Storm入門系列之一:storm核心概念及特性 本文的將介紹一些 storm 入門的基礎知識,包括 storm ...
    zhaif閱讀 3,142評論 0 17
  • 一. wordCount Topology開發: 1.spout數據收集器(SentenceSpout類): 有...
    奉先閱讀 1,198評論 0 0
  • 我在這家飲食公司做了那么久,一起工作的同事發生好多是是非非,我善良又沖動的性格不太會交際拉關系討好人落得如此下場,...
    Nataliechan我很快樂閱讀 150評論 0 0