※当サイトの記事には、広告・プロモーションが含まれます。

REST APIのレスポンス作成でOOEM(OutOfMemoryError)は簡単に起こり得るという話

gigazine.net

⇧「XZ Utils」の問題は、偶然発見された感じだったような気がするから、コミュニティの健全性は関係ない気はしますが、影響範囲が大きい機能については、AIとかで自動的に脆弱性の検知をしてソースコードに反映できないようにとかして欲しいですな。

REST APIのレスポンス作成でOOEM(OutOfMemoryError)は簡単に起こり得るという話

画面とかであれば、ページング機能を実装して、一度に大量のデータをレスポンスに持たせないようにするなどができるんだけど、疎結合になっているシステム間で、Rest APIで処理のリクエストを送り、別システムで大量の処理を行った後に、その結果を全て返すような感じの実装をしてしまうと、簡単にOutOfMemoryErrorが起こりそうだなと。

そもそも、データベースからデータを取得する際に、取得する件数の制限を設けておかないとデータ量によってOutOfMemoryErrorになってしまうことが有り得ますな...

ちなみに、

symfoware.blog.fc2.com

-Xmx10mのオプションをつけて、使用するメモリを10MBに制限して実行し、
何個Listに突っ込めるか試してみました。

Javaで大量データをメモリに展開するテクニックの考察 - Symfoware

結果をまとめると、このようになります。
かなり単純なサンプルデータですが、一般的なデータにも同様の傾向が
みられるんじゃないかと思っています。

Javaで大量データをメモリに展開するテクニックの考察 - Symfoware

ちなみに、Mapをバイト配列に変換していますが、

シリアライズのみ:2062byte

シリアライズ + zip:565byte

でした。

Javaで大量データをメモリに展開するテクニックの考察 - Symfoware

⇧上記サイト様によりますと、「Java仮想マシンJVMJava Virtual Machine)」のメモリを極端に制限しているものの、想像以上に簡単にOutOfMemoryErrorになってしまう...

あとは、

qiita.com

2147483648以上も確保するプログラムがあるならば、設計を見直すべきかもなので、例外を投げるのは妥当かもしれない。

【Java】ArrayListのcapacityの増え方 #Java - Qiita

⇧ とあるので、どちらにしろ、限界はあると。

さらに、

lab.mo-t.com

テストデータ登録後に、実験的に1000万件を1回で更新しようとすると、2589秒かかりました。

PostgreSQL大量レコードの更新する作業でやったこと | MoT Lab (GO Inc. Engineering Blog)

⇧ 上記サイト様によりますと、

 2589秒 \div 60秒 = 43.15分

という時間がかかるらしいとのことで、定期実行での処理の場合、処理件数を絞る必要があるっぽいですな。

件数を絞るにせよ、

qiita.com

PostgreSQLのLIMIT句が曲者らしい。

どちらにしろ、Rest APIなどで外部のシステムに処理を委譲して、且つ、委譲先で大量の処理をしているような場合は、

  • 委譲先で処理の結果をログに出力する(エラーについても)
  • 委譲先で処理の結果をデータベースに保存する(エラーについても)
  • エラーが起こったかどうかが分かる情報だけレスポンスで返す

みたいな感じにしておいた方が良さそうではあると。

つまり、変数に大量のデータを格納して、メモリを枯渇させることの無いように気を付ける必要があるってことですな。

Javaに限らず、どんなプログラミング言語でも起こり得るんじゃないかしらね。

まぁ、そもそも、処理を委譲している時点で、移譲先で処理の結果を残したりするべきであるというべきな気もするので、レスポンスで返すのは、

  • 処理の総数
  • エラーの総数

ぐらいで良いということになるんかな?

エラーがあって、詳細を知りたいとなった場合はログやデータベースに保存してる情報を確認すれば良いとは思いますし。

毎度モヤモヤ感が半端ない…

今回はこのへんで。