ソモサン

私rohkiによる活動や読書の記録をつらつらと書くページです

Scala で Array 等を制限に合わせて分割する

短く

grouped(size) を使いましょう

背景

ScalaAWS Kinesis へ PutRecords しようとしたときに、上限に引っ掛かりました。
で今回抵触した上限というのが、PutRecords 1 回あたりに含められるレコード数で、500 までとのこと。*1
なので 500 毎に分割して PutRecords したいわけだけど、分割…あるはずだよなーと探して見つかりました。

方法

(1 to 10000)
  .grouped(500) // これ
  .foreach(put)

たったこれだけです。
ただまぁ自前で作ると脳みその裏側でいろいろ考えたりするわけですよ。
そも動くようにするところから始まり、速度とか、オブジェクト生成の回数とか、いろんな Collections への対応とか。
あるなら使うがベストです。こんなの絶対にあるはずですし

おわりに

名前がよくない!(理不尽)
splitAt は違うしなぁとかで引っかかってました。
sliding まで行きついてコード書いた後に、あれよく見たら grouped あるやん、でやっとこさ到達しました。
Rust では chunk で、そうか chunk というワードがあったか、という感じ。検索のための語彙が増えました。

Prometheus + Grafana + Elasticsearch + Kibana を Docker でいじり中

prometheus.io

いじってます。

進捗

docker-compose.yml はこんな感じ

version: '3'
services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - .\prometheus.yml:/var/app/prometheus/prometheus.yml
    command:
      - '--config.file=/var/app/prometheus/prometheus.yml'
    ports:
      - 9090:9090
    depends_on:
      - elasticsearch_exporter
    links:
      - elasticsearch_exporter
  grafana:
    image: grafana/grafana
    container_name: grafana
    ports:
      - 3000:3000
    env_file:
      - /prom/grafana.env
  elasticsearch_exporter:
      image: justwatch/elasticsearch_exporter:1.0.2
      command:
        - '-es.uri=http://elasticsearch:9200'
      restart: always
      ports:
        - 9108:9108
      depends_on:
        - elasticsearch
      links:
        - elasticsearch
  elasticsearch:
    image: elasticsearch
    ports: 
      - 9200:9200
  kibana:
    image: kibana
    ports:
      - 5601:5601
    depends_on:
      - elasticsearch

prometheus.yml

global:
  scrape_interval:     15s 
  evaluation_interval: 15s 
  external_labels:
      monitor: 'codelab-monitor'

rule_files:
#   - "/var/app/prometheus/alert.rules"

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: 
          - '127.0.0.1:9090'
  - job_name: 'elasticsearch-exporter'
    static_configs:
      - targets:
          - 'elasticsearch_exporter:9108'

Prometheus + Grafana を Mac 上で docker-compose で起動 - Qiita

上記の記事をベースに、Elasticsearch + Kibana を追加して、Elasticsearch 用の Exporter も入れました。
Docker でのアドレス解決がわからなかったので、そこはこちらを読みながらなるほどー、と書いてみました。
Windows でやったので、一部ファイルがおかしいかも…

メトリクス周りを前から調べていて、Graphite や Influx、Mackerel もさわったし、はやりの Prometheus もやってみよう、という感じ。
去年の 2.0 出たときにいじりたかったけど、まぁほかに触るものがあれやこれやそれやあり遅れました。

Elasticsearch で GC に関連した値もとれるってのが個人的には気になってます。exporter よいなー。
一方で、いろいろ手広くやりすぎててまずいです。*1
ここのところ毎年いってるけど来年度は絞る。

*1:僕のせいだけではない

elastic4s の json ライブラリ切り替えの実装にちょっと感動してる話

いつかの続き

GitHub - sksamuel/elastic4s: Elasticsearch Scala Client - Non Blocking, Type Safe, HTTP, REST API, TCP

リポジトリ上記

elastic4s/package.scala at master · sksamuel/elastic4s · GitHub

で、件のコードがこの辺り。ひっじょうに薄くて、なんと 1 ファイルだけだったりします。
以前フォーマッター切り替えについて考えた記事を書きましたが、さらに先にある実現方法がこれか! と感動しております。
そうだよなー。中間の型クラス作って、委譲すればできるよな。

Kinesis Firehose のデータ変換 Lambda を Golang で作って計測してみた

概要

前回 やるといってたやつです。
AWS Lambda が Golang を公式サポートしたので、これまでやってきたのと同じような Lambda を作って計測してみました。

先に結果だけ書くと、

  • Rust: 55.8 k レコードを 23.4 秒で処理
    => 1 秒あたり約 2384.6 レコードを処理
  • Python: 56.7 k レコードを 397 秒で処理
    => 1 秒あたり約 142.8 レコードを処理
  • Golang: 52.4k レコードを 13.4 秒で処理
    => 1 秒あたり約 3910.4 レコードを処理

表にするとこんな感じ。

Runtime record/s
Python 142.8
Rust 2348.6
Golang 3910.0

すごい。

仮説

当初立てていた仮説では、Rust とそんなに差はでないかな、と考えていました。
というのも、風の噂でGolang の正規表現は遅い場合があると聞いていたので、ネイティブで動くにしてもそのあたりで差が詰まってトントンという見込みでした。

実装

github.com

実装が上です。これまで同様、 Apache のログを JSON に変換する Lambda です。
AWS CodeStar で作った Web サービス用のものをゴリゴリ書き換えました。

Golang は初めて書きましたが、あんまり違和感なくいけました。
C 書いてましたし、error まわりも Rust の Result と似たような意図を感じたので、そのまま書きました。
ただ、ただ日付には戸惑いました… わかるか!!
そんな僕を助けてくれた記事です。3年以上前…

Goのtimeパッケージのリファレンスタイム(2006年1月2日)は何の日? - Qiita

測定(おさらい)

Lambda の環境

  • Runtime: Go 1.x
  • メモリ: 128 MB
  • 実行時間上限: 5分

Runtime は Go、残り2つは前回と同様です。

指標

  • ExecuteProcessing.Duration: 変換 Lambda の実行時間
  • SucceedProcessing.Records: 変換 Lambda が正常に変換できたレコード数

こちらも前回同様です。
正常に変換できたレコード数を、どれだけの実行時間でさばいたかで測ります。

結果

f:id:rohki:20180218191207p:plain

52.4k レコードを 13.4 秒で処理してます。
ので結果として、1 秒あたり約 3910.4 レコードを処理 した、ってことがわかりました。めっちゃ速いな!

予備計測

上の実装では json-iterator という速い package を使っていたためだきっとそうだ、ということで、JSON へのエンコードを標準の encoding/json でも行いました。
その結果がこちら。

f:id:rohki:20180218192010p:plain

56.2k レコードを 15.8 秒で処理してます。
1 秒あたり約 3557.0 レコードを処理 てことでやっぱり速い!

まとめ

仮説は外れ、Golang は速かったです。
くやしい… Rust の正式対応こい!

API Gateway の Kinesis Proxy で追跡性をちょこっと上げてみる

結論

本文マッピングテンプレートを以下のようにします

#set($inputRoot = $input.path('$'))
#define ($data){"requestId": "$context.requestId","data": "$inputRoot"}#end
{
    "StreamName": "STREAM_NAME",
    "Data": "$util.base64Encode($data)",
    "PartitionKey": "KEY"
}

これでリクエストの ID がとれ、後の処理の追跡がしやすくなる…はず?
設計に応じて、ステージ名とかパスとか入れるとよさそうです。

参考にさせてもらったところ

Amazon Kinesis プロキシとして API Gateway API を作成する - Amazon API Gateway

API Gatewayへの入力値にLambdaからアクセスする - Qiita

蛇足1: ちょっとめんどくさかった Json 文字列の作成

Kinesis Proxy の DataBase64エンコードされてる必要があります。よって、先に JSON 文字列を作ってやる必要がありました。
が、このやり方がひたすら謎で迷走してました。Velocity Template Language てなんやねん…
結局は #define でできました。

Apache Velocity Engine VTL Reference

ほかに試したこと

  • #set ($data = ...) でいれてみる
    -> ダブルクォート なしのやつが出来上がる
  • さらに $data.json() とかしてみる
    -> 空文字が返ってくる
  • #set ($data = ...) の際に '"" をエスケープして追加してみる
    -> いんたーなるさーばーえらー

蛇足2:本当は X-Ray の Trace Id がほしかった

API Gateway からの応答には入っていたので、$input.param('X-Amzn-Trace-Id') と書けばとれたりするかなー、と思ったりしましたがだめでした。
これが取れると X-Ray での描画ができてさらに便利になるやん、と期待してたりしました。

参考: Amazon API Gateway および AWS X-Ray - AWS X-Ray

CodeStar で AWS Lambda + Golang の雛形をサクッと作成してみた

前回 Golang サポートしたらやってみるといってたので、まずは雛形作成と調査だけ。Golang しっかり書いたことないですし。

CodeStar で雛形作成

AWS Lambda Supports Go をよむと CodeStar に対応しているぜー とかいてあったので、そちらで作りました。

f:id:rohki:20180116211837p:plain

github.com

物としては、API Gateway 経由で起動して、ローカルファイルを読み込んで返す Lambda でした。
仕組みについてはこちらをありがたく読ませていただきました。

CodeStar のよかったところ: クロスコンパイラ環境の準備と設定ができてる

CodeStar の利点としてはビルドやデプロイの設定がしてあることですね。とくにクロスコンパイラ環境。
家に帰る途中で調査の段取り考えてた時に、ビルド環境の準備面倒そうだなーとか思ってたので。
実際は $ GOOS=linux GOARCH=amd64 で行けるので手間でない模様。

雑感

バイナリサイズ: 2.4 MB

このぐらいのサイズにはなりますよね。

cold 状態からの起動による遅延: 感じられず

おそらく数ミリ秒

つづく

こちら にて紹介いただいていた sdkFirehose のイベント定義 もありました。
書くぞー計測するぞー

Kinesis Firehose のデータ変換を Rust でやってみて速度向上が見込めた話

概要

Rust コードを Lambda 上で動かせたーと喜んだんですが、活用どころあるんだろうかと考えてみて検証してみました。
結果として Python 比較で1秒当たりで 15 倍ほど多く処理できました。
以下でつらつらと書いていってます。

続きを読む