何とか乗り切った話です。乗り切るまでの過程も忘れないように覚え書きします。GB単位のデータセットを加工→ファイルダンプするシチュエーションをイメージしてください。使って以下のような考え方で機能実現を試みました。1プロセスのNode.jsバッチアプリケーションで処理する。用いて一括でファイルに書き出す。以下サンプルコードです。}}上記の方法で実行してみると、データセットが500万件を超えたあたりで以下のようなエラーが出るようなりました。これはNode.jsのヒープサイズ上限を超えたオブジェクトを保持すると発生するエラーです。元のデータセットと一緒に加工後のデータも全て保持して倍以上のヒープを消費したことが原因でした。Memoryで落ちることあるのですよ。Memoryで死んだのは、ヒープサイズ上限を超えたオブジェクトを保持したからでした。つけて実行することでヒープサイズの上限を引き上げて解決できます。Node.jsのコアであるV8エンジンのヒープサイズ上限は元々1.7GBとそこそこ大きいサイズを持っていますが、それでも足りない場合の対処方法です。stackoverflow.comですが、自分の場合はプラットフォームの制約から安易にヒープサイズを上げることができなかったのでこの方法は断念。スケールアウト(複数のプロセスで実行)の道が閉ざされてしまったので、アプリの処理をヒープサイズを消費しない省エネな作りに変えて対応することにしました。StreamはNode.jsの標準ライブラリに含まれています。入力のオブジェクトをStreamに読み込むと、Stream内部で持っているバッファに読み込んだ要素を順次溜めていき、閾値まで溜めたらアウトプットにまとめて書き出すことができます。書き込み用のStreamが用意されているため、少しずつ読み込み→加工→書き出しとStreamをつなげることでヒープサイズが枯渇しないようなETLの実装が可能です。今回のユースケースにはピッタリです。最終的には大量データの書き出しは以下のコードで解決できました。chunkをObjectで受け取る。Buffer型を期待するため、TYPE_ERRORで例外を投げる。Transformerを3種類を活用しています。書き込みでそれぞれ責務を分割しながらヒープサイズの消費を押さえて大量データをETLできます。それぞれのStreamはInterfaceとして提供されているので、カスタムのStreamを実装も可能です。上記のコードだとデータセットを加工するTransformクラスを継承したStreamクラスを作成しています。Streamは普段使わないと正体が掴めない代物です。避けて通ってみたものの、触ってみると案外使いやすい便利な標準ライブラリでした。Streamがヒープサイズの消費を押さえた省エネな作りをしていたとしても、OOMを回避できない場面が出てきます。一度に大量のオブジェクトを作ってしまったらStreamに流し込む前にヒープサイズが枯渇してしまいます。実際に数百MB以上のデータセットを扱ったときは、100万件程度でデータセットを分割して加工→ダンプ(追記)する方法とStreamで少しずつ流し込む方法の両方を採用していました。ETLサービスを使って実現したいですね。今回は自分にしては珍しいPythonの読書記事です。今年の年末エントリーです。月別アーカイブはてなブログをはじめよう!accelerkさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。