こんにちは、PayPayフリマバックエンド開発の三宅です。 今回、YJTC2019-shibuyaにてPayPayフリマのバックエンド設計について話して来ましたので内容を紹介したいと思います。
本記事ではセッション前半のバックエンド部分をメインに紹介させていただきます。よろしくおねがいします。
PayPayフリマとは
PayPayフリマはフリマに特化したサービスとして10月7日にiOS版をリリースしました。PayPayの名前がつく通り、PayPayを利用してフリマの商品をかんたんに購入でき、買い手から価格の相談をできる機能などが特長です。
また、ヤフオク!とも連携し、ヤフオク!に出品されている固定価格商品の一部もユーザー体験に変わりなく購入できるようになっています。
キャンペーンと販促
PayPayフリマはロンチのタイミングから大きく注目を集めるための仕掛けを用意していました。送料をヤフーが負担する送料0円キャンペーンやCMの投下、販売手数料の一部をPayPayボーナスライトで還元するキャンペーンなど、多くの資本を投下することでダウンロードを促進することに成功しています。結果としてロンチから1カ月で100万ダウンロードをいただき、現在では200万を超え、さらに規模を拡大し続けています。
実現するシステム
このPayPayフリマのバックエンド(以下BE)システムはどうなっているかみていきましょう。
PayPayフリマのBEシステムは主要となる部分をほぼ全て0ベースで開発しています。機能数は18、API数は60以上と立ち上げ期のサービスとしてはかなり大規模だったことがわかるかと思います。
最終的に半年の期間を約20名のエンジニアで走り、プロダクトとしてリリースできたわけですが、これだけのシステムを作り込むために工夫したシステム設計の中から
- 技術選定と開発スタイル
- マイクロサービスアーキテクチャ
- ヤフオク!との連携
- GraphQLの活用
の4つのキーワードとして取り上げ、本記事で紹介しようと思います。
ノウハウ資産を生かす「技術選定と開発スタイル」で開発スピード向上
PayPayフリマのBEシステムでは技術選定と開発スタイルにこだわりました。
まず技術選定ですが、KotlinとSpringBootという組み合わせで開発しています。これは、全社にあるSpringBootのノウハウの活用とAndroidからの人員の流動性、Kotlinが持つ型安全性やコルーチンなどの機能を活用するという前提で採用し、積極的に新技術を取り入れることでコード量に対する生産性を意識しています。
また、マイクロサービスアーキテクチャを採用しコード自体をテンプレート化することで、複数コンポーネントを高速に同時開発しています。
ソフトウエアアーキテクチャは人によって癖が出る部分が大きいと思いますが、チーム内でペアプログラミングを導入し、組み合わせをシャッフルさせながら開発することでコード品質の偏りを軽減させるよう働きかけています。
スケールアウトしやすい「マイクロサービスアーキテクチャ」で並行開発
上記でも少し触れましたが、PayPayフリマは将来的に開発規模を増強し、システム的にも組織的にもスケールアウトしやすいよう、マイクロサービスアーキテクチャを前提としてシステムを設計しています。
ざっくりとしたシステム構成がこちらです。マイクロサービスアーキテクチャの考え方自体はヤフオク!のものを踏襲する形にしていて、主に、BFF、ゲートウェイ、アプリケーションサーバー、プラットフォームサーバー、データベースで構成しています。
下記にそれぞれの機能について説明します。
BFF(Backend for Frontend)
アプリからデータを取得する際にたたくAPIは全てBFFのAPIを利用しています。BFFの役目として、マッシュアップ、フォーマットという責務をもたせています。マイクロサービスアーキテクチャにおいて、データソースは基本的にリソースベースで切ることが多いと思いますが、アプリの画面構成的に単純なリソースの形で利用するケースは少なく、複数のリソースを組み合わせて利用することがほとんどです。
BFFがない場合は状況にあわせてアプリが複数のAPIを同時にたたきデータを取得するわけですが、そうするとアプリ側にデータを取得するためのロジックが乗ってしまい、アプリ自体の保守性が悪くなってしまいます。その解決策として、アプリのロジックを一部肩代わりする形で、BFFがデータの集約とアプリが利用しやすいフォーマットに整形してデータをわたしてあげることで、ロジック量を最小化し、アプリがUI・UXの開発に集中させることを目的としています。
また、PayPayフリマにおいては、ヤフオク!のデータをマッシュアップすることにも利用しています。BFFでヤフオク!のAPIとPayPayフリマのAPIについてフォーマットの差異を吸収することで、アプリは「ヤフオク!・PayPayフリマのどちらの商品であるか」ということを意識せずに商品を扱うことができます。
ゲートウェイ
PayPayフリマでは、BFFとアプリケーションサーバーの間にゲートウェイサーバーを導入しています。全社で用意されている共通のプラットフォームを利用していて、マイクロサービスアーキテクチャの課題であるAPIのホストが分散してしまうという状況を防ぎ、APIの一元管理とその後ろのサーバー構成を隠蔽させることを可能としています。
アプリケーションサーバー
アプリケーションサーバーでは出品・商品情報・質問・いいねごとの機能レベルで分割されたドメインロジックを持ちます。データは直接扱わず、さまざまなPFサーバーからデータを収集し、バリデーションや加工するためのドメインロジックをメインに責務を持つ機能です。
プラットフォームサーバー
データベースにアクセスを行い、IFを提供するためのサーバーです。トランザクション処理を行う場合を除きロジックは持たず、データを受け渡す責務のみを果たします。データは基本的にリソースごとに分断し、GraphQLを採用しているため、クライアント側が必要な情報のみを指定して取得できます。また、データベースに関するキャッシュ機能などもこのサーバー内で隠蔽しています。
プラットフォームサーバーとしてアプリケーションサーバーから分離することによって、将来的にスケールアウトする際にドメインロジックが重く、データベースのコネクション数の関係でサーバーがスケールアウトできないといった問題を軽減しています。
データベース
PayPayフリマではデータソースとして、Oracle、MySQL、Cassandraを採用しています。またデータキャッシュ用にRedisを併用する形にしています。
マイクロサービスアーキテクチャのメリット
マイクロサービスアーキテクチャを採用することで得るメリットを紹介します。
役割が明確
それぞれの層の定義を決め、役割をもたせることでシステムの依存を整理し、全体の構成の見通しを良くしています。今後、さまざまな機能を追加開発した場合に役割が厳密でないとサーバー間の依存が闇雲に増えるだけなので、難解なシステムになってしまいますが、それを軽減させることを目的にしています。
多人数での並行開発がしやすい
PayPayフリマでは、ロンチ前で最大16人程度と複数人で同時並行開発する場面がありました。その場合、1機能に複数の機能を集約させてしまうと、並行開発時にコードがコンフリクトしやすくなり、思った通りの生産性が発揮できなくなります。それを適切に分割することで、コンポーネントを同士並行的に開発することを可能にしました。
コンポーネントごとにスケールアウトしやすい
マイクロサービスにすることによって、コンポーネント間の依存を排除できるため、負荷の偏りによるスケールアウトをしやすいといったメリットがあります。例えばユーザーの機能は負荷が高い、質問の機能は負荷が低いと言ったように実際の負荷状況に合わせてサーバー台数を適切に設定できます。
共通機能は「ヤフオクとの連携」で開発コストを抑制
PayPayフリマはヤフオク!との連携も強みにしています。例えばクロスリスティングといった機能は、ヤフオク!の商品の一部でPayPayフリマと商品仕様が近いものを抽出してPayPayフリマ上にもリスティングさせる機能です。その他にも取引を扱うシステムや課金情報を扱うシステムなどは、ヤフオク!と共通で利用することで全体の開発工数を抑えています。
本記事ではその中でもクロスリスティング機能の概要を説明します。
クロスリスティング
クロスリスティングはBFFと検索のインデックスをヤフオク!・フリマで共用することで実現しています。出品時にヤフオク!からの出品のデータとPayPayフリマからの出品を同じ検索システムに連携し、両方の商品をデータフォーマットを合わせた状態で検索にインデックスさせます。
そうすることで、検索上にはPayPayフリマとヤフオク!の商品の両方が検索データ蓄積されることになり、検索リクエストで両方の商品が混ざったデータを取得することが可能です。
一方で商品詳細閲覧や取引を行う際は、PayPayフリマ、ヤフオク!それぞれの商品データが別にあるため、BFFがたたき分けています。両者の商品は商品IDで区別できるため、PayPayフリマの商品ならPayPayフリマの商品詳細API、ヤフオク!の商品ならヤフオク!の商品詳細APIといったように、たたき先を分け、レスポンスフォーマットを統一してアプリに提供するようにしています。
今回はクロスリスティングについて説明しましたが、PayPayフリマではこれ以外でもさまざまな場面でヤフオク!連携をし、必要な部分はスクラッチ開発、それ以外はヤフオク!の資産を再利用するようにして、有限なリソースを最大限必要な箇所に割り振るように開発をおこないました。
保守しやすい「GraphQLの活用」で変化に強いシステムを構築
PayPayフリマではサーバー間通信においてGraphQLを積極的に採用しています。本記事ではシステムにおける採用場所とメリットについて説明します。
GraphQLとは
すでにご存じの方も多いとは思いますが、GraphQLとはAPIへの問い合わせと操作のための言語です。2015年にFacebookが発表し、現在では弊社を含め多くの企業がシステムに導入しています。
PayPayフリマでもGraphQLをプラットフォーム層とアプリケーションサーバー間の通信において採用しています。それ以外の連携に関してはRestAPIとしてIFを定義する形を取っています。
GraphQLのメリット
PayPayフリマにおいてGraphQLを採用した理由について本記事でいくつか説明します。
スキーマの柔軟性
GraphQLではQueryによってクライアント側が必要とする情報を定義できるため、多数のコンポーネントを持つマイクロサービスにおいて、RestAPIのように都度スキーマを定義する必要がなくなります。また、GraphQLは必要とする情報ごとにACLをかけることができるため情報別にアクセスするサーバーを絞ることが可能です。
RestAPIの思想に照らし合わせたときにリソースの形が複数存在することも同時に防げます。
アクセス元の環境に左右されない
GraphQLはあくまでQueryを定義し実行するためのランタイムのため、クエリが確定している場合はCurlでたたくことが可能です。PayPayフリマではヤフオク!のシステムから複数連携しており、さまざまな環境からリクエストできる必要があります。gRPCのようにクライアントライブラリが提供されているか確認する必要がないため、把握できていない連携が将来的に発生した場合でも対応可能です。
仕様追加への対応
RestAPIはリソースが厳密に定義されていることが重要であり、それが崩れた場合とたんにAPI全体の見通しが悪くなってしまいます。特にデータベースではデータソースがRDBの場合、テーブル同士のJoinによってかんたんにリソースの崩壊を招いてしまいます。
サービスにおいて今後リソースにデータが追加されたりデータ連携が発生することは容易に想像でき、仕様追加が多数発生した場合でも保守しやすい状況を保つためには、スキーマ変更にある程度強い構成を保つ必要があります。
GraphQLはレスポンスとなる定義が追加された場合においてもすでに指定しているQueryのレスポンスは全く変化しなく、リソースごとにデータ構造もかんたんに整理できるように作られているため、度重なる仕様変更に対しても修正コストを低く抑えることが可能です。
これにより、仕様変更によるデータの追加が発生した場合では、RestAPIのように都度スキーマの正当性を検証し、ケースに応じてサーバーに手を加える必要がなくなります。また、既存のGraphQLのクエリに対するレスポンスは一切変更されないため、上流サーバーの影響を検討する必要がなくなります。結果としてRestAPIで発生していた調査や対応にかかるコストを削減できるため、より効率の良いAPI保守が可能です。
まとめ
本記事ではPayPayフリマを支えるBEシステムの構成について
- 技術選定
- マイクロサービスアーキテクチャ
- ヤフオク!連携
- GraphQL
と4つの要素について取り上げ紹介しました。それぞれの要素について目立って珍しい、新しいものではないと思いますが、それらを組み合わせて積極的に導入していくことで効率よくシステム開発することを可能にしてきました。
明日の記事では 、Androidアプリ開発について触れる予定です。
今後の開発でも継続的に新しい技術を取り入れ続けることで新陳代謝のよいシステムを作りながらスピード感よくサービスを大きくしていきたいと思いますので、これからのPayPayフリマを期待していてください!
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました