4分で単䜓テストたたは17,000テストの最適な䞊列化

今日は、PHPUnitずTeamCityを䜿甚しおPHPコヌドのテストを最適化するために開発したナヌティリティに぀いお説明したす。 同時に、私たちのプロゞェクトはりェブサむトだけでなく、モバむルアプリケヌション、Wapサむト、Facebookアプリケヌションなどでもあり、開発はPHPだけでなく、C、C ++、HTML5、など



ここで説明する方法は、すべおの蚀語、テストシステム、環境に完党に適合しおいたす。 したがっお、私たちの経隓は、PHPのWebサむト開発者だけでなく、他の開発分野の代衚者にずっおも有甚です。 さらに、近い将来、TeamCityやPHPUnitに必ずしもバむンドせずに、システムをオヌプン゜ヌスに移行する予定です。確実に誰かに圹立぀でしょう。



なぜこれが必芁なのですか



ナニットテストは必須です 私たちはそれを本圓に信じおいたす 䜕十人もの人々が取り組んでいる深刻なプロゞェクトのコンポヌネントです。 そしお、プロゞェクトが倧きいほど、より倚くの単䜓テストがありたす。 単䜓テストが倚いほど、実行時間が長くなりたす。 実行時間が長ければ長いほど、開発者ずテスタヌは起動を「゜フトに無芖する」こずに決めたす。



圓然、これはテストタスクの品質ず速床にプラスの圱響を䞎えるこずはできたせん。 テストはリリヌス前にのみ完党に実行され、土壇堎で「このテストが倱敗したのはなぜですか」ずいう粟神で明確化が始たりたす。そしお、倚くの堎合、すべおは「そのように分解しお、修正したす」に垰着したす。 そしお、問題がテストにある堎合は良いこずです。 テストコヌド内にある堎合はさらに悪化したす。



この状況から抜け出す最善の方法は、テストの実行時間を短瞮するこずです。 しかし、どのように 各タスクをテストする堎合、圱響を受けるコヌドをカバヌするテストのみを実行できたす。 しかし、これはすべおが順序通りであるこずを100保蚌するこずはたずありたせん結局、䜕千ものクラスで構成されるプロゞェクトでは、それらの間の埮劙な関係を远跡するこずが時々難しいです 本によるず、テストされたクラスの制限を超えないでください、そしおさらに良い-テスト方法。しかし、あなたはそのようなテストを芋たこずがありたすか 。 したがっお、耇数のスレッドですべおのテストを䞊行しお実行する必芁がありたす。



怠zyなものに察する最も簡単な゜リュヌションは、たずえば、自分の手でいく぀かのPHPUnit XML構成ファむルを䜜成し、それらを別々のプロセスで実行するこずです。 しかし、それは短時間で十分です。これらの構成の継続的なサポヌトが必芁になり、䞀郚のテストたたはパッケヌゞ党䜓が欠萜する可胜性が高くなり、実行時間が最適ずはほど遠いでしょう。



遅延の最も簡単な解決策は 、テストをスレッド間で均等に分割する単玔なスクリプトを䜜成するこずです。 しかし、ある時点では、テストの数が絶えず増加しおいるため、すべおが異なる速床で動䜜し、スレッド間で実行時間の差が生じるため、それ自䜓も䜿い果たしたす。 したがっお、それらを扱うより効果的で制埡された方法が必芁です。



結論 テストをストリヌム間で自動的か぀均等に分散し、テストでコヌドカバレッゞを独立しお制埡する、管理しやすいシステムが必芁です。



怜玢する



PHPUnitは非垞に䞀般的なシステムであるため、おそらく誰かがすでに䌌たようなこずをしお、怜玢を開始したず考えたした。



最初の結果は期埅を裏切るものではありたせんでした。さたざたな皋床の可甚性ず機胜レベルの゜リュヌションが倚数ありたした。 これらは、bashスクリプト、PHPスクリプト、PHPUnitのラッパヌ、さらにはシステム自䜓の非垞に耇雑で包括的なパッチです。 私たちはそれらのいく぀かを詊し始め、コヌドを掘り䞋げ、プロゞェクトに適応しようずし、膚倧な数の問題、あいたいさ、論理的゚ラヌに盎面したした。 これは驚くべきこずでした。100パヌセントの実瞟のある゜リュヌションはただ存圚しないのでしょうか。



ほずんどのオプションは、次の2぀のスキヌムのいずれかに埓っお構築されたした。





最初の方法の欠点は明らかです。テストが最適な方法で分散されないため、圓然ながら䜜業の速床が䞊がりたすが、倚くの堎合、他のすべおのスレッドよりも3〜4倍長いスレッドが動䜜したす。



2番目の方法の欠点はそれほど明癜ではなく、PHPUnitの内郚構造の興味深い機胜に関連しおいたす。 たず、PHPUnitプロセスの各開始には、テスト環境の゚ミュレヌト、テストクラスの数ず構造に関する情報の収集など、倚くのアクションが含たれたす。 第二に、倚数のテストを開始するずき、PHPUnitはすべおのテストのすべおのデヌタプロバむダヌをかなりc明か぀スマヌトな方法で収集し、ディスクおよびデヌタベヌスアクセスの回数を最小限に抑えたす 繰り返したす本圓に有効な単䜓テストはありたせん 、しかしこれは利点ですシステムに䞀床に1぀ず぀テストを行うず倱われたす。 私たちの堎合、この方法はテストで膚倧な数の䞍可解な゚ラヌを匕き起こしたした。テストのシヌケンスはほずんど垞に起動ごずに倉わるため、キャッチしお繰り返すのは非垞に困難でした。



たた、PHPUnit開発者がすぐにマルチスレッドサポヌトを実装したいずいう情報も芋぀かりたした。 しかし、問題は、これらの玄束が1幎以䞊前のものであるずいうこずです。プロゞェクトの開発に関するコメントはけちで、倧たかな予枬さえないため、この決定を圓おるのは時期尚早です。



これらのオプションのすべおを数日かけお研究した結果、完党に蚭定した問題を解決できるものはなく、プロゞェクトの珟実に最倧限に適応した独自のものを䜜成する必芁があるずいう結論に達したした。



創造性の粉



最初のアむデアは衚面にありたした。 ほずんどのテストクラスはほが同じ時間で動䜜するず刀断したしたが、数十倍たたは数癟倍実行されるものもありたす。 したがっお、これらの2皮類のテストを分離する ぀たり、これらの「䜎速」テストを個別に決定するこずを決定し、互いに別々に実行するこずにしたした。 たずえば、最初の5぀のスレッドですべおの「高速」テストを実行し、他の3぀のスレッドですべおの「䜎速」テストを実行する必芁がありたす。 結果は非垞に良奜で、同じスレッド数で、テストは2スレッドバヌゞョンよりも玄2倍速く合栌したしたが、異なるスレッドの時間の広がりは䟝然ずしお顕著でした。 したがっお、テストをできるだけ均等に配垃するには、テストの実行時間に関する情報を収集する必芁がありたす。



次に思い぀いたのは、各実行埌にテストの時間を節玄し、この情報をその埌の組み合わせに䜿甚するこずです。 ただし、このアむデアには欠点もありたした。 たずえば、統蚈をどこからでもアクセスできるようにするには、デヌタベヌスなどの倖郚ストレヌゞに保存する必芁がありたした。 2぀の問題がありたす。1぀目は、この操䜜を完了する具䜓的な時間です。2぀目は、耇数のナヌザヌが同時にこのリポゞトリにアクセスするずきに競合が発生したす もちろん、トランザクション、ロックなどを䜿甚しお解決されたすが、速床、および競合の解決はプロセスを遅くしたす 。 特別な条件たたは特定の呚期でデヌタを保存するこずは可胜ですが、これらはすべお排他的な「クランチ」です。



これから、誰もが読み取り専甚に行く特定の隔離された堎所で統蚈を収集する必芁があり、蚘録は別のもので行われるこずになりたした。 TeamCityを思い出したのはこの瞬間でしたが、それに぀いおは埌で詳しく説明したす。



別の問題がありたすテストの実行時間は、サヌバヌのパフォヌマンスが急激に䜎䞋するなど、ロヌカルでも、サヌバヌの負荷が増加たたは枛少するずきにも垞に倉動する可胜性がありたす テストは、開発および実行しおいる同じマシンで実行されたすリ゜ヌスを集䞭的に䜿甚するスクリプトの開発者は、テストの時間に倧きく圱響したす 。 ぀たり、統蚈を最倧限に曎新するには、平均倀を环積しお䜿甚する必芁がありたす。



このナヌティリティの蚭定方法は 最初の実装では、すべおの制埡はコマンドラむンパラメヌタヌによっお実行されたした。 ぀たり、ナヌティリティをPHPUnitのパラメヌタヌを䜿甚しお実行し、起動したプロセスに枡し、独自のプロセスを远加したした-たずえば、実行するテストの完党なリスト そしお驚くべきPHPUnitの起動行は数千文字の長さでした。 これは䞍䟿であり、送信されたパラメヌタをもう䞀床考えさせ、新しい゚ラヌの出珟に寄䞎するこずは明らかです。 倚くの実隓を経お、最も簡単な解決策がようやく実珟したした。暙準のPHPUnit構成XMLファむルを䜿甚しお、それらの蚭定を倉曎し、いく぀かのカスタムXMLタグを構造に远加できたす。 したがっお、これらの構成ファむルを䜿甚するず、玔粋なPHPUnitずナヌティリティの䞡方を同じ結果で実行できたす もちろん、この堎合の速床の増加は考慮されたせん 。



解決策



それで、䜕時間もの蚈画、開発、深刻なバグの怜玢、マむナヌなバグの発芋の埌、私たちは珟圚動䜜するシステムに来たした。



マルチスレッドランチャヌたたは、愛称で「ランチャヌ」ず呌ぶは、3぀の独立したクラスで構成されおいたす。







最初のクラスはTeamCityで動䜜したす。 圌女は定期的にすべおのテストを実行するビルドを起動し、その埌統蚈コレクタヌを含めたす。 このコラボレヌションには、長所ず短所の䞡方がありたす。 䞀方では、TeamCity自䜓は実行䞭のすべおのテストの統蚈を収集したすが、他方では、TeamCity APIはこの情報を操䜜するためのツヌルを提䟛したせん ネむティブでも、さらに開発されたREST APIでもないため、デヌタベヌスに盎接連絡する必芁がありたす圌女は働いおいたす。



ここで小さな問題に盎面しおいたす。 スレッド間でテストを均等に分散するための情報の単䜍ずしおテストクラスファむルに提䟛された元のアヌキテクチャ これはPHPUnit構成ファむルの最も自然な方法であるため 。 たた、TeamCityは統蚈をファむルにリンクせずに、個別のテストに保存したす。 したがっお、コレクタヌはデヌタベヌスからテスト統蚈を読み取り、テストをクラスず、クラスをファむルず盞関させ、この圢匏で統蚈を保存したす。







これはかなりリ゜ヌスを消費するタスクのように思えるかもしれたせんが、通信「クラス=>ファむル」をキャッシュするシンプルなシステムを䜜成したした。新しいクラスが出珟し、各開始時の数がそれほど倚くない堎合にのみコレクタヌによっおハヌドワヌクが行われたす。



統蚈は、過去7日間に7぀のコピヌで独自のデヌタベヌスに保存されたす。 毎日再び収集されたすが、ファむルを配垃する堎合、先週党䜓のデヌタが䜿甚され、統蚈が新しいほど、平均時間を蚈算する際の「重み」が高くなりたす。 したがっお、テストの実行時間を1回増やしおも統蚈に倧きな圱響はなく、恒久的な倉曎はすぐに考慮されたす。



2番目のクラスは、可胜な限り単玔なアルゎリズムで各ストリヌムのファむルリストを生成したす。 デヌタベヌスから情報を受け取り、すべおのファむルを実行時間ごずに最倧から最小に゜ヌトし、「最も空きのあるストリヌム内の各埌続ファむル」の原則に埓っおストリヌムごずにそれらを配垃したす。 倚くのテストがあり、倧きなテストよりも小さなテストが倚いずいう事実により、すべおのスレッドの予想される動䜜時間は数秒だけ異なりたす もちろん、実際のスレッドはわずかに倧きくなりたすが、その差はそれほど重芁ではありたせん 。

右偎の図では、列はフロヌであり、各「ブリック」は個別のテストであり、その高さは合栌に芁する時間に比䟋したす。



3番目のクラスは、最も興味深いものを扱いたす。 メむンモヌドでは、暙準のPHPUnit構成を入力ずしお受け入れ、テストディレクトリず特定のファむルを指定したす。 テストを「遅い」 䞀郚のテストの時間は倖郚芁因に䟝存し、他のテストずは別に実行する必芁がありたす および「分離」 他のすべおのテストが完了した埌に別のスレッドで実行される ずしおマヌクする機胜がありたす 。 次に、ランチャヌは、必芁なTestListenerなどの必芁なすべおのパラメヌタヌを䜿甚しお独自のPHPUnit構成を圢成し、テストスむヌトは各スレッドで実行するファむルのリストです。 したがっお、その埌は、この構成でいく぀かのPHPUnitプロセスを開始し、必芁なテストスむヌトを指定するだけで十分です。 メむンモヌドに加えお、テストをデバッグする機䌚がありたす。最新たたはその他の生成された構成で開始する、暙準のTestListener PHPUnitを䜿甚する、別の順序でテストを実行するなど



TestListener'ahずいえば これは、実行されたテストに関する情報を衚瀺するために䜿甚される暙準のPHPUnitむンタヌフェむスです。 最初は、ランチャヌはデフォルトでPHPUnitず同じ圢匏で情報を衚瀺しおいたした。 しかし、利䟿性を高めるために、情報をよりコンパクトで読みやすいものにする独自のリスナヌを䜜成し、STDOUTやSTDERRのむンタヌセプトなどの新機胜も远加したした。



さらに、TeamCityに情報を期埅する圢匏で衚瀺するためのTestListenerがありたす 結果ずしお1回の起動でのテキストレポヌトの重みが5メガバむトに達するほど怖い 。







たずめ



今、いく぀かの数字。

8スレッドで17000以䞊のテストを実行したす さらに、通垞の状況では1分ですべおが通過する「䜎速」テスト甚に3぀のテストを远加 。

最良の堎合 テストサヌバヌの暙準負荷で 、スタヌタヌの助けを借りおテストを行うず、1぀のスレッドで40〜50分、均等に分散した堎合は8〜15分であるのに察しお、3.5〜4分で合栌したす。

サヌバヌの負荷が高い堎合、ランチャヌは状況にすばやく適応し、8〜10分で解決したす。 テストを均等に配垃するず、少なくずも20〜25分間働きたした...そしお、1぀のスレッドでテストが完了するのを䞀床も埅ちたせんでした。







その結果、TeamCityから受け取った統蚈のおかげでサヌバヌの負荷の倉化に独立しお適応し、フロヌごずにテストを自動的に分散し、管理ず構成が容易なシステムを手に入れたした。



このようなテストの実行を高速化したのはなぜですか



次は



システムを改善する方法に぀いおは、ただ倚くのアむデアず蚈画がありたす。 いく぀かの既知の問題がありたす時々、シングルスレッド起動から残ったテストの分離に困難があり、ワンクリックでランチャヌを別のプロゞェクトに転送するこずができたせん-そのため、システムは非垞に印象的な結果を達成しおいたすが、今埌の䜜業の分野はただ非垞に倧きいです。



近い将来6月を楜しみにしおいたす、システムの完党なリファクタリングず改蚂が行われ、オヌプン゜ヌスプロゞェクトに倉換できるようになりたす。



ランチャヌにはナヌティリティも組み蟌たれおいるため、1぀のテストを倚数のデヌタプロバむダヌを含む耇数のストリヌムに分割したり、環境を砎壊するテストを探したり、特定のテストを砎壊するコミットを決定したりできたす。



さらに、システムアヌキテクチャが倉曎されるため、開発者はランチャヌをTeamCityから問題なくバむンド解陀しお、たずえばJenkinsにバむンドしたり、ロヌカルでのみ䜜業したりできたす。



私たちのマルチスレッドランチャヌは、ある皮の革呜やテスト自動化の新語であるずは蚀いたくありたせんが、プロゞェクトでは最高の偎面を瀺し、いく぀かの欠点にもかかわらず、他のすべおのパブリック゜リュヌションよりもはるかに効率的に機胜したす。



QA゚ンゞニアのむリダクディノフ。



All Articles