なぜ、あなたの開発したシステムが遅いのか?第1回

Co-Wellのエンジニアによるシステム開発担当者のための情報共有BLOGです。

TrongNV

なぜ、あなたの開発したシステムが遅いのか?

担当>林 隆洋(Takahiro Hayashi)
Engineering Headquarters
Web制作会社、個人事業主を経て2011年株式会社コウェルに参画。 Web黎明期からPerl CGI~Java~Flash/Flex~PHPなどカバーする開発言語を拡大。 2014年から2017年までベトナムに3年ほど駐在しCTOとして教育カリキュラム構築、大学連携などに従事。 近年はセキュリティ方面に注力。2018年からMagentoの性能向上についてのプロジェクトに参画。

悩めるエンジニア
/悩める孤独な担当者Aの独り言/
「こんな課題を解決するシステムが作りたい。こういう機能でこういう画面で、クラウドでホストしてモダンなフレームワークでやっていこう。」
「オフショア開発でチームに仕様を伝えていれば、想像していたよりサクサク動くものが出来てくる。しかも安い!いいね!」
「スモールスタートでローンチしてどうか・・・」
「なんてこった、遅い!というクレームがユーザから結構くる。変なエラーメッセージが出てきたという問合せもあった。開発中は特に問題を感じなかったけど、ユーザが使い始めたら確かに色々モッサリしてきている気がする。」
「さてどうしたものか……。」

このように、開発した後に問題が明らかになったシステムの性能問題について取り扱うことが弊社でも増えてきた。おそらく開発に関わるポストにいれば、少なからずこういった場面に直面する経験があるのでは無いだろうか。

これから数回にわたって、システムの性能問題についての取り組みを、具体的な情報や事例を挙げながら情報共有していこうと思う。

1.是非、知っておきたいシステム開発の流れ

システム開発において、開発を請け負う立場としては基本的に以下の流れで進める。

1.要件定義
2.仕様設計
3.実装
4.テスト
5.受入・導入

この最初の「要件定義」は、実は詳細を詰めると「ビジネス要件」と「ユーザ・業務要件」とに分けられることが多い。

ルーチンとしては、まずビジネス要件がありそれを実現するためのユーザ(業務)要件があって、ユーザ要件を実現するために必要なシステム要件に落とし込まれて設計→実装→テストと進んで行く。開発の進め方がアジャイルであっても、この流れが小刻みになるだけで、本質的には変わらない。
この中で、ビジネス要件というのは本来、性能やセキュリティと言った非機能要件を多く含み、ユーザ・業務要件は機能要件を多く含む。
そしてエンジニア側視点でシステム開発を進めていく際には機能要件を最初に考え、非機能要件と呼ばれる実体の無い要件は後回しにされがちである。
そんな状態で「機能」が開発されて動くようになり、テスト環境で触ってみても何の問題も無さそうだ!しかし、いざローンチして運用を始めると、ユーザやデータが増えてきたときに「遅くて使い物にならない!」という悲鳴を聞くことはとても多いのだ。


2. 感覚的に「遅い!」と言われても・・・

感覚的に「遅い!」と言われても、指標が無ければ現場としてはどこから手を付ければ良いのか分からない。とは言え性能指標について決めるにしても、初めての場合は妥当な数値を出すのも難しい。そこで、まずは現状を数値化して、客観的に見られるようにするのが先決だ。
性能テストも他のテストと同様だが、実際に利用されている環境とほぼ同じ環境であることは非常に重要。特にデータ量については遅いと言われている環境と同じにしなければ正確なテストが出来ない。
負荷が集中している時に遅いのか、データ量が多いときに遅いのか、注文する立場からすれば「とにかくあらゆる状況を想定してテストして欲しい」と言いたいところだが、一刻も早く是正したい時ほど、現状を正確に把握して優先順位を決めるのはとても重要だ。
まずはどこが遅いのかを可視化すべきだ。よく使われるのはNew RelicやDynatraceといったサーバにエージェントを仕込んで全てのトラフィックをモニタリングするツール群や、想定したシナリオでJmeterを動かしてシステム全体の機能を舐めるのも良いだろう。ただし、Jmeterの場合は作り手が考えたシナリオでしかないため、実際のユーザはあまり使わない機能が含まれる事もあり、優先順位を決める際にノイズとなってしまう事もある点は認識しておきたい。逆に稼働中のサーバに仕込むNew Relicなどのツールの場合は、まだ起きてない状況をシミュレートすることは当然出来ない。
要するに、どちらが良いという話では無く、状況に応じて適したものを選ぶ、もしくは両方使えばよい。
指標として、プロダクトの責任者と共通認識を持っておきたいのは以下の2点だ。

1. 同時接続数
2. データ量

どんなにデータ量が少なくても同時接続数が多ければ極端に遅い、というケースの場合、サーバをスケールアップすることで解決してしまえることもままある。もちろん、ピークに合わせてスケールを決めてしまうとコスト的な無駄が増えるので最適解では無いのだが、根本解決までの時間稼ぎにはなる。
こんなとき、クラウドならサーバのスペックはすぐに変えられるので本当に便利な世の中になったものだ。^ ^

3.ロジックが重くない?というかエラーで動かなくなるんだけど・・・

システム全体で重い部分が見えてきたら、詳しく分析しよう。

PHPであればBlackfireが便利である。一昔前なら自分でxdebugやwebgrind等を入れて可視化していたが、それに比べると大分楽であるし、フレームグラフもとても見やすいので本当にオススメである。
アンチパターンでは無いので見過ごし後から発見されやすいのは、大量のデータを繰り返し処理するような部分。
数百件のデータをforループで繰り返しながら、その内側でDBアクセスが発生し数千回のSQLクエリが発行されているというのは初心者に多く見られがちである。確かにプログラミングは簡単なので、とりあえずの実装としては致し方ない部分はある。
※ データを一括で取得してメモリに保持するという方法が良いとは限らないのでアンチパターンとは言い切れない。

この辺、例えばORマッパーの性質をよく知ってないと全く予想していないクエリの出し方をしたりするので、自分たちの使っているライブラリがどういうものなのかを深く理解するのは本当に重要である。
開発時のテストでは全く問題が無いが、本番ではすぐに再現するというケースも本当に良くある。
色々な原因は考えられるが、まずはデータを問題が発生しているサーバと同じ状態にしてみると、大体は再現できたりする。
その他にも、最近のWebアプリケーションエンジニアはサーバ側のことを意識しなくて済むようになっている場合もあるので気付きにくいこともあるが、「同時に開けるファイル数」がシステムにはパラメータとして存在しており、ファイルの閉じ忘れによって上限を超えてしまい、リソースはスカスカなのにエラーになる、という状況も見かける。
これはプロファイリングツールでは分からないので、エラーログを注意深く見ていくことで発見する。これは遅いというケースでは無いが、遅さを調べる過程でこのような問題が見つかる場合も多い。

 To be continued...
さて、次回は・・・「具体的にはどうやって進めるの?」   

pagetop