[インフラエンジニア向け]性能・拡張性設計の考え方

#性能・拡張性とは
一言でいうと、**処理負荷がかかった時にどれだけ性能を上げられるか**、という指標です。

例えばチケット販売サイトなどは、販売開始の時間はアクセスが集中して負荷が高まりますが、そのほかの時間帯はそこまで負荷が高くない、という場合があります。
そのような負荷を見越したリソースをどれだけあらかじめ積むのか、という部分が設計ポイントになります。

#サイジング
では実際に性能・拡張性を設計するために行うことは何か？
それが**サイジング**です。

サイジングでは以下のポイントからどの程度のリソースが必要かを見積もります。
・利用ユーザー数
・同時アクセスする可能性があるユーザー数
・システムで扱うデータ量と保存期間
・レスポンスタイムの目標値(処理の開始〜終了までの時間)
・スループットの目標値(一定時間あたりの処理量)

この情報を元に見積もった値に通常は安全率として、1.2〜1.5倍を上乗せしておきます。
ただ、この時点での見積もりはあくまで概算でしか出せないので、この安全率をどの程度上乗せするかはお客さんと合意をとる必要があります。

また、機種選定も考慮する必要があります。
サイジングしてこれだけのリソースが必要だよね、となった時に
サーバー台数を増やすのか？
もしくはサーバーにリソースの追加(CPU、メモリ、ハードディスク)がどれだけできるか？
を考慮しておく必要があります。

通常は初期搭載時の１．５〜２倍程度の空き領域を確保しておくと、必要なリソース拡張は行えるかと思います。

#CPU、メモリの選定
システムの処理量やレスポンスタイム、スループットの要件に基づき、**ベンチマーク値**を参考に選定していきます。
CPUはコア数も考慮し、どれだけ並列処理を行う場面があるのかも検討対象に入れた方がいいです。

注意すべき点としては、CPUやメモリは製品によって拡張に対応していないものがあったりするので、基本的には拡張可能なものを採用した方がいいです。

#ヒープ領域の確保
アプリケーションを動かす際に、メモリに一定の領域を確保しておく必要があります。
これを**ヒープ領域**と呼びます。
アプリケーションが動作する際には、Javaのオブジェクトがメモリ上に作成されて動作しますが、このヒープ領域を超えて動作することはできません。(Out Of Memoryとなってプロセスダウンしてしまう)

ヒープ領域はどのように設計するのか？
実はヒープ領域は作成するアプリケーションによって依存するので、実際に動かしてからでないと必要領域の算出は難しい、という特性があります。
なので、ヒープ領域の設計は主にテスト工程のなかで実施していきます。
テストの中でどれだけ負荷をかけるのか、どういった形でヒープ領域を確認するのか、という点でテストをしていき設計をしていきます。

なので、初期の段階ではこのような特性をユーザー側に理解してもらう必要があります。

またヒープ領域にからむ部分で、**ガベージコレクション**という機能があります。
これはアプリケーションで使用されたオブジェクトが残り続けてしまうのを掃除してくれる機能で、その作業を**ガベージコレクタ(GC)**と呼びます。
GCを行うことで不要となったオブジェクトが削除されるので、ヒープ領域が確保されます。
ですが、GCを行っている間は新しいオブジェクトの作成やオブジェクトの実行ができなくなります。
GCの時間はヒープ領域の大きさに比例するので、GCをどの頻度で実施するのか、という点も考慮してヒープ領域を決めていく必要があります。

#DBのメモリ設計
アプリケーションからDBのデータを参照する際に、毎回ディスクを参照するのでは処理に時間がかかります。
そのため、頻繁に参照されるデータはメモリにキャッシュしておくことで高速な処理を実現することができます。

データキャッシュに参照したいデータが存在する確率を**キャッシュヒット率**と言います。
これには計算式が存在して(ここでは割愛)、ある一定の領域を確保しておけば、それ以上キャッシュメモリ量を増やしても性能は大して上がらない、という性質があるので、コストや処理性能のバランスを考慮してデータキャッシュサイズを設計する必要があります。

#スケールアップとスケールアウト
スケールアップ・・・負荷が高くなった時に、リソースを追加することです。(**CPU,メモリの性能アップ、追加**)
スケールアウト・・・負荷が高くなった時に、リソースを追加することです。(**サーバーを増設する**)

両者の違いですが、クラスタリングの考え方からいうと
並列クラスタ(ロードバランシング)はスケールアウト向きで、HAクラスタはスケールアップに向いています。

また、コスト面から見てもサーバーを追加するスケールアウトに比べて、メモリやCPUの追加で良いスケールアップが使われることが多いです。
ただ、クラウド技術(AWSやAzure)を使えば必要な時にスケールアウトができる、ということもあるのでこの辺りは別記事で書いていこうと思います。

#拡張性を考慮するケース
運用の中で以下のようなケースで拡張性を検討する場面があるかと思います。
・レスポンス低下
・ディスク領域の不足
・業務機能拡張に伴ってインフラリソースの拡張

##レスポンス低下の対応
まず、どこがボトルネックになっているかを見極める必要があります。
調査項目としては以下の内容が主にあります。
・利用ユーザの急激な増加があったか
・CPUやメモリの使用率は高くないか
・APサーバーのヒープサイズは問題ないか
・キャッシュヒット率は高いレベルで安定しているか
・ネットワーク転送速度は問題ないか
・APサーバーやDBサーバーのディスクとのI/Oが問題になっていないか

ここではざっくり対応例について書いていきます。
ヒープサイズやキャッシュヒット率に問題がある場合は、キャッシュ領域の拡張を検討します。
ただ、物理メモリ以上の割り当てはできないので、リソース内でどれだけ効率的に対応できるか、もしくはメモリ増設を検討するのかを考慮します。

ネットワーク転送速度については、ネットワークの帯域に問題があるのか、ルーターの処理速度に問題があるのかといった点を切り分けて対応していく必要があります。

ディスクI/Oの問題は、基本的にはスケールアウトする方法となります。ディスクに関しては単純に追加すれば良いというものではなく、アクセス量が問題になることがほとんどです。

##ディスク領域不足
ディスクアレイと呼ばれるディスクの筐体に空きが有る場合は増設にさほど手間はかかりません。
ディスクアレイの増設が必要となる場合には
・影響範囲
・ドキュメント更新
・作業期間の調整
など諸々の工数がかかってきます。

##業務機能拡張に伴ってインフラリソースの拡張
新しい業務機能が追加となる場合、リソースはどの程度確保する必要があるのかを抑えておく必要があります。
それによってCPU,メモリはもちろんヒープ領域のサイズやディスクI/Oは耐えられるのかなどを検討し、必要に応じて拡張を検討します。

##仮想化によるリソース拡張
VMWareやHypaerーVなどの仮想化技術によって、仮想マシンのスケーラビリティは容易になりました。
メモリやCPU、ディスクサイズも定義ファイルを更新すればスケールアップが可能となるため、現地にエンジニアを向かわせる必要もなくなります。

先述しましたが、現在はクラウドの技術がどんどん進歩していて、自動でスケールアウトやスケールアップする機能もあります。
クラウド技術は日々更新されていくので、インフラエンジニアとしてはオンプレだけでなくクラウド技術についてもキャッチアップしておく必要があります。

#まとめ
インフラ領域の性能・拡張性については、結局のところ利用するアプリケーションによります。
多くの企業ではインフラ担当、アプリ担当のように領域が分かれていることが多いので、うまく連携をとっておかないといざリリースして運用となった時に、思った処理スピードが出ないといった問題が発生することがあります。

インフラエンジニアとしては、アプリの開発工程にも目を光らせておき、都度調整が必要であると感じました。
もはやこれからの時代、インフラだけ、アプリだけ、というのではなくどちらもある程度理解してるエンジニアが重宝されるんだろうなと思います。