パフォーマンスの改善

システムを作ったは良いけれども、稼働してみたら重くて使い物にならない。
最初はちゃんと動いていたんだけれど、利用者が増えてきたら反応が遅いシステムになってしまった。
既に実績のあるASPのシステムだけれども、今まで以上に大規模なお客様に適用するにあたって負荷の増加が気になるので先手を打ちたい。

そんな症状の解決……あるいは予防を目指します。

目次:

はじめに

多くのシステムは、サーバーサイドとクライアントサイドに分かれています。
これはブラウザで動く場合にしても、あるいは専用クライアントソフトがある場合にしても、同様です。

専用クライアントソフトが直接サーバー上のデータベースにアクセスするのは、セキュリティ上の問題があります。
そのため、クライアントソフトが存在する場合であってもサーバー側にはAPIという形で機能ごとの呼び出し口を設ける場合がほとんどです。
この時のプロトコル(通信方法。UDPやTCP/IP、それからHTTP、あるいはRESTfulの段階までも含めて、抽象的にプロトコルと呼ぶことができるはずです)がどのようなものであっても、抽象的にはほぼ同じと見なせます。

このため、ブラウザで動く場合であっても、専用クライアントソフトがある場合であっても、おおまかな構成はほとんど同じになります。

このときの、クライアントサイドのことをフロントエンドと呼びます。
また、サーバーサイドのことをバックエンドと呼びます。

フロントエンドの高速化

ブラウザで動くアプリの場合は、HTML/JavaScript/Flashなどが、フロントエンドにあたります。
専用クライアントソフトの場合は、専用クライアントソフト自体がフロントエンドにあたります。

  • システムを作ったは良いけれども、稼働してみたら重くて使い物にならない。

という様な症状の場合、フロントエンドが原因である場合があります。

静的データのダウンロード

ブラウザで動くアプリの場合、HTMLやCSSやJSや画像等の静的データをダウンロードしながら動作することになります。
専用クライアントソフトがある場合でも、場合によっては画像等の静的データのダウンロードを行いながら動作することはあるでしょう。
どちらの場合でも、抽象化して同じ様に考えることができます。

これらの高速化のポイントは、なるべく少ないファイルにデータをまとめること。
また、必要以上に解像度の高い画像は、表示サイズに合ったサムネイル画像を用意することです。

不要なデータを含めない、必要に応じて圧縮する……などの措置が必要な場合もあります。

動的データのダウンロード

ブラウザで動くアプリの場合、HTMLそのものや、あるいはJavaScript/Flash等から読み込まれるRESTful API経由のデータなどがあります。
これらの中で、バックエンドで何らかの処理が行われ、生成されたものを指します。

これらの高速化のポイントは、処理を適切にまとめ、適切に分けることです。

たとえば、利用者は操作してから応答までに1秒以上かかると重たいと感じ易いので、ひとまず1秒以内に応答を返してもらい、それから詳細を再度問い合わせるなどがあります。
ブラウザで動くアプリの場合、一旦HTMLが返ってきて、その後でJS等で非同期に追加データを読み込むことになります。
専用クライアントソフトの場合でも概要データだけ先に引っ張って表示した後で詳細データを順次問い合わせる等、本質的には同じと見なせます。

また、直列でAPIを叩いている場所は、並列でAPIを叩ける様にすると良い場合もあります。

API1 API2 API3 API4 API5

という様な直列の呼び出しから

API2
API1 API3 API5
API4

の様な部分的に並列な呼び出しへと修正可能な場合があります。
(並列化は、静的データのダウンロードでも同じ様に可能な場合があります)

フロントエンドでの処理量

一般的なシステムではフロントエンドで行うべき処理というのはそんなに多くないはずですが、表示をリッチにし過ぎたり、あるいはクライアント側で取り扱うデータ量が非常に大きい場合など、フロントエンドでの処理量が問題になることが稀にあります。

部分的な計算アルゴリズムを見直すことで、どうにかなる場合があります。
フロントエンド側で処理するデータ量を制限することでどうにかなる場合もあります。
設計の見直しが必要な場合等、ちょっとやそっとの工数ではどうにもならない場合もあります。
ケースバイケースで対応する必要があります。

バックエンドの高速化

サーバー側の高速化を目指します。
PHP/Python/Ruby/Java/Scala/C#/NodeJSなど、非常に多くの言語がありますが、やってることはそんなに変わりません。
MySQL/Oracle/PostgreSQLなどのデータベース、あるいは分散KVストレージやmemcacheなどを使うこともあります。

  • 最初はちゃんと動いていたんだけれど、利用者が増えてきたら反応が遅いシステムになってしまった。
  • 既に実績のあるASPのシステムだけれども、今まで以上に大規模なお客様に適用するにあたって負荷の増加が気になるので先手を打ちたい。

の場合は、ほとんどがバックエンド側を見直すことになります。

  • システムを作ったは良いけれども、稼働してみたら重くて使い物にならない。

の場合でも、バックエンド側に問題がある場合もあります。

SQL文の実行計画

パフォーマンスが落ちているとき、真っ先に確認するのがここです。
スロークエリを確認し、その実行計画を見ます。
実行計画が妥当でない場合、インデックス等を貼って実行計画を修正するか、あるいはSQL文そのものを変更して実行計画を修正します。

また、データベースサーバーのキャッシュサイズ等が妥当であるか調べ、必要に応じて拡張します。
どうやっても毎回のデータ取り出し量が多くならざるを得ない様な特殊ケースでは、SSD等を検討すべきな場合もあります。
(工数をかけて、設計を見直すべきな気がしますが…)

O/Rマッパ

メモリ上のオブジェクトと、データベース上のリレーショナルデータとは、その形状に大きな差異があります。
これをマッピングするものをO/Rマッパと呼びます。

O/Rマッパの中には、データの必要に応じて自動的にSQL文を生成してデータベースへと問い合わせる様なものがあります。
必要になった時点で問い合わせるのですが、このときのO/Rマッパは、将来的にどこまでのデータが必要になるのかを知りません。
そのため、必要に応じて問い合わせ、必要に応じて問い合わせ、必要に応じて問い合わせ、、、を繰り返す場合があります。
事前にどこまでのデータが必要なのか、明確に分かっている場合、まとめて取得する様にすることで、大幅な高速化が期待できる場合があります。

キャッシュ機構

バックエンドの処理は、HTMLを返す場合であってもXMLやJSONなど(あるいは独自形式)のデータを返す場合であっても、APIの様なものと見なすことができます。
APIを呼び出す際、引数を用いて呼び出すことになります。
ユーザー認証等のセッションに保存されているデータも引数と見なすことができます。

また、一つの大きなAPIの中で、小さなAPIが複数呼び出されていると見なせる場合もあります。

さてここで、コンテンツID以外に引数を取らない様なAPIは、キャッシュ機構を用いることで高速化が可能な場合が多く存在します。

文字列連結

XMLの生成など、ライブラリの実装方法によっては、最終的に作成する文字列の長さの二乗に比例して処理時間がかかります。(10kバイトのときは0.3秒なのに、100kバイトになると30秒かかる…など)
ライブラリを置き換えることによって、処理時間を大幅に削減可能な場合があります。

その他

その他、色々な改善のパターンがあります。
アルゴリズムやテーブル設計などを見直しての臨機応変な対応が必要な場合もあります。

システム工房コルンでやっていること

基本的に、設計まで含めて任せて頂いた案件に関しては、可能な限りバッドパターンを回避して設計を行っています。

また、第三者が開発し既に稼働中のシステムについて、パフォーマンス改善の依頼を請けることもあります。
そうした場合、調査(結果が出るまでに1週間程度。15万円〜)を行って、その結果を交えて改めてご提案させて頂いております。

→ お問い合わせは、フォームからお願いします。