日本とグローバルのクックパッドを統合しました

こんにちは、レシピ事業部プロダクト開発グループの赤松(@ukstudio)です。

昨年の10月頃からレシピ事業部ではひとつの大きなプロジェクトに取り組んでいました。このプロジェクトは社内ではOne experienceと呼ばれています。本記事ではこのOne experienceについてご紹介します。

One experienceとはなにか

クックパッドではレシピサービスを日本を含めた71ヶ国、29言語で展開しています。これまでは日本のサービスと海外のサービスは独立した別のシステムで別のサービスとして展開してきました。日本のレシピサービスは日本の組織が、海外のレシピサービスはイギリスにオフィスを置く海外の組織によって開発・運営を行なっていました。

One experienceはこの独立した2つのサービスを1つに統合し、国内・国外関係なく、全ユーザーに同じ体験を提供することを目的としたプロジェクトです。

現在、このOne experienceプロジェクトはほぼ完了しており、すでに海外で開発されていたシステム (以後グローバル版) に日本のレシピサービスが統合されています。一部の古いバージョンのモバイルアプリを使っているユーザーを除いてほぼすべての日本のユーザーのアクセスがグローバル版システムによって処理されるようになっています。

リソースを集中させ、大きなインパクトを生み出す

なぜ私たちはレシピサービスを統合することにしたのでしょうか。

私たちは「毎日の料理を楽しみにする」をミッションに掲げ、全力で取り組んでいます。このミッションの実現のためには様々なチャレンジを通して大きなインパクトを生み出していく必要があります。

ですが、日本と海外のサービスがそれぞれ別の組織で開発されていると、開発のためのリソースが分散してしまいますし、どちらかのみに作られた機能は当然そのサービスを使っているユーザーにしか届きません。

そうではなく、より大きな価値をよりたくさんの人に届けるために、2つのレシピサービスを1つに統合し、全員が1つのサービスを開発することとなりました。

日本のレシピサービスを海外のレシピサービスへ統合する

レシピサービスを統合することが決まったあと、日本のシステムをベースに統合するのか、グローバル版のシステムをベースに統合するのか議論しました。

日本版もグローバル版も主要なWebアプリケーションがRailsで実装されているという点では同じですが、インフラやWebフロントエンドで採用している技術スタックや、非同期ジョブやバッチ実行のための仕組みなど様々な点が異なっています。同様にモバイルアプリケーションも採用しているアーキテクチャなど日本版とグローバル版とで異なっていました。

このように日本版とグローバル版には様々な違いがあり、どちらに統合するにしてもなんらかのメリット・デメリットが存在します。そのうえで、最終的に「グローバル版をベースに日本のサービスを統合する」という決断を行いました。16年運用されてきた日本のRailsアプリが、10年運用されてきたグローバルのRailsアプリへ統合されることとなったのです。

決定の背景として、海外で展開していたレシピサービスは他の国や地域のレシピサービスを買収し取り込むことで成長してきた経緯があり、そのため外部のデータなどを取り込むための機能が既に存在していました。また、複数地域・言語でサービスを展開しているため、国際化の仕組みも備わっています。このような仕組みがない日本版システムに統合するよりも、グローバル版システムに統合する方がトータルでもっとも素早くシステムを統合できると判断したため、今回の決定に至りました。

サービスの統合は難しい

グローバル版に日本のレシピサービスを移行することが決まったとは言え、考えることはとても多くありました。

例えばグローバル版と日本版のレシピサービスではレシピを投稿したり、探すことができるというコアな部分は一緒ですが、グローバル版にしかない機能、日本版にしかない機能、グローバル版にも日本版にもあるが仕様が異なる機能、UIが違うものなど様々な違いがあります。

これらについては主に以下の観点から整理を行いました。

  • 日本版で実装されていて、One experienceプロジェクト完了後も残したい機能を移植する
    • = 日本版で実装されていて、One experienceプロジェクト完了後になくなる機能を決める
  • グローバル版で実装されていて、One experienceプロジェクト完了後に残さない機能は削除する

特に日本版からグローバル版への機能の移植は、そのまま移植するのではなく、利用してくれているユーザーにとってあるべき形は何なのか、改めて考えながら移植を行いました。そのため一部の機能は日本版で提供していたものと変わっているものもあります。

また、検索はレシピサービスにおいて非常に重要な要素であり、特に人気順は有料会員向けの機能です。よって、日本版システムで実現できていたのと同等の品質でグローバル版の検索システムでも提供できる必要がありました。

そして、グローバル版は日本版とは別のシステムとして稼動しているサービスなため、当然データベースも別で運用されています。これは日本版のデータをグローバル版のデータベースに持っていく必要があるということです。グローバル版は日本の開発組織とは完全に独立して0から開発されていたため、日本版とグローバル版ではデータベースのスキーマにも違いがありますし、データを移行するにあたってダウンタイムを設けるかどうかで対応の難易度も変わってきます。今回、データ移行については両システムともダウンタイムなしでデータ移行を実現できました。

このような課題をひとつひとつ解決し、無事統合を完了させることができましたが、まだ今後の土台ができただけとも言えます。今後はよりたくさんの価値を届けられるよう引き続き開発を続けていきます。また、今回の統合によりレシピサービスを利用してくださっているユーザーにとって体験が大きく変わりました。現在も様々なご意見が寄せられており、これらにも目を通しながら鋭意改善を続けています。

さいごに

以上がOne experienceプロジェクトの概要です。

One experienceプロジェクトは、最初に立てた計画をそのまま最後まで実行したわけではありません。途中でユーザーインタビューやテストも実施して、その結果を踏まえて実装するものが変わることも何度もありました。最初はなくす予定だった機能を最終的に復活させたこともあります。

最終的な形がはっきりしないままプロジェクトを進めるのは心理的にそれなりの負荷がありましたが、ユーザーによりよい価値を届けるためにはこのやり方で良かったと今では思っています。最初にすべてを決めてしまうと、それを作り切ることだけが目的になってしまいかねないからです。

この不確実な状況でもOne experienceプロジェクトが完遂できたのは、データマイグレーションや採用する技術スタックなどの技術的な方針を最初に決め最後までほぼブレなかったこと、プロジェクトの各領域のリーダーたちがしっかりと各々の責任を果たし、連携できたからでしょう。

長らく運用してきたサービスのシステムを統合することはここでは書ききれない課題がたくさんありました。

この記事で軽く触れたものもありますが、いくつか例を挙げると以下のようなものがあります。

  • 両システムを稼動させたまま、どうやって日本版のデータの変更をグローバル版にリアルタイムに反映するのか
  • 日本の検索をグローバル版のシステムにどう移植したか
  • 日本のチーム主導で作る機能をどのようにして国際化対応するか
  • グローバル版への移行による日本からのアクセスにおけるパフォーマンスの劣化をできる限り軽減したい
  • などなど

これらについても今後このブログで発信していく予定です。ぜひ弊社のXアカウントをフォローして更新をお待ちください。

Cookpad Summer Internship 2024に参加しました

はじめに

こんにちは。9月からクックパッドで1ヶ月間サマーインターンシップに参加していた中尾です。 今回はクックパッドで1ヶ月間過ごしてみて、やったことや感じたことをレポートしていきます。

自己紹介

私は現在、立命館大学の学部3年で、情報系を専攻しています。今回のインターンシップでは遠方に住んでいるということもあり、初めの1週間はオフィスに出社し、以降はリモートで勤務していました。宿泊したホテルからオフィスまでが徒歩2分くらいで激アツでした。

インターンシップに参加するまで

クックパッドは技術力の高い会社というイメージで、ロゴやデザインが好きだったということもあり(かわいいですよね?)、募集が始まる前からインターンシップに参加したいと思っていました。そんなとき、いつものように魔法のスプレッドシートというインターンシップの情報が集まるサイトを監視していたところ、クックパッドの募集を見つけたためすぐさま応募しました。技術課題や技術面接を終えて、合格の連絡をいただいた時はとても嬉しかったです。みなとみらい行くぞ!!!と思っていたら、オフィスが移転していて渋谷駅の隣の池尻大橋でした。みなさん、クックパッドは今は池尻大橋にあります!!!

会社の雰囲気

技術が好きで、性格は穏やかな人が多いと思います。 初週にインターン生のために懇親会を開いてもらったのですが、そこで「技術のキャッチアップ方法」や、「技術力をもっと深めたい」などの質問や悩んでいることを話すと、親身になって色々教えてくださいました。今まではぼんやりしていた自分にとって目指すべきエンジニア像が明確になり、冗談抜きで人生が変わったと思います。自分は技術がすごく好きなので、みんなでワイワイ技術について話せて楽しかったです。 また、Slackでの会話も盛んで、気軽に質問や提案ができる環境でした。そのおかげで、あまり話したことのない方にも気軽にメンションしてタスクについての質問をすることができました。

インターンシップの内容

タスク

最初はonboardingタスクのような感じで、簡単なWebフロントの修正などから始めました。そこから徐々に大きめのタスクを触らせてもらい、新規機能の開発にも携わることができました。私はRailsを触るのは初めてだったのですが、各タスクで少しずつ触る領域が違ったので、徐々にRailsのことがわかってきて楽しかったです。また、DWHに対してSQLクエリを叩いて対象レコードの数を調査したり、作成したバッチ処理の実行時間を計測したりは、実際に運用されている大規模なプロダクトならではという感じで楽しかったです。 どのようなタスクがやりたいかをヒアリングして尊重してくれたので、やりたいことがあればどんどん挑戦できる環境だと思います!

スクラム

私はスクラム開発をするのが初めてだったので、良い経験になりました。現在のクックパッドのスクラム開発では、1週間を1スプリントとして、週に1度スプリントのプランニングやレビューを行います。また、毎日集まって進捗報告をするデイリースクラムというものもあります。チームって感じがして良いですね!!! スクラム開発では、チームとしての課題や進捗を全員で共有して取り組むことができるので、全体像が把握しやすいのが良いと思いました。また、デイリースクラムでチームメンバーそれぞれの声を聞くことができたので、親近感が高まって話しかけやすくなったのがよかったです。チームとしての結束力は間違いなく高まると思います。 一方で、プランニングやレビューでかなり時間を取られてしまうので、メリットもデメリットもそれぞれあるなと思いました。

メンタリング

サポートは非常に充実していました。 メンターの方と毎日1on1ミーティングを開いて、タスクの進捗や悩みの共有、ちょっとした雑談などをしていました。また、1on1以外の時間でも、「今話せますか?」と声をかけると気軽にSlackのハドルミーティングで話すことができました。とてもコミュニケーションの取りやすい方で、勉強になる部分が多かったです。 メンターの方がお休みの期間があったりもしたのですが、その期間は別の方がメンター代理をやってくださり、サポート面で困ったことは全くありませんでした。

成果発表

インターン期間の総括として、最後に成果発表を行いました。 成果発表というと少し緊迫したイメージが湧いてしまうかもしれませんが、ワイワイとした賑やかな雰囲気でした。 スライドを使って10-15分くらい発表をし、質疑応答やフィードバックを行いました。 自分の発表に対して質問やリアクションをたくさんしてもらえて嬉しかったです!!

成果発表中のSlack

最後に

仕様に関しての提案をしたり、新規機能の開発に携わらせていただくなど、本当に1人の社員のように働くことができて楽しかったです。 1ヶ月間本当にありがとうございました!!

開発環境のデータベースでも本番環境相当のデータを使う

こんにちは。レシピ事業部バックエンド基盤グループの石川です。

2014 年、このブログに『開発環境のデータをできるだけ本番に近づける』というタイトルの記事が投稿されました。

クックパッドでは、ユーザーさんが実際に体験している状況と近い状況を再現しながら開発することに価値があると考えています。技術的には、最初からレコードがたくさんあることによってパフォーマンス問題に気付きやすくなるなどの長所がありますし、サービス開発としても、実際のユーザーさんの体験を最速でなぞって素早くフィードバックループを回せるようになるという長所があります。

この慣習は 2014 年の記事から 10 年経った今でも続いています。一方でその実現手法については変化を続けてきました。現在のクックパッドでは状況に応じていくつかの手段を使い分けています。それらの手段については今まであまり公開されていなかったような気がするため、この記事ではそのうちのひとつをご紹介いたします。

なおこの記事で紹介する手法は社内で数年使っているもので、以前弊社に在籍していた菅原 (@sgwr_dts) が作成し、その後奥村 (@hfm)、鈴木 (id:eagletmt)、小川 (@coord_e)、および自分を含めたチームとして開発してきました。ご承知おきください。

前提

クックパッドでアプリケーションがデプロイされる環境としては本番環境の他に、本番環境へ出す前の検証作業で使う環境(検証環境)があります。これらふたつは AWS 上にデプロイされています。それとは別に開発者ひとりひとりの手元のパソコンでアプリケーションを動かす環境を開発環境と呼ぶことにしましょう。このあたりは文献によって微妙に呼び方が異なるので、この記事ではこれらの呼び方を使うことにします。

クックパッドでは RDBMS として Amazon Aurora MySQL を多用しており、特に cookpad.com を提供するアプリケーション群が使う RDBMS の多くは Aurora MySQL です。Aurora のリリースが 2014 年 11 月らしい ので、早速 10 年前にはなかったものが出てきましたね。

それではここから、Aurora を対象として、定期的に本番環境のデータベースの複製を作って検証環境や開発環境のデータベースとして使うやり方についてご説明します。

Aurora クラスターのリストア

さて、Aurora ではリストアという操作を行うことで既存の DB クラスターを元に同じデータを持った別の DB クラスターを作成できます。Aurora のリストアはそれなりに速く、クラスターの VolumeBytesUsed が 1 テラバイトを超えていても 5 分程度で完了します。そのあと出来上がったクラスターに DB インスタンスをひとつ作る作業に 10 分程度かかるので、そちらの方が長いです。

こうして出来上がったクラスターをそのまま検証環境として使えるとラクなのですが、そのままだとセキュリティやプライバシー上の懸念があります。たとえばユーザーさんのメールアドレスを開発者全員が読めてしまうと問題なわけです。これを避けるため、リストアによって出来上がったクラスターに入っているデータのマスキングを行います。

どのデータをマスクしてどのデータをそのまま残すかは、DB クラスターごとに設定ファイルを作って管理しています。たとえば以下の Jsonnet ファイルのような感じです。この設定では、どのテーブルを残してよいか許可する一覧を持っておいて、それ以外のテーブルは truncate で空っぽにしてしまいます。

local allowed_tables = [
    'recipes',
    'ingredients',
    'users',
    // などなど……
];

{
    database: 'global_main',
    truncate: true,
    only: allowed_tables,
    pre_queries: [],
    rules: [],
    post_queries: [],
}

上の例には書きませんでしたが、特定のテーブルの特定のカラムだけ処理するクエリを流すこともできます。たとえば credentials テーブルの email カラムの値をすべて ${user_id}@example.com のようなダミー文字列に書き換えてしまう、などです。

ただし特定のテーブルのカラムを書き換える処理は、テーブルが巨大な場合は長い時間がかかります。実際にあった例として、すぐ上に書いた credentials テーブルの書き換えはデータ量が小さい場合はうまくいくのですが、本番環境の巨大なデータで試すと一晩経ってもクエリ実行が終わりませんでした。もちろん DB インスタンスのタイプやどういう書き換えをするかで実行時間は変わるので、このあたりは兼ね合いになります。credentials テーブルについては要件の方を変え、全レコードを残すことは諦め、一度レコードをすべて消したあと特定のスタッフユーザーだけ新しくレコードを作る処理を入れて回避しました。

なお、このマスキングの仕組みは社内的には新しいものではなく、2020 年に公開した『Amazon RDS/Auroraをクローンするシステムを作った話』でも同じ仕組みを使っています。設定ファイルも共用しています。こちらは検証環境や開発環境と直接は関係なく、単に複製を作ってクエリパフォーマンスを計測するなどの用途で使うものです。

定期的な実行

この記事の最初の方で定期的に複製を作っていると書いたように、検証環境のデータベースについて、データベースを新しくリストアし古い方と入れ替える作業を、日次のバッチジョブとして実行しています。

この際、Aurora のリストア操作はパラメーターグループなどの設定値を指定しないとデフォルトのものが使われるため、古い方に設定されているものを引き継ぐようにしています。DB ユーザーも改めて作る必要があり、古い方のデータベースのユーザー情報と権限を調べ新しい方に再作成します。

また、検証環境にしかないレコードについても移行処理を行っています。実はリストアした後のデータベースでは各テーブルの主キーの AUTO_INCREMENT を大きな値に設定しています。これによりそれぞれのレコードについて主キーがしきい値より大きい場合は検証環境のみにあるデータだと判断し、古い方のデータベースから新しい方のデータベースへレコードを流し込んでいます。これにより開発者による検証環境での作業をなるべく壊さないようにしています。

外部キー制約がある場合は少しやっかいで、検証環境にのみ存在するレコードの参照している先が本番環境のレコードの場合、参照先のレコードが入れ替えのタイミングで削除されている可能性があります。このような場合どうするかは各チームに任せていて、たとえばとあるチームではこのような外部キーの不整合を見つけて検証環境側のレコードを消してしまう処理を入れています。

古い方と新しい方のデータベースを入れ替えると書きましたが、これは対象のデータベースを参照するための DNS レコードを作り、DNS レコードの参照先を書き換えることで実現しています。これにより接続元が持っている情報は書き換えずにデータベースを入れ替えられます。

クロスリージョン・リードレプリカ

今回のツールで作られたデータベースに対しては、手元の開発環境からでも接続できるように設定しています。弊社では Twingate を利用して開発者が手元からクラウドへ安全に接続できるようにしており、その一環で接続を許可しています。

ここで問題になるのは通信速度です。AWS にあるデータベースに対して、検証環境では同じく AWS にあるアプリケーションとの通信になりますが、開発環境では手元のパソコンで動くアプリケーションとの通信になります。この通信に時間がかかると、ちょっと手元でサーバーアプリを動かしてレスポンスを見ようとしても、複数のクエリを実行するために何回も通信が往復してレスポンスまでの時間が遅くなり、ユーザー体験に乖離が生まれてしまいます。他の環境と比べてクエリ 1 回あたり 100 ミリ秒遅くなったとしても、直列で 10 クエリしていると合計 1 秒遅くなってしまいます。正直まともに確認できません。

特に、目的のデータベースが海を越えた向こう側に位置している場合は厄介です。実際、データベースはアメリカにありつつ開発者は日本に居るといった状況が起こっています。クエリが海の上を行ったり来たりして、しっかり時間がかかります。

そこでそのような場合は、Aurora が備えているリージョンを跨いでリードレプリカを作成できる機能を使っています(クロスリージョン・リードレプリカ)。つまりライターインスタンスはアメリカに置きつつ、リーダーインスタンスは東京にあるものを参照できるようにします。クックパッドのサービスは多くの部分で read heavy なので、開発環境でもそれなりの応答時間で確認できるようになります。

ただし、クロスリージョン・リードレプリカの作成には多少時間がかかります。いま実際に動かしている例では 2 時間弱を要します。1 日は超えていないので許容範囲ではあるのですが、実行失敗時のリトライまで考えると少し面倒な点ではあります。

長所と短所

以上、検証環境や開発環境で本番環境相当のデータを使えるようにするために使っている仕組みのひとつを解説しました。このように本番環境相当の検証ができるようにすることで、サービス開発を高速に進められるようにしています。またここでは説明しませんでしたが、本番環境の DB バージョンを上げたいとき先に検証環境で試せるように、リストアした後に DB バージョンを変更できる機能を入れていたりもしています。

今回の仕組みはマスキングがそれなりに柔軟にできるという意味で扱いやすく、社内では複数のデータベースで利用しています。一方で本番環境に起こった変更の反映は翌日となるため、本番環境でのデータ変更の勢いも再現したいような場合には不向きです。イベントドリブンな部分の検証を受動的には行いづらい、などですね。

リアルタイムに近い状態で本番環境に近いデータを用意したい場合は、MySQL の binlog を直接使った仕組みや、AWS Database Migration Service (DMS) を使った仕組みが考えられます。これらも状況によっては便利なのですが、AUTO_INCREMENT の調整の簡易さ、マスキングの柔軟性、壊れたときのメンテナンスの容易さなどに差異があります。特に何かしらが壊れたときに直すのがやや面倒なため、日次入れ替えで充分な場合はそうするようにしています。

ところで……。途中でデータベースがアメリカにある事例の話をしましたが、一体それはどんな場合なのでしょうか? 詳細はこの記事ではまだ秘密! 後日ご紹介予定ですので、弊社の X アカウントをフォローして更新をお待ちください。