/home/by-natures/dev*

ソフトウェア開発者としての技術的なメモと、たまに普通の日記。

2019/06/24 PlantUML によるロバストネス図

ユースケース駆動開発の手法を実践しているのですが、ロバストネス図・シーケンス図・ドメインモデルと、とにかく「図」を作ることが多いです。これを簡易にしないと作業効率がとても悪いということで、調べたところ PlantUML というツールがありました。

同じユースケース駆動開発を実践されているかたのブログも見つかりました。この方は vscode を利用されていますが、Atom にも PlantUML 可視化のツールがあったので、Atom でも大丈夫です。UML をコーディングしながらそれがすぐに可視化されて、そこからベクターファイルにも変換できるのでとても便利でした。

tk2000ex.blogspot.com

こちらは PlantUML の公式サイトです。各図の作成方法が詳しく紹介されています。

plantuml.com

私は既存のプロジェクトに対してユースケース駆動開発を当てはめようとしていて、ドメインモデルを構築するのがかなり煩雑で、言わんやクラス図をや・・・といった状態ですが、ロバストネス図までなら適切な工数で適切なアウトプットが出せそうかなと試行錯誤しています。どちらにしてもロバストネス図は必要なので、ひとまずここをターゲットに整理しています。このあたり詳しい方と話がしたい昨今。Twitter でご連絡お待ちしています〜。

2019/06/19 Elastic Beanstalk の ALB の scaling trigger では RequestCount がうまく機能しない

Elastic Beanstalk では ALB を簡単に定義することができます。今構築しているアプリケーションでは、リクエストがシンプルかつ大量であるため、リクエスト数に応じてスケーリングさせようと思い、スケーリングトリガーのメトリクスで RequestCount を設定していました。

ただあまりこの値を利用している例が見つからず、、AutoScalingGroup で直接、RequestCountPerTarget を設定している方はいましたが、RequestCountPerTarget は Elastic Beanstalk の管理画面では設定できません。ひとまずインスタンス化下限を十分大きな値にしてステージング環境で色々と調べたところ、RequestCount は ELB に対する指標で、有効指標が Sum であることから、ロードバランサーにどれだけリクエストが届いているか、という値で、いくらスケーリングしてもこの値は変化することはないようです。この辺りのフォーラムと:

https://forums.aws.amazon.com/thread.jspa?threadID=247542

https://forums.aws.amazon.com/message.jspa?messageID=399607

あとは公式の指標説明のドキュメントが役に立ちます:

docs.aws.amazon.com

そうすると、TargetResponseTime を使うか、NetworkIn/Out を使うかといったところで(CPU 消費するアプリケーションならCPUが良いと思いますが今回はCPUほとんど消費しないアプリケーションなのです)、リクエストがシンプルなので NetworkOut が有効指標になるかなと思っています。まだクラスタ立ち上げたばかりなので多めのインスタンスで立てておいて様子見中です。Beanstalk の公式ドキュメントでは NetworkOut をベースに説明されていて、初期値も NetworkOut の下限2MB上限6MBなので、とりあえずこれを参考にしつつ閾値調整かなぁと思っています。

docs.aws.amazon.com

2019/06/18 AWS ELB 配下の tomcat が X-Forwarded-For を取得できない? -> 解決しました

ロードバランサー配下のWebサーバは、ロードバランサーがもともとのクライアントのリクエスト情報を保持するために X-Forwarded- というHTTPヘッダを追加します。このリクエスト元の情報を保存するヘッダはただのデファクトスタンダードでしたが、今は RFC にもなっているようです。

X-Forwarded-For - Wikipedia

AWS 環境でもこれは同じで、公式サイトや色々なブログでも、ELB配下のWebサーバは X-Forwarded-For を利用してクライアントのIPアドレスを取得できると記載されています。例えば tomcat のアクセスログでは、以下のように変更することでリクエスト元のIPアドレスを取得することができます:

# デフォルトのアクセスログフォーマット
pattern="%h %l %u %t "%r" %s %b"

# X-Forwarded-For などの、リクエスト元の情報を追加したアクセスログフォーマット
pattern="%{X-Forwarded-For}i %{X-Forwarded-Proto}i %h %l %u %t "%r" %s %b"

ここで私がハマった、、というか今でもよくわからないのですが、サーブレット側で X-Forwarded-For を取得しようとすると null が返ってきてしまいました。アクセスログで X-Fowarded-For にクライアントのIPが出力されたところで安心していて、アクセスログで出力している HTTPヘッダがサーブレットで取得できないなんて考えも及びませんでした。。サーブレットでHTTPヘッダを全て出力させましたが、 X-Forwarded-Proto はあるのに X-Forwarded-For が見当たりません。

// これが null になる、アクセスログでは取得できているのに
String clientIP = request.getHeader("X-Forwarded-For");

検索すると同じ問題を質問している AWS スレッドがありました: https://forums.aws.amazon.com/thread.jspa?messageID=260007

かいつまむと、理由はわからないが Tomcat(というかサーブレット) だと request.getRemoteAddr() でリクエスト元のIPアドレスが取得できる・・・ということです。 getRemoteAddr() はネットワーク層のリクエスト元 IP アドレスを返却するようなので、本来であれば EC2 インスタンスの手前にある ELB のIPアドレスになるはずです。上のスレッドに回答は付いていないのですが、手元のAWS環境で試すと、確かに getRemoteAddr() でリクエスト元のIPアドレスが取得できました。

今後 X-Forwarded-For でリクエスト元の IPアドレスが取得でき、 getRemoteAddr() でELBのIPアドレスが返ってこないとも限らないので、 X-Forwarded-For をチェックして null であれば getRemoteAddr() で埋めておくのが無難でしょうか。どなたかこの辺りの事情詳しければぜひ教えてください。

追記

Twitter で先輩から、tomcat の機能でそうなっているのではないか、ということで以下のモジュールを紹介してもらいました:

RemoteIpValve (Apache Tomcat 8.5.42 API Documentation)

このモジュールはクライアントのIPアドレスなどを X-Forwarded- 系のプロトコルの値と置き換えるモジュールで、今回の挙動が説明できます。実際に、Elastic beanstalk 経由で入れた tomcat の server.xml には上記モジュールが設定されていて、内部プロキシのIPアドレスも定義されていました。

<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" internalProxies="10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|169\.254\.\d+\.\d+|127\.\d+\.\d+\.\d+|172\.(1[6-9]|2[0-9]|3[0-1])\.\d+\.\d+" />

2019/06/12 Hive CLI のアーキテクチャ

hive CLI コマンドは非推奨で、今後は beeline 推奨(JDBC/Thrift で HiveServer2 へ接続)とのことですが、どうにも HiveServer2 は運用していて良い思い出がないので(私が利用している環境だと定期的に再起動しないと応答がなくなる。。)、最近あまり状況追っていないのでどうなっているのかなぁと思いつつ、そもそも hive CLI ってどういう風に動いているんだっけ?と思って調べました。

cwiki.apache.org

公式はざっくりした図です。

beeline は HS2 に接続するだけなのでシンプルですが、hive CLI は自分自身で metastore に接続したりクエリパースしたり、ジョブを投げたりしています。ですので hive CLI を動かす環境にも hive-site.xml などクラスタに接続する設定情報が必要になります。

ただ、簡単なクエリ(例えばパーティションに対する SELECT * )を動かすと、MapReduce に変換されずに hive CLI が直接 HDFS にデータを取得しに行っているようです。上の図だと Execution Engine が簡易的なものになるイメージでしょうか。簡単なクエリでも巨大なパーティション群に対してスキャンが掛かると kill したいことがたまにあるのですが、YARN アプリケーションに変換されていないのでやや面倒です。

2019/04/09 Java でのメモリチューニング

メモリチューニングを久々に。前回は OOM でアプリケーションが落ちる問題に対して調査したのですが、今回はマイナーGCが多発していました。

簡単な処理を大量にさばくアプリケーションなので基本的には Eden からすぐにメモリ解放されるオブジェクトばかりなのですが、処理時間は数十msほど、頻度が数分に一度だったので気になって調整を試みました。当たり前といえば当たり前なのですが、Eden 領域を増やすとマイナーGCにかかる時間が増え、頻度が減ります。Eden 領域を減らすと逆のことが起きました。Eden 領域だけが対象になる GC だとアルゴリズム間で大差ないかもしれません。(環境が Java7 だったので G1GC は試していないです)

余談ですが tomcat は <tomcat>/bin/setenv.sh に Java のオプションを追加していました。Java の起動オプションを変更したくて、起動スクリプトや conf/ のしたばかり探してしまって少し手間取りました。 bin/ の下のファイルを書き換えるのはいつも抵抗あります。

以下のブログではコンカレントGCを利用しない場合の各種パラメータの意味や設定例が紹介されています。コンカレントGCを利用すると、いくつかの値のデフォルト値が大きく変わってしまいますので注意。

d.hatena.ne.jp

GCViewer の紹介。簡単に使えました。

qiita.com

CMS

各種オプションの紹介。コンカレントGC を利用した時の各値の変化も記載されていて分かりやすいです。

fomsan.sakura.ne.jp

G1GC

G1GC を簡単に解説しつつ、他の GC のアルゴリズムとの比較も紹介されています。

qiita.com

2019/04/05 ITP 2.1 対応, ElasticBeanstalk での tomcat 設定値書き換え

4月からオフィスが新しくなって、また一緒に働いていた人が退職したこともあり、労働環境が大きく変わりました。やることは増えましたが、やれることも増えそうなので案外楽しめています。開発リソースが足らず、一緒に働く方を増やしたいので色々と整備しているところです。

ITP 2.1

iOS12.2以降で搭載されるSafari 12.1からITP 2.1が導入される ということで、この対応で手を煩わせている方も多いかもしれません。公式アナウンス:

webkit.org

日本語の解説サイト:

webtan.impress.co.jp

サーバ側の対策としては、secure 属性と HttpOnly 属性をつけましょう、ということです。ただし、HttpOnly をつけてしまうと、JavaScript の document.cookie で呼び出せなくなってしまうので注意です。また、secure 属性をつけると、HTTPS での通信時にしかクライアントからサーバへ該当クッキーは送信されません。

逆に捉えると、HTTP での通信では8日以上保存するクッキーはもう取り扱えない、ということなんですかね。HttpOnly なので document.cookie では読めず、サーバから読もうとすると secure なので送信されず、と。

www.marketechlabo.com

kenzo0107.hatenablog.com

Customize Elastic Beanstalk Using Configuration Files

aws.amazon.com

Beanstalk は便利なのですが、環境の値を変えようと思うと結構面倒です。今回は tomcat の web.xml の値を書き換えたかったのですが、 web.xml ファイルが大きくて ebextensions で扱えず、XML を部分的に置換するような形で対応しました。

扱おうと思っているアプリケーションはアクセスが多いので、ネットワークの値もチューニングしたいのですが、ebextensions がどんどん肥大化します。。

network パフォーマンスチューニング

TIME_WAIT でポート食い尽くしそうだったので少しチューニングしました。

https://www.ginnokagi.com/2012/03/tomcat-3.html