Mac OS X環境で、Apache Stormの基本動作を試してみる

BigDataのリアルタイムデータ処理基盤として活用されている、[Apache Storm](http://storm.apache.org)の基本動作を試してみました。ちなみに、Apache Stormとは、2011年にTwitterがOSS化した耐障害性を持つリアルタイム分散ストリーム基盤だそうです。

#◼︎ Storm動作環境をつくる
[Apache Stormの公式サイト](http://storm.apache.org/documentation/Setting-up-a-Storm-cluster.html)を参考にしながら、Storm環境セットアップを行います。
なお、ここでの記事は、MacOS X環境を前提にした手順になりますが、Ubuntu環境でも同様の手順で動作することを確認しました。もちろん、Homebrewは使えないですけど。


+ zooKeeper本体をインストールして、起動しておきます

```
$ brew install zookeeper
$ zkServer start
JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Starting zookeeper ... STARTED
```

+ storm本体を"/usr/local/storm"にインストールします

```
$ brew install wget
$ cd /usr/local/
$ wget http://ftp.jaist.ac.jp/pub/apache/storm/apache-storm-0.10.0/apache-storm-0.10.0.tar.gz

$ tar zxvf apache-storm-0.10.0.tar.gz
$ ln -s apache-storm-0.10.0 storm
$ rm apache-storm-0.10.0.tar.gz
```

+ storm環境設定を行います（インストール先に応じて、"storm.local.dir"を変更します）

```
$ cd storm/conf
$ vi storm.yaml

...(snip)

storm.zookeeper.servers:
  - "127.0.0.1"

storm.local.dir: "/usr/local/storm"

nimbus.host: "127.0.0.1"

supervisor.slots.ports:
    - 6700
    - 6701
    - 6702
    - 6703
```

+ stormコマンドが簡易に起動できるように、パス設定を行っておきます。

```
$ vi $HOME/.profile

...(snip)

export PATH=$PATH:/usr/local/storm/bin
```

+ <b>"Nimbus"</b>を起動します

```
$ storm nimbus
Running: java -server -Ddaemon.name=nimbus -Dstorm.options= -Dstorm.home=/usr/local/apache-storm-0.10.0 -Dstorm.log.dir=/usr/local/apache-storm-0.10.0/logs -Djava.library.path=/usr/local/lib:/opt/local/lib:/usr/lib -Dstorm.conf.file= -cp /usr/local/apache-storm-0.10.0/lib/asm-4.0.jar:/usr/local/apache-storm-0.10.0/lib/clojure-1.6.0.jar:/usr/local/apache-storm-0.10.0/lib/disruptor-2.10.4.jar:/usr/local/apache-storm-0.10.0/lib/hadoop-auth-2.4.0.jar:/usr/local/apache-storm-0.10.0/lib/kryo-2.21.jar:/usr/local/apache-storm-0.10.0/lib/log4j-api-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-core-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-over-slf4j-1.6.6.jar:/usr/local/apache-storm-0.10.0/lib/log4j-slf4j-impl-2.1.jar:/usr/local/apache-storm-0.10.0/lib/minlog-1.2.jar:/usr/local/apache-storm-0.10.0/lib/reflectasm-1.07-shaded.jar:/usr/local/apache-storm-0.10.0/lib/servlet-api-2.5.jar:/usr/local/apache-storm-0.10.0/lib/slf4j-api-1.7.7.jar:/usr/local/apache-storm-0.10.0/lib/storm-core-0.10.0.jar:/usr/local/storm/conf -Xmx1024m -Dlogfile.name=nimbus.log -Dlog4j.configurationFile=/usr/local/apache-storm-0.10.0/log4j2/cluster.xml backtype.storm.daemon.nimbus
```

+ <b>"Supervisor"</b>を起動します

```
$ storm supervisor
Running: java -server -Ddaemon.name=supervisor -Dstorm.options= -Dstorm.home=/usr/local/apache-storm-0.10.0 -Dstorm.log.dir=/usr/local/apache-storm-0.10.0/logs -Djava.library.path=/usr/local/lib:/opt/local/lib:/usr/lib -Dstorm.conf.file= -cp /usr/local/apache-storm-0.10.0/lib/asm-4.0.jar:/usr/local/apache-storm-0.10.0/lib/clojure-1.6.0.jar:/usr/local/apache-storm-0.10.0/lib/disruptor-2.10.4.jar:/usr/local/apache-storm-0.10.0/lib/hadoop-auth-2.4.0.jar:/usr/local/apache-storm-0.10.0/lib/kryo-2.21.jar:/usr/local/apache-storm-0.10.0/lib/log4j-api-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-core-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-over-slf4j-1.6.6.jar:/usr/local/apache-storm-0.10.0/lib/log4j-slf4j-impl-2.1.jar:/usr/local/apache-storm-0.10.0/lib/minlog-1.2.jar:/usr/local/apache-storm-0.10.0/lib/reflectasm-1.07-shaded.jar:/usr/local/apache-storm-0.10.0/lib/servlet-api-2.5.jar:/usr/local/apache-storm-0.10.0/lib/slf4j-api-1.7.7.jar:/usr/local/apache-storm-0.10.0/lib/storm-core-0.10.0.jar:/usr/local/storm/conf -Xmx256m -Dlogfile.name=supervisor.log -Dlog4j.configurationFile=/usr/local/apache-storm-0.10.0/log4j2/cluster.xml backtype.storm.daemon.supervisor
```

+ <b>"UI"</b>を起動します

```
$ storm ui
Running: java -server -Ddaemon.name=ui -Dstorm.options= -Dstorm.home=/usr/local/apache-storm-0.10.0 -Dstorm.log.dir=/usr/local/apache-storm-0.10.0/logs -Djava.library.path=/usr/local/lib:/opt/local/lib:/usr/lib -Dstorm.conf.file= -cp /usr/local/apache-storm-0.10.0/lib/asm-4.0.jar:/usr/local/apache-storm-0.10.0/lib/clojure-1.6.0.jar:/usr/local/apache-storm-0.10.0/lib/disruptor-2.10.4.jar:/usr/local/apache-storm-0.10.0/lib/hadoop-auth-2.4.0.jar:/usr/local/apache-storm-0.10.0/lib/kryo-2.21.jar:/usr/local/apache-storm-0.10.0/lib/log4j-api-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-core-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-over-slf4j-1.6.6.jar:/usr/local/apache-storm-0.10.0/lib/log4j-slf4j-impl-2.1.jar:/usr/local/apache-storm-0.10.0/lib/minlog-1.2.jar:/usr/local/apache-storm-0.10.0/lib/reflectasm-1.07-shaded.jar:/usr/local/apache-storm-0.10.0/lib/servlet-api-2.5.jar:/usr/local/apache-storm-0.10.0/lib/slf4j-api-1.7.7.jar:/usr/local/apache-storm-0.10.0/lib/storm-core-0.10.0.jar:/usr/local/apache-storm-0.10.0:/usr/local/storm/conf -Xmx768m -Dlogfile.name=ui.log -Dlog4j.configurationFile=/usr/local/apache-storm-0.10.0/log4j2/cluster.xml backtype.storm.ui.core
```

#◼︎ Storm UI画面を確認してみる
Storm UI画面にて、Storm動作環境を確認してみます。
<b>http://{nimbus host}:8080</b>

![storm_ui.png](https://qiita-image-store.s3.amazonaws.com/0/103595/a0134df7-fbdd-3b3d-fce9-4e27d82ad95b.png)

ただ、現段階では、Topologyを動作させていないので、単に、UI画面構成を確認できる程度です。

#◼︎ "ExclamationTopology"をローカルモードで試してみる
Apache Stormの登竜門として、よく活用されている"storm-starter"を用いて、Topologyをローカルモードで動作させてみます。

ローカルモードとは。。。

> 「ローカルモード（Local Mode）」では、Stormトポロジーは、ローカルマシン上で単一のJVMを使って実行される。トポロジーコンポーネントすべての協働関係がわかりやすいことから、開発、テスト、デバッグに使われる。このモードでは、パラメータを動かしてさまざまなStorm構成環境を作り、トポロジーの動作を確認できる。ローカルモードでトポロジーを実行するには、Stormのトポロジー開発とテストに必要な依存ファイルをダウンロードしなければならない。

抜粋：: Jonathan Leibiusky, Gabriel Eisbruch, Dario Simonassi  “Stormをはじめよう”。 iBooks  

+ まずは、環境セットアップから、、、

```
$ git clone git://github.com/nathanmarz/storm-starter.git
$ cd storm-starter/
$ brew install leiningen
$ lein deps
$ lein compile
```

+ 実際、動かしてみます

```
$ java -cp $(lein classpath) storm.starter.ExclamationTopology

...(snip)

4158 [Thread-26-word] INFO  backtype.storm.daemon.task - Emitting: word default [bertels]
4159 [Thread-16-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:7, stream: default, id: {}, [bertels]
4160 [Thread-16-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [bertels!!!]
4160 [Thread-24-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:2, stream: default, id: {}, [bertels!!!]
4160 [Thread-24-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [bertels!!!!!!]
4162 [Thread-28-word] INFO  backtype.storm.daemon.task - Emitting: word default [golda]
4162 [Thread-16-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:8, stream: default, id: {}, [golda]
4163 [Thread-16-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [golda!!!]
4163 [Thread-22-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:2, stream: default, id: {}, [golda!!!]
4163 [Thread-22-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [golda!!!!!!]
4168 [Thread-30-word] INFO  backtype.storm.daemon.task - Emitting: word default [golda]
4168 [Thread-16-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:9, stream: default, id: {}, [golda]
4168 [Thread-16-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [golda!!!]
4169 [Thread-24-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:2, stream: default, id: {}, [golda!!!]
4169 [Thread-24-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [golda!!!!!!]
4175 [Thread-32-word] INFO  backtype.storm.daemon.task - Emitting: word default [mike]
4175 [Thread-20-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:10, stream: default, id: {}, [mike]
4175 [Thread-20-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [mike!!!]
4176 [Thread-24-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:4, stream: default, id: {}, [mike!!!]
4176 [Thread-24-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [mike!!!!!!]
4181 [Thread-34-word] INFO  backtype.storm.daemon.task - Emitting: word default [golda]
4181 [Thread-18-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:11, stream: default, id: {}, [golda]
4181 [Thread-18-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [golda!!!]
4181 [Thread-22-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:3, stream: default, id: {}, [golda!!!]
4181 [Thread-22-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [golda!!!!!!]
4184 [Thread-36-word] INFO  backtype.storm.daemon.task - Emitting: word default [mike]
4184 [Thread-18-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:12, stream: default, id: {}, [mike]
4184 [Thread-18-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [mike!!!]
4185 [Thread-24-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:3, stream: default, id: {}, [mike!!!]
4185 [Thread-24-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [mike!!!!!!]
4191 [Thread-38-word] INFO  backtype.storm.daemon.task - Emitting: word default [nathan]
4192 [Thread-18-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:13, stream: default, id: {}, [nathan]
4192 [Thread-18-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [nathan!!!]
4192 [Thread-22-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:3, stream: default, id: {}, [nathan!!!]
4192 [Thread-22-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [nathan!!!!!!]
4197 [Thread-40-word] INFO  backtype.storm.daemon.task - Emitting: word default [jackson]
4197 [Thread-42-word] INFO  backtype.storm.daemon.task - Emitting: word default [bertels]
4198 [Thread-18-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:14, stream: default, id: {}, [jackson]
4198 [Thread-18-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [jackson!!!]
4198 [Thread-18-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:15, stream: default, id: {}, [bertels]
4198 [Thread-18-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [bertels!!!]
4198 [Thread-24-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:3, stream: default, id: {}, [jackson!!!]
4198 [Thread-24-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [jackson!!!!!!]
4199 [Thread-22-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:3, stream: default, id: {}, [bertels!!!]
4199 [Thread-22-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [bertels!!!!!!]
4204 [Thread-44-word] INFO  backtype.storm.daemon.task - Emitting: word default [golda]
4204 [Thread-16-exclaim1] INFO  backtype.storm.daemon.executor - Processing received message source: word:16, stream: default, id: {}, [golda]
4205 [Thread-16-exclaim1] INFO  backtype.storm.daemon.task - Emitting: exclaim1 default [golda!!!]
4205 [Thread-22-exclaim2] INFO  backtype.storm.daemon.executor - Processing received message source: exclaim1:2, stream: default, id: {}, [golda!!!]
4205 [Thread-22-exclaim2] INFO  backtype.storm.daemon.task - Emitting: exclaim2 default [golda!!!!!!]
4264 [Thread-26-word] INFO  backtype.storm.daemon.task - Emitting: word default [jackson]
4264 [Thread-28-word] INFO  backtype.storm.daemon.task - Emitting: word default [jackson]

...(snip)
```
ここでのストリーム処理動作の解説は、こちらの記事が参考になると思います。
「[とりあえずStormをローカルモードで動かしてみた。- wyukawa’s blog]
(http://d.hatena.ne.jp/wyukawa/20130310/1362907874)」

なお、Spout"TestWordSpout"のコード自体は、[Githubリポジトリ"apache/storm"](https://github.com/apache/storm/blob/master/storm-core/src/jvm/org/apache/storm/testing/TestWordSpout.java)で確認することができます。

```java:TestWordSpout.java
    public void nextTuple() {
        Utils.sleep(100);
        final String[] words = new String[] {"nathan", "mike", "jackson", "golda", "bertels"};
        final Random rand = new Random();
        final String word = words[rand.nextInt(words.length)];
        _collector.emit(new Values(word));
    }
```


以上より、<b>word(TestWordSpout) → exclaim1(ExclamationBolt) → exclaim2(ExclamationBolt)</b>とストリーム処理として、<b>"nathan” → ”nathan!!!” → ”nathan!!!!!!"</b>のように動作している様子が確認できました。

#◼︎ "ExclamationTopology"をリモートモードで試してみる
引き続き、storm-starterを用いて、Topologyをリモートモードで動作させてみます。

リモートモードとは。。。

> 「リモートモード（Remote Mode）」は、異なるマシン上で実行されている複数のプロセスで構成されるトポロジーを、Stormクラスタとして動作させる。リモートモードではデバッグ情報が表示されないため、「本番モード（Production Mode）」とも言われる。ただし、Stormクラスタを単一の開発マシン上で作成することも可能だ。トポロジーの実行に問題がないか確認できるため、本番に移行する前に試してみるのもよい。

抜粋：: Jonathan Leibiusky, Gabriel Eisbruch, Dario Simonassi  “Stormをはじめよう”。 iBooks  

+ まずは、環境セットアップから、、、

```
$ brew install maven
$ mvn -version
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T20:57:37+09:00)
Maven home: /usr/local/Cellar/maven/3.3.3/libexec
Java version: 1.8.0_66, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.11.3", arch: "x86_64", family: "mac"

$ mvn -f m2-pom.xml package

$ ls -l target/
total 5800
drwxr-xr-x   2 ttsubo  staff       68  2 13 17:04 archive-tmp
drwxr-xr-x   6 ttsubo  staff      204  2 13 17:03 classes
drwxr-xr-x   3 ttsubo  staff      102  2 13 17:03 generated-sources
drwxr-xr-x   3 ttsubo  staff      102  2 13 17:04 generated-test-sources
drwxr-xr-x   3 ttsubo  staff      102  2 13 17:04 maven-archiver
drwxr-xr-x   3 ttsubo  staff      102  2 13 17:03 maven-status
drwxr-xr-x   3 ttsubo  staff      102  2 13 16:57 stale
-rw-r--r--   1 ttsubo  staff  2840715  2 13 17:04 storm-starter-0.0.1-SNAPSHOT-jar-with-dependencies.jar
-rw-r--r--   1 ttsubo  staff   123716  2 13 17:04 storm-starter-0.0.1-SNAPSHOT.jar
drwxr-xr-x  20 ttsubo  staff      680  2 13 17:04 surefire-reports
drwxr-xr-x   3 ttsubo  staff      102  2 13 17:04 test-classes

```

+ 実際に、動かしてみます

リモートモードで動作させる場合には、引数部分に、トポロジ名を入力します。

```text:stormコマンド
$ storm jar [jarファイル] [メインクラス] (引数…)
```
今回は、トポロジ名として、"testTopology"としてTopogyを動作させました。

```
$ storm jar target/storm-starter-0.0.1-SNAPSHOT.jar storm.starter.ExclamationTopology testTopology
Running: java -client -Ddaemon.name= -Dstorm.options= -Dstorm.home=/usr/local/apache-storm-0.10.0 -Dstorm.log.dir=/usr/local/apache-storm-0.10.0/logs -Djava.library.path=/usr/local/lib:/opt/local/lib:/usr/lib -Dstorm.conf.file= -cp /usr/local/apache-storm-0.10.0/lib/asm-4.0.jar:/usr/local/apache-storm-0.10.0/lib/clojure-1.6.0.jar:/usr/local/apache-storm-0.10.0/lib/disruptor-2.10.4.jar:/usr/local/apache-storm-0.10.0/lib/hadoop-auth-2.4.0.jar:/usr/local/apache-storm-0.10.0/lib/kryo-2.21.jar:/usr/local/apache-storm-0.10.0/lib/log4j-api-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-core-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-over-slf4j-1.6.6.jar:/usr/local/apache-storm-0.10.0/lib/log4j-slf4j-impl-2.1.jar:/usr/local/apache-storm-0.10.0/lib/minlog-1.2.jar:/usr/local/apache-storm-0.10.0/lib/reflectasm-1.07-shaded.jar:/usr/local/apache-storm-0.10.0/lib/servlet-api-2.5.jar:/usr/local/apache-storm-0.10.0/lib/slf4j-api-1.7.7.jar:/usr/local/apache-storm-0.10.0/lib/storm-core-0.10.0.jar:target/storm-starter-0.0.1-SNAPSHOT.jar:/usr/local/storm/conf:/usr/local/apache-storm-0.10.0/bin -Dstorm.jar=target/storm-starter-0.0.1-SNAPSHOT.jar storm.starter.ExclamationTopology testTopology
342  [main] INFO  b.s.u.Utils - Using defaults.yaml from resources
398  [main] INFO  b.s.u.Utils - Using storm.yaml from resources
423  [main] INFO  b.s.u.Utils - Using defaults.yaml from resources
438  [main] INFO  b.s.u.Utils - Using storm.yaml from resources
441  [main] INFO  b.s.StormSubmitter - Generated ZooKeeper secret payload for MD5-digest: -6940210794385617701:-9088493929288438785
442  [main] INFO  b.s.s.a.AuthUtils - Got AutoCreds []
452  [main] INFO  b.s.u.StormBoundedExponentialBackoffRetry - The baseSleepTimeMs [2000] the maxSleepTimeMs [60000] the maxRetries [5]
462  [main] INFO  b.s.u.StormBoundedExponentialBackoffRetry - The baseSleepTimeMs [2000] the maxSleepTimeMs [60000] the maxRetries [5]
472  [main] INFO  b.s.u.StormBoundedExponentialBackoffRetry - The baseSleepTimeMs [2000] the maxSleepTimeMs [60000] the maxRetries [5]
486  [main] INFO  b.s.StormSubmitter - Uploading topology jar target/storm-starter-0.0.1-SNAPSHOT.jar to assigned location: /usr/local/storm/nimbus/inbox/stormjar-399db7b8-8d11-466e-a73e-a7b8afa17469.jar
503  [main] INFO  b.s.StormSubmitter - Successfully uploaded topology jar to assigned location: /usr/local/storm/nimbus/inbox/stormjar-399db7b8-8d11-466e-a73e-a7b8afa17469.jar
503  [main] INFO  b.s.StormSubmitter - Submitting topology testTopology in distributed mode with conf {"storm.zookeeper.topology.auth.scheme":"digest","storm.zookeeper.topology.auth.payload":"-6940210794385617701:-9088493929288438785","topology.workers":3,"topology.debug":true}
573  [main] INFO  b.s.StormSubmitter - Finished submitting topology: testTopology
```
ちなみに、"ExclamationTopology.java"を確認してところ、引数を指定しないと、ローカルモードとして動作し、引数を指定すると、リモートモードで動作する実装になっておりました。
[StormSubmitter (Storm 0.10.0-SNAPSHOT API)](https://storm.apache.org/javadoc/apidocs/backtype/storm/StormSubmitter.html)

```java:ExclamationTopology.java
  public static void main(String[] args) throws Exception {
    TopologyBuilder builder = new TopologyBuilder();

    builder.setSpout("word", new TestWordSpout(), 10);
    builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");
    builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");

    Config conf = new Config();
    conf.setDebug(true);

    if (args != null && args.length > 0) {
      conf.setNumWorkers(3);

      StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
    }
    else {

      LocalCluster cluster = new LocalCluster();
      cluster.submitTopology("test", conf, builder.createTopology());
      Utils.sleep(10000);
      cluster.killTopology("test");
      cluster.shutdown();
    }
  }
```

#◼︎ 再度、Storm UI画面を確認してみる
Storm UI画面にて、Storm動作環境を確認してみます。
今回は、"Topology Summary"欄に、<b>"testTopology"</b>の情報が表示されるようになりました。
![storm_ui.png](https://qiita-image-store.s3.amazonaws.com/0/103595/184a42f7-47a8-1cac-dae5-fa54d3046b5a.png)

さらに、"testTopology"のサマリ情報として、Spout, boltでのデータ転送量なども確認できるようになりました。
![topology_summary.png](https://qiita-image-store.s3.amazonaws.com/0/103595/805ba945-b1ad-f6bb-306e-87082e06a0b7.png)

さらに、<b>word(TestWordSpout) → exclaim1(ExclamationBolt) → exclaim2(ExclamationBolt)</b>とストリーム処理の様子も、ビジュアルに確認できるようになりました。
![Topology Visualization.png](https://qiita-image-store.s3.amazonaws.com/0/103595/11eab1f3-e98e-f497-1b51-30f33b7be683.png)



最後に、リモートモードで動作中の、"testTopology"トポロジを停止させます。

```
$ storm kill testTopology
Running: java -client -Ddaemon.name= -Dstorm.options= -Dstorm.home=/usr/local/apache-storm-0.10.0 -Dstorm.log.dir=/usr/local/apache-storm-0.10.0/logs -Djava.library.path=/usr/local/lib:/opt/local/lib:/usr/lib -Dstorm.conf.file= -cp /usr/local/apache-storm-0.10.0/lib/asm-4.0.jar:/usr/local/apache-storm-0.10.0/lib/clojure-1.6.0.jar:/usr/local/apache-storm-0.10.0/lib/disruptor-2.10.4.jar:/usr/local/apache-storm-0.10.0/lib/hadoop-auth-2.4.0.jar:/usr/local/apache-storm-0.10.0/lib/kryo-2.21.jar:/usr/local/apache-storm-0.10.0/lib/log4j-api-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-core-2.1.jar:/usr/local/apache-storm-0.10.0/lib/log4j-over-slf4j-1.6.6.jar:/usr/local/apache-storm-0.10.0/lib/log4j-slf4j-impl-2.1.jar:/usr/local/apache-storm-0.10.0/lib/minlog-1.2.jar:/usr/local/apache-storm-0.10.0/lib/reflectasm-1.07-shaded.jar:/usr/local/apache-storm-0.10.0/lib/servlet-api-2.5.jar:/usr/local/apache-storm-0.10.0/lib/slf4j-api-1.7.7.jar:/usr/local/apache-storm-0.10.0/lib/storm-core-0.10.0.jar:/usr/local/storm/conf:/usr/local/apache-storm-0.10.0/bin backtype.storm.command.kill_topology testTopology
1086 [main] INFO  b.s.u.Utils - Using defaults.yaml from resources
1145 [main] INFO  b.s.u.Utils - Using storm.yaml from resources
1555 [main] INFO  b.s.u.Utils - Using defaults.yaml from resources
1562 [main] INFO  b.s.u.Utils - Using storm.yaml from resources
1571 [main] INFO  b.s.thrift - Connecting to Nimbus at 127.0.0.1:6627 as user: 
1571 [main] INFO  b.s.u.Utils - Using defaults.yaml from resources
1578 [main] INFO  b.s.u.Utils - Using storm.yaml from resources
1596 [main] INFO  b.s.u.StormBoundedExponentialBackoffRetry - The baseSleepTimeMs [2000] the maxSleepTimeMs [60000] the maxRetries [5]
1629 [main] INFO  b.s.c.kill-topology - Killed topology: testTopology
```

#◼︎ 終わりに
Apache Stormとは、2011年にTwitterがOSS化した耐障害性を持つリアルタイム分散ストリーム基盤とのことなので、最近のBigData分野での活用技術としては枯れた技術に分類される気がします。
その割には、storm関連の書籍を、巷で見かけることはありません。storm自体、マルチランゲージに対応していたり、ストリーム処理基盤としての長年の実績があると思うので、もう少し、ベストプラクティスなどの活用事例が広く浸透しても良いのかなと思いました。

#◼︎ 参照元
+ [Stormをはじめよう](http://www.oreilly.co.jp/books/9784873116013/)
+ [twitterが発表したリアルタイム分散処理フレームワークStorm](http://tjun.org/2011/10/storm_intro/)
+ [Apache storm チュートリアルの和訳](http://akashik.hateblo.jp/entry/2015/03/25/004419)
+ [とりあえずStormをローカルモードで動かしてみた。- wyukawa’s blog]
(http://d.hatena.ne.jp/wyukawa/20130310/1362907874)