ClojureとKinesisの相性が良さそうという話


__Clojureを使うと面倒なKCLアプリケーションが簡単にかけますよ__といったような話をします。


## 1. ClojureとAWS

実はAWSにそこまで詳しいわけではないのですが、AWSのアプリケーションは大体Javaから使用されることが想定されているような気がします。  

もちろん、各言語向けのSDKもありますし、中の人たちも好きにJSやらRubyやら使っているようですが、どうにもJavaのSDKを使ったほうが色々とサポートが手厚いような印象を、Kinesisを試したときに受けました。  

しかしできればJavaは書きたくないものです。
もっというならEclipseも起動したくありません。Emacsが使いたい。  

そう思い、どうしたもんかなあと悩んでいたのですが、そんなときにうってつけの言語があることを思い出しました。  

そうです。Clojureです。  

ClojureはJVMで動くので、Javaの資産が使えます。しかもLispなのでEmacsとの相性が抜群です。  

### Amazonica

しかも、「単にJavaの資産を使えますといっても結局自分で諸々実装しなきゃだし、それどころかClojure公式のSDKもないじゃん」ということにはならず、ちゃんとClojure用にポーティングしてくれているプロジェクトまであります。  

- [Amazonica](https://github.com/mcohen01/amazonica)

※ 残念ながら一部実装が漏れていたりといった部分もあるのですが、そうしたところは自分でごにょごにょすればなんとかなります。幸いにもサンプルになるJavaコードは沢山あるので、それをClojureで何とかするだけです。


## 2. Kinesis

- [Kinesis](http://aws.amazon.com/jp/kinesis/)

AWS Advent Carenderを見てる方々にKinesisの説明をするのはアレだと思うので簡単にですが

Kinesisとは一言で言うなら「Pub/Subモデルの大容量メッセージキューのようなもの」と言えます。

しかし単なるメッセージキューとは、

1. 一度取得したデータを(24時間以内なら)何度でもどこからでも取得できる

2. 順序性が保持されるので何度取得しても同じ順序でとれる

といったようなところで違いがあります。
ハマりどころもいくつかあって、例えば

1. HTTPSの接続を毎度張るので連続的・同期的なデータをコンマ秒単位で送り続けたい、ということに不向き
    - 最近`putRecords`が実装されたようですがまだ試してません

2. PartitionKeyの用途がよくわからない
    - PartitionKeyを元に各Shardにデータが分散されますが、Shardごとの流量に偏りがでても困ります

なんて点で戸惑うこともあります。  

それぞれうまいこと設計すれば良い話ですが、いかんせんKinesisはフルマネージドで動いていてプロセスを監視したりなんだりということができないので、中々面倒なのも事実です。  
そして話が面倒になるので、Fluentdと何が違うんだ、Kafkaとはどうなんだ、とか結局のところどう使うんだ、という点は今回は触れません。  


### KCL

Kinesisの使用においては、基本的にKinesisの活用にはデータを投げる側のPublisherと、データを取得する側のSubscriberの実装を自分でする必要があります。  

ここで、Publisher側はそんなに問題になりません。

データを`putRecord`するだけなので特に問題になるところはありませんし、データはKinesisがうまいこと受けてくれるので安心です。Web上にサンプルもごろごろあります。  

問題はSubscriber側です。こっちは少しやっかいです。  

普通にRubyなどのSDKを使っている場合、自分でShardの数をとったり、イテレータをgetしたりと思いの外やることが多くなります。

そしてどこまでデータを取得したかの管理だとか、障害時のリカバリーはどうしようだとか考え始めると途端に手が止まってしまうのです。  

また、レコードの量が増えて、Shardの数も増えた状態で単純にShardの数だけ同期的にループを回して処理するようなことだと、なんのためにKinesisを使っているのかもわからなくなります。  


そこで役に立つのが[Kinesis Client Library](https://github.com/awslabs/amazon-kinesis-client)です。  

なんと、KCLを使うと今挙げた問題が全て解決されます。

KCLを使用したアプリケーションはShardごとにWorkerインスタンスが立ち上がり別スレッドで動作しますし、特にShardの数なんかは意識せずにアプリケーションを書くことも可能になります。  
Shardを意識しなくて良いということはPartitionKeyとはなんだったんだと一瞬頭によぎりますが、ともかく素晴らしいことです

そんなKinesisを使う上でほぼ必須とも言えるKCLですが、残念ながら現在Javaのみのサポートとなっています。  
スレッド周りだとかプロセスの管理だかが問題なのかわかりませんが、他言語ユーザは指を咥えて見ているしかありません。  

しかしClojureは違うのです。これが言いたかった。  

※for Pythonもあるようですが、[中身は結局Javaとのこと...](http://marcy.hatenablog.com/entry/2014/12/09/030227)  


## 3. ClojureとKCL

KCLを使うとアプリケーションが簡単に書けるようになりますが、Javaという時点でどのファイルのどこに自分のコードを書けば良いかも素人には厳しいものです。  

しかし、`amazonica.aws.kinesis`を使うと話は大変シンプルになります。  

データのput側は今回は割愛させていただくとして、ただ単にSubscriberアプリを作りたい場合は`(:use [amazonica.aws.kinesis])`した上で

```
;; Amazonicaサンプルより
(worker! :app "app-name"
         :stream "my-stream"
         :processor (fn [records]
                      (doseq [row records]
                        (println (:data row)
                                 (:sequence-number row)
                                 (:partition-key row)))))
```

を書くだけです。  
Rubyで書くのも、コンソールからAPI叩くのも、Javaで書くのも、どれも面倒だったKinesisの世界でしたが、Clojureを使うことで一気に身近になった気がしませんか？


注意点としては、__app-name__でKCLアプリケーションとして一意識別してるという点と、取ってくるレコードは__java.nio.ByteBuffer__が使われている前提なので、他の言語なんかでカジュアルに投げたデータを処理しようとするとエラーが起きるてという点です。  
後者はAmazonicaのドキュメントやソースを見れば分かりますが、`:deserializer`の指定を`(worker!)`の中ですれば大丈夫です。


### Kinesis Connector Library

ちなみに、KinesisにはKinesis Connector Libraryなるものがありますが、ようはJavaで一々レコードのオブジェクト作ってどうのは面倒臭いでしょっていう世界の話なので、簡単なものならClojureで自分で実装してもそんなに手間ではありません。  

以前試したときはS3、Elasticsearch向けにコネクタモドキ書きましたが、簡単なものならすぐに書けました。とは言ってもさすがにConnector Libraryの方が汎用的且つ高機能なので誰かが本格的なポーティングをしてくれてももちろん良いと思います。  

最悪投稿できないのを避けるためにもう投稿しちゃいますが、  
後日(か今日中に)そのときのソースコードを探しだして追記するかもしれません。


## 4. まとめ

Clojureを使うとKinesisのアプリケーションが簡単にかけそうな感じがご理解いただけたかと思います。  
Clojureはとても覚えやすい言語ですし、これをきっかけにAWSを使うときはClojureを検討してはいかがでしょうか。