tmpfsを使ったDISK IOの高速化のススメ

これはSupership株式会社の 「データソリューションスタジオ プロダクト開発グループ」における社内勉強会の発表資料を外部公開向けに再編したものになります。

アジェンダ

・tmpfsとは?
 ・tmpfsの良いところ
 ・tmpfsを用いる上で考えるべき点
・tmpfsのベンチマーク
・以上を踏まえて tmpfs が有用と思われるケース
・アプリ向けコンテンツ配信基盤が抱えていた課題とtmpfsの検討と比較
Dockerコンテナ環境下におけるのキャッシュストアの選択肢
・Rails Cacheって異なるプロセスで共有できるの?

tmpfsとは?

tmpfsはメインメモリをファイルシステムとして扱うことができるファイルシステムの名称
 ・一昔前で言うならばRAM DISKのようなもの
POSIX準拠の環境では /dev/shm にマウントされている
 ・ちなみにmac OSにはない

tmpfsの良いところ

ファイルシステムの処理速度+メモリアクセスの速度でアクセスが可能

最近のLinuxならば特別な設定は不要で利用できる
Linux kernel version 2.4以降(glibc 2.2)

ファイルシステム越しの操作になるのでファイルシステムのデータ一貫性などに頼ることができる
→独自で実装しなくてもファイルシステムの仕様を利用できる

tmpfsを用いる上でよく考えるべきこと

・メモリを使用するので大きなファイルを扱おうとするとお金的な意味でのコストがかかる
→本当にそのデータをメモリに載せなければならないかを考える

・動的にメモリ割り当てが行われるため、OOM Killが起きることやswap領域の利用が起きる可能性がある
→対象のファイルが事前にどの程度のファイル容量≒(メモリ使用量)になるかを予め予想できる必要がある

メモリ上のデータなので再起動時には消える
→本当に消えても良いデータか再生成可能な一時データなどで用いる

HDDとtmpfsのベンチマーク

画像1

以上を踏まえて tmpfs が有用と思われるケース

・高速なIOが要求され複数のプロセスから参照されるデータを扱うケース
・再起動時に揮発しても良いデータ
 ・キャッシュデータなどの再生成可能なもの
・データのサイズが事前にある程度予測できるもの
 ・メモリ不足時にはswapを領域を使用するため予測ができる必要がある
 ・最悪メモリ確保のためにOOM Killが発生しプロセスがKillされる可能性があるため

スマホ向けコンテンツ配信基盤が抱えていた課題とtmpfsの検討

スマホ向けコンテンツ配信基盤についての説明
・ピーク時に6000Request/secを超えるリクエストを受けるシステム
・歴史的経緯からRailsで作られている
・プッシュ通知配信も行っているため非常にスパイクしやすい
・現在AWS EC2環境からAWS ECS(Dockerコンテナ環境)に移行中
 ※本記事の再編時には移行済
・Go言語で書き直す話もあるのでコストをかけずにランニングコストを抑えたい
・今のキャッシュ可能部分はRails Cacheを用いてAmazon ElastiCache上にキャッシュを配置している
 ・ネットワークレイテンシーもありもう少し最適化できるのでは
 ・検討時のElastiCacheのキャッシュヒット率は50%前後
 ・求めるもの:
  とにかく早いキャッシュがほしい!でもヒット率も維持したい!

このような背景からDockerコンテナに移行するついでにキャッシュストレージを見直すことでコストカットと最適化ができそうな背景があった。

Dockerコンテナ環境下におけるのキャッシュストアの選択肢

コンテナ内のメモリ
 ・メリット:アクセス速度は早い
 ・デメリット:個々のコンテナでメモリ空間が分かれているためキャッシュの共有は難しい

画像2

ホストのストレージのボリューム
メリット:Dockerホストの同じボリュームを参照すれば複数のコンテナから同じキャッシュが読める
デメリット:IOPSが速くない

画像3

・ホストのtmpfsを用いたボリューム
メリット:
・アクセス速度が速い
・ホストのtmpfsをマウントすることで各コンテナでキャッシュを共有できる(キャッシュヒット率が向上する)
デメリット:
・再起動時に揮発する
・メモリを食いつぶしてswapしたり OOM Killされるされる可能性がある

画像4

Rails Cacheって異なるプロセスで共有できるの?

これを知るにはRailsとRubyとPOSIXについて知る必要があります。

・Railsのfile_storeの書き込みは Railsのatomic_writeを使っている
atomic_writeは新規ファイルを作ってrenameで置き換えている
・Rubyのrenameはrenameのシステムコール
・Linux(POSIX)において rename はアトミックな操作

This rename() function is equivalent for regular files to that defined by the ISO C standard. Its inclusion here expands that definition to include actions on directories and specifies behavior when the new parameter names a file that already exists. That specification requires that the action of the function be atomic.
引用元:https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html

つまり他のプロセスから書き換え途中のデータが見えることはなく、(=ダーティーリードは発生しない)安全にキャッシュデータを共有可能である。

次回以降の記事では実際に検証環境で行ったベンチマークと本番環境での運用結果を以下の点から書いていきたいと思います。

・切り替え前後のリソース消費の比較
・切り替え前後コストの比較
・ロードバランサからみたアプリケーションのレイテンシの比較
・実運用に載せるまでのトラブル解決



この記事が気に入ったらサポートをしてみませんか?