リクルートの大規模・長期運用プロダクトを支えるアーキテクチャ・SREチームの取り組み──RECRUIT TECH MEETUP #2

リクルートの大規模・長期運用プロダクトを支えるアーキテクチャ・SREチームの取り組み──RECRUIT TECH MEETUP #2
『タウンワーク』『じゃらん』『ホットペッパーグルメ』『ホットペッパービューティー』など、リクルートが運営する大規模かつ、長期でサービスを提供しつづけるプロダクトは多くある。リクルート内にあるプロダクトやサービス共通の課題に取り組むRECRUIT TECH MEETUP #2では、タウンワークとホットペッパーグルメにおけるアーキテクチャやSREチームの取り組みを紹介する。

アーカイブ動画

■登壇者プロフィール


株式会社リクルート プロダクト統括本部
HRアーキテクトグループ 西村 祐樹氏

2019年リクルート入社。 入社後はタウンワークのアーキテクチャ改善などに従事し、現在はタウンワークを始めとするアルバイト・パート系メディアのシステムアーキテクトとして活動。


株式会社リクルート プロダクト統括本部
プロダクティビティエンジニアリンググループ 明智 那央氏

2015年リクルートに新卒入社し、社内向けログ収集基盤の構築・運用に従事。2019年からホットペッパーグルメのSREチームリーダーとして、インフラの構築や運用改善の推進を担当。

【タウンワークの事例】アーキテクトが考えるシステム改善を継続する心得

まずは西村祐樹氏が登壇し、リクルートグループが提供するサービスや、自身が所属するグループについて紹介した。

「SUUMOやホットペッパーといった販促領域、リクナビやタウンワークなどの人材領域。リクルートグループでは私たちの生活に馴染み深い、2つの大きな領域でサービスを提供しています」(西村氏)


上記に挙げたサービスの多くが10年以上運用されており、時代の流れと共に紙媒体からWebやアプリへとサービスのかたちを変えてきているのも特徴だ。フリーペーパーの求人情報誌として、タウンワークが発刊されたのは1998年。10年どころか25年近く続くサービスであり、現在はWebも展開している。

タウンワーク Webの掲載求人数は数十万件と膨大だ。月間トラフィック数は約数億アクセス、1秒間では数百アクセスにもおよぶため、「トラブルが発生して数秒止まっただけで、多くの利用者に迷惑をかけてしまう」と、西村氏は技術者としての矜持と責任感を語る。

利用者数が膨大であるため、サービスを支えるシステム規模も当然ながら膨大なものとなる。そのシステムを支えているのが、西村氏が所属するアーキテクトグループだ。

「我々の役割を一言で説明すると、ビジネス規模の大きなシステムにおける、技術難度の高い課題に取り組んでいるグループと言えます」(西村氏)

西村氏はさらに、タウンワークにおける技術課題を解決した事例について詳しく紹介していった。

タウンワークのシステム・開発環境においては、大きく分けて以下の課題があった。

・CIサーバー(Jenkins)が物理マシン上にあり、動作が不安定のため手動で再実行していた
・自動テストと手動テストが同時に行えない
・テスト環境が2つしかなく、大型案件と並行して実施するなど、調整コストがかかる

「CIサーバーをオンプレにすれば動作は安定するだろう。当初はこのような解決方法を考えていました。しかし、そもそもなぜCIサーバーを物理マシン上に設置したのか。自動テスト導入時における背景を、改めて深堀りすることにしました」(西村氏)

すると、CI専用環境の追加には初期構築、調整、ランニングコストなどが必要で、当時はCI導入のためだけにそこまでできなかったという背景が見えてきた。これにより物理マシン上でCIサーバーが構築され結果、自分たちの首を締めていた。

視点を変えるとCI導入によって運用を楽にしたつもりが別の問題を引き起こしていたということになる。この状況に対して開発環境の根本改善のために、開発者が自由に扱える基盤の構築が必要と考えた。


これは西村氏がセッション中に何度も繰り返し強調したメッセージであるが、単に新しい技術を導入することが目的ではなく、アーキテクトグループの役割は、課題解決がメインである。そのためには、開発者の意図を深堀りすることが重要だ。

このような考えからタウンワークの場合はクラウドに着目し、新たなシステムに刷新することを目指した。

「もうひとつ重要なことは現状を把握し、どのスコープに注力すべきか。つまり、スコープを絞ることです」(西村氏)


本事例の主な目的は、自動テストでは開発中のソースコードのデグレード(degrade)確認であった。一方、手動テストではUI、画面側の開発が主だった。そこで前者では開発コードの動作確認を、後者ではWebアプリケーションが動く環境に重きを置くことにした。逆に、インフラ部分の再現やバッチの動作確認などはスコープ対象外とした。

目指すべきシステムがイメージできた後は、検証を行った。具体的には、これまでのオンプレ環境からクラウドに移行して動くかどうか。タウンワークWebを動かすためには、以下のスライドのように大きく4つの要素が必要である。それぞれ検証を進めていった。

「まずは、コンテナ化を進めました。Apache、Tomcatはすぐに作成できましたが、データベースにやや苦労しました。ただ結果として4要素とも、ローカルマシンでDocker Composeで起動し、動作を確認できました」(西村氏)


続いては、環境の複製が可能かについても検証した。こちらは、Kubernetesで実現。スライドどおり、サブドメインで利用環境を切り替える構成とした。

まず実現したいイメージをかため、それに沿った検証を進めていくことが重要だと西村氏は強調する。その結果、実現可能という検証の成果を得る。


続いてはクラウド上での動作検証だ。GCPには、Kubernetesを構築するマネージドサービスとしてGKE(Google Kubernetes Engine)が用意されているため、同システムを導入すれば問題ないことは明白であった。しかし西村氏は、ここでももう一歩踏み込んで考える。

「GCPを利用するには弊社のルールとして、利用者それぞれがアカウントを取得する必要がありました。つまり、当初の案だと開発者全員にアカウントを発行する必要があり、手間もコストもかかるだろうと。そこで、発想を変えました」(西村氏)


端的に説明すれば、スコープを絞ったと言えるだろう。というのも、開発者がこれまでのオンプレで着目していたのは、ターミナルでのログ確認やDBアクセスといった動作確認であり、同業務であればKubernetesWebUIダッシュボードで可能であったからだ。

あとは検証結果を実際に構築し、運用を開始するだけである。テストの自動化では、他のサービスで成功事例のあったConcourse CIを採用し、実現は間近であった。西村氏は再び、さらなる深堀りを行う。

「そもそも自動化を簡単に捉えてよいものなのかと、これまでの経験から感じていました。具体的には時間の経過と共に、自動化が止まったり、運用現場が混乱したりする問題が起きる可能性があります。そうした問題が起きないために、運用も踏まえた初期の工夫が大事だと考えています」(西村氏)

●自動化ステップにおいて実施した4点

1.やりすぎ防止:現場開発メンバーから早期のFBをもらう
2.可逆的に進める:最悪捨ててもよいと割り切って取り組む
3.属人化の軽減:特定の人だけは全てを把握する状況を避ける
4.運用の陳腐化防止:目的や背景を文書化して残す


自動化構築でも、ソフトウエア開発と同じ思考で取り組んだ。長い期間トラブルなく運用できる、設計がしっかりとしたものを構築することを意識し、自動化を実施。システムは問題なく刷新された。


効果検証まで見届けることも大事だ、と西村氏は語る。実際、今回刷新したシステムでは副次効果も含め、スライドに記載された多くの効果が得られた。そして、改めてここまでの流れと思考をイメージ化したスライドを見せながら、次のように語り、セッションを締めた。

「課題解決の思考で取り組んでいるのが、リクルートグループの特徴であり、システム改善におけるポイントだと考えています」(西村氏)


【ホットペッパーグルメの事例】Redisのメモリー溢れと戦った話

続いて登壇した明智那央氏は、まずリクルートの飲食店予約サイト「ホットペッパーグルメ」のシステム構成について細かく説明していった。

ホットペッパーグルメのシステムはカスタマー・クライアント(飲食店)と、大きく2つの領域に分かれており、OracleDBは共通で使用している。Apache、TomcatといったWebサーバはタウンワークと同様で、検索エンジンはElastichsearchで構成される。


同システムでは、セッションでサーバの振り分けを行なっていたため、Tomcatの再起動時にエラーが発生する問題があった。このようなアクセス断を解消し、共用しているDBから負荷の高い処理を切り離すことで、サイト全体の信頼性を上げるため、Redisの導入を検討する。

だが、セッション管理用データストアにRedisを導入したところ、リリース後にメモリ溢れが発生してしまったという。

ちなみにRedisとは、Remote dictionary server。データをメインメモリ上の領域に格納するよう設計されたインメモリデータベース(IMDB)である。外部ハードディスクといった従来型のストレージ上に構築させるDBに比べ、データの読み書きが圧倒的に早いという特徴を持つ。


Redisのシステム構成は上記スライドのように、冗長性を担保するため3台用意。マスターノード障害時にフェイルオーバーできるようにsentinelを使用し、ロードバランサーの向き先を自動で切り替えるために内製のhealthcheckerを実装した。しかし、導入から1カ月も経たずに問題が生じた。

「24日目のことでした。メモリが上限の16GBに到達。メモリ上限を引き上げることで対応しましたが、セッションが有効期限前のデータが破棄されている可能性がありました」(明智氏)


メモリの増加量を調べると、1日0.67GB増えていることがわかった。セッションの有効期限は1カ月なので、0.67×30日で20.1G。より安全性を担保するために、上限を3割増しの27GBにアップした。

サーバーメモリのスペックも同期に必要な容量を確保するために、32GBから倍の64GBにスケールアップした。だが、フェイルオーバーが発生してもslaveに同期されない。つまり、冗長性が担保されないという新たな問題が発生した。


明智氏は同期できなかった理由について、マスターノードのメモリが確保できず、ダンプファイルが出力できていなかったことだと説明。そして、同期に必要なメモリを確保するために、スワップ領域を拡張するとの対応策を講じた。

加えて、メモリの使用量が先述のときよりも増加していることを考慮し、上限をさらに33GBにまで引き上げた。ところが、再びメモリ溢れが起きてしまう。

「改めてRedisの公式ドキュメントをチェックし、メモリをどこまで引き上げられるのかを確認しました。すると、OSのフリーメモリの8~9割に設定すべきとの解釈を得たので、OSのフリーメモリ17GB、Redisが確保しているメモリ33GBの合計の9割、45GBに引き上げることとしました」(明智氏)

また、slaveへの同期もRedisと同じメモリ量が必要になるため、スワップ領域も同様に拡張した。すると、メモリの上限引き上げは問題なく実施でき、3台のRedisが同期する冗長化システムが復旧した。ところが、再びメモリ溢れが生じる。このままサーバ側でメモリを増やす対応しても埒が明かないと、別の方法を検討し始める。

着目したのは、データの種類だ。Redisに格納しているデータは、以下スライドのようにmemory・token・permanentdb・infoである。


明智氏はRedisのデータを解析するソフトウェア「redis-rdb-tools」を使い、データを可視化した。すると、大きく2つの気づきを得る。

1つ目は、infoデータの割合が高いこと(92.52%)。2つ目は、メモリ使用量(45GB)に対し、ダンプデータのサイズ(18.17GB)が大きく乖離している点だ。明智氏は特に後者に注目、有効期限切れのキーが削除されていないために、データ量が増え続けているのではないかという仮説を立て、Redisの有効期限切れキーの削除アルゴリズムを確認した。


アルゴリズムは、passive wayとactive wayという、2つの方法で削除を行っている。passive wayは言葉のとおり、開発者が手を動かすことでキーを削除。一方、active wayはこちらもスライドに書かれたルールで処理を実行していることが分かった。同アルゴリズムを見て、明智氏は次のような仮説を立てる。

有効期限の長いinfoキーがサンプリングされていて消すものがない、と判断しているのではないか。つまり、有効期限の短いmemoryやtokenと有効期限の長いinfoキーが、ひとつのDBに混在していることが問題ではないかと考えたのである。


「ソースコードを確認すると、仮説は正しいことが確認できました。また、Redisの中にもデータベースがあり、そのデータベースごとに削除アルゴリズムが実行されていることも分かりました。その結果、Redisのデータベースを有効期限に応じて分離すればいいとの結論を得ました」(明智氏)


passive wayで有効期限切れキーを削除するジョブを実行すると同時に、これまで何度もトラブルが繰り返されてきたことを考慮し、コンテプランも講じる。overcommit_memoryの有効化、セッションデータの全破棄である。

実際、Redisのトラブル対応を行っている際に、今度はサーバーのホスト側メモリが95%という警告状態になってしまう。メモリ上限を引き下げて対応すると、slave同期がしない状態となる。ここでもスワップ領域の拡張で対応するが、スワップを拡張しても同期されない事態にまで陥る。だが、有効期限切れキー削除ジョブとオーバーコミットメモリの有効化により、slave同期は正常に戻る。

その後、RedisのDB分離を行うと、有効期限切れキーの削除は促進されたがその分新しいキーが登録され、再びslaveに同期されないなどのトラブルが発生するも、最終的にはRedisのプロセスを再起動。不要なキーを日次削除するジョブを実行することで、Redisのメモリ使用量は10GB以下との安定稼働に至る。


さらに明智氏は、RedisのDBを分離する際に事前に効果を検証したこと、コンテプランを実行した際は実サービスにどのような影響があるのか、不要なキーの日次削除における注意点など、事前に細かくリスクなどを検証していることを丁寧に紹介した。

そして今回の取り組みを次のように振り返り、セッションを締めた。

「ユーザーに迷惑をかけるといった二次障害を発生させないよう、大きな対策を講じる際は、必ず事前にレイテンシーやリスクといった要因を調べること。また、実際にソースコードレベルで挙動を把握することが大切だと改めて感じました」(明智氏)

【Q&A】参加者から寄せられた質問に回答

セッション後は、参加者からの質問に登壇者が答える質疑応答が行われた。そのいくつかを紹介する。

Q.クラウドはAWSの利用が多い中、GCPを選択した理由は?

西村:Kubernetesを使うと決定した後、マネージドサービスはどれが適切なのか。ネットやオライリーから出ている書籍『Kubernetesで実践するクラウドネイティブDevOps』 を読み込んで、いろいろ調べました。当初はECSやEKSなど、AWSも検討しましたが、最終的にKubernetesの知見に長けているGCPを選びました。

Q.実際、EKSなどと比較してGKEは扱いやすいか

西村:EKSも使ったことはありますが、個人的にはGKEの方が使いやすいと感じています。例えばロギング機能を使えば、Kubernetes上で各コンテナのモニタリングを手軽に見ることができます。ただ、商用サービスはどちらも使ったことがないので、違った意見もあると思います。

Q.システム改善で最も注力しているところは?

西村:事業・サービスで見るのか。それとも、サーバー・インフラ・フロントなど、システムとして考えるのかなど、いろいろな軸があるとは思いますが、ボトルネックがどこにあるのかを見極め、そのボトルネックに注力すべきだと考えています。例えばコードがレガシーであっても、レガシーコードに対応できるエンジニアがいれば、特に問題ないでしょう。逆に、モダンなコードであっても、コードが汚い場合はそこがエンハンスをするうえでのボトルネックになりえるはずです。

Q.開発用DBの管理は案件ごとにDBを立てるのか、それとも共通なのか

西村:開発環境ごとにデータベースを立てています。流れとしては、もともとオンプレにあるデータベースを週に一度、GCPのCIツールによってクラウドにアップロード。ただ、あくまでDokerイメージなので、そこから環境ごとにimageを使い、コンテナを立てています。また、データベースが合わない際は、適宜アップデートし対応しています。

Q.アプリケーション側でメモリを抑えてもらうような取り組みはあったか

明智:当然ありましたし、密にコミュニケーションを取り、無駄なメモリは使わないなどの対応をしてもらっています。ただ、ホットペッパーグルメは10年以上続いているサービスのため、コードが複雑である問題も多く、インフラ側での対応を進めました。

Q.システム運用改善も含め、リクルートにおける意思決定について

西村:リクルートは自由度の高い風土であり、権限移譲もされています。そのため現場で起きている事象や課題は、現場のメンバーが率先して動き、解決していくことが多いです。


株式会社リクルート
https://www.recruit.co.jp/
株式会社リクルートの採用情報
https://recruit-saiyo.jp/

テクノロジーと共に成長しよう、
活躍しよう。

TECH PLAYに登録すると、
スキルアップやキャリアアップのための
情報がもっと簡単に見つけられます。

面白そうなイベントを見つけたら
積極的に参加してみましょう。
ログインはこちら

タグからイベントをさがす