Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Webのバッチ処理とオンライン処理のポイントとシステムの応答性能を学ぶ#1(社内勉強会)

こんにちは、hachi8833です。BPS Webチームのmorimorihogeさんの社内勉強会スライドを元にした記事を6回に分けてお送りします。

morimorihogeコメント)
ちょっと分割数多いですが、主に初心者向けということで冗長な解説や一部詳細を端折ったりしている点はご容赦下さい 🙇

概要

  • 対象:
    • 主にWeb開発者(Rails開発者)
      • サーバーサイトを扱うスマホアプリ開発者も含む
    • コードは書けるけど設計レベルでの戦略選びに自信が持てない人
    • バッチ処理を書いたことが(ほとんど)ない人
  • 話すこと:
    • 「アクセス頻度が高い」「処理に時間がかかる」場合に取れる戦略
    • バッチ処理やオンライン処理の注意点
    • ジョブ管理
    • UXの工夫
    • すぐに役立つノウハウ
  • 話さないこと
    • 処理の具体的な高速化

処理時間とレスポンス時間

最近はCPU/メモリ/ネットワークが高速になったこともあって、実行速度を気にしながら実装することはだいぶ減ってきました。管理者しか使わない管理画面のCRUDや、アクセス頻度が低い想定の社内システムなどでは、実行時間を無視できることがほとんどですし、それよりも機能開発の方が中心になることの方が多いでしょう。

感覚的には、最近の実装の9割では処理時間を気にすることはなくなってきています。極端に言えばN+1問題ですら、目に見えて速度が低下しているのでなければさほど目くじらを立てることもないほどです(明らかに遅い書き方はもちろんNGですが)。

しかし一部のシステムや処理においては、やはり処理の速度を考慮して実装する必要があります。

特にWebでプログラミングを始めた人は重たい処理を書くことに慣れてないことが多く、実行時間に関する感覚が鈍くなりがちなので、本番で地雷を踏む前にぜひ知っておきましょう。

morimorihoge注)
本記事ではいわゆる業務系システムなんかを想定しています。人間が主な操作を行う業務システムでは1秒を0.5秒にする高速化よりも機能面の拡充が求められる傾向にあります。そうしたシステムではカリカリの速度チューニングよりは、よりミスを減らしたり不整合データが出ないようなチェック処理に力を入れる方が喜ばることが多くなります。
※高速化が不要ということではなく、あくまで優先度の問題です。開発に費やせる時間と資源は無限ではないのです

一方、速度がとても大きなファクターとなるシステムもあります。代表的なのはゲームや大量アクセスを想定するニュースサイトなどのCMS(Contents Management System)で、こうしたシステムでは応答速度が遅いことでサービス自体がまともに提供できなくなってしまうため、常に速度を意識する必要があります。
また、組み込み系デバイスの制御では規定の処理時間内に処理を行わなければ機器が壊れたり人を傷つけたりする可能性もあるため、リアルタイム(ハードリアルタイム)処理が必要となる分野もあります。

業務系Web開発は他の分野に比べると比較的レスポンスタイムに甘い印象がありますが、昨今のフロントエンドチューニングや応答速度のSEOスコアへの影響などを考えると気にしないといけない度合いは年々上がってきているように感じます。

どの部分の「実行時間」かを理解する

上の図の青いブロックは「クライアントサイド」(Webブラウザ)、緑のブロックは「バックエンド/システムサイド」(サーバーやミドルウェアやOS)を表します。

  • サーバー側で完結する処理の場合、下にある緑の「バックエンド/システムサイド」の実行時間に配慮すれば十分です。定期実行バッチの多くがこれに相当します。

  • ユーザーが利用する機能の場合、緑の他に、上にある青の「クライアントサイド」での実行時間にも配慮が必要です。後述する「非同期処理」もこれに含まれることがよくあります(ブラウザからのファイルアップロードなど)。

morimorihoge注)
実際には間に複数システムやミドルウェアが入ることでもっと複雑になることもあります。
大事なのは処理を行って終えるまでに何がどんな仕事をする必要があるのか、それぞれの時間はどれくらいかかるのかをざっくりと把握しておくことです。

実行時間を計測するときの注意点

実行時間に配慮する際は、実行時間の計測がつきものです。計測について詳しくは後述しますが、基本的な注意点は以下のとおりです。

  • 「CPU時間」だけの測定では不十分

特にバッチ処理ではディスクの読み書きが多数発生するため、CPU時間の他にI/Oも実行速度に大きく影響することに注意しましょう。

もちろんCPU時間も、たとえばライブラリの性能を測定するうえでは重要な指標となります。

なお、CPU時間と同様、クロック数や実行インストラクション数もIO待ち時間を含んでいないので、実質的にCPU時間と同じ指標となります。

  • 適切なツールで測定する
    • コマンド処理の場合: timeコマンドでtotal値をチェック
    • Webアプリの場合: ブラウザのDeveloper Toolsでチェック

timeコマンドに続けてコマンドを実行すると、実際にプロセスが応答するまでに要した時間(real)、ユーザー側での処理時間(user)、システム側での処理(sys)のtotal値を得られます↓。

morimorihoge注)
昨今のCPUやOS環境はマルチプロセッサ化・仮想化されているため、ライブラリ等における「正確な」CPU時間を計測するためにはCPUアフィニティなどを使った計測が必要です。
timeコマンドによる計測はあくまで処理全体に対する簡易的な計測だと認識し、きちんと計測が必要な場合にはしっかり環境を構築するようにしましょう。

ブラウザのDeveloper Tools(Chromeの場合: 赤枠↓)を使えばレンダリング時間なども測定できます。

速度が重要な処理については本番に近い環境で計測することが重要です。ローカルPC環境は本番環境とかけ離れているのが普通なので、結果はあくまで参考にとどまります。

本番がHD環境だとローカルのSSD環境の方が速いことすらありますし、細かいファイルに多数アクセスするような処理だとその差はさらに開きます。

測定に使うデータも、極力本番に近い内容と量を備えたデータを使いましょう。データ量が半分のときに実行時間も半分になるとは限りませんし、ランダムなデータと意味のあるデータで結果が違うこともあるからです。

例えばMySQLでは、保存されるデータの内容(カーディナリティ)によってインデックスのアルゴリズムが変わってきます。

毎回本番環境で測定するのは難しいとしても、実行時間を適切に見積もるためにも、一度は本番相当の環境で測定しておきましょう。

morimorihogeコメント)
ある程度開発に慣れてくると、どんな処理が実業務で支障を来すのかがわかるようになってきます。
常に注意すべき処理は以下です。

  • 処理自体が特に重いわけではないが、実行される回数がとても多くなる可能性のある処理(トップページやそこから1クリック以内で到達できたり、SNSシェアされやすいページ)
  • 実行される回数は少ないが、多くのデータを横断的に参照・更新する処理

前者はキャッシュや事前実行などを使い高速化を試み、後者は本記事で扱うバッチ処理になることが多いでしょう。
この辺りの設計は、一度作った後で修正しようとすると大工事になってしまうことが多い部分でもありますので、アーキテクトの腕の見せどころになります。

昨今ではNew Relicなど、自動で実行時のメトリクスを収集してくれるツールも増えていますが、こうしたデータ収集ツールはあくまで動いているシステムからデータを集めるものであり、初期設計の筋の悪さを解決するものではありません。
バッチにしたい処理というのはシステム上も重要な処理になることが多いため、慣れるまではなるべく熟練者のアドバイスやレビューを受けながら設計すると良いかなと思います。


  • #1 処理時間とレスポンス時間(本記事
  • #2 バッチ処理とオンライン処理
  • #3 バッチ処理を設計するときの注意点
  • #4 オンライン処理とUXの工夫
  • #5 Railsのジョブ管理システムと注意点
  • #6 バッチ処理ですぐに使えるノウハウ、まとめ

関連記事

Webアプリのセッション管理とデータ保存を学ぶ#1(社内勉強会)

Linuxのサービス起動周りとDockerとの関連を理解する#1(社内勉強会)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。