AWS SQSの代替として使える elasticmq の公式dockerイメージでqueueを起動時に作る方法

elasticmqの公式dockerイメージでqueueを起動時に作成する方法を紹介します。 動作は、softwaremill/elasticmq:0.15.7で確認しました。

TL;DR

  • 環境変数JAVA_OPTSに "-Dconfig.override_with_env_vars=true" を追加する
  • CONFIG_FORCE_queues<your-queue-name>fifoに "false" を設定する
    • fifoじゃなくても良いけど、振る舞いに影響を与えないような設定としてfifoをfalseに設定しています。

以下はCircleCIの設定例です。

      - image: softwaremill/elasticmq:0.15.7
        environment:
          JAVA_OPTS: "-Dconfig.override_with_env_vars=true"
          CONFIG_FORCE_queues_queue1_fifo: false

なぜこれが動くのか

elasticmqは設定ファイルとして、typesafe configを使っています。 そのため、System propertiesとして、config.override_with_env_vars=trueを渡すと 環境変数で設定を上書き出来るようになります。 また環境変数は以下のルールで変形された後、設定名として使われます。

  • CONFIG_FORCE_ を取り除く
  • 単一の アンダースコア _ を ドット . に置き換える
  • 2連続の アンダースコア __ダッシュ - に置き換える
  • 3連続の アンダースコア ___ を 単一のアンダースコア _ に置き換える

今回は、queues.<queue-name>がobjectである必要があるので queues.<queue-name>からネストした値である fifo に値を与えることで queues.<queue-name> を objectになるように設定します。

そのため、環境変数としては、CONFIG_FORCE_queues<queue-name>fifoにfalse を設定することで 起動時にqueueが作成されることになります。

終わり

goでJavaのクラスファイルのパーサを書いた

そういえば、書いたことがないなぁと思って、Javaのクラスファイルのパーサを書きました。 Java SE 15のJVM Specification だけを見ながら フルスペックのクラスファイルのパーサを書きました。

書いたけど、パース出来るだけで pretty printが出来たり、なんかいい感じのAPIが生えてたりするわけではないです。

元々、emc(enhanced memory calculator) のために tinycedar/classp の フォークである wreulicke/go-java-class-parser を弄っていましたが メモリ計算のためのツールのために実装したので、フルスペックのパーサではなく、必要な部分しか実装していません。

実装の流れとしては、class File Format の項を上から読みながら実装していきました。 ハマったところは何個かあって、以下のようなところでハマりました。

  • Long/DoubleのConstantはなぜかConstantPoolのindexを1つ先にずらすこと
  • LineNumberTable attributeの場合になぜか、attributeLengthとlineNumberTableLengthから計算できる消費するバイト数が一致しないこと
  • uint8のところをuint16で読み取りしていて、位置がズレてデバッグが大変
  • パースする処理を単純に飛ばしてしまっていて、これまた位置がずれて大変

実装に掛かった時間としては、色々やりながら、大体2日で終わりました。 まだちょっと直せる部分とかはあるのと、APIとしては弱いので もう少し弄ろうと思います。

たぶん、これから互換性が失われるところがいくつか出ると思います。 終わり。

コードはここに置いてあります。

Javaでcloud profilerを使ってpprofフォーマットのプロファイルデータをローカルに出力する

cloud profilerにはローカルに、pb.gzフォーマットでプロファイルデータを出力する機能がある。 このファイルは、pprofのprotocol bufferをgzip圧縮したものだ。

やり方は以下のような形でagentに -cprof_profile_filename パラメータを渡して下さい。パラメータを渡さない場合、GCPにプロファイル結果を投げようとします。

$ java -agentpath:./cprof/profiler_java_agent.so=-cprof_profile_filename=./prof_ test &
$ ls
prof_cpu_1601995223.pb.gz  prof_cpu_1601995253.pb.gz  prof_wall_1601995160.pb.gz  prof_wall_1601995233.pb.gz  prof_wall_1601995243.pb.gz test.class  test.java

ちなみに自分が作ったエンドポイントに投げるような機能は存在せず、ローカルに吐くか GCPのほうに投げるかのどちらかになっている。 出てきたプロファイルデータはpprofを使って見て下さい。

pprof -http=: ./prof_cpu_1601995223.pb.gz

ちなみに、ローカルにプロファイルデータを吐く場合 この辺がパラメータとして弄れるようです。