Pub/Sub を駆使するマイクロサービスにおける PR 単位の検証環境導入の取り組み
メルカリ・メルペイのエンジニアが、Pub/Sub の Pull 型アーキテクチャを維持したまま PR 単位の検証環境を実現する独自のアプローチと課題解決策を報告している。
キーポイント
Pull 型 Pub/Sub の並列 QA 制約
従来の Pull 型サブスクリプションでは、Publisher が特定の Consumer にメッセージを送信する指定ができないため、複数の PR で同じ環境を共有すると検証が困難になる課題があった。
既存アーキテクチャの尊重
本番環境の非同期処理構造を大きく変更せず、QA 改善のみを目的として解決策を検討し、Pull 型の特性を維持したまま PR 隔離を実現する方針を採用した。
要件定義とアーキテクチャ設計
Dev 環境と PRRC(PR 検証)環境間でメッセージを分けて受け取り、かつ文脈情報を後続処理へ正しく引き継ぐという2つの厳格な要件を設定し、これに基づいて実装を行った。
技術的解決の方向性
gRPC Pusher などの既存ツールをそのまま適用するのではなく、Pull 型の制約下で如何にメッセージルーティングと文脈継承を行うかという独自の実装アプローチが取られた。
影響分析・編集コメントを表示
影響分析
この記事は、大規模マイクロサービスアーキテクチャにおける QA プロセスのボトルネック解消に向けた実践的な知見を提供しています。特に、Pub/Sub の Pull 型という制約条件下で如何にして CI/CD の効率化を図るかという課題解決プロセスは、類似の非同期処理システムを運用する組織にとって非常に参考になるケーススタディです。
編集コメント
AI 技術そのものの進展を報じる記事ではありませんが、大規模システム運用における QA 効率化の知見として、エンジニアリングコミュニティにとって価値の高い実践レポートです。
こんにちは。今年4月に入社したメルペイ Loyalty & Santa(Growth Platform)チームでBackend Engineerをしている@mikupoです。この記事は「Merpay&Mercoin Tech Openness Month 2026」の8日目の記事です!
はじめに
私が所属しているSantaチームは、メルカリ・メルペイにおけるポイント還元やキャンペーンの基盤となるシステムを開発・運用しています。Santaの処理はすべて非同期で、Pub/Sub の Pull 型 subscription(購読)を中心に構成されています。
Santaの開発で課題になっていたのが、QAプロセスです。検証に使える開発環境(Dev環境)はチームに1つしかなく、複数の開発(Pull Request 以降、PR) が重なると QA を並列に進められませんでした。実装は終わっているのに、検証環境が空くのを待つ、そんな状況が発生していました。
PRごとに独立した環境を用意できれば、この待ち時間はなくせます。ただ、Santaでそれを実現するのは簡単ではありませんでした。Pull型のsubscriptionでは、複数のconsumer(消費者)が同じsubscriptionに接続している場合、どのconsumerがどのmessageを受け取るかをpublisher側から指定できません。そのため、「このイベントはこの PR 環境へ」と狙って届けることができません。
社内にはすでに、こうした課題に使えそうな仕組みもいくつかありました。ただ、それらを Santa に取り入れるには、本番の非同期処理の作りに大きく手を入れる必要がありました。今回達成したいのは QA の改善であり、そのために本番の非同期処理のかたちを大きく作り変えるのは避けたいと考えました。
本記事では、この制約のなかで「Pull型を保ったまま、PRごとに環境を分ける」 をどう実現したのかを紹介します。
Santaについてくわしく知りたい方は、「メルペイのキャンペーンを支えるサンタの秘密」をご確認ください。
PR単位の検証環境が必要になった背景
従来、Santaチームの検証に使えるDev環境は1つしかありませんでした。複数のPRを同じDev環境へ同時に反映すると、不具合が起きたときに原因となった変更を切り分けづらくなります。変更同士がconflictする場合は、そもそも並行して QA を進められませんでした。
このボトルネックを減らすための選択肢として、SantaではPull Request Replication Controller(PRRC)に注目しました。PRRCとは、GitHubのPRを起点としてDev環境とは別に、PRごとの検証環境(PRRC環境)を作成するためのKubernetes custom controllerを使った仕組みです。
PRRC によって PR ごとの検証環境を作る道筋は見えました。次に検討したのが、社内で使われている Pub/Sub gRPC Pusher です。Pub/Sub message を gRPC request として扱えれば、既存の Dynamic Service Routing と組み合わせて PRRC 環境へルーティングできるように見えました。
しかし、Santa の Pub/Sub 処理は Pull 型 subscription を前提に作られています。今回解決したかったのは QA プロセスのボトルネックであり、本番の非同期処理の仕組みを大きく変えることではありませんでした。一方で、gRPC Pusher をそのまま使うには、既存の Pub/Sub handler を gRPC endpoint として受けられる形に変える必要があります。そのため、QA 環境の改善として取り組むには、本番環境への影響や変更範囲が大きくなりすぎると判断しました。
そのため、私たちは既存の Pull 型 Pub/Subを保ったまま PR 単位の検証環境を実現するために、Santa 側で満たすべき要件を整理しました。
Pull 型 Pub/Subを保ったまま PR 単位の検証環境を作るための要件
既存の gRPC Pusher をそのまま使うのではなく、Santa の Pull 型 subscription を保ったまま PR 単位の検証環境を実現するには、まず満たすべき要件を整理する必要がありました。PRRC 環境を実際の検証に使える状態にするには、message を意図した環境で受け取れることと、PRRC 向けの文脈を後続処理へ引き継げることが重要でした。
ここでは、この 2 つの要件を順に説明します。
要件 1:Dev 環境と PRRC 環境で message を分けて受け取れること
1 つ目の要件は、Dev 環境で確認したい message と、特定の PRRC 環境で確認したい message を分けて受け取れることです。PR ごとの検証環境を作れたとしても、それぞれの環境で確認したい message が混ざってしまうと、どの PR の変更による挙動なのかを切り分けづらくなります。
message が混ざる原因は、Pull 型 subscription の受け取り先を publisher 側から指定できないことにあります。図 1 のように、PRRC 環境の consumer を Dev 環境と同じ subscription につなぐと、複数の consumer が同じ subscription から message を受け取る構成になります。そのため、Dev 環境で確認したい message を PRRC 環境が受け取ったり、PRRC 環境で確認したい message を Dev 環境が受け取ったりする可能性があります。

このため、PR 単位の検証環境として使うには、メッセージを環境ごとに分けて受け取れる仕組みが必要になります。
要件 2:PRRC 環境向けのルーティング情報を後続処理へ引き継げること
2 つ目の要件は、メッセージがどの PRRC 環境向けなのかを、後続の処理にも引き継げることです。Santa の処理は Pub/Sub メッセージを受け取って終わりではなく、処理の途中で他のマイクロサービス(microservice)を gRPC で呼び出したり、別の Pub/Sub メッセージを publish したりします。
そのため、Santa の Dev 環境と PRRC 環境でメッセージを分けて受け取れるだけでは不十分です。結合テストでは、Santa から呼び出すマイクロサービス側にも PRRC 環境が用意されている場合があります。その場合、Santa からの呼び出しも通常の Dev 環境ではなく、対応するマイクロサービスの PRRC 環境へルーティングできる必要があります。
図 2 のように、このルーティングを実現するには、Santa が受け取ったメッセージに付与されたルーティング情報を、後続の gRPC 呼び出しや Pub/Sub publish にも引き継ぐ必要があります。つまり、メッセージ自体にルーティング情報を持たせ、Santa 内の処理でもその情報を落とさない仕組みが必要になります。

実現方法の検討
ここまで整理した 2 つの要件を満たすには、Pub/Sub メッセージにルーティング情報を持たせたうえで、その情報をどの段階で使ってメッセージを振り分けるかを決める必要がありました。大きく分けると、consumer がメッセージを受け取ったあとに判断する方法、Topic 自体を分ける方法、subscription の filter で受け取るメッセージを分ける方法があります。
私たちは、それぞれの方法について、Pull 型 subscription を維持できるか、対象外のメッセージを余計に pull しないか、PRRC ごとの運用負荷が大きくなりすぎないか、という観点で比較しました。

最初に検討したのは、consumer 側でメッセージ attribute を見て、対象外のメッセージを処理しない方法でした。この方法は実装範囲が小さく見えますが、対象外のメッセージも一度 pull してしまいます。対象外のメッセージを ack すると本来処理すべき環境に届かず、nack すると redelivery が繰り返される可能性があります。
Topic を Dev 用と PRRC 用に分離する方法も検討しました。この方法では、あらかじめ PRRC 用の Topic と subscription のペアを用意しておき、PR ごとにどのペアを使うかを割り当てます。Topic 単位で分離できるため構成は直感的ですが、PR ごとの割り当てを手動で管理する必要があります。そのため、割り当て忘れや重複割り当てが起きやすく、PRRC 環境が増えるほど運用負荷が高くなります。
これらに対して、subscription filter を使う方法では、consumer が message を pull する前に、subscription 側で受け取る message を分けられます。さらに、振り分けに使う message attribute をそのままルーティング情報として扱えるため、後続の Pub/Sub publish や gRPC 呼び出しにも同じ情報を引き継げます。つまり、要件 1 の「message を環境ごとに分けて受け取ること」と、要件 2 の「ルーティング情報を後続処理へ引き継ぐこと」を、同じ message attribute を軸に実現できます。
最終的な方針
最終的な方針は、Pull 型 subscription を維持したまま、pubsub message の attribute で配送先を分けることです。各 message の attribute にルーティング情報を付け、subscription 側はその値を filter の条件にします。こうすると、同じ topic に届いた message でも、条件に一致した subscription だけが message を受け取ります。
図のように、たとえば PR 番号 1234 を検証する場合、その message の attribute には、PR 番号に対応するルーティング情報 (PR1234) を付与します。Dev 環境の subscription はこの message を受け取らず、PR1234 用の subscription だけが受け取ります。

さらにこのルーティング情報は、Santa が publish する message にも引き継げます。受け取った Pub/Sub message の attribute からルーティング情報を読み取り、context に格納し、後続の publish や外部 microservice の呼び出しへ渡します。これにより、PRRC の文脈が処理の途中で途切れません。
一方で、外部サービスの subscription にそのまま filter を足すことはできませんでした。Santa は、ポイント還元などのトリガーとなるイベントを、決済をはじめとする他の microservice から Pub/Sub で受け取っています。これらの外部 subscription は発行側の microservice(=別チーム)の管理範囲にあり、Santa が直接 filter を加えると、別チームが管理するリソースに手を入れることになってしまいます。そこで外部 subscription については proxy sidecar を挟み、Santa 側の proxy topic へ再 publish する構成にしました。Santa の Pod は外部 subscription を直接 pull せず、proxy topic に対して作った Dev / PRRC 用の filtered subscription を読みます。
この方針により、Pull 型 subscription を維持したまま、Pub/Sub message を意図した環境だけに届けられ、しかも変更を Santa の管轄内だけで完結できます。一方で、PRRC ごとに subscription を作る必要があるため、その自動作成・削除の設計が新たに必要になりました。
まとめ
本記事では、Pull 型 Pub/Sub を維持したまま、Pub/Sub message attribute と filtered subscription を使って Santa に PRRC 環境を導入した取り組みを紹介しました。
従来は、QA 期間が重複する場合には統合環境を用意するか、複雑なプロジェクト同士の場合は直列で進めて QA 待ちが発生するしかありませんでした。しかし、実際にこの仕組みを用いることで、直近の大きな 2 つのプロジェクトでは QA を並列化して進めることができました。また、共有設定を変更するテストを直列でしか実施できなかったのが、QA メンバーの人数に合わせて 3 つ 4 つとスケールできるようになり、QA 期間の短縮にも貢献できました。
自分たちのチームの状況も踏まえながら、よりチームに合った解決策を模索し、それを実現できたのは、チームの皆さんの協力があってこそです。Loyalty & Incentive チームの皆様、ありがとうございました!
次の記事は sapuri さんの「内製ワークフローエンジンの設計とメルカリでの活用事例」です。引き続きお楽しみください。
原文を表示
こんにちは。今年4月に入社したメルペイ Loyalty & Santa(Growth Platform)チームでBackend Engineerをしている@mikupoです。この記事は「Merpay&Mercoin Tech Openness Month 2026」の8日目の記事です!
はじめに
私が所属しているSantaチームは、メルカリ・メルペイにおけるポイント還元やキャンペーンの基盤となるシステムを開発・運用しています。Santaの処理はすべて非同期で、Pub/SubのPull型 subscriptionを中心に構成されています。
Santaの開発で課題になっていたのが、QAプロセスです。検証に使える開発環境(Dev環境)はチームに1つしかなく、複数の開発(Pull Request 以降、 PR) が重なるとQAを並列に進められませんでした。実装は終わっているのに、検証環境が空くのを待つ、そんな状況が発生していました。
PRごとに独立した環境を用意できれば、この待ち時間はなくせます。ただ、Santaでそれを実現するのは簡単ではありませんでした。Pull型のsubscriptionでは、複数のconsumerが同じsubscriptionに接続している場合、どのconsumerがどのmessageを受け取るかをpublisher側から指定できません。そのため、「このイベントはこのPR環境へ」と狙って届けることができません。
社内にはすでに、こうした課題に使えそうな仕組みもいくつかありました。ただ、それらを Santa に取り入れるには、本番の非同期処理の作りに大きく手を入れる必要がありました。今回達成したいのは QA の改善であり、そのために本番の非同期処理のかたちを大きく作り変えるのは避けたいと考えました。
本記事では、この制約のなかで「Pull型を保ったまま、PRごとに環境を分ける」 をどう実現したのかを紹介します。
Santaについてくわしく知りたい方は、「メルペイのキャンペーンを支えるサンタの秘密」をご確認ください。
PR単位の検証環境が必要になった背景
従来、Santaチームの検証に使えるDev環境は1つしかありませんでした。複数のPRを同じDev環境へ同時に反映すると、不具合が起きたときに原因となった変更を切り分けづらくなります。変更同士がconflictする場合は、そもそも並行してQAを進められませんでした。
このボトルネックを減らすための選択肢として、SantaではPull Request Replication Controller(PRRC)に注目しました。PRRCとは、GitHubのPRを起点としてDev環境とは別に、PRごとの検証環境(PRRC環境)を作成するためのKubernetes custom controllerを使った仕組みです。
PRRCによってPRごとの検証環境を作る道筋は見えました。次に検討したのが、社内で使われているPub/Sub gRPC Pusherです。Pub/Sub messageをgRPC requestとして扱えれば、既存のDynamic Service Routingと組み合わせてPRRC環境へルーティングできるように見えました
しかし、SantaのPub/Sub処理はPull型subscriptionを前提に作られています。今回解決したかったのはQAプロセスのボトルネックであり、本番の非同期処理の仕組みを大きく変えることではありませんでした。一方で、gRPC Pusherをそのまま使うには、既存のPub/Sub handlerをgRPC endpointとして受けられる形に変える必要があります。そのため、QA環境の改善として取り組むには、本番環境への影響や変更範囲が大きくなりすぎると判断しました。
そのため、私たちは既存のPull型Pub/Subを保ったままPR単位の検証環境を実現するために、Santa側で満たすべき要件を整理しました。
Pull型Pub/Subを保ったままPR単位の検証環境を作るための要件
既存のgRPC Pusherをそのまま使うのではなく、SantaのPull型 subscriptionを保ったままPR単位の検証環境を実現するには、まず満たすべき要件を整理する必要がありました。PRRC環境を実際の検証に使える状態にするには、messageを意図した環境で受け取れることと、PRRC向けの文脈を後続処理へ引き継げることが重要でした。
ここでは、この2つの要件を順に説明します。
要件1:Dev環境とPRRC環境でmessageを分けて受け取れること
1つ目の要件は、Dev環境で確認したいmessageと、特定のPRRC環境で確認したいmessageを分けて受け取れることです。PRごとの検証環境を作れたとしても、それぞれの環境で確認したいmessageが混ざってしまうと、どのPRの変更による挙動なのかを切り分けづらくなります。
messageが混ざる原因は、Pull型subscriptionの受け取り先をpublisher側から指定できないことにあります。図1のように、PRRC環境のconsumerをDev環境と同じsubscriptionにつなぐと、複数のconsumerが同じsubscriptionからmessageを受け取る構成になります。そのため、Dev環境で確認したいmessageをPRRC環境が受け取ったり、PRRC環境で確認したいmessageをDev環境が受け取ったりする可能性があります。

このため、PR単位の検証環境として使うには、messageを環境ごとに分けて受け取れる仕組みが必要になります。
要件2:PRRC環境向けのルーティング情報を後続処理へ引き継げること
2つ目の要件は、messageがどのPRRC環境向けなのかを、後続の処理にも引き継げることです。Santaの処理はPub/Sub messageを受け取って終わりではなく、処理の途中で他のmicroserviceをgRPCで呼び出したり、別のPub/Sub messageをpublishしたりします。
そのため、SantaのDev環境とPRRC環境でmessageを分けて受け取れるだけでは不十分です。結合テストでは、Santaから呼び出すmicroservice側にもPRRC環境が用意されている場合があります。その場合、Santaからの呼び出しも通常のDev環境ではなく、対応するmicroserviceのPRRC環境へルーティングできる必要があります。
図2のように、このルーティングを実現するには、Santaが受け取ったmessageに付与されたルーティング情報を、後続のgRPC呼び出しやPub/Sub publishにも引き継ぐ必要があります。つまり、message自体にルーティング情報を持たせ、Santa内の処理でもその情報を落とさない仕組みが必要になります。

実現方法の検討
ここまで整理した2つの要件を満たすには、Pub/Sub messageにルーティング情報を持たせたうえで、その情報をどの段階で使ってmessageを振り分けるかを決める必要がありました。大きく分けると、consumerがmessageを受け取ったあとに判断する方法、Topic自体を分ける方法、subscriptionのfilterで受け取るmessageを分ける方法があります。
私たちは、それぞれの方法について、Pull型subscriptionを維持できるか、対象外のmessageを余計にpullしないか、PRRCごとの運用負荷が大きくなりすぎないか、という観点で比較しました。

最初に検討したのは、consumer側でmessage attributeを見て、対象外のmessageを処理しない方法でした。この方法は実装範囲が小さく見えますが、対象外のmessageも一度pullしてしまいます。対象外のmessageをackすると本来処理すべき環境に届かず、nackするとredeliveryが繰り返される可能性があります。
TopicをDev用とPRRC用に分ける方法も検討しました。この方法では、あらかじめPRRC用のTopicとsubscriptionのペアを用意しておき、PRごとにどのペアを使うかを割り当てます。Topic単位で分離できるため構成は直感的ですが、PRごとの割り当てを手動で管理する必要があります。そのため、割り当て忘れや重複割り当てが起きやすく、PRRC環境が増えるほど運用負荷が高くなります。
これらに対して、subscription filterを使う方法では、consumerがmessageをpullする前に、subscription側で受け取るmessageを分けられます。さらに、振り分けに使うmessage attributeをそのままルーティング情報として扱えるため、後続のPub/Sub publishやgRPC呼び出しにも同じ情報を引き継げます。つまり、要件1の「messageを環境ごとに分けて受け取ること」と、要件2の「ルーティング情報を後続処理へ引き継ぐこと」を、同じmessage attributeを軸に実現できます。
最終的な方針
最終的な方針は、Pull型subscriptionを維持したまま、pubsub messageのattributeで配送先を分けることです。各messageのattributeにルーティング情報を付け、subscription側はその値をfilterの条件にします。こうすると、同じtopicに届いたmessageでも、条件に一致したsubscriptionだけがmessageを受け取ります。
図のように、たとえば PR番号1234 を検証する場合、その message の attribute には、PR番号に対応するルーティング情報(PR1234)を付与します。Dev環境のsubscriptionはこのmessageを受け取らず、PR1234用のsubscriptionだけが受け取ります。

さらにこのルーティング情報は、Santaがpublishするmessageにも引き継げます。受け取ったPub/Sub messageのattributeからルーティング情報を読み取り、contextに格納し、後続のpublishや外部microserviceの呼び出しへ渡します。これにより、PRRC の文脈が処理の途中で途切れません。
一方で、外部サービスの subscription にそのまま filterを足すことはできませんでした。Santa は、ポイント還元などのトリガーとなるイベントを、決済をはじめとする他のmicroservice から Pub/Sub で受け取っています。これらの外部 subscriptionは発行側の microservice(=別チーム)の管理範囲にあり、Santa が直接 filterを足すと、別チームが管理するリソースに手を入れることになってしまいます。そこで外部 subscription については proxy sidecar を挟み、Santa 側の proxy topicへ再 publish する構成にしました。Santa の Pod は外部 subscription を直接 pullせず、proxy topic に対して作った Dev / PRRC 用の filtered subscriptionを読みます。

この方針により、Pull型subscriptionを維持したまま、Pub/Sub messageを意図した環境だけに届けられ、しかも変更をSantaの管轄内だけで完結できます。一方で、PRRCごとにsubscriptionを作る必要があるため、その自動作成・削除の設計が新たに必要になりました。
まとめ
本記事では、Pull型Pub/Subを維持したまま、Pub/Sub message attributeとfiltered subscriptionを使ってSantaにPRRC環境を導入した取り組みを紹介しました。
従来は、QA期間が重複する場合には統合環境を用意するか、複雑なプロジェクト同士の場合は直列で進めてQA待ちが発生するしかありませんでした。しかし、実際にこの仕組みを用いることで、直近の大きな2つのプロジェクトではQAを並列化して進めることができました。また、共有設定を変更するテストを直列でしか実施できなかったのが、QAメンバーの人数に合わせて3つ4つとスケールできるようになり、QA期間の短縮にも貢献できました。
自分たちのチームの状況も踏まえながら、よりチームに合った解決策を模索し、それを実現できたのは、チームの皆さんの協力があってこそです。Loyalty & Incentiveチームの皆様、ありがとうございました!
次の記事は sapuriさんの「内製ワークフローエンジンの設計とメルカリでの活用事例」です。引き続きお楽しみください。
関連記事
クラウドネイティブ会議に出展しました
メルカリの DBRE チームと IDP チームは、2026 年 5 月 14 日から 15 日に開催されたクラウドネイティブ会議にスポンサーとして出展し、認証やマイクロサービス規模に関する議論を交わした。
CLI のデプロイ制限が撤廃されました
Vercel が CLI ツールのデプロイに関する制限を撤廃し、開発者がより柔軟にアプリケーションを公開できるようになりました。
Vercel Drop の紹介:ブラウザ上でファイルをドラッグするだけでデプロイ可能に
Vercel は、Git や CLI を不要とする新機能「Vercel Drop」を発表した。ユーザーはブラウザでファイルやフォルダをドラッグするだけで、フレームワークを検知し数秒で本番環境へ公開できる。
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み