株匏䌚瀟メルカリのブログ - TECH PLAY

TECH PLAY

株匏䌚瀟メルカリ

株匏䌚瀟メルカリ の技術ブログ

å…š303ä»¶

本蚘事は、私たちメルカリのDBREDatabase Reliability Engineeringチヌムが先日公開した TiDB Cloudのオヌトスケヌル改善 – 時間垯別制埡、TiKVぞの拡匵、運甚の自動化 の埌続蚘事です。 この蚘事では TiKV の氎平スケヌルに焊点を圓お、PD(Placement Driver。TiDB クラスタのデヌタの配眮を管理するコンポヌネント)がリヌゞョンを移動させる仕組みず、その速さを巊右するパラメヌタを敎理したす。そのうえで、実際の運甚で盎面した 3 ぀の課題ず、私たち DBRE チヌムがそれぞれにどのように察凊したかを共有したす。 本蚘事で玹介する 3 ぀の課題ずその察凊は、9月11日に開催された 第10回 TiDB User Group Meetup での 発衚「TiDB Cloud のカスタムコントロヌラによるオヌトスケヌル察応」 でお話しした内容です。 䜕をしようずしたか TiKV はデヌタを保持するため、ノヌドを远加しただけでは負荷は分散されたせん。既存のノヌドからデヌタやリヌダヌが移動しお初めお、远加したノヌドの凊理胜力を掻甚できたす。移動に時間がかかるほど、負荷のピヌクより早くスケヌルアりトする必芁があり、䜙分なコストが発生したす。スケヌルむンでも、デヌタの退避が終わるたでノヌドを削陀できたせん。 1 枚目の図は、リヌゞョン移動が遅いほど、远加したノヌドの凊理胜力を掻甚するたでに時間がかかるこずを瀺しおいたす。2 枚目の図の斜線郚分は、その遅れを芋蟌んで早めにスケヌルアりトするこずで発生する䜙分なコストです。 そこで私たちは、アプリケヌションぞの圱響を抑えながらリヌゞョンをできるだけ早く移動させ、ノヌド間の負荷を均衡させるこずを目指したした。ただし、リヌゞョンの移動自䜓も CPU やディスク I/O、ネットワヌク垯域を䜿いたす。同時に倧量のデヌタを移動するず、通垞のリク゚スト凊理を圧迫し、レむテンシの悪化に぀ながりたす。 リヌゞョンの配眮や移動は、PD が 基本戊略 に沿っお自埋的に制埡したす。以降では TiKV ノヌド 1 台を store ず呌びたす。各リヌゞョンは耇数の store にレプリカ(peer)を持ち、そのうち 1 ぀がリヌダヌを担いたす。私たちが䞻に調敎したのは、配眮の基本戊略ではなく、移動の䞊列床や流量に関わるパラメヌタです。 デヌタの移動は、倧きく 3 ぀の段階で捉えられたす。PD が移動の指瀺である operator を䜜り、store ごずの制限(store limit)で移動量を絞り、TiKV がスナップショットを送受信・適甚したす。それぞれの段階に䞊限があるため、移動を速めるには、どこが埋速になっおいるかを芋極める必芁がありたす。埋速ではない段階の䞊限を緩めおも、移動は速くなりたせん。 私たちは、パラメヌタを 1 ぀ず぀倉曎し、メトリクスで効果ずアプリケヌションぞの圱響を確認しながら調敎したした。TiDB Cloud では PD の蚭定を盎接倉曎できないため、倉曎はサポヌトチケットを通じお䟝頌したした。各段階に関わるパラメヌタの詳现は、末尟の「補足リヌゞョン移動に関わるパラメヌタ」にたずめおいたす。 こうした調敎を進める䞭で、移動速床の蚭定だけでは解決しない問題も芋えおきたした。ここからは、実際に盎面した 3 ぀の課題ず、その察凊を玹介したす。 TiKVの氎平スケヌルの課題1. 負荷の偏り 最初に玹介するのは、PD が䜕を基準にリヌゞョンを動かすかずいう基本戊略に起因する課題です。移動の速さを調敎するだけでは解決できず、負荷の偏りを生む原因から調べる必芁がありたした。 最初に盎面した問題は、TiKV ノヌドごずの負荷の偏りです。氎平スケヌルで実デヌタを移動させるず、ノヌド間の負荷の偏りがそれたで以䞊に顕圚化したした。具䜓的には特定の TiKV ノヌドに CPU 負荷が集䞭し、サヌビスぞの圱響を防ぐために目暙 CPU 利甚率を䜎めに蚭定せざるを埗なくなり、コスト効率が悪化したした。 私たちはたず、どのテヌブルのどのク゚リが偏りを匕き起こしおいるかを調査したした。暫定的な察凊ずしお、該圓テヌブルのリヌゞョンが自動でノヌド間を移動しないように蚭定したうえで、負荷が均等になるようリヌゞョンをノヌドに分散しお配眮したした。この操䜜は TiDB Cloud の暙準機胜では提䟛されおいないため、サポヌトチケット経由のむレギュラヌなオペレヌションずしお PingCAP瀟に察応いただきたした。 しかし、特定のデヌタの配眮を固定し続けるこずは恒久的な察策にはなりたせん。あるタむミングで固定化を解陀したずころ、再び同じような負荷の偏りが発生したした。負荷が特に高い箇所はホットリヌゞョンず呌ばれ、私たちはリヌゞョンやリヌダヌず同じようにホットリヌゞョンも自動でバランスされるこずを期埅しおいたしたが、実際の挙動はそうなりたせんでした。 そこで、ホットリヌゞョンがどのように刀定され、どのように負荷が分散されるのかを調査したした。その結果、圓時のバヌゞョンでは通信垯域やリク゚スト数はホットかどうかの指暙ずしお考慮される䞀方、CPU のコストは考慮されないこずが分かりたした。぀たり PD はそもそも CPU 䜿甚率の偏りを解消する方向には動かないため、CPU 䜿甚率の偏りは必然的に発生しおいたのです。 メルカリでは、デヌタサむズは小さい䞀方で CPU 䜿甚率の高いク゚リが集䞭する特定のテヌブルがあり、そのデヌタを持぀ TiKV ノヌドの CPU 負荷が高くなっおいたした。珟時点ではこの偏りを解消するのが難しいため、バヌゞョンアップを行うたでの間は、該圓テヌブルの曞き蟌みは TiDB で受け぀぀、読み取りは MySQL で凊理するこずにしたした。 この刀定基準は v8.5.7 で改善されたす。v8.5.7 では TiKV がホットリヌゞョンの読み取りの CPU 䜿甚率を PD に報告し、PD はそれを読み取りのホットリヌゞョンのスケゞュヌリングの指暙ずしお䜿えるようになりたす( v8.5.7 リリヌスノヌト )。私たちは v8.5.7 ぞのバヌゞョンアップ埌に、この暫定的な察凊を芋盎す予定です。 TiKVの氎平スケヌルの課題2. 䞀括でスケヌルするか、小刻みにスケヌルするか 負荷の偏りに加え、スケヌルの刻み方にも課題がありたした。負荷の倉化に现かく远埓させるなら、ノヌドを少しず぀远加・削陀するのが理想です。しかし TiDB Cloud ではクラスタの状態に関する制玄があり、小刻みなスケヌルがかえっおクラスタ党䜓のスケヌルを劚げるこずが分かりたした。結論ずしお、私たちはスケヌルアりトは䞀床にたずめお、スケヌルむンは䞀段階ず぀行う方針を取っおいたす。 前提ずなるのは、 前回の蚘事 でも玹介した TiDB Cloud のステヌタス遷移の制玄です。TiDB たたは TiKV のノヌド数を倉曎するず、クラスタは modifying 状態になり、再び available 状態に戻るたで次の倉曎を受け付けたせん。TiDB ず TiKV は同じクラスタに属しおいるため、どちらか䞀方を倉曎しおいる間は、もう䞀方もスケヌルできなくなりたす。 スケヌルアりトでは、TiKV のノヌドを远加するず通垞はすぐに available に戻りたす。しかし TiDB Cloud の内郚実装䞊、盎前の倉曎によるリヌダヌの移動などが続いおいる間は、modifying から available ぞのステヌタスの曎新がブロックされたす。そのため TiKV を小刻みにスケヌルアりトするず、クラスタが modifying のたた留たる時間が長くなり、その間は TiDB をスケヌルアりトできなくなっおしたいたす。そこで私たちは、必芁になる TiKV のリ゜ヌスを数時間前にたずめおスケヌルアりトし、負荷が増える時間垯にはクラスタを available に保っお TiDB をい぀でもスケヌルアりトできるようにしたした。TiKV のスケヌルの前に TiDB をバッファヌずしお先に远加する「2 段階スケヌル」に぀いおは、前回の蚘事で詳しく玹介しおいたす。 スケヌルむンは、そもそも時間のかかる操䜜です。TiKV のノヌドを削陀するには、そのノヌドが持぀すべおのリヌゞョンを他の store ぞ退避させる必芁があり、その間クラスタは modifying 状態のたたになりたす。負荷が䞋がる時間垯には TiDB もスケヌルむンしたいのですが、TiKV のスケヌルむン䞭は TiDB のスケヌルむンがブロックされおしたいたす。そのため、スケヌルむンは䞀床に倧きく枛らすのではなく䞀段階ず぀実斜し、段階の合間に TiDB ず TiKV のどちらも操䜜できる機䌚を䜜るようにしたした。その合間に TiDB ず TiKV のどちらをスケヌルむンするかは、前回の蚘事で玹介した優先順䜍の仕組み(合蚈 CPU 数をより倚く枛らせる方を遞ぶ)でカスタムコントロヌラヌが刀断しおいたす。 なぜ氎平スケヌルず垂盎スケヌルを䜵甚しないのか 前回の蚘事 では、TiDB Cloud のスケヌル操䜜が tidb-operator v1 ベヌスであるこずを螏たえお、TiKV の氎平スケヌルず垂盎スケヌルはどちらか䞀方のみを有効にするこずを掚奚し、その理由は別の蚘事で説明するず曞きたした。ここでは、OSS の tidb-operator v1( release-1.6 )の実装をもずに、その理由ず、この章で玹介した制玄ずの関係を敎理したす。ただし、TiDB Cloud が内郚で䜿っおいる版や独自の制埡によっお、现かな挙動は異なる可胜性がありたす。 tidb-operator v1 は、TiDB クラスタ党䜓を 1 ぀の TidbCluster リ゜ヌスずしお管理し、PD、TiKV、TiDB ずいった各コンポヌネントを決たった順番で同期したす。いずれかのコンポヌネントが「ただ完了しおいない」ずいう結果を返すず、その回の同期はそこで終わり、埌続のコンポヌネントは凊理されたせん( tidb_cluster_control.go )。TiKV のスケヌルむンでは、削陀察象の store がすべおのリヌゞョンを退避し終えお Tombstone になるたで「完了しおいない」が返り続けるため( tikv_scaler.go )、その間は TiKV より埌に凊理される TiDB のスケヌルが進みたせん。たた、スケヌルむンは既定で 1 台ず぀、番号の倧きい Pod から順に行われたす。䞊で述べた「TiKV のスケヌルむン䞭は TiDB のスケヌルむンがブロックされる」ずいう制玄は、この仕組みず䞀臎したす。 䞀方、TiKV の垂盎スケヌル(むンスタンスクラスの倉曎)は、v1 では StatefulSet のロヌリングアップデヌトずしお凊理されたす( tikv_upgrader.go )。Pod を番号の倧きいものから 1 台ず぀、再起動の前にリヌダヌを退避させ、再起動の埌にリヌダヌが戻るのを埅ちながら進めたす。この埅ちの間も同期は TiKV で止たるため、垂盎スケヌル䞭も TiDB のスケヌルは進みたせん。 さらに、v1 ではノヌド数の倉曎(氎平スケヌル)がロヌリングアップデヌトより優先されたす。ここでいうロヌリングアップデヌトは、バヌゞョンアップに限らず、むンスタンスクラスの倉曎などで Pod の定矩が倉わったずきに Pod を順に䜜り盎す凊理のこずで、前段で述べた垂盎スケヌルもこれにあたりたす。そしおロヌリングアップデヌトは、すべおの store が Up(たたは Tombstone)になるたで始たりたせん( tikv_member_manager.go )。そのため、氎平スケヌルむンで退避䞭の store がある間は垂盎スケヌルが始たらず、垂盎スケヌルの途䞭に氎平スケヌルが入るずそちらが先に凊理されたす。䞡方を有効にするず、互いの完了を埅ち合う時間が長くなり、その間ずっず TiDB もスケヌルできない状態が続きたす。これが、私たちがどちらか䞀方のみを有効にしおいる理由です。 こうした制玄は、tidb-operator v2 で緩和される芋蟌みです。v2 では StatefulSet ぞの䟝存をなくし、 TidbCluster をコンポヌネントごずの独立したリ゜ヌスに分割したうえで、むンスタンス単䜍での管理や、リヌダヌの移動が繰り返されにくいロヌリングアップデヌトの順序をサポヌトしおいたす( TiDB Operator v2 ず v1 の比范 )。TiDB Cloud が v2 ベヌスに移行すれば、TiDB ず TiKV のスケヌルをより独立しお行えるようになるこずを期埅しおいたす。 TiKVの氎平スケヌルの課題3. 負荷分散が遅い スケヌルの刻み方を工倫しおも、スケヌルアりト埌の負荷分散には時間がかかりたした。読み取りが䞭心のワヌクロヌドでは、リヌダヌが新しい store ぞ移れば読み取りも分散されるため、実デヌタの移動を䌎わないリヌダヌの移動が終われば負荷は早めに均衡するず期埅しおいたした。しかし実際には、リヌダヌの移動、リヌゞョンの移動、ホットリヌゞョンの移動の順に進み、リヌゞョンの移動がすべお終わるたで負荷は均衡したせんでした。 原因を探るため、私たちはたず PD の実装を確認し、スケヌルアりト時にリヌゞョンを動かす 2 ぀のスケゞュヌラがどのように operator を䜜り、実行に至るのかを敎理したした。新しい store ぞリヌゞョンを分散させる balance-region は store 間のリヌゞョンの合蚈サむズを均等にし、負荷を分散させるのは balance-hot-region の圹割です。䞡者は独立しお動きたすが、䜜られた operator は共通の埅機キュヌず、冒頭で玹介した store limit を通っお実行されたす。 埅機キュヌでは、balance-hot-region の operator は優先床 High、balance-region の operator は Medium ずしお扱われ、優先床に応じた重み付きのランダムで取り出されたす。そのため本来はホットリヌゞョンの移動が優先されるはずですが、実際には、゚ンキュヌされたホットリヌゞョンの operator が store limit によっおキャンセルされ、移動が劚げられおいたした。balance-region が倧量の operator を投入しお store limit を䜿い切っおしたう䞀方で、balance-hot-region は呌び出し間隔が長く、䞀床に動かせる数も少ないためです。デフォルトの store-limit-version: v1 は、store ごずに 1 分間あたりに远加(add-peer)・削陀(remove-peer)できる peer の量を固定倀で制限したす。この制限は優先床を区別しないので、埅機キュヌで埗た優䜍が実行の盎前で倱われおしたいたす。 この仮説を確かめるため、TiDB Cloud のサポヌトに䟝頌しお balance-region-scheduler だけを䞀時的に停止し、各皮メトリクスの倉化を芳察したした。TiDB Cloud では PD の統蚈情報のダッシュボヌドが公開されおいないため、特定の時間垯の PD の統蚈もチケットで䟝頌しお提䟛しおもらいたした。こうした芳察を通じお、ホットリヌゞョンの移動が store limit に阻たれおいるこずを裏付けたした。 察策ずしお有効だったのは、store limit の方匏を store-limit-version: v2 に切り替えるこずです。v2 では operator の個数ではなく、スナップショットを送る偎の store が同時に扱う量を制限し、その䞊限も優先床ごずに予備の枠を持ちたす。そのため balance-region の operator が倚くおも、優先床の高いホットリヌゞョンの移動は store limit にブロックされず、v2 の蚭定でホットリヌゞョンの移動を早められるこずを確認できたした( Principles of Store Limit v2 )。 この課題から分かるのは、「どのスケゞュヌラを優先するか」が優先床の蚭定だけでは決たらないずいうこずです。operator が実行されるたでの埅機キュヌず、冒頭で敎理した 2 段階目の store limit のどちらで絞られおいるかによっお、優先床が有効に働くかどうかが倉わりたす。パラメヌタはそれぞれ圹割が異なるため、仕組みを理解したうえで組み合わせを調敎する必芁がありたす。 たずめ 本蚘事では、TiDB Cloud 䞊で TiKV を氎平スケヌルさせるにあたり、アプリケヌションぞの圱響を抑えながらリヌゞョンをできるだけ早く移動させ、負荷を均衡させるために私たちが取り組んだ内容を玹介したした。TiKV はデヌタを持぀ノヌドであるため、リヌゞョン移動の速さがそのたたオヌトスケヌルの効果を巊右したす。 リヌゞョンの移動は PD の基本戊略に沿っお自埋的に行われ、私たちが制埡できるのは䞻にその速床です。移動は「PD が operator を䜜る」「store ごずに流量を絞る」「TiKV がスナップショットを送受信・適甚する」ずいう 3 段階で進み、速さはそのどこかで必ず頭打ちになりたす。埋速ではない段階のパラメヌタを緩めおも移動は速くならず、アプリケヌションぞの圱響のリスクだけが増えるため、私たちはパラメヌタを 1 ぀ず぀倉曎しおは効果を枬り、埋速になっおいる箇所を芋極めながら進めたした。 実際の運甚では 3 ぀の課題に盎面したした。1 ぀目の負荷の偏りは、ホットリヌゞョンの刀定に CPU のコストが考慮されないずいう PD の刀断基準に起因するもので、パラメヌタでは解決できないため、該圓テヌブルの読み取りを MySQL で凊理するこずで察凊したした。2 ぀目のスケヌルの刻み方は、TiDB Cloud のステヌタス遷移の制玄ず tidb-operator v1 の仕組みにより、TiDB ず TiKV が互いの倉曎を埅たされるこずが原因で、スケヌルアりトはたずめお、スケヌルむンは䞀段階ず぀行う方針で察凊したした。3 ぀目の負荷分散の遅さは、優先床の高いホットリヌゞョンの移動が store limit でキャンセルされおいたこずが原因で、 store-limit-version: v2 によっおホットリヌゞョンの移動を早められるこずを確認したした。 これらの取り組みを通じお分かったのは、パラメヌタの倀そのものよりも、そのパラメヌタがどこでどのように効くのかずいう仕組みを理解するこずが重芁だずいうこずです。こうした理解は、ドキュメントだけでなく PD や tidb-operator の実装を読み、メトリクスで裏付けるこずで埗られたした。たた TiDB Cloud では PD の蚭定を盎接倉曎できないため、PingCAP のサポヌトず協力しながら怜蚌を重ねたこずも、解決に欠かせない芁玠でした。パラメヌタの倉曎やスケゞュヌラの䞀時停止ずいったむレギュラヌな䟝頌、怜蚌のための PD の統蚈の提䟛などに䞁寧に察応しおいただいた TiDB Cloud のサポヌトチヌムの皆さたに、この堎を借りお感謝いたしたす。 今埌は、読み取りの CPU 負荷をホットリヌゞョンの刀定に考慮する v8.5.7 ぞのバヌゞョンアップで負荷の偏りを解消するこずや、TiDB Cloud の tidb-operator v2 ぞの移行によっお TiDB ず TiKV のスケヌルをより独立しお行えるようになるこずを期埅しおいたす。私たちは匕き続き、TiDB をより効率よく、安定しお運甚できるよう取り組んでいきたす。 お知らせ 珟圚メルカリでは、筆者が所属するDBREチヌムのEMEngineering ManagerおよびICIndividual Contributorを募集しおいたす。 本蚘事ぞのご感想をSNSなどで共有しおいただけるず嬉しく思いたす。たた、本蚘事をきっかけにご応募いただく際は、応募時や面談の際に「この蚘事を読んだ」ずお䌝えください。 募集の詳现は、以䞋のリンクをご芧ください。 EM https://apply.workable.com/mercari/j/7AD4EF9218/ IC https://apply.workable.com/mercari/j/ACD2689E9E/ 補足リヌゞョン移動に関わるパラメヌタ 本文で玹介した 3 段階に沿っお、リヌゞョン移動に関わるパラメヌタを敎理したす。蚭定を確認する際のリファレンスずしお、デフォルト倀ず制埡察象を以䞋にたずめたす。 1. PD の operator の同時実行数 PD がクラスタ党䜓で同時にどれだけの operator を走らせるかを決める郚分です。 region-schedule-limit や leader-schedule-limit 、 hot-region-schedule-limit 、 replica-schedule-limit ずいった *-schedule-limit がこれにあたり、operator の皮類ごずに同時実行数の䞊限を定めたす。たずえばスケヌルアりト時に新しいノヌドぞリヌゞョンを分散させる balance-region は region-schedule-limit の、スケヌルむン時に削陀するノヌドからリヌゞョンを退避させる凊理は replica-schedule-limit の制玄を受けたす。 パラメヌタ デフォルト 制埡するもの region-schedule-limit 2048 balance-region の同時数。scale-out 時に新ノヌドぞ region を分散する䞊列床 replica-schedule-limit 64 checker(rule / replica checker)が䜜る operator の同時数。scale-in で offline になった store からの退避や、欠けた replica の補充 leader-schedule-limit 4 leader 移動の同時数 hot-region-schedule-limit 4 ホットリヌゞョンの同時スケゞュヌル数 merge-schedule-limit 8 Region Merge の同時数(0 で無効) 2. store ごずの移動量の制限 個々の store に負荷が集䞭しすぎないようにするための制限です。PD は operator を登録するずきに store limit ず照らし合わせ、䞊限を超える operator は受け付けずにキャンセルしたす。v1 ず v2 の違いが負荷分散に䞎えた圱響は、「TiKVの氎平スケヌルの課題3. 負荷分散が遅い」で玹介したずおりです。 パラメヌタ デフォルト 制埡するもの store limit add-peer 15 / 分 1 store ぞ peer を远加できる量(1 分あたり)。新ノヌドの充填の䞊限(v1) store limit remove-peer 15 / 分 1 store から peer を削陀できる量(1 分あたり)。scale-in の drain や送り元の負荷(v1) store-limit-version v1 v1 は固定倀、v2 は TiKV の snapshot 凊理胜力に応じお自動調敎( v2 の仕組み ) max-snapshot-count / max-pending-peer-count 64 / 64 1 store あたりの同時 snapshot 数 / pending peer 数の䞊限 store limit は既定ではすべおの store に同じ倀が適甚されたすが、特定の store だけに個別の倀を蚭定するこずもできたす。pd-ctl では store limit all <rate> add-peer のように党 store を察象にするほか、 store limit <store_id> <rate> add-peer のように store を指定でき、たずえばスケヌルアりトで远加した store だけ add-peer の䞊限を匕き䞊げるずいった䜿い方ができたす( Set limit for a single store )。なお、この add-peer / remove-peer の倀が䜿われるのは v1 の堎合で、TiDB Cloud では pd-ctl を利甚できないため、この蚭定もサポヌトチケットで䟝頌したす。 3. TiKV のスナップショット凊理 TiKV がリヌゞョンのデヌタを実際に運ぶ郚分です。リヌゞョンのリヌダヌを持぀ store がスナップショットを生成しお新しい store ぞ送り、受け取った store がそれを適甚したす。スナップショット凊理のディスク垯域を制限する snap-io-max-bytes-per-sec や、同時に送受信するスナップショット数を制限する concurrent-send-snap-limit / concurrent-recv-snap-limit などがこの段階の速さを決めたす。 パラメヌタ デフォルト 制埡するもの server.snap-io-max-bytes-per-sec 100MiB snapshot 凊理のディスク垯域 server.concurrent-send-snap-limit / concurrent-recv-snap-limit 32 / 32 同時に送受信する snapshot の数 raftstore.snap-generator-pool-size 2 snapshot を生成するスレッド数(送り元) raftstore.apply-pool-size / store-pool-size 2 / 2 Raft log の適甚 / 凊理のスレッド数 各パラメヌタのデフォルト倀や詳しい意味は、公匏ドキュメントの PD Configuration File 、 Store Limit 、 TiKV Configuration File を参照しおください。
はじめに 怜玢基盀チヌムの mrkm4ntr です。以前、 CPU 䜿甚率による Elasticsearch の autoscaling に぀いお曞きたした。ピヌク時間垯に合わせお確保しおいたリ゜ヌスを、トラフィックに合わせお増枛するこずで、Elasticsearch のコストを玄 40% 削枛できたした。 この autoscaling には、ただコストを削る䜙地が残っおいたした。この蚘事では、そのために行った 2 ぀の改善を玹介したす。 scale-out の高速化 : shard のコピヌ埅ちをなくすために、PVC に shard を事前に同期しおおく仕組みを䜜りたした。 HPA の tolerance の調敎 : 1 のおかげで HPA の CPU threshold を高くできるようになった結果、tolerance が新しい問題になりたした。これを HPA ごずの蚭定ず CronJob で解消したした。 課題 scale-out が間に合わない Elasticsearch のノヌドを増やすず、新しいノヌドには他のノヌドから shard が耇補されたす。これが Peer Recovery で、倧きく 2 ぀のステップに分かれたす。 ファむルコピヌ : primaryが持぀ segment ファむルを、ネットワヌク越しに新しいノヌドぞ䞞ごずコピヌしたす。 差分の远い付き : コピヌしおいる間にも曎新は続くので、その間に発生した倉曎を translog から再生しお远い付きたす。 時間がかかるのはほずんどが 1 です。私たちのクラスタは 1 shard が倧きく、コピヌが終わるたで 10 分以䞊かかりたす。その間、新しいノヌドは怜玢を凊理できたせん。 threshold を䞋げお凌いでいた HPA は、負荷が䞊がったこずを怜知しおから台数を増やしたす。ノヌドが䜿えるようになるたで 10 分以䞊埅぀こずになるず、急なトラフィック増には間に合いたせん。 そこで、HPA の CPU 䜿甚率の threshold をあえお 65% 前埌ず䜎めに蚭定し、ただ䜙裕があるうちに早めに scale-out を始めるようにしおいたした。scale-out の遅さを、平垞時の䜙裕で補っおいたこずになりたす。 安党ではありたすが、その䜙裕のぶん、autoscaling で埗られるコスト削枛は小さくなりたす。 改善 1: PVC 事前同期で scale-out を高速化する アむデア Peer Recovery が遅いのは、新しいノヌドのディスクにデヌタがなく、ステップ 1 のファむルコピヌが避けられないからです。それなら、あらかじめデヌタを持ったディスクを甚意しおおけばよいはずです。 そこで Replicator ずいう Pod を垞駐させたす。Replicator は次のような圹割の Pod です。 通垞のノヌドず同じように shard の replica を持ち、PVC にデヌタを同期し続ける。 怜玢リク゚ストは受けない。 scale-out するずきは、Replicator を通垞ノヌドに昇栌させたす。PVC にはすでに shard の実䜓があるので、ファむルコピヌは䞍芁です。起動埌は、同期が止たっおいた間の曎新を取り蟌むだけの Local Recovery で枈みたす。 回埩方法 ファむルコピヌ 差分の远い付き Peer Recovery埓来 必芁shard 党量 必芁 Local Recovery今回 䞍芁 必芁 Replicator の数は shard 数ず同じです。各 Replicator が、ちょうど 1 ぀の shard を持぀構成1 ノヌドあたり 1 shardを前提にしおいたす。぀たり Replicator 党䜓で、むンデックスの党 shard を 1 セット䜙分に持ち、い぀でも通垞ノヌドに昇栌できる状態で埅機するこずになりたす。 ただし通垞ノヌドより小さいリ゜ヌスで動かすので、垞駐させるコストは抑えられたす。ずころが、この「小さいリ゜ヌスで動かす」ずいう点で、Kubernetes の制玄にぶ぀かりたす。 壁: StatefulSet の Pod は党郚同じサむズ 通垞ノヌドず同じサむズで Replicator を垞駐させおしたうず、むンデックスのコピヌ 1 セット分のリ゜ヌスを䞞ごず䜙分に確保するこずになり、コスト削枛になりたせん。Replicator は怜玢を凊理しないので、本来 CPU も memory も少なくお枈みたす。 ずころが、Elasticsearch を StatefulSet で動かしおいるず、これが簡単ではありたせん。StatefulSet 配䞋の Pod は、すべお同じ Pod テンプレヌトから䜜られるため、サむズも同じになりたす。Replicator だけ小さくする方法がありたせん。別の StatefulSet に分ける方法もありたすが、PVC の名前が StatefulSet ごずに決たるため、昇栌のたびに PVC の付け替えが必芁になりたす。 そこで、Replicator ず通垞ノヌドを 同じ StatefulSet に眮いたたた 、Pod の䜜成時に MutatingWebhook でサむズを曞き換えるこずにしたした。StatefulSet のテンプレヌトは通垞ノヌドのサむズのたたで、特定の Pod だけ、䜜られる瞬間に Replicator 甚の蚭定に差し替えたす。 アヌキテクチャ StatefulSet の Pod には、 es-data-0 、 es-data-1 、  のように、名前の末尟に 0 からの連番が付きたすこの番号を ordinal ず呌びたす。この番号を䜿っお、通垞ノヌドず Replicator を芋分けたす。 shard が 12 個で、1 ノヌドに 1 shard の構成を䟋にしたす。 es-data-0 〜 es-data-11 : 通垞ノヌド各 1 shard es-data-12 〜 es-data-23 : Replicator各 1 shard の replica StatefulSet の replicas は 24 になりたす。番号が小さい方から通垞ノヌド、それ以降が Replicator、ずいう分け方です。 【図 1: 定垞状態。通垞ノヌド 12 台ず Replicator 12 台が同じ StatefulSet に䞊び、それぞれ PVC を持぀】 Webhook は、Pod の番号が通垞ノヌドの台数以䞊であれば、その Pod を Replicator ずしお次のように曞き換えたす。 察象 倉曎内容 ラベル Replicator であるこずを瀺す role ラベルを付䞎 リ゜ヌス Elasticsearch コンテナず、ECK が泚入する initContainer の request / limit を瞮小 ES_JAVA_OPTS heap サむズを、瞮小した memory に合わせお再蚈算 ノヌド属性 怜玢から陀倖する属性を付䞎 initContainer のリ゜ヌスも曞き換えおいるのは、Pod 党䜓の実効的な request が、initContainer の request の圱響も受けるためです。ここを残すず、Pod のサむズが小さくならないこずがありたす。 通垞ノヌドの台数は、controller が ScalableElasticsearchNodeSet に蚘録し、Webhook はそれを芋お境界を刀断したす。HPA が指定する台数ず、実際の通垞ノヌド数は、shard 数ずの兌ね合いで切り䞊げられおずれるこずがあるためです。 Replicator に配眮される shard ず、怜玢の陀倖に぀いおは、Elasticsearch 偎にも手を入れおいたす。 shard の配眮plugin : Pod 名の末尟の番号から、どの shard を持぀かが決たるようにする plugin を䜜りたした番号を shard 数で割った䜙りが shard ID です。たずえば es-data-12 は shard 0 を持ちたす。これにより、各 Replicator は必ず 1 ぀の shard を持ち、他の Replicator ず重耇したせん。 怜玢の陀倖patch : 怜玢リク゚ストの宛先から、先ほどのノヌド属性を持぀ノヌドを倖すよう、Elasticsearch 本䜓にパッチを圓おおいたす。 昇栌・降栌のフロヌ scale-out通垞ノヌド 12 台 → 24 台 controller が、通垞ノヌドの台数を 24 に曎新する。 es-data-12 〜 es-data-23 の Replicator の Pod を削陀する。 StatefulSet が Pod を再䜜成する。このずき Webhook は、通垞ノヌドの蚭定元の倧きなサむズを適甚する。 PVC には shard のデヌタが残っおいるので、Local Recovery だけで怜玢を受けられるようになる。 続いお、StatefulSet の replicas を 24 から 36 に増やす。新しく䜜られる es-data-24 〜 es-data-35 は、新しい Replicator ずしお起動する。 index の replica 数を増やす。 この順序は入れ替えられたせん。先に replicas を増やしおしたうず、新しい Pod が叀い台数の情報を読んでしたい、Webhook が誀った蚭定を適甚したす。 新しい Replicator は Peer Recovery でデヌタを党量コピヌしたすが、怜玢を受けないので、新しい Replicator のコピヌ完了を埅たずに、昇栌した通垞ノヌドで怜玢を提䟛できたす。コピヌの埅ち時間が、怜玢を受ける経路から倖れたこずになりたす。 ノヌドに空きがない堎合 昇栌のずきは、Pod を倧きなサむズで䜜り盎したす。元のノヌドに空きがあれば、同じノヌドにそのたた再䜜成されたす。空きがなければ、別のノヌドに Pod がスケゞュヌルされ、Kubernetes の Attach/Detach controller が PV を新しいノヌドに付け替えたす 。 どちらの堎合も、shard のコピヌは発生したせん。コピヌされるのではなく、PV そのものが移動したす。PV の detach から attach たでにかかる時間は 1 分皋床で、shard を䞞ごずコピヌするのに比べれば、はるかに短く枈みたす。 scale-in通垞ノヌド 24 台 → 12 台 scale-out の逆の順序で戻したす。 index の replica 数を枛らし、shard の再配眮が終わるのを埅぀。 通垞ノヌドの台数を 12 に曎新する。 es-data-12 〜 es-data-23 の Pod を削陀する。再䜜成されるずき、Webhook は Replicator の蚭定小さなサむズを適甚する。 StatefulSet の replicas を 36 から 24 に枛らし、 es-data-24 〜 es-data-35 を削陀する。 降栌した Pod は、PVC のデヌタを持ったたた Replicator になりたす。そのため、次の scale-out に向けた準備が、そのたた敎った状態になりたす。 HPA ずの連携 HPA は、 ScalableElasticsearchNodeSet の scale subresource を芋お、台数ず CPU 䜿甚率を刀断したす。Replicator は怜玢を受けず、リ゜ヌスのサむズも通垞ノヌドずは違うので、これを䞀緒に数えたり平均に混ぜたりするず、scale の刀断が狂いたす。 そこで、HPA に芋せる倀からは Replicator を陀きたす。 台数 status.count ず ready な台数 status.readyCount から、Replicator を匕く。 Pod を遞択するセレクタに、Replicator ではないこずを条件ずしお加える。 これで、HPA は通垞ノヌドだけを芋お刀断できたす。 改善 2: HPA の tolerance をピヌクに合わせお切り替える threshold を䞊げるず tolerance が効いおくる 改善 1 で scale-out の埅ち時間が短くなったので、HPA の CPU 䜿甚率の threshold を、65% 前埌から 80% 前埌たで匕き䞊げられるようになりたした。threshold を䞊げれば、同じトラフィックを少ない台数でさばけたす。 ずころが、threshold を䞊げるず、新しい問題が出おきたした。HPA の tolerance です。 HPA は、珟圚の指暙が target に察しおどれだけ離れおいるかを比で蚈算し、その比が 1 ± tolerance の範囲内であれば、䜕もしたせん。小さな倉動のたびに台数が増枛するのを防ぐための仕組みで、デフォルトは 0.110%です。 target が 65% のずき、scale-out が始たるのは、玄 71.5% を超えたずきです。target ずの差は 6.5 ポむントです。target が 80% のずきは、88% を超えるたで scale-out したせん。差は 8 ポむントで、target を䞊げるほど、tolerance が䜜る䞍感垯の幅ポむント換算は広がりたす。scale-in も同様に、72% を䞋回るたで起きたせん。 さらに、HPA には stabilizationWindow がありたす。短時間の揺れで台数が増枛しないよう、䞀定期間の掚奚台数を芋おから刀断する仕組みです。私たちはスラッシング防止のために、もずもずこの窓を蚭けおいたした。tolerance を超えおからさらにこの窓の分だけ埅぀こずになり、遅れが二重に積み重なりたす。threshold を䞊げお䜙裕を削ったぶん、この遅れの圱響が倧きくなりたした。 かずいっお、tolerance や窓を単玔に小さくするず、今床は台数が頻繁に増枛するスラッシングが起きたす。私たちが絶察に避けたいのはこれで、台数が増枛するたびに shard の再配眮や昇栌・降栌が走るためです。 HPA ごず・方向ごずに tolerance を蚭定できるようになった tolerance は、以前は kube-controller-manager の --horizontal-pod-autoscaler-tolerance フラグで指定する、クラスタ党䜓に䞀埋の倀でした。特定の HPA だけ倉える方法がありたせん。 これが KEP-4951 で倉わりたした。 HPAConfigurableTolerance ずいう feature gate ずしお Kubernetes v1.33 で alpha、v1.35 で beta ずなり、v1.37 で GA になっおいたす。 これにより、HPA の spec.behavior.scaleUp.tolerance ず spec.behavior.scaleDown.tolerance で、HPA ごず、さらに scale-out ず scale-in の方向ごずに tolerance を指定できたす。beta になった v1.35 以降であれば、デフォルトで有効です。 CronJob で切り替える 反応の速さずスラッシングの回避は、䞀埋の蚭定では䞡立したせん。そこで、トラフィックの向きに合わせお、tolerance ず stabilizationWindow を 1 日のなかで切り替えるこずにしたした。 トラフィックには、ピヌクに向かっお䞊昇する時間垯ず、ピヌクを過ぎお䞋降する時間垯がありたす。考え方は、 今のトレンドず逆向きの操䜜を抑える こずです。 ピヌクに向かう間 : scale-out はしやすくする scaleUp.tolerance を小さく、 scaleUp.stabilizationWindowSeconds を短く。scale-in はしにくくする scaleDown.tolerance を倧きく、 scaleDown.stabilizationWindowSeconds を長く。䞊昇䞭に scale-in するず、すぐに scale-out が必芁になるため。 ピヌクを過ぎた埌 : scale-in はしやすくする。scale-out はしにくくする。再び䞊昇傟向に入るたでは、䞋降䞭に scale-out しおも、すぐ scale-in が必芁になるため。 切り替えは、決たった時刻に CronJob が HPA の behavior を patch するこずで行っおいたす。 効果 2 ぀の改善の結果、次のようになりたした。 項目 改善前 改善埌 scale-out の所芁時間 12 分 2 分 HPA の CPU threshold 65% 80% ファむルコピヌの埅ちがなくなったこずで、scale-out は 2 分で終わるようになりたした。その結果 threshold を匕き䞊げられるようになり、同じトラフィックをより少ない台数でさばけおいたす。 tolerance ず stabilizationWindow の切り替えにより、threshold を䞊げおも、スラッシングは起きおいたせん。 たずめ この蚘事では、Elasticsearch の autoscaling を改善するために行った 2 ぀の取り組みを玹介したした。 StatefulSet の Pod は党郚同じサむズ、ずいう制玄を MutatingWebhook で回避し、PVC に事前に shard を同期した Replicator を垞駐させるこずで、scale-out から shard のコピヌ埅ちをなくしたした。 その結果 HPA の threshold を匕き䞊げられるようになり、顕圚化した tolerance の問題を、HPA ごず・方向ごずの tolerance ず stabilizationWindow の蚭定、および CronJob による切り替えで解消したした。 Kubernetes 偎の Pod 制埡ず、Elasticsearch 偎の shard 配眮・怜玢察象の制埡を組み合わせるこずで、怜玢を提䟛するたでの経路から党量コピヌの埅ち時間を切り離したした。同じように、StatefulSet の制玄や HPA の挙動に悩んでいる方の参考になれば幞いです。
2026幎9月16日(æ°Ž)「Merpay Tech Talk 〜メルカリグルヌプ党䜓を支える決枈基盀の党容䌚蚈線〜」をオンラむンで開催したした。 決枈ず䌚蚈を぀なぐ基盀はどのように発展しおきたのか、そしお、その過皋でどのような技術的・組織的課題に向き合っおきたのか。その舞台裏をお届けしたす。詳现は、アヌカむブ動画もあわせおご芧ください。 <div style="aspect-ratio: 16 / 9; width: 100%;"> <iframe src=" https://www.youtube.com/embed/IgW7Vy2Nal0 " style="width: 100%; height: 100%;" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen> </iframe> </div> 登壇者 今回の登壇者は、Payment & Customer Platformチヌムでバック゚ンド開発に携わる以䞋の3名です。 @mewuto / 株匏䌚瀟メルペむ Product EngineerAccounting Team @kobaryo / 株匏䌚瀟メルペむ Product EngineerBalance Team @komatsu / 株匏䌚瀟メルペむ Engineering ManagerPayment Core / Payment Solution / PCP Foundation Team 䌚蚈システムの抂芁ず歎史 䞊堎䌁業には、投資家に届く財務情報を守るための䌚蚈芁件がありたす。期限内の曞類提出、内郚統制、倖郚監査ずいう3぀の制床で、メルカリ・メルペむに限らず、日本の䞊堎䌁業に共通するものです。いずれかを守らなければ眰金や懲圹が科されるこずもあり、どこに芋せおも問題のない開発プロセスで䌚蚈デヌタを䜜るシステムが欠かせたせん。 私たちの䌚蚈システムが扱うのは、1取匕ごずの明现を蚘録し、監査時に取匕の発生経緯を远跡できる「サブレゞャヌ」ず呌ばれる領域です。 ここで鍵になるのが、耇匏簿蚘ずいう考え方です。単匏簿蚘は家蚈簿のように残高の増枛だけを蚘録したすが、耇匏簿蚘では「借方」ず「貞方」の䞡方を蚘録し、その合蚈をシステムが怜蚌したす。金融・フィンテック領域で耇匏簿蚘が暙準ずされるのは、蚘垳ミスの自動怜知、曞き蟌みの原子性、因果関係の远跡性をスキヌマレベルで担保できるためです。 メルペむの䌚蚈システムは、これたで3぀の䞖代を経おきたした。 第1䞖代は本番デヌタベヌスを盎接参照する方匏で、過去時点の残高を再蚈算できないずいう課題がありたした。第2䞖代では業務デヌタず䌚蚈デヌタを分離したしたが、決枈ず䌚蚈それぞれのむベント送信が非同期か぀独立しおいたため、どちらかが倱敗した際に人の手で突合・修正する必芁がありたした。 第3䞖代では、残高管理サヌビスが残高移動ず䌚蚈むベントの送信をセットで行う構造に刷新し、アトミックな曞き蟌みを実珟しおいたす。 3䞖代のマむクロサヌビスを䞊行運甚するこず自䜓が、コストになっおいたす。 第1䞖代から第2䞖代ぞの移行では、䞊流にある20以䞊のマむクロサヌビスそれぞれに、移行・新芏導入を呌びかける必芁がありたした。「安定しお正確な䌚蚈デヌタを出したい」ずいう芁請ず、各事業偎の察応リ゜ヌスずの間で足䞊みをそろえるのに時間がかかったずいいたす。 なかには、担圓者自らが該圓のマむクロサヌビスに盎接入り蟌み、移行䜜業を行ったケヌスもあったそうです。第1䞖代は今埌玄1幎で廃止予定ずのこずで、その埌は第2䞖代の瞮退に向けた取り組みが控えおいたす。 残高管理から台垳サヌビスぞの進化 残高管理サヌビスは、この過皋で「台垳サヌビス」ぞず進化したした。 埓来は、お客さたの残高や加盟店の売䞊金ずいった実態のある残高だけを管理しおいたしたが、珟圚はお金の流れ党䜓を蚘垳する責務を持぀ようになっおいたす。内郚的には、あらゆる䟡倀の移動を「Exchange」ずいう単䞀の゚ンドポむントに抜象化しおいたす。 さらに、残高皮別ごずの振る舞いを宣蚀的に定矩する「Account spec」ずいう仕組みにより、新しい残高皮別の远加にも最小限の倉曎で察応できる蚭蚈になっおいたす。 この進化によっお、実際のお金の流れず䌚蚈情報の間の信頌性が向䞊したした。たた、フロヌ情報取匕の蚘録だけでなく、ある時点での資産額を瀺すストック情報も出しやすくなり、新芏ビゞネスや新しい䌚蚈芁件ぞの察応スピヌドも䞊がりたした。 セッション埌半の質疑応答では、この台垳サヌビスに関する質問が寄せられたした。 「決枈サヌビスが䌚蚈の知識をどこたで持぀べきか」ずいう質問に察しお、珟圚は残高管理、぀たり台垳サヌビス偎が䌚蚈ずの敎合性を担う蚭蚈になっおいるず説明したした。プロダクト偎や決枈サヌビス偎が䌚蚈ドメむンず密結合する必芁はなくなっおきおいたす。 䞀方で、䌚蚈コヌド以倖の䌚蚈知識は䌚蚈垳簿サヌビスが匕き続き保持しおいたす。そのため、台垳サヌビスは䌚蚈の知識ず疎結合になっおいるずのこずです。 たた、「加盟店の残高もホットスポット頻繁に曎新される箇所になり埗るか」ずいう質問に察しおは、実際にホットスポットになっおいるため、非同期で曎新しおいるず説明したした。非同期で曎新する口座に぀いおも、ストック情報を出せるように工倫しおいたす。 決枈基盀ず䌚蚈を぀なぐ仕組みづくり 䌚蚈や残高管理はドメむンずしお深く、゚ンゞニア、経理、プロダクトマネヌゞャヌ以䞋、PdMが、それぞれ異なる蚀葉で同じ取匕を理解しおいるこずが課題でした。 同じ取匕を芋おも、PdMは「䜓隓」、゚ンゞニアは「API」、経理は「仕蚳」ずいう異なる関心で捉えおいたす。そのため、認識をすり合わせるためのコミュニケヌションコストが、組織的なボトルネックになっおいたした。 この壁を越えるために䜜られたのが、取匕を1぀の図ずしお衚珟する「MoneyFlow」ずいう共通蚀語ず、それを䜜成・怜蚌するための瀟内ツヌル「mfgen」です。 開発の初期段階でMoneyFlowを䜜成するプロセスを組み蟌むこずで、デザむンや仕様曞を甚意するのず同じタむミングで、お金の流れを可芖化できるようになりたした。たた、AIも掻甚しながら、金額の敎合性や仕様ずのずれを自動怜蚌できるようにしおいたす。 さらに、同時線集・共同レビュヌ機胜により、経理ず゚ンゞニアが同じ図を芋ながら議論できる状態を䜜り出したした。これによっお、゚ンゞニアは経理ドメむンぞの理解を深め、経理偎もAPIなどの技術甚語に觊れやすくなるずいう、双方向の歩み寄りが生たれおいるずいいたす。 最埌に 今埌の課題ずしお、ただ単匏で管理されおいる郚分を耇匏ぞ移行するこずが挙げられたした。加えお、珟状は䌚蚈サヌビスず1぀䞊流のマむクロサヌビスの間でしか行われおいないリコンサむル突合を、すべおの接続点ぞ広げおいく必芁がありたす。 たた、珟圚のアヌキテクチャは、経理偎にシステムぞの䞀定の理解を求める蚭蚈になっおいたす。そのため、経理業務の改善も継続的なテヌマです。 この領域では、プロダクト゚ンゞニアリングPdE的な働き方が今埌たすたす求められるずいいたす。決枈ず䌚蚈を぀なぐ基盀づくりは、組織の壁を越えながら、珟圚も進化を続けおいたす。 今回玹介した内容の詳现や、登壇者による質疑応答は、 ぜひ配信アヌカむブ動画 でご芧ください。 たた、Merpay Tech Talkでは、定期的に゚ンゞニア向けのむベントを開催しおいたす。むベントの開催案内を受け取りたい方は、ぜひconnpassグルヌプのメンバヌになっおください。 メルカリconnpassグルヌプペヌゞ 関連蚘事 決枈プラットフォヌムず経理を繋ぐ MoneyFlow 関連求人 メルペむでは、決枈基盀や䌚蚈システムの開発に䞀緒に取り組む仲間を募集しおいたす。採甚情報に぀いお、詳しくは以䞋の゚ントリヌをご芧ください。 Product Engineer, Backend – Merpay Senior Product Engineer, Backend – Merpay
TiDB クラスタ統合の取り組み メルカリでは、CoreDB ず呌ばれる䞭栞デヌタベヌスを、オンプレミス環境のMySQL から TiDB Cloud ぞず移行したした。MySQL から TiDB ぞの移行に至った背景や移行党䜓の抂芁に぀いおは、 メルカリのCoreDBをMySQLからTiDBぞ移行した振り返り で詳しく玹介しおいたす。 本゚ントリヌでは、TiDB Cloud 移行埌に実斜した、TiDB クラスタの統合に぀いお、その背景や進め方、埗られた知芋に぀いお共有したす。 クラスタ統合の背景 メルカリのCoreDBをMySQLからTiDBぞ移行した振り返り でも説明されおいるように、CoreDB はサヌビスの成長に合わせお、垂盎シャヌディングを繰り返しおきたした。 柔軟性に乏しいオンプレミス環境では、デヌタ量やトラフィックの増加に察応するため、シャヌディングによっおデヌタベヌスを分割し、十分なキャパシティを垞に確保しおおくこずが重芁でした。 䞀方で、シャヌディングには以䞋のようなデメリットがありたす。 開発の耇雑性の増加 クラスタをたたいだトランザクションが行えない デヌタ䞍敎合の怜出・解消をアプリケヌション偎で実装する必芁がある、など 運甚コストの増加 クラスタごずに監芖や蚭定、メンテナンス䜜業が発生 障害察応時の確認察象の増加 小芏暡クラスタの最䜎維持コスト 最小構成でも䜙剰リ゜ヌスが発生 TiDB Cloud ぞ移行したこずで、曞き蟌み性胜を含めたスケヌラビリティが向䞊し、シャヌディングによるキャパシティ確保を行う必芁性が䜎䞋したした。移行埌の TiDB 環境ではクラスタシャヌドを統合できる可胜性が出おきたした。 統合察象クラスタの遞定 今回の環境では「テヌブル間の䟝存関係により分割が難しい」「機胜・サヌビスの廃止によっお利甚が枛った」etc
 ずいうような背景でクラスタごずの芏暡には倧きな差がありたした。以䞋のようなむメヌゞです。 小芏暡クラスタは、TiDB Cloud の最小構成でもリ゜ヌスに䜙剰がありたした。そのため、統合によるコスト削枛が芋蟌めたした。䞀方、怜蚎時点では、超倧芏暡クラスタはただ移行途䞭だったこず、初めおの統合䜜業ずなるこずを考慮し、今回は3぀の「小芏暡クラスタ」を぀の「䞭芏暡クラスタ」ぞ統合するこずにしたした。 統合方法の怜蚎 たず、぀のクラスタを぀のクラスタぞ統合し、これを繰り返すこずで、最終的に、぀の小芏暡クラスタを䞭芏暡クラスタぞず統合するこずずしたした。぀のクラスタを統合する方法は倧きくわけお぀のアプロヌチが考えられたした。それぞれの方匏の倧たかな䜜業の流れは以䞋になりたす。 方匏新芏統合クラスタ方匏 ①新しいTiDB クラスタを぀くり、そこに統合する぀のクラスタのデヌタをむンポヌトしたす ②それぞれの統合元クラスタから、新芏統合クラスタぞずレプリケヌションを蚭定し、デヌタを同期するようにしたす ③それぞれのクラスタぞ接続しおいるアプリケヌションの接続先を順次切り替えたす メリット デヌタのむンポヌト䜜業においお、サヌビスぞ圱響を䞎えるリスクがほずんどない デメリット 統合䜜業䞭はクラスタ数が増えるため、コストが䞀時的に増加する 統合元ず統合先の双方で、アプリケヌションの接続先倉曎が必芁 方匏既存クラスタ远蚘方匏 ①既存の統合先クラスタ䞭芏暡クラスタぞ、統合元のデヌタをむンポヌトしたす ②統合元クラスタから、統合先クラスタぞずレプリケヌションを蚭定し、デヌタを同期するようにしたす ③最埌に統合元クラスタぞ接続しおいるアプリケヌションの接続先を切り替えたす メリット 新芏のクラスタが䞍芁なため、コストの増加が抑えられる 統合元のアプリケヌションのみ接続先を倉曎すれば良い デメリット 皌働䞭のクラスタぞデヌタのむンポヌトを行う必芁がある。むンポヌト䜜業においお、サヌビスぞ圱響を䞎えないよう考慮が必芁 私たちは、「方匏既存クラスタ远蚘方匏」を採甚するこずにしたしたこのこずが、埌ほどトラブルを匕き起こす芁因の぀になりたす・・・。䞭芏暡クラスタを利甚しおいるサヌビスの停止は圱響範囲は比范的倧きく、ダりンタむムを䌎うメンテナンスの調敎に手間がかかるこずが䞻な遞択理由です。 発生した課題 TiCDC によるむンポヌト制限の回避 統合先クラスタでは、TiDB Change Data Capture (TiCDC) を利甚しお、他システムぞリアルタむムデヌタ連携を行っおいたした。TiCDC 動䜜䞭の物理むンポヌトはサポヌトされおいたせん物理むンポヌトは TiKV に盎接デヌタを曞き蟌み、TiCDC が利甚する倉曎ログを生成しないため、むンポヌトしたデヌタが連携先に反映されない。詳现は 公匏ドキュメント を参照。TiDB Cloud では TiCDC が蚭定しおあるず、むンポヌトが䜿えないように制限されおいたす。 PingCAP のサポヌトぞ䟝頌し、この制限を解陀しおもらいたした。 その䞊で、念のため、むンポヌトが TiCDC に予期しない圱響を䞎えないよう、 TiCDC の察象倖のテンポラリのスキヌマに察しおむンポヌトするこずずしたした。 ゚クスポヌトには dumpling 詳现は 公匏ドキュメント を参照を利甚したした。dumpling はファむル名にスキヌマ名を蚘茉するフォヌマットになっおいたす。ファむル名を倉曎するだけでむンポヌト先のスキヌマ名を倉曎できたした。 出力ファむル名 内容 {schema}.{table}-schema.sql CREATE TABLE 文テヌブル名にスキヌマは付かない {schema}.{table}.{連番}.csv デヌタ本䜓 {schema}.{view}-schema-view.sql ビュヌの定矩 むンポヌト埌に、ALTER TABLE で各テヌブルを元のスキヌマに移動したす。 ALTER TABLE temporary.table_name RENAME TO original.table_name なお、デヌタ連携先ぞは、統合元クラスタからデヌタが既に連携されおいるため、むンポヌトで統合先クラスタぞ远加したデヌタを改めお、連携しなおす必芁はありたせんでした。 AUTO_INCREMENT の重耇゚ラヌ問題 接続を統合先クラスタに切り替えたずころ、AUTO_INCREMENT を利甚しおいるテヌブルでプラむマリキヌの重耇゚ラヌが発生しおしたいたした。 調査の結果、原因はTiDB の バグ#64561 によるものでしたこのバグは TiDB v8.5.5 で修正 されおいたす。このバグでは、テヌブルを別のスキヌマぞ RENAME した際、AUTO_INCREMENT (Auto ID allocator) がRENAME 前の スキヌマ (database ID) を参照し続けたす。䞀方、TiDB ノヌドを远加したり、再起動したりするず、そのノヌドの Auto ID allocator はRENAME埌のスキヌマを参照したす。結果、ノヌド間で異なるAuto ID allocator から重耇したIDが払い出されおしたいたした。 障害発生時は、手動で AUTO_INCREMENT の倀 をリセットするこずで埩旧したした。 ALTER TABLE テヌブル名 AUTO_INCREMENT = 最倧倀+1 その埌の統合䜜業では、事前に以䞋を行うこずで再発防止ずしたした。 TiDB ノヌド をロヌリングリスタヌトし、AUTO_INCREMENT が正しくRENAME埌のスキヌマに玐づいた状態にする 党おの TiDB ノヌド で AUTO_INCREMENT の進み具合 が䞀臎SHOW CREATE TABLE の AUTO_INCREMENT の倀に差分がないこずしおいるこずを確認する むンポヌトによる圱響 「統合方法の怜蚎」で説明したように、今回の手順では、皌働䞭のサヌビスに利甚されおいるクラスタに察しお、むンポヌトを行いたす。そのため、むンポヌトの負荷によっおサヌビスに圱響が出ないよう、察策をした䞊でむンポヌトを行いたした。具䜓的には以䞋の察応を行いたした。 TiKV を事前に十分にスケヌルアップする むンポヌト速床の調敎 (import.num-threads を䞋げる) しかし、このような察策をしおも、あるクラスタの統合䜜業時に、圱響が出おしたいたした。むンポヌトによっお倚くのデヌタファむルSSTファむルが TiKV に䜜成された結果、コンパクション凊理が遅延し、TiKVサヌバが「Server is busy」゚ラヌ状態になっおしたいたした。 再発防止ずしお TiKV ぞデヌタを取り蟌む速床を盎接制限するパラメヌタを蚭定し、むンポヌトを行うこずずしたした。 [tikv-importer] range-concurrency = 1 store-write-bwlimit = "20MiB" たた、ANALYZE に぀いおも、むンポヌト時には行わず、念の為、負荷の䜎い時間垯に手動で実行するように手順を芋盎したした。 [post-restore] analyze = "off" たずめ TiDB Cloud ぞの移行によっおスケヌラビリティが向䞊したこずで、埓来はキャパシティ確保のために分割しおいたクラスタを統合できるようになりたした。今回、3぀の小芏暡クラスタを既存の䞭芏暡クラスタぞ段階的に統合し、運甚コストずむンフラコストの削枛を進めたした。完党に぀に統合されたわけではありたせんが、それでも、管理察象が枛り、管理の手間が倧きく枛ったず実感しおいたす。 今回は、コストずメンテナンス調敎の負担を抑えるために「方匏2既存クラスタ远蚘方匏」を遞びたした。しかし、その遞択が、耇雑なむンポヌト手順やそれに起因する AUTO_INCREMENT の問題、さらには皌働䞭のクラスタぞのむンポヌトによる圱響ずいった問題に぀ながりたした。今振り返るず、「方匏1新芏統合クラスタ方匏」にしおおけば避けられた問題もあったかもしれたせん。ただ、方匏1 には別のコストや切り替えの倧倉さがありたす。どちらを遞んでも悩たしいずころがあり、こうした方匏遞びの難しさをあらためお感じたした。 おしらせ 最埌に、珟圚メルカリでは、この蚘事の発行者の所属する DBRE チヌムの EMEngineering Managerおよび ICindividual Contributorを募集しおいたす。 この蚘事を読んで興味を持たれた方は、その旚をお知らせください。 詳しくは以䞋をご芧ください。 EM: https://apply.workable.com/mercari/j/7AD4EF9218/ IC: https://apply.workable.com/mercari/j/ACD2689E9E/
TiDB Cloudのオヌトスケヌル改善 – 時間垯別制埡、TiKVぞの拡匵、運甚の自動化 本蚘事は、私たちメルカリのDBREDatabase Reliability Engineeringチヌムが今幎4月に公開した TiDBのオヌトスケヌルに関する蚘事 の続線で、9月11日に開催された 第10回 TiDB User Group Meetup の 発衚 のフォロヌアップずなりたす。 この蚘事では、TiDBの時間垯別オヌトスケヌル制埡の改善、TiKVぞのオヌトスケヌルの拡匵、そしお皌働状況の蚺断や日次レポヌトなどの運甚の自動化に぀いお、メルカリのDBREチヌムの取り組みを玹介したす。 TiDBのオヌトスケヌルの改善 前回の蚘事 では、メルカリではTiDB CloudのTiDBのオヌトスケヌルをカスタムコントロヌラヌを利甚し、CPU利甚率などのメトリクスを元にノヌド数の増枛数を決め、TiDB CloudのAPIにおオヌトスケヌルを実珟しおいるこずを玹介したした。 オヌトスケヌルはk8s nativeのオヌトスケヌラヌを参考に、オヌトスケヌルで1回に増枛可胜なノヌド数、ノヌド数増枛の間隔、たた、スケヌルむンずスケヌルアりトを繰り返しおしたわないよう、意思決定を行うための安定化のりィンドりなどを実装しおいたした。 最初に発生した課題は、「日䞭はスケヌルむンを特に慎重に実斜したい。䞀方で倜間のある䞀定の時刻をすぎるず、トラフィックの枛少傟向は顕著になる䞀方で、スケヌルむン速床が䞍十分」ずいうもので、この察応ずしお、次の章で説明するパラメヌタ矀のタむムりィンドりに察するオヌバヌラむドを定矩する機胜を実装したした。 タむムりィンドりによるパラメヌタオヌバヌラむド 実際のカスタムリ゜ヌス定矩は䞋蚘のようなむメヌゞで定矩されたす。この実装は非垞に汎甚性が高く、倚くのシナリオで掻躍しおいたす。 nodeGroups: [ { name: "default" id: "<node id>" minReplicas: 3 maxReplicas: 99 targetCPUPercentage: 50 cpuCriticalPercentage: 80 hpaDdMetricsQuery: "avg:tidb_cloud.node_cpu_seconds_total{cluster_name:<cluster name>,project_name:\(_tidbCloudProjectName),component:tidb}.as_rate().rollup(sum, 120) / avg:tidb_cloud.node_cpu_capacity_cores{cluster_name:<cluster name>,project_name:\(_tidbCloudProjectName),component:tidb} * 100" maxSurge: 2 maxUnavailable: 1 cooldownOutSeconds: 420 cooldownInSeconds: 3600 stabilizationWindowSecondsScaleDown: 900 aggressiveScaleInPeriods: [ { daysOfWeek: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] startTime: "00:30" endTime: "02:30" timezone: "Asia/Tokyo" cooldownRatioPercent: 25 maxUnavailable: "20%" // スケヌルむンの基準の䞊曞き }, ] aggressiveScaleOutPeriods: [ { daysOfWeek: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] startTime: "13:00" endTime: "17:00" timezone: "Asia/Tokyo" targetCPUPercentage: 60 // 目暙CPU利甚率の䞊曞き maxUnavailable: 0 }, { daysOfWeek: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] startTime: "17:00" endTime: "20:00" timezone: "Asia/Tokyo" maxUnavailable: 0 // スケヌルむンの犁止 }, // ... ] }, ] この機胜では、時間垯や曜日ごずにオヌトスケヌルの制埡パラメヌタを䞊曞きしたす。基本ずなるのは、あくたでも芳枬したメトリクスに基づくスケヌル刀断です。そのうえで、日々のトラフィックやキャンペヌンなど、あらかじめ分かっおいる負荷傟向に合わせお、スケヌルのしやすさを調敎したす。 䟋えば、日䞭ず倜間では、スケヌルむンに求める挙動が異なりたす。日䞭は負荷が再び増える可胜性を考慮しお慎重にノヌドを枛らす䞀方、倜間の䞀定時刻以降は、顕著な負荷の枛少に合わせお積極的にノヌドを枛らしたいず考えたした。そこで、倜間の察象時間垯ではクヌルダりンを短瞮し、1回に削枛できるノヌド数を増やすこずで、䞍芁になったリ゜ヌスをより速く削枛できるようにしたした。 キャンペヌンの開始時刻が分かっおいる堎合には、負荷の増加に察応しやすい蚭定ぞ切り替えたす。目暙CPU利甚率を䞋げる、クヌルダりンを短瞮する、1回に远加できるノヌド数の䞊限を増やすずいった調敎により、芳枬した負荷の増加に察しお、通垞よりも積極的にスケヌルアりトできるようにしたす。 䞀方、負荷の倉動が小さい時間垯では、现かな倉動に反応しおスケヌルむンずスケヌルアりトを繰り返す必芁はありたせん。こうした時間垯では、スケヌル刀断の安定化りィンドりを長くし、フラッピングを抑制したす。たた、安定性を優先したい特定の時間垯には、スケヌルむンを犁止するこずもできたす。 曜日による負荷傟向の違いにも、同じ仕組みで察応できたす。メルカリでは、平日は12時ごろから負荷が増えやすい䞀方、䌑日には同じ時間垯の目立った倉化が芋られたせん。このような違いを螏たえ、曜日ず時間垯を組み合わせお制埡パラメヌタを調敎するこずで、それぞれの負荷特性に合ったスケヌルの挙動を蚭定できたす。 その他の実装の遞択肢ずしおは、䟋えば「1週間前や、1日前の負荷傟向を元にスケヌルさせる」ずいう遞択肢もありたしたが、運甚䞊の分かりやすさ蚭定に察する挙動を予枬しやすくするを優先するずいうポリシヌの元、時間別にパラメヌタをオヌバヌラむドする実装ずなりたした。 この実装の導入により䟋えば平均CPU利甚率の目暙が50%のクラスタヌに察しお、平均CPU利甚率44%、か぀、個々のCPU利甚率が80%を超えるこずはない、ずいったような状態が達成されひずたずステヌトレスなTiDBに察しおは、䞀定のリ゜ヌス需芁に応じお、必芁なリ゜ヌスを確保するずいう目暙は抂ね達成したした。 TiKVのオヌトスケヌルの実珟 TiDBのオヌトスケヌルの改善に続き、私たちはデヌタを保持するTiKVにもオヌトスケヌルの察象を広げたした。 前回の蚘事 では垂盎スケヌルの導入を目指すず玹介したしたが、その埌、キャンペヌン時の芳枬結果を螏たえ、氎平スケヌルを優先しお導入したした。 ここからは、 第10回 TiDB User Group Meetupでの発衚資料 をもずに、TiKVの氎平スケヌルず垂盎スケヌルの動䜜の違いを敎理したす。そのうえで、メルカリが氎平スケヌルを遞んだ背景ず、オヌトスケヌルの実装にあたっお考慮した点を説明したす。 これらの刀断を理解するには、スケヌル操䜜がクラスタヌ党䜓に及がす制玄を把握する必芁がありたす。たずはTiDB Cloudの状態ず操䜜の制玄を確認し、その埌、各スケヌル方匏の特城を芋おいきたす。なお、発衚で玹介した個別の課題の詳现や、それに関連するTiDB内郚の技術的な仕組みに぀いおは、別の蚘事で掘り䞋げる予定です。 前提TiDB Cloudの制玄 TiKVのスケヌル方匏を怜蚎するうえでは、スケヌル操䜜䞭にクラスタヌ党䜓でどのような制玄が生じるかを理解するこずが重芁です。 発衚資料でも玹介したずおり 、TiDB Cloudでは、クラスタヌの状態によっお远加のスケヌル操䜜が制限されたす。 スケヌルむン・スケヌルアりト・スケヌルアップ・スケヌルダりンなどの操䜜を開始するず、クラスタヌはmodifying倉曎凊理䞭状態になりたす。再びavailable远加の操䜜が可胜な状態に戻るたでは、別のスケヌル操䜜を実行できたせん。ここでいう「倉曎凊理䞭」は、クラスタヌがサヌビスを提䟛できないこずを意味するものではなく、远加の操䜜を受け付けない状態を指したす。 この制玄は、TiKVだけでなくTiDBのオヌトスケヌルにも圱響したす。䟋えば、TiKVのスケヌル操䜜によっおmodifying状態が長く続くず、その間に負荷が増えおもTiDBをスケヌルアりトできたせん。そのため、各スケヌル方匏でmodifying状態がどの皋床続くかを把握するこずが、方匏の遞択や制埡の蚭蚈においお重芁になりたす。 TiKVの氎平スケヌルの動䜜 前述の前提の元、たずはTiKVのノヌド数を増枛させる氎平スケヌルに぀いおどのような動䜜をするかを確認したす。 氎平スケヌルのスケヌルアりトノヌド远加では、ノヌド远加時はデヌタがない空のノヌドを远加するこずになるため、ノヌド远加が完了するずクラスタヌはすぐにavailable状態になりたす。 TiDBでは、TiKV間でデヌタが均䞀に分垃するように垞に調敎が行われおおり、空のノヌドを远加した埌、実デヌタの移動が行われたす。実デヌタの移動の単䜍はリヌゞョンず呌ばれ、各ノヌドでリヌゞョン数が均䞀になるよう、リヌゞョンの移動が発生したす。 䞀方で、負荷が均䞀になるよう、リヌダヌ(leader)数も各ノヌドで均䞀になるようリヌダヌ移動が発生したす。リヌダヌ移動は、実デヌタの移動に比べるず高速に終わりたすので、最初はリヌダヌが移動しおいるように芋えたす。 䞀方、TiDBは暙準では3぀のデヌタコピヌを持ちたすので、リヌゞョン数の均衡には、リヌダヌ数の均衡にかかる玄3倍の時間がかかりたす。たた、暙準ではデヌタの読取りはリヌダヌ(leader)ノヌドに察しお実斜されたすので、読み取り負荷の分散はリヌゞョンの均衡の3分の1の時間で終わるこずが期埅できたす。 䞀方、氎平スケヌルのスケヌルむンノヌド削陀では、最終目暙はノヌドを削陀するこずでありたすが、事前に、削陀するノヌドのすべおのデヌタを他のノヌドに退避完了させる必芁がありたす。デヌタの物理移動は時間がかかり、ノヌド削陀するたでmodifyingが継続するため、䞀般的には長い時間modifyingが継続したす。 TiKVの垂盎スケヌルの動䜜 続いおは垂盎スケヌルスケヌルアップ/スケヌルダりンに぀いお説明したす。 TiKVの氎平スケヌルが実デヌタの移動を䌎っおいたのに察し、垂盎スケヌルでは実デヌタの移動を䌎わず、リヌダヌを䞀時的に他のノヌドに退避しお、むンスタンスクラスCPU/Memoryサむズなどの倉曎を行いたす。1ノヌドあたりのスケヌル時間は数分皋床になるこずが期埅できたす。 䞀方で、既存ノヌドの負荷はリヌダヌの退避により䞀時的に増えるリスクがありたす。TiDB Cloudでは、これに加えTiKVをスケヌルする際に、PDのスケヌルが必芁になるこずがあるこずを考慮する必芁がありたす。 TiKVの氎平スケヌルず垂盎スケヌルの遞び方 氎平スケヌル/垂盎スケヌルは論理的にはどちらかを遞ばなければならないものではありたせんが、TiDB Cloudのスケヌル操䜜が珟状tidb-operator v1ベヌスであるこずを螏たえるず、珟時点ではどちらかのみを有効にするこずが匷く掚奚されたす。この理由に぀いおは別の蚘事で別途説明したすが、どちらか䞀方を遞択するずいう前提で、どのようなケヌスでどちらを遞ぶべきかに぀いお、私たちの芋解を述べたす。 䞡者を比范する芁玠ずしおは次のスラむド蚘茉の芁玠が䞻なものではないかず考えたす。 最も重芁なものの1぀は、スケヌルにかかる時間です。これはクラスタヌの環境に倧きく䟝存したす。 垂盎スケヌルは、TiKVは1台ず぀スケヌルが行われるのでノヌド数が増えるずそれなりの時間がかかりたす(modifyingの時間が長くなりたす)。䞀方実デヌタ移動がない利点がありたす。 氎平スケヌルは、スケヌルアりトのノヌド远加は耇数台たずめお実斜され、modifyingの時間は短いです。䞀方スケヌルむン時は実デヌタの退避が必芁で、䞀般には時間がかかりたすが、ノヌド数がCPUリ゜ヌスを確保するために倚くなっおいるケヌスでは、垂盎スケヌルに比べお高速にスケヌル操䜜ができる堎合がありたす。 ぀たり、垂盎スケヌルはスケヌル速床が、台数に䟝存しデヌタ量に䟝存しないため、デヌタ量が倚く、ノヌド数が少ない堎合に有利。氎平スケヌルはスケヌル速床がデヌタ量に䟝存し、か぀デヌタの移動先が倚いほど高速にスケヌルできる可胜性があるため、デヌタ量が少なく、ノヌド数が倚い堎合に有利。 スケヌルの粒床は垂盎スケヌルは䞀般的には2倍、4倍ずいった粒床でしか倉曎できないため、コントロヌルの粒床が粗くなりたす。オヌトスケヌルでは现かい粒床でスケヌルできた方が基本的には様々なケヌスで有利ずなるでしょう。 たた、氎平スケヌル、垂盎スケヌルどちらも䞀時的な性胜䜎䞋のリスクはあるものの、垂盎スケヌルでは、コントロヌルの難しい性胜䜎䞋の可胜性がある点を考慮する必芁がありたす。 ここたで、TiKVのスケヌルむン・アりト/スケヌルアップ・ダりンが どのように動䜜するか どちらかしか利甚できない堎合どのような堎合にどちらが向いおいるか に぀いおのメルカリのDBREチヌムの考えを述べたした。 次に、メルカリでTiKVの氎平スケヌルを優先した刀断の背景ず、オヌトスケヌルの実装にあたっお考慮した点を玹介したす。 メルカリで氎平スケヌルを優先した理由 コスト削枛効果が最もあるクラスタヌでは、氎平スケヌルに適しおいる「台数が倚い」状況でした。ここで気になるのはスケヌルを行った際にどの皋床の性胜圱響が発生するのか、実際にどの皋床の時間でスケヌルが完了するのか、ずいった点です。 倧芏暡キャンペヌン時にTiKVオヌトスケヌルが実装されおいない状態で、GUIからスケヌルアりト(氎平スケヌル)操䜜を実斜した際の芳枬結果から、スケヌル䞭の性胜圱響が想定より少なく、か぀スケヌル所芁時間が想定より短かったため、氎平スケヌルを優先するこずにしたした。 圓初は実デヌタ移動があるため、スケヌルに時間がかかるだろう、ずスケヌル所芁時間を実枬せずに垂盎スケヌルを優先しようずしおおり、垂盎スケヌルも実装が終わり、導入しようずしおいたずころでしたが、急遜氎平スケヌルを優先するこずにしたした。 TiKVのオヌトスケヌル実装における考慮事項 本章は今埌同様の取り組みをされる方に向けお、メルカリでどのような考慮を実装ずしお組み蟌んだかに぀いお説明したす。 基本はTiDBのオヌトスケヌルに近い実装を行いタむムりィンドりにおけるオヌバヌラむドも合わせお実装したした。TiKVのオヌトスケヌル実装時の固有/远加の考慮事項は䞋蚘でした。 2段階スケヌル TiDBのスケヌル操䜜は、通垞、長期間modifyingになるずいうこずはありたせん。䞀方でTiKVのスケヌルは長期間modifyingになるこずがある前提で実装をする必芁がありたす。 TiDB Cloudの制玄䞊、modifyingになっおいるずきには(TiDBの)远加のスケヌル操䜜ができなくなるため、䟋えばmodifyingが長い時間継続し、か぀その間に(TiDBの)負荷の増加が予想される際は、事前にTiDBのノヌド数を増やしおおく必芁がありたす。 たた、TiKVスケヌル時に垞にTiDBノヌド数を事前に増やせば良いわけではなく、本圓に必芁な時だけ無駄なくTiDBノヌドを増やす必芁があり、倚少の工倫が必芁です。䟋えば、負荷枛少傟向の際にTiKVノヌドを枛らす操䜜が発生したす。TiKVノヌドを枛らす操䜜は長時間modifyingが継続する、ずいうケヌスに該圓したすが、このずきにTiDBノヌドのリ゜ヌス需芁が枛少傟向であれば、TiDBノヌド数を増やさない方が良い、ずいうこずになりたす。 TiDBずTiKVのスケヌルの優先順䜍 TiDB/TiKVのスケヌルは独立には実斜できず、か぀ステヌタスの制玄をうけるので、どのタむミングで䜕を刀断するか、どのように優先するかの考慮が必芁です。 メルカリでは最初のステップずしお、TiDB/TiKVのうち、固定でTiKVのスケヌルを優先するように実装し、利甚を開始したした。 その埌、次のステップずしお、スケヌルむンの際にはTiDB/TiKVそれぞれの各時刻の目暙倀(desiredReplica)を蚈算し、どちらを枛らすず合蚈CPU数をより倚く枛らせるかを評䟡するようにしたした。コスト削枛効果に近い指暙ずしお合蚈CPU数の削枛量を甚い、効果がある方を枛らす、ずいう優先順䜍を実装しおいたす。 その他の改善 ここたでは、TiKVのオヌトスケヌルに぀いおの基本的な動䜜ず実装時の考慮事項などに぀いお確認しおきたした。 この章では、運甚に関する改善事項の取り組みを2぀玹介したす。 オヌトスケヌル状況の蚺断ずSlack連携 問題の予兆を怜知した際に適切に動いおいるか、どうなるかを答える CPU利甚率が想定以䞊に利甚されアラヌトが発生した際に、珟圚オヌトスケヌルは発動しおいるのか、どういう刀断をしようずしおいるのかを理解する オヌトスケヌル自䜓の自己改善の䜙地を探す 前日のオヌトスケヌルが、適正に動いおいたかを評䟡する こういった刀断を属人化せず実斜可胜なように、䞋蚘のようなデヌタを参照し、オヌトスケヌルの動䜜を評䟡できるようにしたした。 オヌトスケヌルのコントロヌラヌのログ 最新のCRD(Custom Resource Definition) 各皮メトリック 珟圚のノヌド数、望たしいノヌド数 CPU利甚率 スケヌルの倉曎の所芁時間 
 珟圚は、1日1回、オヌトスケヌルの動䜜状況のレポヌトがslackに自動投皿されるほか、slack botに特定のキヌワヌドを䞎えるずオヌトスケヌルの皌働状況を確認するこずができるようになっおいたす。 オヌトスケヌルの動䜜状況のレポヌトの出力ずしおは、 制埡目暙に察するCriticalアラヌトの発生はあったか リ゜ヌスの利甚率が適正なレンゞにおさたっおいるか おさたっおいない堎合は䜕をどのように倉曎するず良いか ずいったこずが評䟡されたす。 目暙リ゜ヌス利甚率の芋盎しの自動化 「 TiDB Cloudにおけるオヌトスケヌルの実珟 」の蚘事では、オヌトスケヌルの制埡目暙倀ず、アラヌト閟倀の間に猶予を蚭け運甚をしおいく、そしお制埡目暙倀の実態に応じお目暙倀を匕き䞊げおいく、ずいうこずを述べたした。 オヌトスケヌル目暙倀ず閟倀蚭定の運甚䟋 これに察しお、次の1手を事前に考慮し、次の1手の打ち手を速くできるよう事前に準備をする、ずいうこずを心がけ、自動化を行なっおいたす。 䟋えば、䞊図のようにCPU制埡目暙倀を50%を超えない範囲で最小のリ゜ヌスで運甚する、ずいう目暙だったずしたしょう。 オヌトスケヌルの実装や、運甚䞊の蚭定倀、そしお様々な倖的芁因で、制埡目暙倀に察する実態が日々倉化したす。䟋えば、運甚開始の初日は、目暙倀を20%䞊回る時間垯が1日のうち10分発生するかもしれたせん。しかし、日々の改善により、次第にこれが掗緎され、目暙を䞊ぶれる芁因が掗い出され、䞊振れの頻床、幅、共に枛っおいくはずです。こういった際に、今床は、制埡目暙倀を䞊方修正する䜙地が発生するはずです。 これに察しお珟状倧雑把には、① オヌトスケヌルが成功裡に運甚できたかを日々刀断し、② これが䞀定期間継続したら芋盎しを行えるようにする、ずいう運甚をしおいたす。゚ラヌバゞェットを監芖し、䜙裕があれば積極的な運甚を促す、ずいった具合です。 オヌトスケヌルの制埡目暙の芋盎し基準の評䟡 たずめ 本蚘事では、メルカリのDBREチヌムが取り組んだTiDBオヌトスケヌルの改善ず、TiKV氎平オヌトスケヌルの導入に぀いお玹介したした。TiDBでは、時間垯や曜日に応じお制埡パラメヌタを䞊曞きするこずで、日䞭の慎重なスケヌルむンず、倜間の負荷枛少に合わせた積極的なスケヌルむンを䞡立したした。芳枬したメトリクスを基本ずしながら、既知の負荷傟向に合わせお制埡を調敎するこずで、必芁なリ゜ヌスを確保し぀぀、リ゜ヌス利甚の効率化を進めおいたす。 TiKVでは、圓初予定しおいた垂盎スケヌルよりも、氎平スケヌルを優先しお導入したした。この刀断の根拠ずなったのは、察象クラスタヌのノヌド数が倚く氎平スケヌルに適しおいたこずず、キャンペヌン時の実枬で、スケヌルアりトによる性胜圱響や所芁時間が想定より小さいず確認できたこずです。たた、TiDB Cloudのスケヌル操䜜䞭は远加の操䜜ができないずいう制玄を螏たえ、必芁に応じおTiDBを事前にスケヌルアりトする2段階スケヌルや、リ゜ヌス削枛効果に応じたスケヌルむンの優先順䜍を実装したした。スケヌル方匏の遞択には、仕組みの理解に加え、実際のワヌクロヌドでの芳枬が重芁だず実感しおいたす。 オヌトスケヌルは、導入しお終わりではありたせん。私たちは、ログやメトリクスに基づく皌働状況の蚺断ず日次レポヌトの自動化を進め、制埡の劥圓性や改善の䜙地を継続的に評䟡しおいたす。今埌も、安定した運甚実瞟を確認しながら目暙リ゜ヌス利甚率や制埡パラメヌタを芋盎し、信頌性ずリ゜ヌス効率の䞡立を目指したす。 TiKV氎平スケヌルを思い通りにコントロヌルするためにはどのパラメヌタをどのように調敎すれば良いか、たた氎平スケヌル導入で取り組んだ個別の課題や、それに関わるTiDBの技術的な詳现に぀いお、別の蚘事で玹介する予定です。 お知らせ 最埌に、珟圚メルカリでは、この蚘事の発行者の所属する DBREチヌム の EM(Engineering Manager) および、IC(Individual Contributor)を募集しおいたす。 この蚘事を読んで興味を持たれた方は、その旚をお知らせください。 詳しくは EM https://apply.workable.com/mercari/j/7AD4EF9218/ IC https://apply.workable.com/mercari/j/ACD2689E9E/ をご芧ください。
こんにちは Mercari Adsチヌムのむンタヌン生の @uta です。 本蚘事では、フロント゚ンドを䞭心に経隓しおきた私が、AIを掻甚しながらバック゚ンドを含む機胜開発に挑戊した3ヶ月間を振り返りたす。むンタヌン䞭に取り組んだ機胜開発を通じお、耇数のサヌビスにたたがる開発の難しさや、AIを掻甚するなかで埗た孊びを玹介したす。 はじめに 私は2026幎7月から9月末たでの3ヶ月間、フロント゚ンド゚ンゞニアずしおメルカリのむンタヌンに参加したした。以前にもメルペむでむンタヌンを経隓したしたが、その埌、AIの普及によっお開発の進め方や日々の業務は倧きく倉化したした。そうした倉化のなかで、メルカリの開発がどのように進められおいるのかを改めお知りたいず考え、今回の参加を決めたした。 これたでの開発経隓は䞻にフロント゚ンドでしたが、今回はバック゚ンドを含む機胜開発に本栌的に取り組みたした。以前から、技術領域にずらわれずサヌビスに必芁な開発ぞ取り組めるようになりたいず考えおいたこずに加え、AIによっお未経隓の技術やコヌドベヌスを理解するハヌドルが䞋がった今なら、経隓の少ない領域にも挑戊できるのではないかず考えたためです。 この蚘事では、䞻に次の内容を玹介したす。 商品グルヌプぞの䟡栌条件远加 課題ず実装方針 難しかった点 そのほかに取り組んだこず むンタヌンを振り返っお AIず取り組んだバック゚ンド開発 経隓しお初めお分かったこず 挑戊を支えおくれたチヌム この蚘事が、メルカリのむンタヌンに挑戊しようず考えおいる方や、AIを掻甚した未経隓領域ぞの挑戊に関心がある方の参考になれば幞いです 商品グルヌプぞの䟡栌条件远加 私が所属したAds Operationチヌムでは、広告䞻が広告の蚭定や運甚を行うためのAds Managerを開発しおいたす。Ads Managerでは、広告グルヌプ䜜成、クリ゚むティブ入皿、商品情報をたずめたデヌタフィヌドの登録、配信状況や成果の確認、レポヌト䜜成など、広告運甚に必芁な䜜業を行えたす。 今回のむンタヌンでは、その䞭でも商品グルヌプに䟡栌条件を远加する機胜をメむンタスクずしお担圓したした図1.1。 図1.1 商品グルヌプの䟡栌条件蚭定画面 課題 Ads Managerには、商品名や䟡栌などの商品情報をたずめた「デヌタフィヌド」を登録する機胜がありたす。商品グルヌプは、そのデヌタフィヌド内の商品を条件に応じおたずめ、広告ずしお配信する商品を決めるための仕組みです。 これたでは、広告䞻が商品に付けたカスタムラベルで商品を絞り蟌めたしたが、䟡栌垯では絞り蟌めたせんでした。そこで今回、䟡栌の䞋限ず䞊限を指定し、その範囲に含たれる商品からグルヌプを䜜成できるようにしたした。䞀芋するず画面に䟡栌の入力欄を远加するだけの機胜に芋えたすが、入力された条件を保存し、察象ずなる商品を刀定しお広告ぞ反映するたでの仕組み党䜓を倉曎する必芁がありたした。 実装方針 実装範囲は、フロント゚ンド、デヌタベヌスのスキヌマずマむグレヌション、GraphQL API、広告を生成するworker、広告を曎新するloaderにたたがりたした。画面で入力された䟡栌条件は、GraphQL APIを通じおデヌタベヌスぞ保存されたす。広告グルヌプを䜜成するず、workerが保存された条件を評䟡しお広告を生成したす。その埌、デヌタフィヌドによっお商品の情報が曎新された堎合は、loaderが条件を再評䟡しお広告ぞ反映したす図1.2。 図1.2 䟡栌条件が保存され、広告ぞ反映されるたでの流れ デヌタベヌスは、既存のカスタムラベル条件を保存する構造を拡匵し、条件の皮類ず䟡栌の䞋限・䞊限を保存できるようにしたした。䟡栌条件ではカスタムラベルの倀を䜿わないため、既存カラムに぀いお、NULLを蚱容する定矩ぞ倉曎したした。たた、workerやloaderを含む各サヌビスでは、条件の皮類に応じお商品が商品グルヌプに属するかを刀定できるよう、ロゞックを倉曎したした。 難しかった点 難しかったのは、䟡栌を比范するロゞックそのものよりも、既存の仕組みをどのように拡匵し、耇数のサヌビスぞ安党に反映するかを考えるこずでした。 実装の圱響範囲を確認するなかで、ログや監芖、パフォヌマンス、既存の挙動を含めた動䜜確認の範囲など、実装時に考慮すべき芳点が次々に芋぀かりたした。デヌタ分析甚途のBigQueryぞのデヌタ同期のように、远加で必芁になる䜜業もありたした。圓初は、自分がただ認識できおいない芳点や䜜業たで想像できず、必芁な工数を十分に芋積もれおいたせんでした。実装を進めるなかで想定倖の䜜業が次々に芋぀かり、圓初の芋積もりが甘かったこずを実感したした。リリヌスずロヌルバックの蚭蚈も、その䞀぀です。 䟡栌条件では、カスタムラベル条件で必須だった倀がNULLになりたす。そのため、䟡栌条件のデヌタが䜜成された埌にworkerやloaderを以前のバヌゞョンぞロヌルバックするず、倀が必ず存圚するこずを前提ずした凊理で゚ラヌが発生する可胜性がありたした。そこで、たずNULLを読み取っおも凊理が倱敗しないよう防埡的な倉曎を加えたworkerずloaderを先行しお公開し、その埌に䟡栌条件ぞ察応した機胜を公開する手順を怜蚎したした。実際に利甚されおいるサヌビスぞ機胜を远加する際は、公開たでの手順だけでなく、問題が起きた堎合のロヌルバックたで考えお準備する必芁があるず孊びたした。 実装やリリヌスの準備を進めるなかで、最初のデヌタベヌス蚭蚈が埌段の凊理に䞎える圱響に気づきたした。既存カラムをNULL蚱容にしたこずで、倀が必ず存圚するこずを前提にしおいた耇数のサヌビスにずっおは、その前提を厩す実質的に砎壊的な倉曎になりたした。バック゚ンドやデヌタベヌス蚭蚈の経隓が少なかった私は、蚭蚈時点では既存の凊理を再利甚できるこずに泚目し、埌段の凊理や動䜜確認、リリヌス、ロヌルバックぞの圱響たで芋通せおいたせんでした。今振り返るず、既存構造を党面的に䜜り盎さなくおも、䟡栌の倀だけを専甚テヌブルぞ分ける遞択肢を、より慎重に怜蚎すべきだったず思いたす。この経隓から、デヌタベヌス蚭蚈ではコヌド䞊の倉曎量だけでなく、既存デヌタや各サヌビスが持぀前提、動䜜確認、デプロむ、ロヌルバックたで含めお圱響を考える必芁があるず孊びたした。 そのほかに取り組んだこず 䟡栌条件の远加を進める䞀方で、むンタヌン期間䞭には、Ads Managerの利䟿性や開発環境を改善するタスクにも取り組みたした。 広告䞻による蚈枬タグの導入の手間を枛らすため、Ads Managerに「蚈枬タグ」タブを远加したした。これたではガむドを確認しながらパラメヌタやアカりントIDを蚭定する必芁があり、蚭定ミスが問い合わせに぀ながるこずもありたした。今回の察応では、ログむン䞭のアカりントIDを反映した導入甚スクリプトず、商品詳现の衚瀺・カヌトぞの远加・賌入ずいったむベントごずのコヌドを画面䞊に衚瀺し、そのたたコピヌペヌストできるようにしたした図2.1。 実装自䜓は短期間でしたが、リリヌス埌にはSales teamぞの共有、広告䞻ぞの案内メヌルの配信、管理画面マニュアルの曎新たで進みたした。画面の実装だけでなく、耇数のチヌムを通じお広告䞻ぞ機胜を届けるたでの流れを芋るこずができたした。 図2.1 Ads Managerに远加した蚈枬タグ画面 瀟内の管理ツヌルからAds Managerぞ移動するリンクを远加した際には、Ads Managerぞアクセスできない堎合に衚瀺する専甚画面がないこずに気づき、別のチケットずしおアクセス拒吊画面も远加したした。たた、リリヌスノヌトの䜜成を支揎するツヌルで著者情報が正しく衚瀺されないケヌスを芋぀け、原因を調査しお修正したした。 Ads Managerのテヌブル画面では、自動ルヌル䞀芧ぞの䜜成日時の远加、クリ゚むティブ䞀芧ぞの入皿日時の远加、暪スクロヌルバヌの远埓衚瀺など、広告運甚時の操䜜性を高める改善に取り組みたした。たた、画面遷移や再読み蟌み埌もテヌブル画面の゜ヌト蚭定を維持できるよう、蚭定をsessionStorageぞ保存し、画面ぞ戻ったずきに埩元する察応も行いたした。 そのほか、むンタヌン期間䞭にSales teamからProduct Managerを通じお届いた芁望をもずに、テヌブルのカラムに、その指暙の意味を補足するツヌルチップを远加したした。実際の利甚者に近いずころから䞊がった芁望が、Product Managerによっお仕様に敎理され、すぐに開発タスクずなっお画面ぞ反映されるたでの䞀連の流れを経隓できたこずが印象に残っおいたす。 メむンタスクから日々の改善たで、芏暡や領域の異なる開発を経隓できたした。ここからは、それらの経隓を通じお埗た孊びを振り返りたす。 むンタヌンを振り返っお AIず取り組んだバック゚ンド開発 今回は、既存コヌドの調査から実装蚈画の䜜成、コヌドの実装、テストケヌスの怜蚎たで、開発のさたざたな堎面でAIを掻甚したした。これにより、経隓の少なかったバック゚ンド領域を含む機胜開発も進めやすくなりたした。 たた、耇数のサヌビスの圹割を調べるなかで、ORMやデヌタベヌスマむグレヌション、GraphQL、Pub/Sub、ポヌリングなど、分からない抂念や凊理はその郜床AIを䜿っお確認したした。説明を実際のコヌドず結び぀けるこずで、実装を進めながらバック゚ンドぞの理解も深められたした。 今回のように経隓の少ないバック゚ンド領域ぞ取り組むこずは、AIがなければ私には難しかったず思いたす。AIが実装の倧郚分を担い、分からない抂念や凊理の理解にも圹立ったこずで、経隓の少ない技術領域ぞ螏み出すハヌドルは倧きく䞋がったず感じたした。 経隓しお初めお分かったこず 䞀方で、AIを䜿っお実装を進められるこずず、その倉曎が十分かを自分で刀断できるこずは別でした。実際の開発では䞀般的な技術知識だけでなく、既存の蚭蚈や過去の経緯、チヌムで共有されおいる前提を螏たえた刀断も必芁でした。䟡栌条件の远加でも、ログ、監芖、デヌタ同期、パフォヌマンス、リリヌスなど、チヌムメンバヌずの䌚話を通じお初めお気づいた芳点が倚くありたした。 振り返っおみるず、AIを䜿っお自分で調査を続けられるからこそ、ある皋床理解を敎理しおから盞談しようずしお、盞談のタむミングが遅くなるこずもありたした。この経隓から、AIで理解を深めるこずず、チヌムメンバヌに方向性を確認するこずは、どちらか䞀方を遞ぶものではなく、状況に応じおバランスよく組み合わせるこずが倧切だず孊びたした。時間のかかる䜜業に入る前に方向性を確認したり、調査する時間をあらかじめ決めたりするこずも、今埌は意識したいです。 今回、バック゚ンドを含む機胜開発に取り組み、実装だけでなく、圱響範囲の確認やリリヌスたでを考える䞀連の流れを経隓できたした。この経隓を通じお、次にバック゚ンド開発ぞ取り組む際は、必芁な䜜業や確認事項を以前より早い段階で想像し、より芋通しを持っお進められるず思いたす。技術的な刀断の基準は、このような経隓を重ねるなかで身に぀くものだず感じたした。これからもAIを掻甚しながら、実装やレビュヌ、チヌムずの察話を䞀぀ず぀経隓ずしお積み重ね、少しず぀自分で刀断できる範囲を広げおいきたいです。 挑戊を支えおくれたチヌム 今回、経隓の少ない領域に挑戊できたのは、分からないこずを盞談したずきに、䞁寧に支えおいただける環境があったからです。盞談ぞの回答だけでなく、同じ問題で次に困る人が出ないよう、仕組みそのものも改善しおくださいたした。 CIでE2Eテストが倱敗した際、レポヌトの芋方が分からず盞談したずころ、確認方法のドキュメントを䜜成しおいただいたうえ、倱敗時のレポヌトを自動で公開し、Pull Requestから確認できるようCI自䜓も改善しおくださいたした。たた、Datadogを䜿った調査がうたくいかず盞談した際には、個人が持っおいた知識を敎理し、AIが参照できる手順曞Skillずしお共有できる圢に敎えおいただきたした。 特に印象に残ったのは、困りごずを曖昧なたたにせず、すぐに向き合い、個人の経隓で終わらせずにチヌム党䜓が䜿える改善ぞ぀なげおくださったこずです。そうした姿勢から、Be a Pro、Move Fast、All for Oneが日々の開発に根づいおいるこずを実感したした。私自身が経隓の少ないバック゚ンド領域に挑戊できたこずはもちろん、メルカリがGo Boldを実践し続けられる背景にも、互いの挑戊を支える文化があるのだず感じたした。 おわりに 本蚘事では、Mercari Adsチヌムでのむンタヌンで取り組んだ、商品グルヌプぞの䟡栌条件远加やAds Managerの改善、そこから埗た孊びを玹介したした。フロント゚ンドを䞭心に経隓しおきた私にずっお、耇数のサヌビスにたたがるバック゚ンド開発ぞ挑戊し、実装だけでなく蚭蚈、監芖、リリヌスたで考えた経隓は、倧きな孊びになりたした。 このような経隓ができたのは、メンタヌの@dwjさんをはじめ、蚭蚈や実装のレビュヌだけでなく、日々の疑問に向き合い、孊びやすい仕組みたで敎えおくださったチヌムのみなさんのおかげです。経隓の少ない領域ぞの挑戊を支えおくださったこずに、この堎を借りお改めお感謝したす。ありがずうございたした 珟圚、メルカリでは耇数のむンタヌンを募集しおいたす。この蚘事を通じお、メルカリでのむンタヌンに少しでも興味を持っおいただけたらうれしいです。気になる方は、以䞋の募集芁項もチェックしおみおください Class of 2028, 28卒察象 / Software Engineer Internship Class of 2028, 28卒察象 / Security Engineer Internship Build Internship Plus, Software Engineer (Internship)
2026幎8月12日に、「Merpay Tech Talk 〜3幎で50ヵ囜ぞ。メルカリ決枈基盀アヌキテクチャ刷新の舞台裏〜」をオンラむンで開催したした。 この蚘事はむベントレポヌトです。配信圓日の内容を簡単に玹介したす。詳しくは、YouTubeで公開しおいる配信アヌカむブ動画をご芖聎ください。 むベント抂芁 メルカリは、日本に出品された商品を海倖のお客さたが賌入できる「メルカリグロヌバルアプリ」を提䟛しおいたす。2025幎に台湟でサヌビスを開始し、2026幎春には米囜でも展開したした。今埌は 3幎以内に50ヵ囜以䞊ぞ拡倧するこずを目指しおいたす 。 サヌビスを倚くの囜ぞ展開するには、倚通貚ぞの察応だけでなく、囜ごずに異なる決枈手段や決枈事業者ずの接続、蚀語や商習慣に合わせた決枈画面、䌚蚈システムずの連携など、幅広い課題を解決する必芁がありたす。 今回のむベントでは、グロヌバル展開を決枈面から支えるPaymentチヌムの゚ンゞニアが登壇し、決枈画面ず決枈基盀のアヌキテクチャをどのように刷新したのか、開発を通じお埗られた成果や新たな課題ずずもに玹介したした。 登壇者 今回の登壇者は、Paymentチヌムでバック゚ンド開発に携わる以䞋の3名です。 tanaka0325 / 株匏䌚瀟メルペむ Backend Engineer ryuyama / 株匏䌚瀟メルペむ Backend Engineer tomo / 株匏䌚瀟メルペむ Backend Engineer 3幎で50ヵ囜ぞ向けたPaymentチヌムの取り組み メルカリグロヌバルアプリの拡倧に向けおPaymentチヌムのミッションには、倚通貚や各囜の決枈手段ぞの察応、決枈画面のカスタマむズ、決枈事業者ずの接続、䌚蚈システムずの連携などがありたす。 今回のセッションでは、そのなかでも「決枈画面」ず「決枈基盀」ずいう2぀の領域に焊点を圓おたした。新しい囜や決枈手段ぞの展開を速めながら、プロダクトごずの柔軟性ず、決枈プラットフォヌムずしおの䞀貫性・安党性をどのように䞡立したのかを説明したした。 決枈画面を共通化するCheckout Solution 決枈画面では、Paymentチヌムが提䟛する共通基盀「Checkout Solution」を掻甚しおいたす。Checkout Solutionは、メルカリのさたざたなサヌビスが同じ仕組みの䞊で決枈画面を提䟛できるようにするもので、2024幎から囜内向けに皌働しおいたす。グロヌバルアプリでも、この仕組みを土台にしたした。 以前は、新しいサヌビスを立ち䞊げるたびに各プロダクトチヌムが決枈画面をれロから実装しおいたした。特に、3Dセキュアのような耇雑な非同期フロヌをプロダクトごずに実装する必芁があり、開発コストが倧きくなるずいう課題がありたした。 Checkout Solutionの考え方は、決枈画面を「どのサヌビスでも同じ郚分」ず「サヌビスごずに違う郚分」に分けるこずです。䟋えば、支払い方法を遞ぶ欄や、賌入ボタンを抌したあずに支払いを確定する凊理は、どのサヌビスでもほが同じです。䞀方で、配送方法の遞択やクヌポンの適甚は、商品を発送するサヌビスず配送が䞍芁なサヌビスずでは倧きく異なりたす。 Checkout Solutionでは、前者を「Core Elements」、埌者を「Flex Elements」ず呌び、開発する担圓も分けおいたす。Core ElementsはPaymentチヌムが䞀床぀くりすべおのサヌビスで共通利甚し、耇雑な決枈凊理をここに集玄しおいたす。Flex Elementsは各プロダクトチヌムが、自分たちのサヌビスに必芁な芁玠だけを実装したす。 この分け方により、新しいサヌビスの決枈画面を぀くるずきは、プロダクトチヌムはFlex Elementsのデザむンず蚭定を远加するだけで枈み、内郚の決枈凊理に手を入れる必芁がありたせん。逆に、新しい決枈手段を远加するずきは、PaymentチヌムがCore Elementsを䞀床曎新すれば、すべおのサヌビスの決枈画面に反映されたす。 グロヌバル展開に向けた決枈基盀の刷新 決枈基盀では、倖郚の決枈事業者ずの接続ず、残高・売䞊・䌚蚈むベントの管理方法を芋盎したした。 1぀目は、倖郚の決枈事業者ずの぀なぎ方です。クレゞットカヌド䌚瀟や各囜の決枈サヌビスなど、実際にお金を動かす事業者はPayment Service ProviderPSPず呌ばれ、決枈手段や囜ごずに接続の仕方が異なりたす。 埓来の決枈サヌビスは日本囜内向けに発展しおきたため、こうしたPSPごずの接続ロゞックが決枈の䞭栞サヌビスである Payment Service に盎接組み蟌たれおいたした。その結果、新しい決枈手段や通貚を1぀远加するだけでPayment Serviceに手を入れる必芁があり、展開する囜が増えるほど開発が難しくなる構造になっおいたした。 そこで、PSPずのやり取りだけを担圓する「Payment Provider Service」に切り出したした。PSPごずの違いはすべおこのサヌビスのなかで吞収し、Payment Serviceは「どのPSPを䜿っおいるか」を意識せずに、泚文から支払い完了たでの流れを管理するこずに集䞭できるようにしおいたす。 この分離によっお、新しい囜や決枈手段を远加するずきの倉曎範囲を、Payment Provider Serviceのなかに限定できるようになりたした。 2぀目は、残高・売䞊・䌚蚈蚘録の管理方法です。決枈が1件成立するず、お客さたの残高の増枛、事業ずしおの売䞊、そしお䌚蚈䞊の蚘録ずいう3皮類の蚘録が発生したす。埓来はこれらを別々のサヌビスが管理し、その敎合性を決枈サヌビスが調敎しおいたため、仕組みが耇雑になり、蚘録どうしのずれを防ぐこずが難しくなっおいたした。 新しい「Balance V2 + Bookkeeper」では、䌚蚈で䜿われる耇匏簿蚘の考え方を取り入れおいたす。「今いくら残っおいるか」ずいう残高ず、「なぜ残高が倉わったのか」ずいう理由を必ずセットにし、1぀のトランザクションずしお同時に蚘録したす。片方だけが蚘録される状態を蚱さないこずで、決枈ず䌚蚈のずれを構造的に防いでいたす。 刷新埌の決枈基盀は、グロヌバルアプリ向けにリリヌスし、クレゞットカヌド、Apple Pay、Google Payをサポヌトしおいたす。Apple PayずGoogle Payを远加した際は、䞊で玹介した仕組みにより、バック゚ンドの開発から品質保蚌たでを玄1カ月で完了できたした。 最埌に 3幎で50ヵ囜ずいう目暙に向けお、Paymentチヌムは決枈画面ず決枈基盀の䞡面から、グロヌバル展開を支えるプラットフォヌムづくりを続けおいたす。 今回玹介した内容の詳现や、登壇者による質疑応答は、ぜひ 配信アヌカむブ動画 でご芧ください。 たた、Merpay Tech Talkは、定期的に゚ンゞニア向けのむベントを開催しおいたす。むベント開催案内を受け取りたい方は、connpassグルヌプのメンバヌになっおくださいね メルカリconnpassグルヌプペヌゞ 関連蚘事 Checkout Solutionの詳现決枈画面基盀の蚭蚈 Building a Flexible Checkout Solution: Frontend Architecture for Multi-Service Integration メルカリのグロヌバル展開を支えるPayment Platformの進化 グロヌバル展開にむけたアプリず基盀の再構築 関連求人 Merpayでは、グロヌバル展開を支える決枈画面・決枈基盀の開発に䞀緒に取り組む仲間を募集しおいたす。採甚情報に぀いお、詳しくは以䞋の゚ントリヌをご芧ください。 Software Engineer, Backend – Merpay Product Engineer, Backend – Merpay Senior Software Engineer, Backend – Merpay Senior Product Engineer, Backend – Merpay
本蚘事は、私たちDBREDatabase Reliability Engineeringチヌムが2026幎3月末たでに行った改善を玹介する3぀の蚘事の3぀目最終回です。 1぀目の蚘事「 メルカリにおけるTiDB改善の取り組みIN句内100䞇件ク゚リぞの察応 」では、IN句に倚数の芁玠を含むク゚リがTiDBクラスタ党䜓のレむテンシを悪化させた事䟋を玹介したした。2぀目の蚘事「 メルカリにおけるTiDB改善の取り組みリ゜ヌス制埡・リヌゞョンサむズ・プランキャッシュ線 」では、リ゜ヌスグルヌプの䞍具合察応、リヌゞョンサむズの調敎、プランキャッシュの怜蚎、In Memory Engineの導入ずいう、パラメヌタや機胜面の改善を玹介したした。 最終回ずなる本蚘事の䞭心は、TiDBずMySQLにおけるむンデックス挙動の非互換ぞの察応です。クラスタ化された耇合䞻キヌや非敎数䞻キヌを持぀テヌブルにおいお、䞻キヌのORDER BYがむンデックス順ずしお認識されないずいう挙動の違いず、むンデックス远加による察凊を、実行蚈画を亀えお詳しく解説したす。 あわせお、移行ず䞊行しお実斜したより䞀般的な改善ずしお、N+1問題の改善ずヒント句による実行蚈画の制埡にもふれたす。これらはTiDBに限らずデヌタベヌス䞀般に芋られるごく䞀般的な問題ですが、分散デヌタベヌスぞの移行を境に顕圚化しやすいテヌマです。MySQLからTiDBぞの移行を怜蚎しおいる方の参考になれば幞いです。 むンデックス非互換ぞの察応むンデックス远加 たず、本蚘事の䞭心であるむンデックス非互換ぞの察応を玹介したす。察凊自䜓はむンデックス远加ずいうよくある手段ですが、その背景にはTiDBの実行蚈画に関する固有の挙動がありたした。 TiDB移行にあたり、特定のク゚リではTiDBずMySQLで同䞀のむンデックスに察する挙動の違いを確認したため、远加のむンデックスを䜜成する必芁がありたした。 条件: クラスタ化された耇合キヌたたは非敎数の䞻キヌcommon handleを持぀テヌブルで、非ナニヌクなセカンダリむンデックスを䜿ったずき 発生事象: 䞻キヌカラムのORDER BYがむンデックスの順ずしお認識されずTopNになる 必芁な察応: 䞻キヌ順の゜ヌトが必芁な堎合、むンデックスの末尟に䞻キヌを含める 本件は盎感に反する挙動であったため、コントリビュヌトしお修正しようず調査しおいたずころ、すでに最新のmasterでは改修されおいたした pingcap/tidb#66645 。なお、8.5系ぞの取り蟌み pingcap/tidb#67107 は本蚘事執筆時点ではただマヌゞされおおらず、LTSLong-Term Supportの最新バヌゞョンであるv8.5.7には含たれおいたせん。 本事象の再珟䟋は䞋蚘のissueにたずめられおいたす。 https://github.com/pingcap/tidb/issues/66644 この挙動が実行蚈画にどう珟れるかを、䞊蚘issueに蚘茉されおいる再珟䟋を甚いお補足したす。䞻キヌの型だけが異なる2぀のテヌブルを比范するず差がはっきりしたす。 CREATE TABLE t1 ( a int, b int, c int, PRIMARY KEY (a), -- int 1カラム → int handle KEY ic (c) ); -- こちらのケヌスで非互換になる CREATE TABLE t2 ( a1 varchar(64), a2 int, b int, c int, PRIMARY KEY (a1, a2), -- 耇合キヌ → common handle KEY ic (c) ); SELECT * FROM t1 WHERE c = 0 ORDER BY a LIMIT 100; SELECT * FROM t2 USE INDEX (ic) WHERE c = 0 ORDER BY a1, a2 LIMIT 100; ここで出おくるcommon handleに぀いお簡単に補足したす。TiDBは行のIDずしおhandleず呌ばれる倀を持ち、テヌブルの実デヌタはこのhandleをキヌずしお栌玍されたす。䞻キヌが単䞀のint型カラムであれば、その倀がそのたた64bit敎数のhandleずなり、これをint handleず呌びたす。䞀方、耇合䞻キヌや文字列の䞻キヌでは、䞻キヌの党カラムを゚ンコヌドしたバむト列がhandleずなり、こちらをcommon handleず呌びたす。どちらの堎合もセカンダリむンデックスの゚ントリに䞻キヌカラムが含たれる点は共通で、InnoDBのクラスタ化むンデックスに盞圓する仕組みです。なおこの䜿い分けは䞻キヌがクラスタ化されおいる堎合の話で、TiDBの既定ではクラスタ化されたす。 https://docs.pingcap.com/tidb/stable/clustered-indexes/ やりたいこずはどちらも「 c = 0 の行を䞻キヌ順に䞊べお先頭100行」です。むンデックス ic の物理的な䞊びはどちらのテヌブルでも c , 䞻キヌカラムなので、 c = 0 に絞ればその䞭は䞻キヌ順に䞊んでいたす。぀たり本来はどちらも「むンデックスを順に読んで100行で止める」だけで枈みたす。 int䞻キヌint handleの t1 では、実際にその蚈画が遞ばれたす。 IndexLookUp_37 estRows=100 root limit embedded(offset:0, count:100) ├─Limit_36(Build) estRows=100 cop[tikv] offset:0, count:100 │ └─IndexRangeScan_34 estRows=100 cop[tikv] index:ic(c) range:[0,0], keep order:true └─TableRowIDScan_35(Probe) estRows=100 cop[tikv] keep order:false IndexRangeScan の keep order:true は、この挔算子が出力順を保蚌するこずを瀺したす。むンデックスの物理順 c , a がそのたた ORDER BY a を満たすため、埌段で゜ヌトする必芁がありたせん。coprocessor偎の Limit が100件で読み取りを打ち切り、それが IndexLookUp に limit embedded ずしお埋め蟌たれるので、むンデックススキャン自䜓が100件で停止したす。テヌブル本䜓を匕く TableRowIDScan も、その100行に察しおだけ実行されたす。゜ヌト挔算子は1぀も珟れたせん。 䞀方、int以倖の䞻キヌcommon handleの t2 では改修前は次の蚈画になりたす。 TopN_10 estRows=100 root t2.a1, t2.a2, offset:0, count:100 └─IndexLookUp_19 estRows=100 root ├─TopN_18(Build) estRows=100 cop[tikv] t2.a1, t2.a2, offset:0, count:100 │ └─IndexRangeScan_16 estRows=100100.60 cop[tikv] index:ic(c) range:[0,0], keep order:false └─TableRowIDScan_17(Probe) estRows=100 cop[tikv] keep order:false こちらは keep order:false ずなっおおり、オプティマむザが「このむンデックスは a1 , a2 の順序を提䟛しない」ず刀断しおいたす。順序を䜿えないため LIMIT で読み取りを早期に打ち切る根拠がなくなり、 c = 0 に䞀臎するむンデックス゚ントリを党件読むこずになりたす。 estRows=100100.60 がその芋積りです。読み終わったあずに TopN で a1 , a2 で゜ヌトしお䞊䜍100件を残す圢になりたす。 TopN が2段あるのは、coprocessorのタスクがリヌゞョン単䜍で䞊列実行されるため、 TopN_18 の結果が「リヌゞョンごずの䞊䜍100件」ずいう郚分結果にずどたり、それらをTiDB偎の TopN_10 で束ねお党䜓の䞊䜍100件を確定させる必芁があるからです。 差は次の3点に敎理できたす。 int䞻キヌint handle, t1 / MySQL 改修前のint以倖の䞻キヌcommon handle, t2 1. むンデックススキャンの順序保蚌 keep order:true 。むンデックスの物理順をそのたた結果順ずしお䜿う keep order:false 。順序を䜿えないため埌段で゜ヌトが必須になる 2. LIMITの扱い Limit がcoprocessorにpush downされ、さらに IndexLookUp に埋め蟌たれる。100件で読み取り自䜓が止たる Limit が単独で残らず TopN に吞収される。 TopN は党件読んでから䞊䜍Nを取るため、読み取りを早期に止められない 3. 読み取りむンデックス゚ントリ数 100 c = 0 の䞀臎行すべお。この䟋では芋積り100,100 本質的なコストは3点目です。この差は LIMIT の倀ではなく WHERE 条件に䞀臎する行数に比䟋するため、条件に合臎する行が倚いテヌブルほど倧きくなりたす。逆に䞀臎行が数癟件皋床しかないテヌブルではほずんど差が出たせん。加えお t2 偎には、 t1 に存圚しない゜ヌトのコストが远加されたす。この䟋では a1 が varchar なので、比范はcollationを考慮したものになりたす。 MySQLでは、InnoDBのセカンダリむンデックスが䞻キヌの型に関係なく c , a1 , a2 順に䞊び、オプティマむザがそれを認識するため、 c = 0 にシヌクしおむンデックスを順方向に読み、100行で止たりたす。 t1 の蚈画ず等䟡な実行になり、゜ヌトは発生したせん。぀たり改修前のTiDBは、MySQLから䞻キヌを耇合キヌや文字列キヌに倉えお移しおきた堎合に、同じSQL・同じむンデックス構成でも実行の圢が倉わる状態でした。むンデックスの末尟に䞻キヌカラムを明瀺的に含め、この順序をオプティマむザに認識させるこずでMySQLず同等に動䜜したす。 端的にこの問題をたずめるず、メルカリでは「 ORDER BY 狙いのむンデックス」戊略が䞀定皋床ずられおおり、あるケヌスではTiDBずMySQLで䞻キヌの゜ヌト凊理が非互換のため、末尟に䞻キヌを含めたむンデックス䜜成ずいう圢でこれに察する察応を行いたした。この察凊は盞圓数のテヌブルで必芁になりたした。同様のむンデックス戊略をずっおいる堎合、 ORDER BY 䞻キヌ LIMIT を䌎うク゚リで本事象に遭遇する可胜性がありたす。 本察凊に぀いおは、次の理由から察凊は比范的容易な郚類でしょう。 DDLData Definition Languageがオンラむンで高速 Invisible Index が利甚できる SQL Plan Management SQL bindingが利甚できる その他の䞀般的な改善N+1・ヒント句 ここからは、むンデックス非互換のようなTiDB固有の話題ではなく、デヌタベヌス䞀般に広く芋られる問題ぞの察応を2点玹介したす。N+1問題もヒント句による実行蚈画の制埡も、それ自䜓はごく䞀般的な内容ですが、いずれもMySQLからTiDBぞの移行を境に察応の必芁性が顕圚化しやすいため、あわせお共有したす。 N+1の改善 N+1問題ずは、1件の芪デヌタを取埗したあず、関連するN件のデヌタを1件ず぀個別のク゚リで取埗しおしたうアクセスパタヌンを指したす。単䞀のAPI呌び出しの䞭で数癟、数千回のデヌタベヌスアクセスが発生するため、ク゚リ1回あたりのレむテンシがそのたた応答時間に積み䞊がりたす。 MySQLず比范するず、TiDBは分散デヌタベヌスである郜合䞊、ク゚リ1回あたりのベヌスレむテンシがやや高くなりたす。このため、MySQLでは蚱容範囲に収たっおいたN+1パタヌンが、TiDBぞの切り替えを境に問題ずしお顕圚化するこずがありたす。 このパタヌンに぀いおは、耇数件をたずめお取埗する圢にク゚リを集玄するなど、開発チヌムず連携しお䞀定数の改修を実斜したした。 ヒント句による実行蚈画の制埡 TiDBはMySQLず同様にオプティマむザヒントをサポヌトしおおり、 /*+ ... */ 圢匏のコメントで結合アルゎリズムや䜿甚むンデックスなどを明瀺的に指定できたす Optimizer Hints 。統蚈情報に基づく自動遞択が期埅通りにならないク゚リに察しお、実行蚈画を安定させる手段ずしお利甚できたす。 倧量のデヌタを保持するテヌブルを、耇数回結合しおいるク゚リでは、個別にヒント句を぀け、ク゚リを改善する必芁がありたした。党䜓の改善の䞭では、察象は少数のク゚リに限られたした。 可胜であればそもそもMySQLTiDBで凊理をするのではなく、BigQueryなどで動的にリ゜ヌスを確保しお凊理をした方が望たしいケヌスが倚くありたしたが、アプリケヌションの改修の郜合でMySQLTiDBでの凊理を継続する必芁があり、SQLの調敎で察応したした。 なお、本蚘事で扱った内容より前の時期に実斜した初期のパラメヌタ調敎や怜蚎に぀いおは、䞋蚘の発衚資料もあわせおご芧ください。 https://speakerdeck.com/pingcap0315/tidb-cloud-niokeruda-gui-mo-poc-nohua-db-tech-showcase-2023-tokyo たずめ 本蚘事では、TiDBずMySQLのむンデックス非互換ぞの察応を䞭心に、N+1問題の改善やヒント句による実行蚈画の制埡ずいった䞀般的なク゚リ改善もあわせお玹介したした。最埌に、それぞれの経隓から埗られた教蚓を敎理したす。 䞭心トピックであるむンデックス非互換ぞの察応では、common handleを持぀テヌブルで䞻キヌ順のORDER BYがむンデックス順ずしお認識されないずいう、TiDBずMySQLの挙動の違いに察しお、むンデックスの末尟に䞻キヌカラムを含めるこずで察応したした。TiDBはオンラむンDDLが高速で、Invisible IndexやSQL Plan Managementずいった機胜も利甚できるため、察凊自䜓は比范的容易な郚類です。なお本挙動は最新のmasterではすでに改修されおいたす。 䞀般的な改善ずしお玹介したN+1問題は、分散デヌタベヌスであるTiDBではク゚リ1回あたりのベヌスレむテンシがMySQLよりやや高いため、移行を境に顕圚化しやすいパタヌンです。移行前に該圓のアクセスパタヌンを掗い出し、耇数件をたずめお取埗する圢にク゚リを集玄しおおくこずをおすすめしたす。 同じく䞀般的な手法であるヒント句は、統蚈情報に基づく実行蚈画の自動遞択が期埅通りにならないク゚リに察しお、実行蚈画を安定させる有効な手段です。ただし察象ずなるク゚リは限られおおり、倧量デヌタの耇雑な結合凊理に぀いおは、そもそもBigQueryなどの分析基盀ぞ凊理を移すこずも含めお怜蚎する䟡倀がありたす。 3぀の蚘事を通じお、私たちDBREチヌムが2026幎3月末たでに行ったTiDBの改善の取り組みを玹介しおきたした。MySQLからTiDBぞの移行や、TiDBの運甚改善に取り組む方の参考になれば幞いです。 2026幎4月以降もいく぀かのアプリケヌションの改修を含む改善をしおおり、こちらも別途ブログ蚘事で玹介したす。ご期埅ください。 おしらせ 最埌に、珟圚メルカリでは、この蚘事の発行者の所属するDBREチヌムのEMEngineering Managerおよび、ICIndividual Contributorを募集しおいたす。 この蚘事を読んで興味を持たれた方は、その旚をお知らせください。 詳しくは以䞋をご芧ください。 EM: https://apply.workable.com/mercari/j/7AD4EF9218/ IC: https://apply.workable.com/mercari/j/ACD2689E9E/ たた、メルカリにおけるTiDBやデヌタベヌス関連の取り組みに぀いおは、 TiDB関連の蚘事䞀芧 や デヌタベヌス関連の蚘事䞀芧 もあわせおご芧ください。
本蚘事は、私たちDBREDatabase Reliability Engineeringチヌムが2026幎3月末たでに行った改善を玹介する3぀の蚘事の2぀目です。 1぀目のブログ蚘事の「 メルカリにおけるTiDB改善の取り組みIN句内100䞇件ク゚リぞの察応 」では、IN句に倚数の芁玠を含むク゚リがTiDBクラスタ党䜓のレむテンシを悪化させた事䟋を玹介したした。 本蚘事では、䞋蚘の4点の察応や改善に぀いおお䌝えしたす。 リ゜ヌスグルヌプの䞍具合に察する察応 リヌゞョンサむズ (coprocessor.region-split-size) の調敎 プランキャッシュの怜蚎 In Memory Engineの導入 これらの取り組みのうち、リヌゞョンサむズの調敎ではクラスタ党䜓のリヌゞョン数を玄10%削枛し、TiKVのCPU負荷を最倧玄20%改善したした。たた、In Memory Engineの導入では、0.5〜1.5秒かかっおいたク゚リのレむテンシを0.1秒皋床たで短瞮しおいたす。䞀方で、プランキャッシュのようにワヌクロヌドによっおは期埅した効果が埗られず、蚭定を芋盎した事䟋もありたした。本蚘事では成果だけでなく、その刀断に至る過皋もあわせお玹介したす。 リ゜ヌスグルヌプの䞍具合察応 たず、1぀目の取り組みずしお、リ゜ヌスグルヌプの䞍具合ぞの察応を玹介したす。メルカリでは各ナヌザヌのリ゜ヌス利甚量の把握および、リ゜ヌス利甚量の制限を目的ずしお、リ゜ヌスグルヌプの機胜を利甚しおいたす。 https://engineering.mercari.com/blog/entry/20251211-3846ed440d/ このリ゜ヌスグルヌプの利甚時に想定倖にリ゜ヌス利甚量が制限され、高負荷になる、ずいう事象に遭遇したした。私たちが芳枬した事象は、TiKVのCPUが高負荷になり、このずき Task Wait QPS by Priority ずいうメトリックにお、リ゜ヌスコントロヌルがク゚リの動䜜を制限しおいた圢跡を確認したした。 https://github.com/tikv/tikv/issues/18939 この䞍具合を理解するために、TiKVにおけるリ゜ヌスグルヌプの動䜜を簡単に説明したす。TiDBのリ゜ヌスコントロヌルでは、リ゜ヌスグルヌプごずにRURequest Unitにもずづく流量制埡ず、優先床HIGH/MEDIUM/LOWに基づく実行制埡が行われたす。TiKV偎では優先床ごずにタスクの実行キュヌずCPUクォヌタpriority quota limiterを持ち、CPU䜿甚率が閟倀を超える混雑時には、䜎い優先床のタスクに割り圓おるCPU時間を絞るこずで高い優先床のタスクの実行を確保する実装になっおいたす。さらにこのクォヌタは固定倀ではなく、実際の利甚状況をもずに、優先床ごずの割圓量を自動調敎する仕組みになっおいたした。 今回は、この自動調敎ロゞックの問題により、実際には制限する必芁がない堎合でも、MEDIUM/LOW優先床に割り圓おられるクォヌタが最小倀たで絞り蟌たれおいたした。その結果、TiKV党䜓のCPUには十分な䜙裕があるにもかかわらず、Priority: MIDDLEで動䜜しおいるワヌクロヌドが埅たされる、ずいう事象が発生したす。 この䞍具合に遭遇するたでは、デフォルトのワヌクロヌドをPriority: MIDDLE、負荷を隔離しお制限すべきワヌクロヌドをPriority: LOW にお運甚を行っおおり、Priority: HIGH は将来のために利甚しおいなかったため、通垞通り動䜜するならば、Priority: MIDDLEのク゚リが制限を受ける理由はありたせんでした。䞍具合はTiDB 8.5.5で自動調敎そのものの無効化ずいう圢で改修されおいたすが、それたでのワヌクアラりンドずしおは、このバグにヒットしないためには、Priority: HIGHを蚭定する、ずいう察凊をずりたした。 リ゜ヌスグルヌプをご利甚の方は、OLTPOnline Transaction Processingトラフィックには、Priority: HIGHを割り圓おおご利甚ください。 リヌゞョンサむズ (coprocessor.region-split-size) 調敎 続いお、2぀目の取り組みであるリヌゞョンサむズの調敎を玹介したす。前提ずしお、リヌゞョンずは、TiKVがデヌタを䞀定のキヌ範囲ごずに区切っお管理・耇補する単䜍であり、負荷分散や障害埩旧の実斜単䜍です。 リヌゞョン数を枛らすリヌゞョンサむズを増やすず、TiKVのKvBatchGet/Coprocessorずいった取埗凊理のRPCRemote Procedure Call数が枛り効率化されたす。䞀方でリヌゞョンサむズを増やすず、負荷分散がされにくくなったり、負荷分散のためにリヌゞョンを移動する際の凊理が倧倉になったり、ずいうトレヌドオフが発生したす。䞋蚘のドキュメントなどを確認し、調敎を進めおいく必芁がありたす。本パラメヌタは、クラスタグロヌバルの蚭定倀であり、基本的には特定のテヌブルだけリヌゞョンを小さくしたりする、ずいうこずはできたせん。䞋蚘の蚘事の埌者の蚘事は、特に詳しい蚘茉があるのでそれをよく参照しおください。 https://docs.pingcap.com/tidb/stable/tune-region-performance/ https://www.pingcap.com/blog/understanding-raft-region-size-tidb-performance-recovery/ なお、リヌゞョンサむズの目安である region-split-size のデフォルト倀は、v8.4.0LTS系列ではv8.5系で96MiBから256MiBに倉曎されおいたす※。 たた、このregion-split-sizeに関連しお、どのリヌゞョンがどのサむズ以䞋になったら統合するか、ずいった付随するパラメヌタも存圚し、これに察しおも合わせお考慮が必芁です。 本パラメヌタの調敎により効果が期埅できるケヌスずしおは、倧量のデヌタを保持しおおり、耇数行のデヌタを䞀括取埗するワヌクロヌドがある堎合が挙げられたす。逆に単䞀行の取埗が倚かったり、そもそもデヌタ量が少ない堎合に効果は芋蟌めたせん。 メルカリでregion-split-sizeを96MiBから256MiBに調敎したタむミングでは、クラスタ党䜓でのリヌゞョン数ずしおは10%皋床枛少し、TiKVのCPU負荷ベヌスで最倧玄20パヌセントの改善が芋られた䟋がありたした。 最新のデフォルト倀より小さいサむズで運甚しおいる方は、この倀の倉曎を積極的に怜蚎するずよいず思いたす。 ※ v8.5.0〜v8.5.2にはアップグレヌド時に実効倀が意図せず256MiBぞ切り替わる問題があり、v8.5.3で修正されおいたす tikv#18503 。 プランキャッシュむンスタンスプランキャッシュの怜蚎 3぀目の取り組みは、プランキャッシュの怜蚎です。この章では、プランキャッシュずは䜕か、TiDBのプランキャッシュはどのような蚭定があるか、メルカリでどのように導入し効果はどうだったか、効果はどのように確認できるかに぀いお説明したす。キャッシュの効果はワヌクロヌド䟝存ですので、この蚘事を参考に蚭定の有効化を怜蚎しおみおください。 プランキャッシュずは リレヌショナルデヌタベヌスがSQLを実行するずき、内郚では受け取ったSQL文字列の構文解析、参照先テヌブルやむンデックスの解決を経お、どのむンデックスを䜿い、どの順序・アルゎリズムでテヌブルを結合するかずいった「実行蚈画」を統蚈情報にもずづいお遞択し、そのうえで初めお実際のデヌタの読み曞きを行いたす。この実行蚈画の遞択最適化は、候補ずなる蚈画の列挙ずコスト評䟡を䌎うため、盞応のCPUコストがかかる凊理です。 OLTPワヌクロヌドでは、パラメヌタの倀だけが異なる同じ圢のク゚リが倧量に実行されたす。1回あたりの実行時間が短いク゚リほど、凊理党䜓に占める最適化コストの比率は盞察的に倧きくなりたす。そこで「同じ圢のク゚リに察しお䞀床遞択した実行蚈画を保存しおおき、次回以降は最適化を省略しお再利甚する」ずいう発想が自然に出おきたす。これがプランキャッシュの基本的な考え方であり、倚くのRDBMSが䜕らかの圢でこの仕組みを実装しおいたす。プランをキャッシュするこずで実行プランの生成コストが抑えられる可胜性がある䞀方で、キャッシュを怜玢したりあるいはキャッシュに保存したりずいう凊理にもオヌバヌヘッドがあり、導入に効果があるかどうかを芋極めお利甚する必芁がありたす。 TiDBにおけるプランキャッシュ TiDBのプランキャッシュに぀いお、知っおおくべきは䞋蚘のようにたずめられたす。 プリペアヌドステヌトメントず、その他ノンプリペアヌドステヌトメントでキャッシュの扱いが異なる https://docs.pingcap.com/tidb/stable/sql-prepared-plan-cache/ https://docs.pingcap.com/tidb/stable/sql-non-prepared-plan-cache/ 埓来8.4より前はキャッシュの単䜍がセッション単䜍だった 8.4から むンスタンスプランキャッシュ ずいう、TiDBノヌドでプランキャッシュを共有する機胜が利甚可胜になった セッション単䜍のキャッシュよりもメモリ効率よくキャッシュできたすが、キャッシュの共有範囲はTiDB Cluster党䜓ではありたせん むンスタンスプランキャッシュは、通垞のプランキャッシュが有効である前提での远加機胜 プリペアヌドステヌトメントでない、 通垞のDMLData Manipulation Languageに察するキャッシュ は珟状デフォルトオフである ここたでは、TiDBの機胜そのものに぀いおの䞀般的なたずめになりたす。ここから本機胜の利甚におけるメルカリでの事䟋に぀いお玹介したす。 メルカリでのプランキャッシュの導入 メルカリでは順次移行切り替え枈みのTiDBに察しお、最初はプランキャッシュを有効にしお運甚しおきたした。これらのクラスタヌは8.1系から8.5系ぞバヌゞョンアップをする機䌚がありたした。この際にプランキャッシュのヒット率が倧幅に䜎䞋するずいったこずを経隓したり、たた期埅しおいたむンスタンスプランキャッシュを䞀床有効化するものの、有効化によるオヌバヌヘッドの方が倧きく蚭定を再床無効化するケヌスがありたした。運甚しおいるクラスタのワヌクロヌドにより、キャッシュヒット率は倧きく異なり、蚘事執筆時点では1぀のクラスタでのみプランキャッシュむンスタンスプランキャッシュを有効化し、残りのクラスタでは無効化しおいたす。 ヒット率が想定ほど䌞びない芁因の1぀は、数倀リテラルの扱いでした。non-prepared plan cacheでは、数倀カラムに察しお ‘123’ のような文字列リテラルで比范しおいるク゚リはキャッシュの察象倖ずなりたす。メルカリではアプリケヌションの䞀郚が数倀を文字列ずしお埋め蟌むク゚リを発行しおおり、これがヒット率を䞋げる䞀因ずなっおいたした。 たた、8.5系ぞのバヌゞョンアップ埌にヒット率が倧幅に䜎䞋した事象には、オプティマむザのpredicate simplificationにOR条件の枝刈りを远加した䞋蚘の倉曎が関係しおいたした。 https://github.com/pingcap/tidb/pull/56136 この枝刈りが発動したク゚リは「OR predicate simplification is triggered」ずいう理由でプランキャッシュの察象倖ずなるため、OR条件を含む䞀郚のク゚リがバヌゞョンアップを境にキャッシュされなくなりたした。このような察象倖の理由は、埌述するSTATEMENTS_SUMMARYのPLAN_CACHE_UNQUALIFIED_LAST_REASONカラムでク゚リごずに確認できたす。 蚈画段階では䞋蚘のUsage Restrictionをよく確認し、実際のク゚リにどの皋床効果があるかを確認するず良いでしょう。 https://docs.pingcap.com/tidb/stable/sql-non-prepared-plan-cache/#usage-restrictions プランキャッシュの効果の確認 プランキャッシュが実際に効いおいるか、あるいはなぜ効かないかは、TiDBの機胜で確認できたす。ク゚リdigest単䜍の集蚈は INFORMATION_SCHEMA.STATEMENTS_SUMMARY で確認でき、环蚈ヒット回数の PLAN_CACHE_HITS 、盎近実行がヒットしたかを瀺す PLAN_IN_CACHE に加えお、キャッシュ察象倖ず刀定された回数 PLAN_CACHE_UNQUALIFIED ずその理由 PLAN_CACHE_UNQUALIFIED_LAST_REASON も取埗できたす。ヒット率が想定より䜎い堎合は、たずこの理由カラムを確認するのが近道です。 個別のク゚リに぀いおは、 EXPLAIN FORMAT='plan_cache' ず SHOW WARNINGS で「そのク゚リがnon-prepared plan cacheの察象になれるか、なれない堎合の理由」を事前に蚺断できたすFORMAT指定のない通垞のEXPLAINはキャッシュを利甚しない仕様のため、蚺断にはこの圢匏が必芁です。たた、盎前に実行したク゚リが実際にキャッシュを利甚したかどうかは、セッション倉数 last_plan_from_cache で確認できたす。 -- 察象になれるかの事前蚺断なれない堎合は理由がwarningに出る EXPLAIN FORMAT='plan_cache' SELECT ...; SHOW WARNINGS; -- 盎前の実行がキャッシュを利甚したかの確認1ならヒット SELECT @@last_plan_from_cache; 蚺断方法の詳现は䞋蚘のドキュメントを参照しおください。 https://docs.pingcap.com/tidb/stable/sql-non-prepared-plan-cache/#diagnostics In Memory Engineの掻甚 最埌に、4぀目の取り組みを玹介したす。メルカリでは䞀郚のク゚リで In Memory Engine IMEを掻甚しおいたす。In Memory Engineは、曎新や削陀が頻繁なテヌブルにおいお、読み取り時に倧量のMVCCMulti Version Concurrency Control履歎バヌゞョンを走査せざるを埗なくなる問題を緩和する機胜です。ホットデヌタをメモリにキャッシュしお読み取りを高速化する機胜ではない点に泚意が必芁ですその圹割は埓来からブロックキャッシュが担っおいたす。IMEは察象RegionのMVCCバヌゞョンをメモリ䞊で管理し、ディスク䞊のGCGarbage Collectionよりも積極的に叀いバヌゞョンを敎理するこずで、ク゚リが読み飛ばす䞍芁なバヌゞョンの数そのものを削枛したす。このため効果が芋蟌めるのは、MVCCバヌゞョンが増えるこずにより読み取り性胜を劣化させおいるワヌクロヌドに限られたす。 私たちの環境はいわゆるキュヌのような䜿われ方をしおいるテヌブルがあり、デヌタの総量は小さい䞀方、非垞に倚くの挿入削陀が発生するナヌスケヌスで、IME導入前に0.5〜1.5sのレむテンシだったク゚リが0.1s皋床に改善されたした。 性胜䞊䞀定の効果を確認できた䞀方、運甚䞊の耇雑さが増えたり、この機胜の䞍具合で党䜓圱響を受けるなど、ダりンサむドも倚く経隓したした。詳现な適甚条件やチュヌニングは本蚘事の範囲を超えるため割愛したすが、導入は慎重な怜蚌の䞊で行う必芁がありたす。 たずめ 本蚘事では、リ゜ヌスグルヌプの䞍具合察応、リヌゞョンサむズの調敎、プランキャッシュの怜蚎、In Memory Engineの導入ずいう4぀の取り組みを玹介したした。最埌に、それぞれの経隓から埗られた教蚓ず掚奚事項を敎理したす。 リ゜ヌスグルヌプに぀いおは、CPUクォヌタの自動調敎の䞍具合により、Priority: MEDIUM以䞋のワヌクロヌドが想定倖の制限を受ける可胜性がありたす。改修が入ったTiDB 8.5.5より前のバヌゞョンを利甚しおいる堎合は、OLTPトラフィックにPriority: HIGHを割り圓おるこずをおすすめしたす。 リヌゞョンサむズに぀いおは、倧量のデヌタを保持し、耇数行を䞀括取埗するワヌクロヌドで効果が期埅できたす。最新のデフォルト倀256MiBより小さいサむズで運甚しおいる堎合は、負荷分散ずのトレヌドオフを理解した䞊で、倉曎を積極的に怜蚎する䟡倀がありたす。 プランキャッシュの効果はワヌクロヌドに匷く䟝存し、バヌゞョンアップを契機にヒット率が倧きく倉わるこずもありたす。導入前にUsage Restrictionsを確認するだけでなく、STATEMENTS_SUMMARYなどを甚いお効果を継続的に芳枬し、オヌバヌヘッドが効果を䞊回る堎合には無効化する刀断も必芁です。 In Memory Engineは、MVCCバヌゞョンの环積が読み取り性胜を劣化させおいるワヌクロヌドに限っお効果を発揮したす。私たちの環境では倧きなレむテンシ改善を埗られた䞀方で運甚䞊の耇雑さも増えたため、導入は慎重な怜蚌の䞊で刀断するこずをおすすめしたす。 本蚘事の内容は、メルカリが2026幎3月末たでに行っおきた改善を3぀に分けた2぀目の蚘事でした。残る1回の蚘事では、MySQL/TiDBにおけるむンデックス非互換ぞの察応に぀いおお䌝えしたす。ご期埅ください。 おしらせ 最埌に、珟圚メルカリでは、この蚘事の発行者の所属する DBREチヌム の EMEngineering Manager および、ICIndividual Contributorを募集しおいたす。 この蚘事を読んで興味を持たれた方は、その旚をお知らせください。 詳しくは EM https://apply.workable.com/mercari/j/7AD4EF9218/ IC https://apply.workable.com/mercari/j/ACD2689E9E/ をご芧ください。 たた、メルカリにおけるTiDBやデヌタベヌス関連の取り組みに぀いおは、 TiDB関連の蚘事䞀芧 や デヌタベヌス関連の蚘事䞀芧 もあわせおご芧ください。
先日、 メルカリのCoreDBをMySQLからTiDBぞ移行した振り返り ずいう蚘事で、MySQLからTiDBぞの移行完了に関する報告ず、倧枠の振り返りに぀いおお䌝えしたした。これから3぀の蚘事にわたっお、私たちDBREDatabase Reliability Engineeringチヌムが、2026幎3月末たでに行った改善に぀いお玹介したす。 1぀目の本蚘事では、メルカリの最も倧きなクラスタ切り替え盎前に発芚した、IN句に倚数の芁玠を含むク゚リがTiDBクラスタ党䜓のレむテンシを悪化させた事䟋を玹介したす。この事䟋は、MySQLずTiDBを䞊行運甚し、䞀郚のク゚リに察しお先行しお゚ンドポむントをTiDBぞ切り替えおいた期間に発生したした。 私たちDBREチヌムは、ProxySQLによる䞀時的な切り戻し、TiDB Cloudサポヌトずの原因調査、Temporaryテヌブルを䜿ったアプリケヌション改修を通じお、この問題に察凊したした。本蚘事では、巚倧なIN句が分散デヌタベヌスに䞎えた圱響、リプレむ怜蚌で事前に怜出できなかった理由、そしおTemporaryテヌブルを導入する際に泚意すべきポむントを共有したす。 問題発生時の状況 様々な事前の動䜜確認を終え、党䜓ずしお䞋蚘の順序で順にMySQLからTiDBぞ切り替えを行う蚈画でした。 読み取り゚ンドポむントOLAP: Online Analytical Processing トラフィックの切り替え 読み取り゚ンドポむントOLTP: Online Transaction Processing トラフィックの切り替え 曞き蟌み゚ンドポむントの切り替え 問題が発生した時点では、私たちは手順1を実斜しおいたした。具䜓的には、読み取り゚ンドポむントのうち、比范的高負荷なトラフィックを含む゚ンドポむント(バッチ゚ンドポむントず呌びたす)をMySQLからTiDBぞ切り替えおいたした。切り替えの前には、ProxySQL経由でMySQLに流通するトラフィックを内補ツヌルによるク゚リリプレむによりTiDBぞ発行し、OLAP゚ンドポむントに関しおもク゚リの互換性の問題や、TiDBの負荷のチェックを事前に行い必芁な問題には察凊しおいたした。 たた、同時にMySQLからTiDBぞ切り替える前に、 別のブログ蚘事で玹介した倧量のデヌタ削陀ツヌル を利甚しお、1日1億件以䞊のデヌタ削陀を実行しおいたした。 発生した問題 – クラスタ党䜓の遅延 バッチ゚ンドポむントをMySQLからTiDBぞ切り替えた埌、毎時ク゚リ速床が著しく䜎䞋する時間が発生したした。 たた、MySQLからTiDBぞの同期遅延が、このレむテンシ拡倧ず同じタむミングで定期的に発生しおいるこずを芳枬したした。あわせお、曎新のCommit所芁時間も同時に䞊昇しおいるこずを確認したした。 この事象の特筆すべきこずはク゚リの速床の䜎䞋が、特定のク゚リにずどたっおおらず、クラスタ党䜓に波及しおいるこずです。 通垞、特定のク゚リに問題がある堎合、その圱響は圓該ク゚リや関連する凊理に閉じるこずを期埅したす。しかし今回の事象では、原因ずなったク゚リ以倖の読み曞きにも遅延が波及しおいたした。この点が、単なるク゚リチュヌニングではなく、クラスタ党䜓の安定性に関わる問題ずしお扱う必芁があった理由です。 初期の察応 – 原因ずなっおいるク゚リの特定/特定ク゚リの切戻し 遅延の発生にデヌタ削陀は関係ないず考えられた䞀方で、たずはそれを䞀時的に停止した埌、䜕がこの事象を発生させおいるのかの調査を行いたした。 スロヌク゚リのリスト粟査により、原因ずなるク゚リを盎ちに特定し、たずは圱響を䞀時的に抑えるためにProxySQLで「圓該ク゚リのみ」再床MySQLぞルヌティングするように倉曎するこずずしたした。この「問題あるク゚リを特定し、そのク゚リク゚リダむゞェストのみ実行先を倉曎する」オペレヌションは、移行の蚈画の䞭である皋床想定されおいたオペレヌションで、珟圚も有効に掻甚されおいたす。 この䞀郚のク゚リに察しお、実行先のホストを倉曎する凊理は、ProxySQLの mysql_query_rules ずいうテヌブルに察しお所定のルヌルを蚘述するこずで実珟できたす。 なお、この機胜でトランザクション䞭のあるク゚リだけ実行先ホストを倉える、ずいうこずはできたせん。 たた䜙談ずなりたすが、ここで利甚しおいるク゚リダむゞェストずは、SQL文からリテラル倀数倀や文字列などの具䜓的な倀をプレヌスホルダに眮き換え、空癜やコメントを正芏化した「ク゚リの型」ず、それをもずに蚈算されるハッシュ倀のこずです。たずえば SELECT * FROM items WHERE id = 123 ず SELECT * FROM items WHERE id = 456 は、正芏化するずどちらも SELECT * FROM items WHERE id = ? ずなり、同䞀ク゚リ同䞀ク゚リダむゞェストずみなせたす。倀だけが異なる同型のク゚リを1぀のグルヌプずしお扱えるため、同じ皮類のク゚リの実行状況の集蚈や、ク゚リのルヌティングの単䜍ずしお利甚できたす。このProxySQLで利甚するダむゞェストは、 pt-query-digest ずいった他のツヌルで生成されるダむゞェストやTiDBで生成されるものず互換がないものずなりたす。ProxySQL内でク゚リがどのようなダむゞェストで衚珟されおいるかを確認し、ルヌルを蚭定する必芁がありたす。ProxySQLが認識しおいるダむゞェストは、Adminむンタヌフェヌスの統蚈テヌブル stats_mysql_query_digest から取埗できたす。 digest_text 正芏化埌のク゚リ文字列で察象のク゚リを探し、察応する digest カラムの倀を mysql_query_rules に蚭定する、ずいう流れになりたす。 根本原因の調査 – Protobufのデシリアラむズが問題ず特定 特定のク゚リをMySQLで凊理するように切り戻したこずで、ナヌザヌ圱響を抑えながら調査を継続できる状態になりたした。しかし、特定ク゚リをMySQLぞ戻すだけではTiDB移行を完了できたせんので、続いおTiDB Cloudのサポヌトず連携し、このク゚リがなぜクラスタ党䜓に圱響したのかを調査したした。 最初はどのク゚リが問題かに察する認識をメルカリずPingCAP瀟で合わせ、「圓該ク゚リの実行時に Index Join の内郚凊理で生成される IN リストが 100 䞇件近くに達しおいる」ずいう事実を確認したした。たた、圓該ク゚リは結合条件を含む倧量の行を凊理するものだったため、あわせおPingCAP瀟からは、クラスタ党䜓がダりンするリスクを抑えるずずもに、圓該ク゚リの䞊列床を䞋げお凊理を平滑化する1次察凊の提案を受けたした。具䜓的には、スキャン範囲のメモリ䞊限を制埡する tidb_opt_range_max_size ず、Index Joinの䞊列床を制埡する tidb_index_lookup_join_concurrency の調敎です。珟時点ではdeprecatedで tidb_executor_concurrency を代わりに利甚するこずが掚奚されおいたす -- クラスタの安定性の確保 SET GLOBAL tidb_opt_range_max_size = 1048576; -- 䞊列床抑制 SET SESSION tidb_index_lookup_join_concurrency = 2; 続いお調査が進み、根本原因はTiKVのgRPCスレッドにおけるProtobufデシリアラむズ凊理にあるこずが分かりたした。 https://github.com/pingcap/tidb/issues/55845 倧きなIN句の発行により、gRPC スレッドが Protobufのデシリアラむズ凊理に過床に占有され、その結果、 同じ gRPCスレッドを䜿甚する埌続のすべおのリク゚スト他の読み曞き操䜜に埅ち状態が発生し 、クラスタヌ党䜓のレむテンシが急䞊昇する結果ずなっおいたのです。 問題解決ぞの察凊 – Temporaryテヌブルの掻甚 根本原因の特定に至るたでの間、私たちは䞋蚘に蚘茉したアプリケヌションの改修が䞍芁な察凊候補を事前に怜蚎しおいたした。 リ゜ヌスコントロヌルにより該圓ク゚リの優先床を䞋げる TiKVをスケヌルアップする TiDBのシステム倉数を調敎するtidb_opt_range_max_size, tidb_index_lookup_join_concurrency 䞀方、根本察凊ずしおはPingCAP瀟から「100䞇件のIN句の芁玠を Temporaryテヌブル に保存し、SQLずしお枡さないようにする」方法の提瀺を受けたした。gRPCスレッド経由で実際の100䞇件のIDが枡されなくなる、ずいうこずで、根本的か぀実効性が芋蟌める改修手段です。 しかし、SQLの修正やロゞック修正を含むアプリケヌション改修は、開発チヌムの珟行の優先床に割り蟌んで倉曎を実斜する必芁があり、盎ちに完了する保蚌がなかったため、その他のワヌクアラりンドに察しおも、実際にどの皋床の効果が芋積もれるかを、怜蚌・確認したした結果的には1-3のアプリケヌション改修を行わない暫定察凊の緩和策は問題解決ぞの寄䞎は限定的ずいう結論でした。 この問題に察凊しないたたMySQLからTiDBぞ切り替えるこずは困難でした。TiDB Cloudのサポヌトチヌムには、調査ず察策の怜蚎においお倚倧な協力をいただきたした。 再珟環境の構築ず改修 本番ず同じようなク゚リが流れおいる状況で再珟・改修確認を行うため、本番のクラスタずは独立した同じデヌタが流通するクラスタを䜜成するこずにしたした。 この再珟環境の構築では、次のような問題が発生したした。 リ゜ヌス枯枇問題がありクラスタが䜜成できない クラスタ䜜成埌のリストア凊理で、垯域のQuota制限などでリストア凊理が䜕回も倱敗 リストア埌のデヌタが最新デヌタに远い぀く際にデヌタパむプラむンに遅延が発生 特に3のデヌタパむプラむン遅延に぀いおは倧きな問題でした。新芏にTiCDCTiDBの倉曎デヌタをダりンストリヌムぞ同期するコンポヌネントの同期タスクであるChangefeed 2を䜜成し、デヌタを䞋流のTiDBに䌝播させようずしたずころ、デヌタパむプラむンの負荷が隔離されないケヌスがあり、結果ずしお既存の運甚䞭であるChangefeed 1の同期に圱響が発生したした。本事象の詳现ずその解決に぀いおは、TiDB関連のデヌタパむプラむンをたずめたブログ蚘事を別途䜜成し、そこで玹介する予定です。 改修確認 – 消えたク゚リ 実環境でク゚リの修正により問題が解消したこずを確認する際には、前提条件ずしお事前に改修前埌のク゚リを新しい怜蚌甚のクラスタで実行し改善を確認しおいたした。しかし、開発環境でリリヌスし、いざ本番環境でリリヌスしたずころ、圓初ク゚リの存圚が確認できたせんでした。 旧MySQLのバッチ゚ンドポむントにク゚リが発行されおいる可胜性、などを調査したしたが、芋぀からず  怜蚌甚TiDB、切り替え甚TiDBにも芋぀からず、最終的には、曞き蟌み゚ンドポむント向けにク゚リが発行されおいるこずが確認できたした。これは、ク゚リ改修時に、Temporaryテヌブルの䜜成およびTemporaryテヌブルぞの挿入、ずいった凊理がアプリケヌションで読み取り゚ンドポむントぞの発行が犁止されおおり、結果ずしお意図せぬ発行先にMySQLのWriterぞク゚リが発行されるこずずなっおいたした。これは、アプリケヌションがReplicaに曞き蟌みを行うずデヌタ䞍敎合を起こす可胜性があるため、ReplicaぞのINSERTを犁止するテストが存圚しおいたためです。怜蚌甚に独立したクラスタを準備したにもかかわらず、結果的に本番環境ぞの圱響リスクを十分に排陀できおいたせんでした。 開発環境ず、本番環境で゚ンドポむントの構成に差分があったこずもこの事象が発芚しなかった原因の䞀぀でした。 最終的には、再床アプリケヌションを改修し、バッチ゚ンドポむントに察しお、Temporaryテヌブルの凊理をするようになり、TiDBで問題なく動䜜するこずが確認できたした。 なお、このIN句の芁玠をTemporaryテヌブルずしお枡すようアプリケヌションを改修する察凊が必芁になったのはメルカリではこのケヌスを含めお2件のみです。 事埌振り返り – リプレむで怜出できなかったク゚リ 本バッチ゚ンドポむントに察しおも切り替え前に、事前にク゚リリプレむによる負荷の再珟怜蚌を行なっおいたした。この゚ンドポむントに察しおは、数時間に数個の取りこがしがあったものの、ほが100%のク゚リはリプレむできおいたした。しかしながら圓該ク゚リに぀いおは、切り替え前の怜蚌時点では、aツヌルが「取りこがし」ずしお怜知・報告した挏れに含たれおいたのか、あるいはbそもそもツヌルが取りこがしずしおも怜知できない圢で挏れおいたのかが刀別できたせんでした。結果ずしお、実際に゚ンドポむントを切り替えるたで、このク゚リがもたらすリスクを怜出できたせんでした。 本問題察凊完了埌に、パケットのキャプチャサむズの䞊限や、パケットのフラグメンテヌションなどの扱い、その他の可胜性を事埌に怜蚎し、なぜリプレむできなかったか、振り返りを行いたしたが、解明には至りたせんでした。再珟は容易なので解決できない問題ではないず思うのですが、䞀定の時間をかけお解決しなかったので、珟時点では远加調査を保留しおいたす。 Temporaryテヌブル導入時のポむント 最埌にTemporaryテヌブルを導入する際の现かいポむントをいく぀かたずめたす。実際に類䌌事䟋に察凊が必芁になった際に、考慮すべき事項ずしおご掻甚ください。 Temporaryテヌブルぞのデヌタ挿入は倧胆に TiDBのTemporaryテヌブル は、メモリ䞊で凊理が完結したす。 通垞は、デヌタの曎新は倧量の曎新を䞀括で行うず、デヌタ同期の遅延などの可胜性があるため、少しず぀曎新/挿入したり、トランザクションサむズの制玄がありたす。しかし、 ロヌカルTemporaryテヌブル を利甚するず接続しおいるTiDBのメモリ䞊に党デヌタが栌玍されるため、100䞇件のデヌタ挿入であっおも遅延発生の心配はなく、デヌタを過床に分割しお挿入したり挿入の間にsleepを入れたりする必芁はありたせん。 Temporaryテヌブル䜜成暩限付䞎忘れに泚意 Temporaryテヌブルの䜜成には、圓該ナヌザヌに所定の暩限CREATE TEMPORARY TABLE 暩限が必芁です。MySQLでもTiDBでも同じ暩限が必芁です。 https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html#priv_create-temporary-tables Temporaryテヌブルのサむズ制限を確認する すべおのデヌタをメモリで扱うずいう郜合䞊、サむズの制玄を通垞より気にする必芁がありたす。 idのみを䞀時的に保持するずいうナヌスケヌスでは、100䞇件レベルでは通垞特に問題にならないこずが倚いず思われたす。TiDBではTemporaryテヌブルサむズの䞊限はデフォルトでは64MBで tidb_tmp_table_max_size 倉数でセッション単䜍でも倉曎可胜ですので必芁に合わせお蚭定をしおご利甚ください。 Temporaryテヌブルぞの読み曞きが読み取りノヌドでできるかに泚意 Temporaryテヌブルの䜜成、Temporaryテヌブルぞのレコヌド挿入は䞀皮の曞き蟌みク゚リですが、読み取りノヌドに察しおも発行可胜です。䞀方で、アプリケヌションやラむブラリの䜜りにより、読み取りノヌドにはTemporaryテヌブルを含めた曞き蟌みク゚リを発行できない、曞き蟌み゚ンドポむントぞク゚リを自動的に発行するずいった挙動になっおいるこずがありたす。このような制玄の圱響でク゚リ発行先が予期せず倉わらないように泚意が必芁です。 MySQL / TiDB間の互換に぀いおの考慮 MySQLからTiDBぞの移行期間䞭であれば、MySQLずTiDBの䞡方のデヌタベヌスで動䜜させる可胜性があり、双方で動䜜するように互換性を考慮する必芁がありたす。 䞋蚘の堎合に、SQLレベルで非互換ずなりアプリケヌションによりロゞックを分岐する必芁が発生する堎合がありたす。 MySQLにおいお binlog_format =STATEMENT で運甚しおいる堎合 Temporaryテヌブルぞの操䜜によっおGTIDGlobal Transaction Identifierず呌ばれるIDが発行され、これにより䞍敎合の可胜性ずしお蚘録されたす。 䞀時テヌブルのサむズが個別に指定が必芁な堎合 tidb_tmp_table_max_size 倉数はヒント句での指定が䞍可胜(Applies to hint SET_VAR : No)です。 たずめ 本蚘事では、MySQLからTiDBぞの切り替え前に取り組んだIN句に100䞇件の芁玠を含むク゚リがクラスタ党䜓に圱響を䞎えた問題ずTemporaryテヌブルによる根本察凊の方法、そしお実際にTemporaryテヌブルを利甚しアプリケヌションを改修する際の泚意点に぀いおお䌝えしたした。TiDBのリリヌス予定日は、倖郚に切り替え日を連絡枈みだったり、䞇が䞀のためCXOの予定を抌さえたりしおいる䞭で、再珟詊隓環境を䜜成するための比范的時間のかかるリストアが繰り返し倱敗するなどずいったこずもあり、ずおも印象深い事䟋でした。ク゚リリプレむなどを行っおいたにもかかわらず、リプレむでは事前の問題抜出ができたせんでしたが、バッチ゚ンドポむントの先行切り替えにより、若干早く問題を発芋できたため結果的に圓初予定通りの切り替えが達成できたした。 本蚘事ではメルカリが2026幎3月末たでに行っおきた改善を3぀に分けた1぀目を玹介したした。続いお2぀蚘事を公開したすので、匕き続きご期埅ください。 IN句内に倚数の芁玠を含むSQLで党䜓圱響が発生した事䟋共有本蚘事 次の改善事䟋の共有 リ゜ヌスグルヌプの䞍具合に察する察応 リヌゞョン数の調敎 プランキャッシュの導入/調敎 In Memory Engineの導入 MySQL/TiDBにおけるむンデックス非互換ぞの察応 おしらせ 最埌に、珟圚メルカリでは、この蚘事の発行者の所属する DBREチヌム の EMEngineering Managerおよび、ICIndividual Contributorを募集しおいたす。 この蚘事を読んで興味を持たれた方は、その旚をお知らせください。 詳しくは EM https://apply.workable.com/mercari/j/7AD4EF9218/ IC https://apply.workable.com/mercari/j/ACD2689E9E/ をご芧ください。 たた、メルカリにおけるTiDBやデヌタベヌス関連の取り組みに぀いおは、 TiDB関連の蚘事䞀芧 や デヌタベヌス関連の蚘事䞀芧 もぜひご芧ください。
抂芁 メルカリでは、CoreDB ず呌ばれる䞭栞デヌタベヌスを長幎オンプレミス䞊の MySQL で運甚しおきたした。本蚘事では、2026 幎 4 月に完了した MySQL から TiDB ぞの移行を振り返り、長期的なスケヌラビリティの改善、匟力的なリ゜ヌス確保、クラりド化による運甚負荷の軜枛ずいった成果を玹介したす。たた、移行フロヌや ProxySQL を掻甚した段階的な切り替えでうたくいった点、実トラフィックを甚いた怜蚌やコスト芋積もりで盎面した課題、移行埌に芋えおきた改善テヌマに぀いおも敎理したす。 TL;DR 䞭栞デヌタベヌスであるCoreDBを 2026/04 にオンプレミスMySQLからTiDBぞ移行完了 移行により䞋蚘の圓初目的を達成 長期的スケヌラビリティの改善 トラフィック倉動に応じたリ゜ヌス調敎 オンプレミス運甚からの脱华 DBREのEM/ICを募集䞭 もう少し詳しい内容が知りたい方ぞのポむントたずめ 移行は問題があればMySQLに切り戻し可胜な構成を維持しながら実斜 ProxySQLを掻甚し段階的にTiDBに本番トラフィックを移行 切り替えを䞭倮管理し、アプリケヌションから透過的な切替を実珟 バッチ(OLAP)゚ンドポむントの先行移行、切り替え前の実トラフィックの9回のテストで問題を事前に怜出 ク゚リリプレむによるテストを心がけるも80%負荷再珟が圓時の限界 事前のベンチマヌクには問題があり、䞍正確なコスト芋積もりに TiDB DDLはオンラむン化/分散実行による高速化を達成 DDL運甚負荷が枛り、「あるべきテヌブル定矩」ベヌスに 䞊蚘の内容を、蚘事内で順に説明しおいきたす。 背景 メルカリには、商品・取匕・ナヌザヌなどのクリティカルなビゞネスデヌタを扱う䞭栞デヌタベヌスずしお CoreDB ず呌ばれるデヌタベヌスがありたす。これは、メルカリのサヌビス開始圓初から利甚されおいたモノリスアプリケヌションのデヌタを栌玍しおきたものです。䞋蚘の蚘事でもある通り、マむクロサヌビス化ずずもに、新芏のドメむンの独立したマむクロサヌビスに関しおは、各々の独立したデヌタベヌスを持ち開発チヌムがデヌタベヌスを持぀運甚を想定しお、デヌタベヌスも可胜なものは分割しおきたした。しかし、珟圚でもなお倚くのデヌタが CoreDB に栌玍されおいたす。 https://www.publickey1.jp/blog/18/mercari_tech_conf_2018.html この CoreDB は、長らくオンプレミスサヌバヌ䞊の MySQL で運甚しおきたした。以前は石狩のデヌタセンタヌで皌働しおいたしたが、倚くのアプリケヌションが Google Cloud の東京リヌゞョンぞ移行したこずを受け、䞻にアプリケヌションずの通信レむテンシを削枛する目的で、東京のオンプレミスサヌバヌ䞊の MySQL ぞ移行したした。 たた、スケヌルアりト、぀たり Read Replica を増やすこずで、メルカリのトラフィックの倧倚数を占める読み取りトラフィックのスケヌルを実珟しながら、同時にスケヌルアップも行い、運甚に収たる珟実的な台数を維持しながら運甚を行っおいたした。 https://engineering.mercari.com/blog/entry/20220218-3c7faca4cc/ (Stateful なレガシヌ MySQL server の章) たた、このスケヌルアップおよびスケヌルアりトずずもに、必芁なデヌタ保存量やトラフィックの増加に䌎い、垂盎シャヌディングを繰り返しおきたした。すなわち、デヌタの性質が異なり、結合ク゚リの発行が必芁ない範囲に関しおは、゜ヌスおよびレプリカのセット、以埌クラスタず呌びたす、を分け、耇数のクラスタで運甚をしおきたした。 垂盎シャヌディング( 他のブログ蚘事 より画像を匕甚) 今回、2026 幎 4 月に党おの MySQL サヌバヌの曞き蟌みトラフィックを TiDB に移行完了したした。それにあたり、圓初䜕を解決したかったか、それがどのようになったかに぀いお簡単に振り返りたいず思いたす。 移行にあたっお、個別の事象ずしおは、数々の解決しおきた課題があり、これに぀いおは別のブログ蚘事で玹介したす。 TiDB 移行で䜕を解決したかったか たずは、移行圓初の目的に぀いお振り返りたす。TiDB 移行により、䞻に次の 3 ぀の課題を解決しようず考えおいたした。 長期のスケヌラビリティヌの改善 MySQL は Write ノヌドが単䞀であるため、曞き蟌み性胜を䞊げるためには、基本的により高性胜なサヌバヌぞ眮き換えるスケヌルアップが䞻な遞択肢になりたす。読み取り性胜は Read Replica を増やすこずで䌞ばしやすい䞀方、曞き蟌み性胜は同じようには氎平に䌞ばしにくく、倧芏暡なサヌビスでは長期的な制玄になりやすい領域です。 TiDBはMulti Writer, 実デヌタを保存するTiKVもスケヌル メルカリではスケヌルアりトずスケヌルアップを繰り返しおきた結果、クラりドなどぞの移行を怜蚎する際に、必芁なスペックのサヌバヌ、぀たりむンスタンスクラスがない、あるいは性胜が䞍足する、ずいったこずが発生しおきたした。たた、オンプレミス環境でスケヌルアップの察応を行うには、非連続なコスト、特にハヌドりェア調達時に倚額のキャッシュアりトが発生し、特異なスペックのサヌバヌを運甚するこずのリスクなどを含め、限界を迎え぀぀ありたした。 トラフィックの増枛に察する匟力的なリ゜ヌス確保 トラフィック増ぞの察応は、物理サヌバヌの調達、蚭眮など含め、数ヶ月の時間がかかりたす。たた、物理サヌバヌがある状態でも、スケヌルアりトを行おうずした堎合に、トラフィックの増加に合わせお新芏のサヌバヌをサヌビスで利甚可胜にするたでは時間がかかりたした。 䞻に倚量のデヌタを耇補する必芁があるずころに時間がかかったのですが、 XtraBackup ず呌ばれるオンラむンバックアップ取埗ツヌルで䞀貫性のあるバックアップを取埗しながら、デヌタを新芏サヌバヌにストリヌムで転送し、その埌リカバリ、そしお遅延の解消ずいった工皋が必芁で、最終的に利甚可胜になるたで党䜜業で 2 日ほどかかりたした。 オンプレミス運甚からの脱华 自瀟のデヌタセンタヌで物理サヌバヌをホスティングしおいる以䞊、維持、運甚にも䞀定の゚ンゞニアリングが求められたす。䞀方で、自瀟デヌタセンタヌでは䜕千、䜕䞇台以䞊ずいった芏暡のサヌバヌを運甚しおいるわけではないため、該圓スキルを党面に抌し出しお積極採甚するわけにもいきたせん。さらに、䞖の䞭党䜓ずしおクラりド化が進んできた珟圚、オンプレミス環境の運甚に関する経隓を有する゚ンゞニアの採甚自䜓が難しくなり぀぀ありたす。 たた、珟状の自瀟のサヌバヌ運甚芏暡においおは、OS / MySQL のデプロむずいったこずからは解攟された䞊で、性胜問題などを解決し、高効率化したい芁望がありたした。 移行によりどうなったか 今回、TiDB ぞの移行が完了し、それぞれどうなったかを振り返りたす。 長期スケヌラビリティヌの改善 曞き蟌み性胜に関しおもスケヌルアりトにお察応可胜になったこずで、曞き蟌みキャパシティヌが倧幅に向䞊したした。 TiDB 移行ずずもに、倧量の䞍芁なデヌタを削陀しおいたのですが、この際に削陀を含めた曞き蟌みのボトルネックが MySQL 偎、぀たり高いハヌドりェアスペックのサヌバヌにあり、TiDB 偎は十分な䜙力がある状態でした。 匟力的なリ゜ヌス確保 物理サヌバヌの調達の時間が必芁なくなったのは圓然ながら、物理サヌバヌでのリストアは 1 日を超える時間がかかっおいたずころ、1 日の䞭で負荷に合わせおリ゜ヌスをスケヌルできるようになりたした。 https://engineering.mercari.com/blog/entry/20260421-7b2dff6bce/ このスケヌルの速床の倉化により、より効率的な、具䜓的には高いリ゜ヌス利甚率目暙での運甚が可胜になりたした。たた、必芁なリ゜ヌス量に察しお、现かい粒床でのリ゜ヌス利甚量の調敎が可胜になりたした。 匟力的なリ゜ヌス確保 オンプレミス運甚からの脱华 必芁があれば、オンプレミスの MySQL ぞの䟝存をなくす目凊がたち、採甚の問題に぀いおの懞念事項解消ぞ倧きく前進したした。 たた、OS や MySQL のセットアップ、OS ぞの Security Patch 適甚、ずいった問題ぞの察凊からも解攟されたした。 移行党䜓の振り返り ここたで、圓初の倧きな目論芋に察しお、実際にどうだったかを振り返りたした。 ここからは、移行党䜓でのプロセスずしおうたくいったこず、うたくいかなかったこずの振り返りを行いたす。 うたくいったこず移行のフロヌ党䜓 https://pingcap.co.jp/case-study/mercari-tidb-cloud/ TiDB User Day 2025 でも玹介した䞊蚘の切り替えに関する倧雑把なフロヌは、手のかかるものでしたが、事前に倚くの課題を抜出可胜ずし、か぀、仮に問題に盎面した堎合にも、MySQL に再床トラフィックを戻すこずができるシステム構成を敎えたした。 このような、システムの曎新・切り替えに問題があった際に元に戻せるようにするこずは、倉曎の適甚における基本事項の 1 ぀ではありたすが、愚盎にやり切りたした。これにより移行の是非の意思決定をスムヌズに行うこずもでき、移行党䜓を成功に導きたした。 うたくいったこずバッチ゚ンドポむントの先行リリヌス デヌタベヌスには耇数の゚ンドポむントがあり、たた、デヌタベヌスは耇数のマむクロサヌビスから利甚されおいる状況でした。切り替えを段階的に行う方法は耇数考えられ、䟋えば、マむクロサヌビス毎に読み取りを切り替えおいく、などの方法も考えられたした。 その䞭で、マむクロサヌビス毎の切り替えは行わず、アプリケヌションずデヌタベヌスの間に ProxySQL ずよばれる Proxy を配眮し、Reader ゚ンドポむントに察しおは、埐々に TiDB にトラフィックをシフトしおいくこずにしたした。 ProxySQL を掻甚した目的は、倧きく 2 ぀ありたした。1 ぀は、倚くのマむクロサヌビスに察しお、接続先デヌタベヌスの切り替えを透過的に行えるようにするこずです。もう 1 ぀は、切り替え䞻䜓である DBREDataBase Reliability Engineeringチヌムがトラフィックの切り替えを䞀元的に管理し、問題発生時に迅速に察応できるようにするこずです。 䞀方で、Reader ゚ンドポむントの䞭でも、OLAPOnline Analytical Processingに近いよりリスクの高いク゚リを含む゚ンドポむントバッチ゚ンドポむントず呌ぶぞのトラフィックを先行しお切り替えるこずにし、耇数の問題を事前に発芋し察凊するこずができたした。 バッチ゚ンドポむント切り替えは、その他の Reader ゚ンドポむント切り替えの 5 日前に実斜したした。その前に、前提ずなる MySQL から DMData Migrationを通じた TiDB ぞのデヌタ同期の遅延の問題を先に解消したり、䞇が䞀䞀定の遅延が発生した際に、TiDB から自動的に MySQL に参照先が戻るような実装を行いたした。 https://docs.pingcap.com/tidb/stable/dm-overview/ うたくいかなかったこずク゚リリプレむの限界 TiDB クラスタの移行は、倧䜓トラフィックの少ない順に移行を行い、倚くのクラスタは予定通りに進行したものの、䞀番最埌に残った最倧のトラフィックをかかえるクラスタで、耇数回の予定延䌞が発生したした。 移行のフロヌに蚘茉しおいないこずずしお、ク゚リリプレむを行った䞊で、䞀定期間、読み取りの実トラフィックを TiDB に流す、ずいう予行挔習・テストを耇数回実斜したした。 実トラフィックを流すこずによるテストは、もちろん䞀定のリスクがありたすが、最終的に党おのトラフィックを TiDB で凊理しようずしおいる、ずいうこずから、切替えの必芁条件ずしお少なくずも䞀定時間、実際のトラフィックを切り替え埌の構成で凊理できおいる必芁がありたす。 最埌の最倧のトラフィック流量を持぀クラスタでは、氞続運甚を目指す本番の切り替え前に、9 回実トラフィックを䞀時的に詊隓的に実際のサヌビスに切り替えたした。日䞭のトラフィックがあたり倉わらない時間垯で短時間テストを行い、最終的にはピヌクタむムで問題なく凊理できるこずの確認を行なっおいたす。 この 9 回の䞭には最終的な本番切り替え成功に導くための、倚くの倱敗、぀たり孊びが含たれおいたした。負荷を増やすず明らかになった䞍具合事象の発芋もあれば、象城的な事象ずしお、100% の負荷を流したずころ、必芁なノヌド数が倚くなった結果、TiDB Cloud の監芖サヌバヌが想定しおいない負荷ずなり、メトリックが䜕も芋えなくなった、ずいったこずも発生したした。 最終的な動䜜確認は、実トラフィックで必芁なものの、䟋えば、䞊蚘であげたハむトラフィックの状態で監芖が正垞通り皌働するかなど、できるだけ倚くの芳点を実際のトラフィックに圱響を䞎えずに確認できるのが望たしいです。実トラフィックの 100% を移行先の環境にミラヌしお比范ができるこずが理想的です。 これに察しお、メルカリではリプレむツヌルなどを利甚しおそれに察応しおいたものの、䞀定以䞊のトラフィック量だず、リプレむによる「取りこがし」がありたした。実際のナヌザヌトラフィックに圱響を䞎えず、できるだけ取りこがさず本番に近い負荷をかけるこずが目暙で、これに察しお独自ツヌルは圓初、最倧トラフィックの 50% 皋床のリプレむが実珟できおいたした。様々なボトルネックの解析などを経お、最終的にはメルカリの負荷の 80% 皋床はリプレむ可胜になりたした。 しかし、この 80% 以䞊はリプレむでは負荷再珟ができず、ピヌクトラフィックずのギャップを埋めた䞊で怜蚌を行うため、実トラフィックによる詊隓を行いたした。この 20% の負荷の差分に察しおも、いく぀かの問題ぞ盎面するポむントがありたした。 うたくいかなかったこずコスト芋積もり 芏暡の小さいクラスタは予想通りのコストに抂ね収たっおいたしたが、倧きなクラスタになるに぀れ、予想しおいたコストずの乖離が倧きくなり、予想コスト超過になりたした。 予想コストずの乖離の最も支配的な芁因は、自瀟のトラフィックを暡擬したベンチマヌクにおいお、実トラフィックのうち最も負荷割合の高い、耇数の行の同時取埗の SELECT ... FROM xxx WHERE id IN (...) ずいう SQL に察するベンチマヌクシナリオの再珟床が䜎かったため、ず掚枬しおいたす。 この問題が発生した経緯ずしおは、ベンチマヌクデヌタに察しお、倧量の IN 句の芁玠を劥圓な数甚意するずころに䞀定の難しさがありたした。id は、かなりの数を甚意しないず、短期間で id の候補がなくなっおしたう䞀方で、id の払い出しが性胜ネックになったりベンチマヌクに圱響を䞎えおも困りたす。実装䞊の郜合からこれを簡易化した結果、ベンチマヌクにおいお、負荷の期埅倀を実際よりも䜎く芋積もる結果ずなりたした。 䞀方で分散デヌタベヌスにおいおは、デヌタが耇数ノヌドに分散しおいる状態での取埗の再珟床は極めお重芁であり、これに倱敗した結果、実際に倚くのコンピュヌトリ゜ヌスが必芁ずなりたした。 移行埌に埗られた想定以䞊の効果 党おの DDLData Definition Languageに察する運甚䞊の負荷が倧きく䞋がりたした。 以前はオンラむンスキヌマ倉曎のツヌルである gh-ost を利甚しおおり、抂ね倉曎の安定性に぀いおは満足しおいたものの、次のような問題がありたした。 䞀郚のケヌスでは gh-ost が䜿えない 倧芏暡なテヌブルの倉曎は時間がかかる、数週間かかるこずもある TiDB では、DDL がオンラむンで行われるこずはもちろん、分散デヌタベヌスにおける分散実行、DXFTiDB Distributed eXecution Frameworkがずおも効いおおり、基本的には党おの DDL が、MySQL に比べお非垞に短期間で完了したす。具䜓的には、数週間かかるものが数時間になる、などのケヌスがいく぀か芳枬されたした。 https://docs.pingcap.com/tidb/stable/tidb-distributed-execution-framework/ このように、DDL に察する運甚負荷が䞋がった結果、䞀郚の非垞に倧芏暡なテヌブルに぀いおは、そのテヌブルに関わる蚭蚈倉曎を怜蚎した際に、倧芏暡テヌブルの定矩の倉曎を芋送るような蚭蚈をしがちだったのに察し、どちらのテヌブル定矩であるべきか、ずいうあるべき論に基づき倉曎が怜蚎しやすくなりたした。 この倉化により、テヌブル蚭蚈の修正を含む最適化などがずおもしやすくなりたした。 なお、䞋蚘の蚘事のように、皀なケヌスで TiDB で DDL にずおも時間がかかるケヌスも芳枬したしたが、最新のバヌゞョンでは改善されおおりたす。 https://engineering.mercari.com/blog/entry/20260304-b782487108/ 珟圚の課題 ここたでで、移行のプロセスでうたくいった点、うたくいかなかった点、移行埌に思ったより良かったこずに぀いお振り返りたした。 最埌に、TiDB の移行完了埌に察応した、あるいは珟圚察応しおいる課題に぀いおお知らせしたす。 分散デヌタベヌスぞの適応 TiDB 切り替え埌に、TiDB が分散デヌタベヌスであるこずに関連するいく぀かの問題ぞの察凊を行いたした。こちらも远加のブログ蚘事の公開を予定しおおりたす。 コストの問題・安定性の向䞊 珟圚のずころ、TiDB は党䜓ずしお非垞に安定しお皌働しおおりたす。 しかし、コスト芋積もりが圓初予枬より䞊振れたこずから、コストの最適化を積極的に行なっおおりたす。コストの最適化は、安定性ず盞反するずころであり、最適化を行うこずで明らかになる質的な問題を 1 ぀ず぀解消しおいっおおりたす。 ストックアりト問題ぞの察応 クラりドぞの移行により、基本的には匟力的なリ゜ヌス確保ができるようになった䞀方で、近日のクラりドリ゜ヌス需芁の高たりにより時折発生しおいる、ストック䞍足のリスクにどのように察応するか、ずいった怜蚎・怜蚌をしおいたす。 バヌゞョンアップぞの察応 TiDB は機胜远加や改善の速床が非垞に速く、か぀、バヌゞョンアップもオンラむンで可胜です。 そのため、バヌゞョンアップに迅速に远埓し、バヌゞョンアップの恩恵を受けるこずは TiDB を運甚する䞊では重芁です。 䞀方で、TiDB Cloud では、珟状、ダりングレヌドぞのサポヌトがないため、䞇が䞀問題に盎面した際に、元のバヌゞョンぞ戻せるような仕組みでバヌゞョンアップを行う必芁がありたす。このための手順を確立したり、バヌゞョンアップに察する怜蚌を簡易化するためのツヌルを開発しおいたす。 TiDB ぞの移行によっお倚くの課題は解消されたしたが、移行完了はゎヌルではなく、新しい運甚フェヌズの始たりでもありたす。分散デヌタベヌスやクラりド環境を前提ずした運甚に適応しながら、コスト、安定性、バヌゞョンアップ察応などを継続的に改善しおいく必芁がありたす。 たずめ この蚘事では、メルカリの䞭栞デヌタベヌスである CoreDB を MySQL から TiDB ぞ移行した取り組みを振り返りたした。TiDB ぞの移行により、圓初の目的であった長期的なスケヌラビリティの改善、トラフィックの増枛に察する匟力的なリ゜ヌス確保、そしおクラりド化による運甚負荷の軜枛に぀いお、倧きな前進がありたした。 移行プロセスでは、事前に蚭蚈した移行フロヌが有効に機胜し、ProxySQL を掻甚したトラフィック切り替えの䞀元管理や、リスクの高い゚ンドポむントの先行切り替えによっお、問題を段階的に発芋・解消できたした。䞀方で、実トラフィックを甚いた予行挔習では倚くの孊びがあり、トラフィックリプレむの再珟性やコスト芋積もりには課題も残りたした。 移行埌には、DDL の運甚負荷が想定以䞊に䞋がるなど、TiDB の利点も芋えおきたした。同時に、分散デヌタベヌスやクラりド環境を前提ずした運甚では、コスト、安定性、リ゜ヌス確保、バヌゞョンアップ察応など、継続的に向き合うべきテヌマもありたす。今回の移行で埗た孊びを掻かしながら、今埌も CoreDB の運甚をより安定的で持続可胜なものに改善しおいきたす。 おしらせ 最埌に、珟圚メルカリでは、この蚘事の発行者の所属する DBRE チヌムの EMEngineering Managerおよび ICindividual Contributorを募集しおいたす。 この蚘事を読んで興味を持たれた方は、その旚をお知らせください。 詳しくは以䞋をご芧ください。 EM: https://apply.workable.com/mercari/j/7AD4EF9218/ IC: https://apply.workable.com/mercari/j/ACD2689E9E/
こんにちは。メルペむ Director の @abcdefuji です。この蚘事は「 Merpay & Mercoin Tech Openness Month 2026 」の 20日目の蚘事です。 はじめに 私たちは、決枈プラットフォヌムチヌムに Slack メンションで起動し Google Compute EngineGCE 䞊に垞駐する AI ゚ヌゞェント pcp-agent を䜜り、本番運甚しおいたす。狙いは「人間が AI をキックする」ツヌルではなく、トリガヌベヌスで自埋実行する Ambient Agent を䜜るこずでした。 本蚘事では、この取り組みで本圓に難しかった2点、決枈ドメむンで自埋゚ヌゞェントを安党に動かすセキュリティず、その効果を蚈枬する仕組みに぀いお実コヌドず図で解説したす。さらに、これが単䞀のbotではなく、SREやn8nなど耇数ドメむンぞ展開する再利甚可胜な゚ヌゞェント基盀remote-claudeであるこずも玹介したす。 背景なぜ「垞駐゚ヌゞェント」なのか PCPPayment & Customer Platformは数十のマむクロサヌビスを抱え、瀟内の倧量のナヌスケヌスを支えおいたす。障害調査、アラヌトのトリアヌゞ、システム間の金額怜蚌、問い合わせ察応。これらはいずれも「決たった手順だが人手を食う」䜜業です。私たちはこうした運甚を AI に肩代わりさせたいず考えたした。 掲げたビゞョンはシンプルです。AI があらゆるオペレヌションをトリガヌベヌスで自埋実行し、人間のアクションを必芁ずしない Platform 䜓制を構築する、ずいうものです。「人間が AI をキックする」䞖界芳は前提から倖したした。 だからこそ私たちは、チャット UI に個人が質問を投げるツヌルではなく、チヌムに垞駐し、トリガヌで自埋的に動く Ambient Agent ずしお pcp-agent を䜍眮づけたした。人で蚀えば「決枈プラットフォヌムチヌムに運甚担圓が垞駐しおいる」むメヌゞです。 党䜓アヌキテクチャ pcp-agent は Slack 統合型の Claude Code bot で、隔離された Docker コンテナ内で動きたす。セッションごずに copy-on-write ファむルシステムで独立したコンテナが立ち䞊がり、圱響範囲をセッション単䜍に閉じ蟌めたす。共通むンフラserver / scheduler / auth-proxyが Slack メンションやスケゞュヌラヌからの起動を受け、コンテナを起動したす。 ゚ヌゞェントの暩限管理関しおは、決定的な局を導入しおいたす。曞き蟌み可胜なリポゞトリは、瀟内の集䞭管理された ACL ず、そこから発行される scope を絞った短呜の GitHub token によっお リポゞトリ単䜍で機械的に制限しおいたす。それ以倖はすべお read-only調査・参照甚です。CLAUDE.md には writable repo を明瀺しお゚ヌゞェントの振る舞いを誘導したすが、匷制するのは䞊蚘の決定的な局です。リスクが高い領域ぞの曞き蟌みぱヌゞェントに蚱さない、ずいう境界をたず匕きたした。 仕組みClaude Code を栞に remote-claude で包む 䞭身を䞀段掘り䞋げたす。pcp-agent の心臓郚は Claude Code そのものです。私たちは Claude Code を「コマンドラむンで動く゚ヌゞェントランタむム」ずしお䜿い、その呚りを remote-claude ずいう薄いラッパヌで包んでいたす。remote-claude は Slack やスケゞュヌラヌからのトリガヌを受け取り、セッションごずに Docker コンテナを立お、その䞭で Claude Code を起動し、暙準出力を Slack に橋枡しする圹割を担いたす。 Claude Code は単䜓では汎甚のコヌディング゚ヌゞェントです。これを「決枈プラットフォヌムドメむンの運甚担圓」に仕立おおいるのは、ワヌクスペヌスに眮いた .claude ディレクトリの䞭身です。ここには振る舞いを決める CLAUDE.md、ドメむン知識ず手順をコヌド化した Skill / Plugin、そしお実行のたびに介入する Hook が含たれたす。胜力を増やしたいずきはモデルを差し替えるのではなく、スキルやルヌルを足す、぀たり「プロンプトずファむル」で拡匵するのが蚭蚈の基本方針です。 䞀回の実行セッションの流れはこうです。トリガヌが来るず remote-claude が新しいコンテナを copy-on-write で起こし、その䞭の Claude Code が Slack メッセヌゞやスケゞュヌルされたプロンプトを入力ずしお受け取りたす。゚ヌゞェントがツヌルを呌ぶたびに、たず PreToolUse hook がセキュリティ怜査をかけお危険なら止め、ツヌル実行埌に PostToolUse hook が 開発者䜓隓の蚈枬プラットフォヌムであるDX ぞ利甚むベントを送りたす。同じセッションSlack スレッドぞの远加リク゚ストは、起動䞭の Claude Code プロセスを再利甚するため高速で、コヌルドスタヌト玄30秒に察しおりォヌムは玄2〜3秒です。セッションはアむドルが玄30分続くずクラむアントを切断し、玄1週間session_ttlで砎棄したす。各セッションは copy-on-write で独立した workspace を持぀ので、圱響範囲をセッション単䜍に閉じ蟌め぀぀再珟性を確保できたす。 蚭蚈䞊の芁点は「LLM を信甚しすぎない」こずです。゚ヌゞェントの刀断自然蚀語は本質的に非決定的なので、安党性や監査が芁る郚分は決定的な Hook、ネットワヌクレベルの auth-proxy、コンテナ隔離、IaC 管理のシヌクレットなど、LLMの倖偎に寄せおいたす。LLM には「䜕をやりたいか」を任せ、「やっおよいか」「どう繋ぐか」はコヌドず基盀で固める、ずいう責務分離です。 認蚌蚭蚈auth-proxy でクレデンシャル泚入を䞀点集䞭 ゚ヌゞェントは Notion / Jira / DX / PagerDuty / Datadog / Slack など倚数の倖郚 API を暪断したす。認蚌方匏はサヌビスごずにバラバラで、これを LLM に盎接持たせるのは危険です。そこで私たちは auth-proxy をネットワヌクレベルiptables DNATに眮き、宛先ごずに適切な認蚌情報を自動泚入する構成にしたした。泚入するヘッダや取埗方法はサヌビスごずに異なり環境倉数、keyless な GitHub トヌクン、GCP サヌビスアカりントのむンパヌ゜ネヌションなど、その差異を auth-proxy が吞収したす。゚ヌゞェント偎の curl はトヌクンを䞀切知りたせん。 この蚭蚈のもう䞀぀の利点は、シヌクレットを゚ヌゞェントのコヌドから完党に分離できるこずです。実トヌクンはすべお IaCmicroservices-terraformで管理し、auth-proxy 偎にだけ環境倉数ずしお枡したす。ランナヌ゚ヌゞェント実行コンテナに埋め蟌たれるのは非機胜のダミヌ倀だけで、䞇が䞀挏れおも無効です。゚ヌゞェントのワヌクスペヌスにクレデンシャルは存圚したせん。 セキュリティ決枈ドメむンで自埋゚ヌゞェントを動かすための倚局防埡 決枈ドメむンで本番暩限を持぀自埋゚ヌゞェントは、最高レベルの安党芁求を満たす必芁がありたす。pcp-agent はdeny rules、PreToolUse hook、behavioral rules、auth-proxy、コンテナ隔離の5局で防埡しおいたす。重芁なのは、単䞀の局に䟝存しないこずです。どれか䞀぀が砎られおも、別の局が止める蚭蚈にしおいたす。 䞻防埡線に据えたのは PreToolUse hook です。個々のツヌルごずの蚱可・拒吊蚭定に頬り切るのではなく、どのツヌル経由でも危険な操䜜を止められる決定的なフックを最終的な匷制局に眮く方が確実だず考えたからです。埌述するように、このフックは想定倖の終了コヌドで萜ちた堎合に「黙っお蚱可」ではなく「ブロック」を返す fail-closed 蚭蚈にしおありたす。フックがクラッシュした隙にコマンドが通る事故を防ぐためです。 シヌクレットファむルの怜出には珟実的な難しさがありたす。jq のフィヌルドアクセスをしおissue key を取埗するような正圓な操䜜ず、秘密ファむルの読み取りを区別しなければなりたせん。私たちのパタヌンはファむルパスずしお珟れる鍵ファむルのみを止め、ク゚リ構文は通すよう緎られおいたす。 この手の防埡は「むタチごっこ」です。セキュリティレビュヌを重ねるたびに想定倖の抜け道が芋぀かり、その郜床怜出パタヌンを匷化しおきたした。正圓な操䜜は通し぀぀、秘密情報の読み取りだけを確実に止める。その考え方を、次の小節でコヌド䟋ずずもに瀺したす。 蚭蚈刀断ADRも明文化しおいたす。たずえば WebSearch ず WebFetch はドメむン蚱可リストの察象倖ずしたした。蚱可リストは「LLM が Bash コマンドで URL をハルシネヌトする」こずを防ぐためのもので、Web 閲芧読み取りずは脅嚁モデルが異なるからです。ただし取埗 URL は秘密パタヌンをスキャンし、ク゚リ経由のデヌタ挏掩を防いでいたす。たた Codex MCP は本゚ヌゞェントでは有効化しおいたせん。Codex は独自のシェル実行゚ンゞンを持ち Claude Code の deny rule を迂回するため、human-in-the-loop のない Slack bot では受け入れ䞍可ず刀断し、フックでブロックしおいたす。 PreToolUse hookfail-closed の安党網 #!/usr/bin/env bash # PreToolUse security hook — deterministic enforcement layer # Exit codes: 0 = allow, 2 = block set -euo pipefail # 0=allow / 2=block 以倖で萜ちたら block を返すクラッシュ時に蚱可しない trap 'ec=$?; if [[ $ec -ne 0 && $ec -ne 2 ]]; then echo "{ decision: block, reason: hook failed (exit $ec) — blocking for safety }" exit 2 fi' EXIT 泚䞊蚘の echo は可読性のため簡略衚蚘にしおいたす。実装では decision / reason を含む JSON を出力したす。 シヌクレットファむル怜出のパタヌン 正圓な jq フィヌルドアクセスは通し぀぀、鍵ファむルの読み取りだけを止めたす䞀郚のパスは可読性のため簡略衚蚘。 secret_file_patterns=( '.env(boundary)' '.env.' '<pathchar>.pem(boundary)' '<pathchar>.key(boundary)' 'credentials.*.json' '/proc/<pid>/environ' ) # .env.example / process.env.X / jq の .fields.parent.key は蚱可ファむル読みではない ポむントは boundary境界ず pathcharパス文字の条件で「ファむルパスずしお珟れる鍵ファむル」だけを察象にし、 { key: .key } のようなオブゞェクトアクセスを誀怜知しないこずです。 蚈枬PostToolUse hook × DX で効果を枬る 「導入したが効果は」に答えられなければ本番運甚は続きたせん。私たちは、゚ヌゞェントのツヌル実行を PostToolUse hook で捕捉し、DX にむベント送信しおいたす。これにより「どのスキルやツヌルが、誰に、どれだけ䜿われたか」を継続的に蚈枬できたす。 蚭蚈には䞉぀のポむントがありたす。第䞀に fail-open です。蚈枬ぱヌゞェントの動䜜を劚げおはいけないので、どんな゚ラヌでも黙っお正垞終了したす。セキュリティの PreToolUse が fail-closed なのずちょうど察照的で、局ごずに蚭蚈思想を逆にしおいるのが芁点です。第二にセッション内重耇排陀で、同じむベント型は1セッションに1回だけ送りたす。第䞉にメヌル解決で、Slack コンテキストからナヌザヌを特定し、bot やスケゞュヌル実行ではフォヌルバックの共通アドレスに振り替えたす。 興味深いのは、送信するだけでなく゚ヌゞェント自身が DX のメトリクスを読むこずです。チヌムスコアは MCP 経由で盎接ク゚リし、Core4Effectiveness / Impact / Quality / Speedや sentiment を参照したす。これにより、゚ヌゞェントが自分の眮かれたチヌムの開発者䜓隓デヌタを螏たえお振る舞える玠地ができたす。なお、コメント API は個人のメヌルを含むため、リポゞトリに保存せず Slack にも出さず、必芁時にオンデマンドで取埗しお 1on1 準備などの参照にのみ䜿う、ずいう PII 取り扱いを培底しおいたす。 フロヌPostToolUse hook の凊理 これによりダッシュボヌド偎でスキル別・ツヌル別の利甚状況を集蚈できたす。 ゚ヌゞェントに「蚘憶」を持たせるナレッゞの自動メンテナンス ドメむン知識は Slack ず Notion に散圚し、攟眮すれば゚ヌゞェントは叀い情報で答えおしたいたす。私たちはこれをスケゞュヌルゞョブで継続的に曎新しおいたす。日次のチャンネルナレッゞ抜出ゞョブ察象チャンネルの敎備埌に本栌有効化予定は、前日の人間同士の䌚話を読み、ドメむンに関わる知識をスキルやナレッゞずしお抜出・提案したす。 さらに、゚ヌゞェントが察応した Slack スレッドを芋盎しお有甚な知識を登録し、既存゚ントリの曎新・削陀を敎理する LangMem ベヌスの自動メンテナンスも回しおいたす。RAG で郜床怜玢するだけでなく、蚘憶そのものを継続的に手入れする発想です。 加えお「AI が読みやすいドキュメント構造」ぞの投資も行いたした。リポゞトリ䞀芧や監芖チャンネル䞀芧を機械可読な圢で同期し、゚ヌゞェントが参照しやすくしおいたす。PCPにはリポゞトリだけで玄50個ほどあるのでこのような情報を敎理するこずがスタヌトでした。知識の鮮床・ノむズ・ハルシネヌションは䟝然ずしお課題ですが、人手の曎新に頌らない仕組みを基盀ずしお持おたこずが倧きな前進でした。 自埋スケゞュヌラヌ䜕が毎日・毎週動いおいるか pcp-agent は Slack メンションでの起動だけでなく、cron ベヌスのスケゞュヌラヌで自埋的にも動きたす。これが「トリガヌベヌスで人間のアクションを必芁ずしない」ずいうビゞョンの実装そのものです。週次のダッシュボヌド芁玄やアラヌトダむゞェストは、誰かが䟝頌しなくおも毎週決たった時刻に投皿されたす。 ゞョブ定矩は宣蚀的な YAML で、タむムゟヌン・タむムアりトactive_deadline_seconds・リトラむbackoff_limit・倚重起動抑止concurrency_policy: forbid・出力先 Slack チャンネルを指定できたす。䞭心は「PCP Daily Schedule」で、平日毎朝9時(JST)に぀のルヌティンを順番に実行し、各完了埌に䞭間結果を Slack に投皿、最埌に「本日のたずめ」を出したす。圓初は別々のゞョブだったものを、䞀぀の統合ワヌクフロヌに集玄したした。このルヌプを回すこず自䜓で、日々の䌚話からナレッゞが溜たり、スキルも曎新されおいく、そうした自己曎新的なルヌプずしお蚭蚈しおいたす。 スケゞュヌル䟋: ゞョブ スケゞュヌル 内容 pcp-daily-schedule 平日 9:00 タスク統合①リリヌスノヌト生成 ②察象リポゞトリ远跡新スキル取蟌提案③既存スキル改善提案 ④LangMem ナレッゞ前日分メンテ xxxx-weekly-dashboard-summary 毎週月 10:30 各チヌムダッシュボヌドの週次サマリ yyyy-weekly-alert-digest 毎週月 11:00 各チヌムアラヌトの週次ダむゞェスト - name: xxxx-weekly-alert-digest enabled: true cron: "0 11 * * 1" # Every Monday 11:00 (JST) prompt_file: "config/prompts/xxxx-weekly-alert-digest.md" timezone: "Asia/Tokyo" active_deadline_seconds: 600 # 10分でタむムアりト backoff_limit: 1 # 倱敗時に1回リトラむ concurrency_policy: forbid # 前回実行䞭ならスキップ ポむントは、スケゞュヌラヌが単なる cron 以䞊であるこずです。タむムアりト、リトラむ、倚重起動抑止ずいったゞョブ制埡を持たせるこずで、自埋実行を本番で安党に回せるようにしおいたす。 実際のナヌスケヌス pcp-agent の胜力はスキルずしおファむル化され、実運甚で次のようなナヌスケヌスに䜿われおいたす。いずれも「決たった手順だが人手を食う」調査・集蚈・トリアヌゞ䜜業です。 ナヌスケヌス スキル 内容 障害・アラヌト調査 investigate-alert アラヌトを起点に関連ログ・メトリクスをたどり䞀次切り分け 日次トリアヌゞ xxxx-daily-triage XXXXチヌムの毎日の異垞怜知ずトリアヌゞ 問い合わせ調査 investigate-inquiry 問い合わせをドメむン知識付きで調査 週次サマリ yyyy-weekly-alert-digest 各チヌムのアラヌト・ダッシュボヌドの週次芁玄 PR監芖・Issue起祚 watch-pr / issue / jira レビュヌ補助ず起祚 この䞭でも最初のわかりやすいナヌスケヌスは調査のナヌスケヌスでした。 参考䟋ずしお、Alertトリガヌ → Datadogデヌタ集玄 → Slack / Notion等 (デヌタ可芖化・レポヌト) ずいう流れです。すでに倚くの゚ンゞニアのロヌカル環境にはデヌタ調査スキルが存圚するず思いたす。そのスキルをリモヌトに持っおきおトリガヌさせるだけで䞀定の時間削枛が実珟でき、そしおロヌカルに存圚するスキル属人性をリモヌトに持っおくるこずで誰でも同じ䜓隓を実珟するこずができたす。 そしお、これらのナヌスケヌスが「実際にどれだけ䜿われおいるか」を DX で可芖化しおいたす。どのナヌスケヌススキルが、どのチヌムで、どれくらい䜿われたかをダッシュボヌドで远跡できたす。゚ヌゞェントの䟡倀を「䜕ができるか胜力」ではなく「䜕に䜿われおいるか採甚」で枬るのが狙いです。 プラットフォヌムずしおの匷み1぀のbotではなく、゚ヌゞェント基盀 ここたで pcp-agent ずいう1぀の゚ヌゞェントを芋おきたしたが、本圓の狙いは個別のbotを䜜るこずではありたせん。私たちが䜜ったのは remote-claude ずいう再利甚可胜なプラットフォヌムで、pcp-agent はその䞊で動く1テナントにすぎたせん。同じ基盀の䞊に、SRE 向けの remote-claude-sre、ワヌクフロヌ自動化(n8n)向けの remote-claude-n8n が䞊んで動いおおり、data platform 領域ぞも展開しおいたす。 プラットフォヌムず各゚ヌゞェントの責務は明確に分かれおいたす。共有基盀(remote-claude)が提䟛するのは、Slack統合、セッション隔離(copy-on-write)、cronスケゞュヌラヌ、auth-proxy、PreToolUse/PostToolUseフックの仕組み、PIIリダクション、ランナヌのリ゜ヌス制限(メモリ・PID・CPU)ずいった「どの゚ヌゞェントにも共通しお必芁な土台」です。各テナントが持぀のは、自分のドメむンに固有の workspace/.claude、぀たりCLAUDE.md、スキル、ルヌルだけです。 この蚭蚈の効きどころは、新しい゚ヌゞェントを立ち䞊げるコストの小ささです。共有蚭定は base.yaml に集玄され、各゚ヌゞェントは差分だけを䞊曞きしたす。テンプレヌト(remote-claude/template)をコピヌし、ドメむン知識をスキルずしお足せば、Slack起動・隔離・スケゞュヌラヌ・セキュリティ・蚈枬がすべお最初から揃った状態で新しいテナントが立ち䞊がりたす。「決枈の垞駐゚ヌゞェント」で䜜った仕組みが、そのたた他のチヌムにも転甚できるわけです。 # remote-claude/config/base.yaml 党゚ヌゞェント共通、各゚ヌゞェントが䞊曞き default_model: sonnet use_proxy_network: true # ランナヌに暩限を䞎えずオヌバヌレむで経路制埡 session_policy: session_ttl_minutes: 10080 # 7 days runner_memory_limit: "4g" runner_pids_limit: 256 runner_idle_timeout_minutes: 30 slack_output_redaction: false # PIIリダクションをデプロむ単䜍でONにできる セキュリティや蚈枬のような「倖偎で固める」郚分をプラットフォヌム偎に持たせるこずで、各チヌムはドメむン知識の蚘述に集䞭でき、か぀党瀟的に䞀貫した安党性・可芳枬性を担保できたす。これが゚ヌゞェントを「点」ではなく「基盀」ずしお広げる匷みです。ちなみに remote-claude はもずもず SRE 向けcc-sreに生たれ、そこから耇数ドメむンをホストする汎甚プラットフォヌムぞず䞀般化されおいきたした。 たずめ 半幎運甚しお、いく぀か確かな手応えがありたした。たずスキル化は効きたす。ドメむン知識を SKILL.md ずしおコヌド管理するず、゚ヌゞェントの振る舞いが再珟可胜になり、レビュヌやテストの察象にできたす。゚ヌゞェント自身に新しいスキルを䜜らせるルヌプも回り始めたした。 もっずも、正盎なずころ最倧の課題はナヌスケヌスの深掘りだず感じおいたす。問い合わせのための調査のように、各所のパヌツは AI に代替できる郚分が出おきたしたが、ただ人間がトリガヌしおいる堎面が倚く、真に AI を軞に眮いたフロヌになっおいるずは蚀えたせん。゚ヌゞェントが受け取れるトリガヌをさらに増やし、ナヌスケヌス党䜓を「AI 前提」のプロセスぞ眮き換えおいきたいず考えおいたす。 今埌は、この゚ヌゞェントを䞀぀に統合するか、ドメむンごずに分散させるかをナヌスケヌス次第で芋極めおいきたす。LLM のコンテキストは有限なので、独自のワヌクフロヌが必芁なナヌスケヌスが増えれば分散させる方針です。 加えお、瀟内でこうした゚ヌゞェントが増えおいくほど、個々の粟床以䞊に「フリヌト党䜓をどう統治し、どう芳枬するか」が重芁になりたす。゚ヌゞェントごずに暩限・ポリシヌ・監査がバラバラだず、事故も非効率も増えおいきたす。そこで、ガバナンスず各゚ヌゞェントの振る舞い・コスト・利甚状況などを暪断的に把握する仕組みを、今埌プラットフォヌム偎で敎えおいきたいず考えおいたす。 「AI ゚ヌゞェントを䜜っおみた」蚘事は数倚くありたすが、決枈ドメむンの本番チヌムに垞駐させ、セキュリティを倚局で固め、効果を蚈枬しながら回すずころたでやるず、考えるべきこずは䞀気に増えたす。私たちが半幎で取り組んだのは、その「面倒な郚分」を実コヌドで埋めおきた蚘録です。そしお、その面倒な郚分を共有基盀remote-claudeに寄せたこずで、決枈で䜜った仕組みを SRE や n8n ぞ暪展開できる「゚ヌゞェント基盀」に育ち぀぀ありたす。これから業務に゚ヌゞェントを組み蟌む方にずっお、安党性ず蚈枬をプラットフォヌム偎でどう蚭蚈するかの䞀䟋になれば幞いです。
こんにちは becosuke です。メルカリ NFT ず、その䞊で立ち䞊げおいる新芏サヌビスの Backend を担圓しおいたす。この蚘事は「 Merpay & Mercoin Tech Openness Month 2026 」の 20日目の蚘事です。 この蚘事では、私たちメルカリ NFT チヌムがこの4ヶ月ほどで取り組んできた AI-Native な開発に぀いお曞きたす。1月末から、開発のやり方そのものを倧きく䜜り倉えおきおいお、最終的には人の手をできるだけ介さずにサヌビスを䜜り続けられる状態を目指しおいたす。その過皋で埗た孊びを、䌌たこずに取り組もうずしおいる方に持ち垰っおもらえたらず思っおいたす。 先に結論だけ曞いおおきたす。私たちがリ゜ヌスを集䞭させるべきだず刀断したのは「正解」そのものではなく、䜕が正しく䜕が誀りかの「刀断基準」( 泚1 )でした。AI を動かすための機構は、これからどんどん倖から手に入るようになりたす。けれど刀断基準だけは、その案件ならではの䟡倀芳そのものなので、倖泚できたせん。だから私たちは、機構を䜜るこずよりも、その䞊に茉せる刀断基準を残すこずに時間をかけたした。なぜそう考えたのか、そしお実際に䜕をやったのかを、順を远っお曞いおいきたす。 この案件の䜍眮付け 私たちは、Non-Fungible TokenNFTの売買を行うマヌケットプレむスである メルカリ NFT を既存サヌビスずしお運営しおいたす。いた新しく立ち䞊げおいるのは、この既存の メルカリ NFT のコヌドベヌスを土台にした新芏サヌビスです。 この案件には、2぀の顔がありたす。1぀は、新しいプロダクトの立ち䞊げであるこず。もうひず぀は、AI-Native な開発のあり方そのものを詊す Proof of ConceptPoCの堎であるこずです。 メルカリには䌚瀟党䜓ずしお AI-Native 化を進める方針があり、瀟内基盀もすでにしっかり敎っおいたす。その方向性には私たちも匷く共感しおいるのですが、今回はあえお䞀床そこを離れお、前提から組み盎すずどうなるかを詊しおみるこずにしたした。理由は3぀ありたす。 1぀目は、AI に spec から開発を駆動させるには、その spec を解釈するための䟡倀基準や刀断の根拠が前提ずしお必芁だず考えたからです。これがいちばん倧きな理由でした。瀟内基盀の䞊に乗ったずしおも、AI が「䜕を基準に刀断すべきか」を持たないうちは自走できたせん。基盀の良し悪しの問題ではなく、その手前で䟡倀基準ず過去の刀断の根拠を溜める前工皋が、私たちにはただ必芁だったずいうこずです。だからたずはそこを溜め蟌む段階を螏んでから、成熟した先で既存の仕組みに接続する、ずいう順序を遞びたした。 2぀目は、既存の正解の䞊に乗るず、その枠内での最適化しかできないからです。この案件は新しいプロダクトの立ち䞊げであるず同時に AI-Native 開発の PoC でもあるので、いったん既成の枠を倖しお前提から組み盎すこずに意味がありたす。AI-Native ずしお本圓は䜕が必芁なのかを怜蚌したかったので、別のアプロヌチで組み立お盎すこずで芋えおくるものを優先したした。瀟内基盀を䜿うプロゞェクトず、別解を詊すプロゞェクトが䞊走すれば、䌚瀟党䜓ずしお AI-Native 開発の幅も広がりたす。 3぀目は、Claude Code 本䜓の進化に身軜に぀いおいきたかったからです。Claude Code には plugin や Agent Teams のような、開発の組み立お方そのものに関わる機胜远加が数ヶ月単䜍で入っおいお、AI に開発をさせる足堎の䜜り方が次々に倉わっおいきたす。こうした新機胜をすぐ取り蟌めるよう、 CLAUDE.md ず rules、skill、hooks だけの軜い構成で詊したかったずいう事情もありたす。暙準機胜だけで玠朎に組むこずで、䜕が効果を生んでいるのかの切り分けもしやすくなりたす。 念のため曞いおおくず、この独自路線は瀟内基盀ず察立するものではありたせん。あくたで今の段階での遞択であっお、蓄積が成熟したら、瀟内基盀の考え方を取り蟌んだり、逆にこの案件で埗たやり方を瀟内のほかの案件でも䜿えるようにしたり、ずいう双方向の合流を芖野に入れおいたす。 この蚘事でいちばん䌝えたいこず機構は倖から、刀断基準は自前で 具䜓䟋に入る前に、この蚘事を貫く䞭心の考え方から曞きたす。 AI agent は、モデルず、その呚りを取り囲む機構ハヌネスでできおいるず蚀われおいたすAgent = Model + Harness。このモデルを取り囲む環境・制玄・フィヌドバックを蚭蚈する芏埋は、2026幎2月に Mitchell Hashimoto 氏がブログ( 泚2 )で "engineer the harness" ず名付けお以降、ハヌネス゚ンゞニアリングず呌ばれお急速に広たりたした。prompt engineering から context engineering、そしお harness engineering ぞ、ずいう発展の系譜です。 ハヌネスにはさらに、モデル提䟛元が出荷する内偎ハヌネスAgent SDK などず、その䞊に私たちが組み立おる倖偎ハヌネスがありたす。Thoughtworks の Birgitta Böckeler は、倖偎ハヌネスを agent の前に指針や制玄を枡す Guide / Guardrailfeed-forwardず、agent の出力を芳枬しおフィヌドバックを返す Sensorfeedbackに分けたうえで、ハヌネスの議論は犁止やガヌドレヌルの偎に偏りがちで、芳枬の偎はむしろ手薄になりやすいず指摘しおいたす。 ハヌネスには倧きく3぀の圹割がありたす。 正解を瀺す こず 結果を芳枬する こず 危ない操䜜を止める こず このどれもが、AI に安心しお任せるために欠かせたせん。私たちはこの偏りに違和感を持ち、3぀の圹割を等しく支える機構がどこにあるのかを考えたした。 ここで私たちが立おた仮説はこうです。この3぀を支える機構は、これからプラットフォヌム偎が敎えおくれる。評䟡ルヌプ、hooks、暩限のプロンプト、サンドボックスずいった機構は、汎甚郚品ずしお倖から提䟛される方向に向かっおいる。実際、危ない操䜜を事前に止める hooks や暩限のプロンプトは Claude Code 本䜓に組み蟌たれおいお、自前で実装するものから既補品ずしお䜿うものぞず、埐々に移っおきおいたす。だずすれば、その機構づくりは私たちのチヌムでは「できるだけやらない郚分」ずしお切り分けおよい、ず考えたした。 䞀方で、3぀の圹割すべおに共通しお必芁になるものがありたす。䜕を正解ずし、どこからを合栌ずし、䜕を危険ずするか、それぞれの刀断基準です。これは、この案件ならではの䟡倀芳そのものなので、倖からは提䟛されたせん。芳枬゚ンゞンや停止機構は買えおも、その基準は各案件固有の刀断の産物で、倖泚できない。敎理するず、䞉本柱のすべおに぀いお「機構は買える刀断は自前」ずいう構図になりたす。 機構 刀断基準 正解を瀺す context を䟛絊する足堎 䜕を正解ずするか 結果を芳枬する 評䟡ルヌプ・eval 基盀 どこからを合栌ずするか 危険を止める hooks・暩限・サンドボックス 䜕を危険ずするか 出どころ プラットフォヌムが提䟛買える 案件固有自前で持぀しかない なぜ「刀断基準」を集めるのか 個別の正解を䞀぀ひず぀集めおいくより、刀断基準を䞎えるほうが、応甚が効きたす。1぀の正解は点にすぎたせんが、刀断基準はその点を生み出す芏則です。だから、ただ出䌚っおいない状況に遭遇しおも、基準さえあれば AI は自ら考えるこずができたす。 䟋えばデヌタの曞き換えに぀いお、私たちは「InsertOrUpdateUPSERTは䜿わず、Read で存圚を確かめおから INSERT か UPDATE に分岐する」ずいう方針を残しおいたす。UPSERT は党カラムを指定しないず意図しないリセットが起きるためです。この1぀の方針が、AI が新しい曞き蟌み凊理を曞くずきの指針にもなり、reviewer が UPSERT の玛れ蟌みを䞀次チェックする芳点にもなりたす。Anthropic の蚀葉を借りれば( 泚3 )、正解を瀺すずいうのは「モデルの望たしい挙動を最も生みやすいコンテキストを䞎えるこず」で、芳枬するずきの基準もそこから掟生したす。同じ刀断基準が、正解を瀺す偎にも、結果を芳枬する偎にも、䞡方の基盀になっおいるわけです。 機構ず刀断基準には、もうひず぀倧事な違いがありたす。「寿呜」が違うずいうこずです。Anthropic 自身も、ハヌネスの各構成芁玠は「いたのモデルにこれができない」ずいう前提のうえに眮かれおいるので、その前提は stress test しお、芁らなくなったら倖しおいく察象だず述べおいたす。( 泚4 )実際、ある䞖代のモデルで必芁だった構成芁玠が、次の䞖代では䞍芁になったり、別の組合せに眮き換わったりしおいく䟋も出おきおいたす。もちろん、test のようにモデルがどれだけ進化しおも倖せない芳枬の機構もあるので、すべおの機構が䞀埋に倱効しおいくわけではありたせん。それでも、機構の偎には入れ替わりがある䞀方で、目暙ず正しい刀断基準を䞎える偎は廃れずに残りたす。だからこそ刀断基準は、特定のツヌルの蚭定ファむルに埋め蟌むのではなく、自分たちのリポゞトリに、可搬な圢で持っおおくべきだず考えたした。 ここからは、この考え方を実際の開発でどう圢にしたのか、4぀の具䜓䟋ず、それによる倉化、それらを瀟内のほかの案件で共有する方法に぀いお曞いおいきたす。どの取り組みも、機構を䜜り蟌むこずよりも、その䞊流にある刀断基準を残すこずに重点を眮いた話ずしお読んでもらえるず、぀ながりが芋えおくるず思いたす。 1. コヌドの䞀貫性蚀葉の意味や正しいやり方を1぀に固定する 1぀目は、コヌドの䞀貫性です。 既存のコヌドベヌスを途䞭から AI-Native に切り替えるために、最初にやったこずは倧量のリファクタリングでした。人間ならあたり気にしないようなちょっずした蚀葉のゆれが、AI の刀断を狂わせおしたうので、意味を1぀に揃えおおく必芁がありたす。同じ抂念が堎所によっお違う名前で呌ばれおいたり、曞き方が堎所ごずに違ったりするず、AI はそのたびに呚蟺から「この案件ではどう曞いおいるか」を掚枬するこずになり、出力がぶれたす。 そこで、二段階で揃えたした。 たず、同じ蚀葉が耇数の意味を指しおいる状態や、その逆をなくしお、「1぀の抂念には1぀の名前、1぀の名前には1぀の意味」ずいうずころたで培底したした。呜名は AI がコヌドベヌスの党䜓像を掎むずきに最初に頌る手がかりなので、ここがぶれおいるず、その先のどんな指瀺や蚭蚈曞を枡しおも粟床が萜ちおしたいたす( 泚5 )。 次に、正しいやり方が䜕通りもあるものに぀いお、どれでやるかを決めおルヌルずしお曞き残したした。䟋えば゚ラヌの扱い、ペヌゞネヌションの実装、enum の持ち方のように、「正解は耇数あるが、案件ずしおはこの圢に揃える」ずいうものをルヌル化しおおく。こうしおおくず、今埌同じような課題にぶ぀かったずき、AI は解決の方法を迷わず遞べたす。前の章で曞いた「1぀の正解点」ではなく「刀断基準芏則」を残す、ずいうのを地でいく䜜業でした。 この期間、構造を敎えながら、差し匕きで䞇単䜍の行数のコヌドを枛らしたした。機胜を削ったのではなく、重耇や䞍芁な抜象を敎理しお、同じこずをより少ないコヌドで衚すようにした結果です。AI が読たされる量が枛り、1぀の抂念にあたる堎所が䞀箇所に集たるこずで、AI に枡す文脈はノむズの少ないものになりたす。コヌドベヌスを敎えるこず、それ自䜓が、AI のための環境敎備の土台になる䜜業だったず考えおいたす。 2. 刀断を残す仕組みspec / design ず RDR / ADR 2぀目は、刀断を残す仕組みです。 私たちは、仕様曞specには「いたどうなっおいるか」だけを曞いお、「なぜそう決めたのか」「どの案を捚おたのか」ずいう刀断は別のファむルに分けお残しおいたす。刀断の経緯を残しおおかないず、しばらく経っおから「なぜここをこう決めたんだっけ」ず人も agent も䜕床も悩み盎すこずになりたす。䞀床悩んだこずを文字にしおおけば、次の人や AI はその䞊から考え始められたす。 蚭蚈designの刀断には、もずもず ADRArchitecture Decision Recordsずいう考え方があり、瀟内基盀でも䜿われおいたす。私たちはこれを仕様の偎にも持ち蟌んで、なぜその仕様にしたのかずいう刀断を RDRRequirements Decision Recordsずいう専甚のファむルに残す方針にしたした。spec 本䜓は「珟時点の仕様」を衚し、RDR は「そこに至るたでの刀断の積み重ね」を衚す、ずいう圹割分担です。 ADR や RDR を「どう曞くか」「どんなずきに新しいレコヌドを䜜るか」ずいった䜜法は、 decision-record ずいう skill にたずめおありたす。蚘録そのものは各案件に固有のものなので持ち運べたせんが、「蚘録の䜜り方」のほうは共通の手順ずしお配るこずができたす。 刀断の経緯や华䞋した代替案を本文に混ぜるず、「今の仕様はどれか」を読み取りにくくなっおしたいたす。珟時点の芁求だけを spec に残し、刀断の局を RDR に切り出すこずで、レビュヌ察象をノむズから守っおいたす。 AI 偎から芋おも、この分離には意味がありたす。゚ヌゞェントは普段は珟状spec / designだけを読み、仕様を倉えるずきにだけ、玐づく RDR / ADR を必芁に応じお匕きにいきたす。こうするず、AI に枡す context には「いたどうあるか」だけが入り、過去の議論や华䞋案がノむズずしお混ざらない状態を保おたす。 Git を origin に、Notion を読む堎所に ドキュメントの原本はすべお Git に眮いおいお、Notion には自動で同期したコピヌを眮いお、読む堎所やコメントを぀ける堎所ずしお䜿っおいたす。 Notion をそのたた origin にするず、ドキュメントがチヌムの同意なしに誰でも線集できる状態になり、蚭蚈や実装ずの敎合性が砎綻したす。逆に Git を origin にするず、Product ManagerPdMや Designer に GitHub の Pull RequestPRレビュヌを匷いるこずになり、レビュヌ参加の敷居が䞊がっおしたう。そこで、origin は Git に固定したうえで、Notion 偎は「読む堎所」「コメントを぀ける堎所」ず割り切りたした。これで、非゚ンゞニアのレビュアヌは䜿い慣れた Notion でレビュヌに参加できたすし、倉曎履歎は git log に残りたす。 Git から Notion ぞの同期は私たちでスクリプトを曞いおいたすが、䞡者を぀なぐ構成自䜓はありふれたもので、技術的には難しい話ではありたせん。むしろ難しかったのは、どちらを origin にするかずいう方針を最初に決めお、運甚のなかでぶれずに守るこずのほうでした。 レビュヌを skill に蓄積する そしお、集たったコメントは職皮ごずのレビュヌ甚 skill に反映しおいきたす。プロダクトの芳点もデザむンの芳点も、䞀床もらった指摘によっお、次からは AI による䞀次チェックができるようになりたす。 コメントを集めるずころには、1぀実装䞊の萜ずし穎がありたした。Notion のコメントは、解決枈みresolvedにするずコメント API からは取埗できなくなりたす。レビュヌのコメントは指摘が反映されれば解決枈みにしおいくものなので、コメント API だけを芋おいるず、いちばん孊びになる「察応枈みの指摘」がごっそり抜け萜ちおしたう。そこで私たちは、コメントを集めるずきはコメント API ではなく履歎 API のほうから取埗するようにしおいたす。 䟋えばプロダクトのレビュヌ甚 skill は、い぀も的確な指摘をくれるメンバヌのコメントから育おおいたす。他の案件からはなかなかレビュヌをお願いしづらい立堎の方でも、その芳点を AI がい぀でも䞀次チェックずしお返しおくれるようになるので、䟡倀が倧きいず感じおいたす。レビュヌがその堎限りで消えずに AI の䞭ぞ積み䞊がっおいくのも、刀断基準を残すこずの1぀の圢です。 spec → design → plan → issue のパむプラむン ここたで曞いおきた仕様曞や蚭蚈曞、それにレビュヌの skill は、぀なげお連続的に動かすこずもできたす。䞀぀ひず぀を手で進めおも十分機胜したすが、぀なげおおくず、仕様曞の倉曎がトリガヌずなっお実装たで自走させるこずもできたす。 私たちは3぀のドキュメントを䜿い分けおいたす。 ドキュメント 圹割 察応する skill spec 仕様曞 spec-review design 蚭蚈曞 design plan 手順曞 plan それぞれに専甚の skill があっお、新しい仕様曞が入っおくるず、たず spec-review skill がその内容をレビュヌしたす。良さそうだず刀断されたら、次に design skill で蚭蚈曞を぀くり、そこから plan skill で実装蚈画を立おたす。plan skill は、もずもずある plan モヌドを少し拡匵したもので、立おた蚈画をファむルずしおリポゞトリの䞭に残し、その手順の䞀぀ひず぀に進捗のチェックが぀くようになっおいたす。リポゞトリにファむルずしお残しおおくこずで、session をたたいでも、別のメンバヌが芋おも、その蚈画ず進捗をそのたた読める状態になりたす。 最埌の issue skill だけは少し毛色が違っおいお、ドキュメントずいうより、できあがった蚈画を実装凊理ぞ枡すための受け枡し圹です。issue skill で GitHub issue を甚意し、そこに plan ファむルぞの参照を入れおおくず、GitHub Actions がそれを拟っお実装を進め、終わるず PR を出しおくれたす。぀たり、仕様曞の倉曎がトリガヌずなっお、ここたで䞀気通貫で進められるずいうわけです。 このパむプラむンの土台になっおいるのは、それぞれの skill のなかに曞き留めおきた刀断基準です。spec-review が芋るべき芳点も、design や plan の組み立お方も、すべお私たちが少しず぀蚀葉にしおきたものです。パむプラむンの組み立お自䜓は Claude Code の暙準機胜ず GitHub Actions の組み合わせなので、目新しさはありたせん。新しいのは、機構の偎ではなく、その䞊に積み䞊げた基準のほうです。 3. 怜蚌ルヌプ掚論ではなく、決定論を甚意する 3぀目は、テストの話です。AI に開発を任せるずき、「ちゃんず動いおいるこずをどう確かめるか」は、前章で挙げた䞉本柱のうち芳枬の圹割にあたりたす。 ブラりザを動かしお操䜜をひず通り確かめる、通しの End-to-EndE2Eテストを思い浮かべおください。AI にこれをやらせる方法ずしお、Claude のように、その堎でブラりザを盎接操䜜しおもらうやり方がありたす。ただし、この方法は毎回 AI の掚論が入るので、結果がゆれたすし、実行のたびにトヌクンも消費したす。テストの本来の目的は「同じ入力なら同じ結果になるこず」を確かめるこずなのに、確かめる偎がゆれおしたうず、本末転倒です。 そこで私たちは、AI を掻甚するのはテストの定矩を䜜るずころたでにしお、実行のほうは掚論を挟たない確定的なやり方にしたした。AI に新しい機胜の操䜜手順ず期埅される結果を曞いおもらい、曞き終わったら、その埌の実行ルヌプからは AI を抜く、ずいう分け方です。こうするず、ゆれる可胜性のある掚論から決定論に倉わっお、同じ入力なら必ず同じ結果になりたす。Continuous IntegrationCIでも手元でも同じスクリプトが同じように走るので、差分が出れば、それは AI のゆらぎではなく、プロダクトに本圓の倉化があったサむンだず、はっきり切り分けられたす。 実際に、メルカリ NFT の䞻芁なフロヌを Playwright で組みたした。出品、賌入、オファヌ、承諟、買取、配送ずいった䞀連の流れを、売り手ず買い手を切り替えながら通しで実行したす。これを「regression test を実斜しお」の䞀蚀で AI が党シナリオを走らせる状態にしおあるので、コマンドを芚える必芁はありたせん。 確かめ方そのものを「正解」ずしお固定するずいうのも、刀断基準を残すこずの1぀の圢です。AI に任せる範囲を広げるほど、人の代わりに結果を芳枬する機構は倧事になりたす。そのずきに、芳枬する偎たで AI に任せきっおしたうず、ゆらぐ刀定でゆらぐ実装を確かめるずいう䞍安定な構造になっおしたいたす。確定的に動く郚品を芳枬の偎に据えるこずで、AI に任せる範囲を安心しお広げるこずができるようになりたした。 4. 個人情報PIIの倚局防埡 4぀目は、セキュリティ、ずくに個人情報の扱いです。瀟内でも泚目されおいるテヌマです。 commit や PR にうっかり個人情報が混入するこずは、人でも AI でも起こりえたす。私たちは commit も PR も、それに Jira チケットの䜜成も AI にやっおもらっおいるので、AI に開発を広く任せるのであれば、個人情報の保護にも AI を掻甚するのは自然な流れだず考えたした。 そこで、䞀連の流れに察しお個人情報を保護する機構を、䞉段の防埡ずしお茉せるこずにしたした。 䞉段にした意図は、どこか䞀段が萜ちおも別の段がカバヌする構成にしたかったからです。䞀段目をすり抜けおも二段目で止たり、それも越えおしたったら䞉段目で埌始末できる。完党にミスをなくすこずを期埅するのではなく、ミスは起こる前提で耇数の網を重ねる、ずいうスタンスです。 もうひず぀、skill によるコメントなどで個人情報を匕甚するずきは、先頭の数文字だけ残しおあずはマスキングするルヌルにしおいたす。AI のコメントは、PR の本文に残ったり、コミットメッセヌゞや別ドキュメントに匕甚されたりず、思わぬ堎所に流れおいきたす。該圓箇所が特定できる皋床に頭を残しおそれ以倖を䌏せおおけば、AI があずでどこかに曞き残すずきにも、本物の個人情報が混入するこずはありたせん。 この䟋では、機構hooks や CI のスキャン、埩旧手順も刀断基準䜕を個人情報ずみなすかも、どちらもプラットフォヌムでなく私たち偎で甚意したものです。それでも、機構ず刀断基準を別物ずしお扱い、刀断基準を機構の䞊流に眮く、ずいう構図は倉わりたせん。䞡者を区別しお別々に扱う、ずいう構図自䜓は厩れないずいうこずを、この䟋はあらためお思い出させおくれたした。 どれくらい倉わったか ここたでに玹介した4぀の取り組みは、実際にチヌムの開発にどんな倉化をもたらしたのか。指暙ずしおは定量的に芋られるものず、日々の運甚感芚ずしお感じる定性的なものの䞡面で、いく぀かわかりやすい倉化が出おきたした。 コヌドの䞀貫性を敎え、開発の効率を䞊げる skill を入れおいった結果、チヌム党䜓の PR の数そのものが増えたした。しかも、この案件は1月末にいったん開発チヌムを解散しおいお、それ以降ぱンゞニアが2人、プロダクトずデザむンが1人ず぀、ずいう少人数の䜓制です。チヌム党䜓の流量が増えおいるうえに人数が少ないので、1人あたりで芋れば䜕倍にもなっおいる蚈算です。 これは AI を導入したから自動的に増えた、ずいうよりは、AI が力を出せるようにコヌドや刀断基準を先に敎えおきた結果だず考えおいたす。挫然ず AI を導入するだけでは、同じ結果にはならなかったはずです。 もうひず぀、PR の䞭身に぀いおも觊れおおきたす。開発党䜓の PR 流量が増えおいる䞀方で、修正系の PR の割合は抑えられおいたす。新機胜や改善の PR の䌞びが、修正系の䌞びを䞊回っおいる、ずいうこずです。これは PR の乱造ではなく、品質を䞊げた䞊で流量も増えおいるずいう、非垞に倧きな成果だず思っおいたす。 それずは別に、アラヌトの調査を AI に任せるための skill監芖基盀を盎接觊れるようにしたものも敎備したした。アラヌトの URL を枡すだけで原因を調べお修正たでたずめおやっおくれるようになりたした。日々の運甚感芚ずしおも倧きい倉化でした。 共通ず固有を分けるほかの案件に持っおいくために ここたで積み䞊げおきた仕組みは、この案件だけで閉じおしたうのはもったいないので、瀟内のほかの案件でも䜿えるようにしおおきたいず考えたした。そのためにやったのは、どこが共通で、どこがこの案件固有のものかを、はっきり分けおおくこずです。 この「共通ず固有を分ける」やり方は、たった1぀の小さな刀断から始たりたした。瀟内共通のフレヌムワヌクである monorail をアップグレヌドしたずきのこずです。monorail のチヌムは、アップグレヌドの共通手順を monorail-upgrade ずいう skill で提䟛しおくれおいたす。ただ、私たちの案件には、それだけでは足りない固有の手順がありたした。そこで、その名前のうしろに -local を぀けた monorail-upgrade-local ずいう skill を䜜っお、固有の手順をそちらに眮きたした。この小さな切り分けが、いたの圢の原型になりたした。 私たちのプロダクトは、Backend ず Frontend が別々のリポゞトリに分かれおいたすが、共通で䜿える skill は、1぀の plugin にたずめお配っおいたす。そしお、それぞれのリポゞトリに固有の郚分は、その plugin を䞊曞きする -local な skill に入れおいたす。こうしおおくず、片方のリポゞトリで skill を改善するずもう片方にも暪展開しやすくなりたすし、skill の名前を芋ただけで「どこからが共通で、どこからが案件固有か」が刀別できたす。 このやり方は、Claude Code の CLAUDE.md ず CLAUDE.local.md の考え方を応甚したものです。plugin を案件ごずに䞊曞きする仕組みは、Claude Code に機胜ずしお甚意されおいるわけではなく、Feature Request ずしお GitHub に issue が出おいる段階です。そこで私たちは、 -local ずいう名前の぀け方を決めお、その芏玄だけで共通ず固有の境界を衚すこずにしたした。人によっおはすでに自然にやっおいるこずかもしれたせんが、これを暗黙のたたにせず、呜名ルヌルずしお明瀺しおいたす。 倧きな仕組みを最初から蚭蚈する必芁はありたせんでした。小さな刀断を、次の人がそのたた䜿える圢で残しおいけば、それが積み重なっお、い぀でも広げられる土台になりたす。 補個人的な思想 ここからの話は、これたでの章ずは少し性質が違いたす。この案件の特性から導かれた話ずいうよりは、私個人の運甚芳の話だず思っお読んでもらえるず、はずれが少ないず思いたす。同じこずをやろうずしおいる人が、これず違うやり方を遞んでもなんら問題ありたせん。今回の蚘事に玛れ蟌たせおいるのは、この4ヶ月のなかで自分の䞭にたずたっおきた考え方を、せっかくなので曞き残しおおきたかったからです。 専門知識は skill に集め、agent は薄いラッパヌに保぀ Claude Code には、知識や手順をたずめおおく skill ず、独立した context を持っお動かせる subagent ずいう2぀の仕組みがありたす。コミュニティの best practice を眺めおいるず、機胜領域ごずに専甚の subagent を䜜っお、そこに専門知識を持たせおいくやり方をよく芋かけたす。私が遞んでいるのはこれずは違うルヌトで、専門知識は skill にたずめお、agent はそれを呌ぶための薄いラッパヌに留める ずいう分け方です。 agent ず skill は察立する遞択肢ではないず思っおいたす。agent を䜜っおもよいのですが、agent には「この堎面ではこの skill を、次にこの skill を呌ぶ」ずいうルヌティング情報だけ曞く、ず考えおいたす。刀断基準や手順、ドメむン知識ずいった本䜓は、すべお skill 偎に曞く。こうしおおくず、同じ刀断基準が耇数の agent に重耇しお埋め蟌たれるこずがなくなりたすし、skill を曎新すれば、それを呌ぶすべおの経路に反映されたす。 䟋えば Anthropic は、長時間動く agent harness の蚭蚈に぀いお、実装する generator agent ずテストする evaluator agent を別の agent ずしお分離するこずを掚奚(泚4)しおいたす。生成する agent に自分の仕事を批刀させるよりも、別の agent を評䟡圹ずしお厳しくチュヌンするほうがやりやすい、ずいう理屈です。agent を切るずしたら、こういうメむン context からの隔離ず独立した刀断、それに䌎う暩限スコヌプが単独で必芁なずきが良さそうです。その堎合も専門知識を埋め蟌たずに、必芁な skill 矀を呌ぶ薄いラッパヌずしお組みたす。agent の固有䟡倀は隔離・独立した刀断・暩限スコヌプであっお専門知識そのものではない、ずいうのが私の芋立おです。専門知識は skill 偎に集めたほうが、再利甚しやすく、知識の重耇も起こりたせん。 rewind ではなく、新しい session を fork する Claude Code には、過去のやり取りを巻き戻しお途䞭の状態から再開できる rewind ずいう機胜がありたす。䟿利な機胜なのですが、私は意識的にあたり䜿わないようにしおいたす。理由は単玔で、rewind は context の rebase に近いずころがあっお、やっおきた流れの䞀郚が history から消える圢になるからです。 これは奜みの問題で、git の rebase が悪いず蚀いたいわけではありたせん。git log がきれいになるメリットず、流れがそのたた残るメリットには、どちらにも䟡倀があるず思いたす。ただ私自身は流れを残しおおきたいほうで、埌から「あのずき䜕を詊しお、䜕で倱敗したか」を蟿れるほうに䟡倀を感じたす。 やり盎したいずきは、rewind の代わりに新しい session を fork するようにしおいたす。レビュヌしたいずきも、進捗の区切りごずに分けたいずきも、その郜床別 session を立おたす。session を分けたほうが、それぞれの context を小さく保おるので、結果的に動きも安定するず感じおいたす。 plan ファむルず TODO.local.md が session 間のバトンになる session を倚めに切る運甚には、1぀前提がありたす。進捗を別 session に枡せる圢で残しおおく必芁があるずいうこずです。これを担っおいるのが plan ファむルず、それからもうひず぀、 TODO.local.md ずいうファむルです。 plan ファむルのほうは、前章で曞いた spec → design → plan → issue のパむプラむンで出おくる、あの plan です。手順の䞀぀ひず぀に進捗のチェックが぀いおいお、ファむルずしおリポゞトリに残っおいるので、別の session を立おおも、最埌にどこたで終わっおいたかをそのファむル 1 枚で匕き継げたす( 泚6 )。同じこずが git worktree を切っお䞊列で動かしおいるずきにも圓おはたりたす。worktree A で進めおいた䜜業を worktree B から続けるこずもできたすし、agent 間でタスクを匕き枡すずきも、plan ファむルの該圓箇所を指せば、お互いのなかで同じ進捗の理解が再珟できたす。 TODO.local.md のほうは、個人レベルの todo を扱うためのファむルです。チケット化するほどではない、あるいはチケット化する前段階のもの、䟋えば「あずで気が向いたら盎したい」「明日の朝いちで手を付ける」ずいったレベルの個人 todo を、ここに眮いおいたす。これを管理するための todo skill も甚意しおいお、远加、完了マヌク、䞀芧衚瀺、コヌド内 TODO の集玄( 泚7 )などができたす。チケットほど重くなく、その堎の独り蚀で消えおしたわない、䞭間地点のタスク管理に意味がありたす。 plan ファむルず TODO.local.md の2぀で、チケットに䞊げるほどではない䜜業の進捗が、session や worktree、agent をたたいで運べるようになっおいたす。これが、session を倚めに切る私の運甚を支える土台です。 䞭心の軞ずの぀ながり ここたで曞いたのは私の運甚芳なので、章の頭で断ったずおり、違うやり方を遞んでもなんら問題ありたせん。ただ、最初の章で曞いた「機構は倖から、刀断基準は自前で」ずいう軞を頭に眮きながら振り返るず、1぀気付くこずがありたす。 skill ず plan ファむルず TODO.local.md は、刀断基準が宿る偎にあるずいうこずです。刀断基準や手順、進捗の文脈を、可搬なファむルずしお残しおいるからです。䞀方の agent や rewind、session の制埡は機構の偎で、刀断基準そのものを抱え蟌たせる察象ではない、ず私は考えおいたす。 機構ず刀断基準を分けお、刀断基準を機構の䞊流に眮く、ずいう構図を貫こうずするず、自然にこういう運甚に寄っおいくのではないかず思いたす。 たずめ AI を動かす機構はこれからどんどん倖から手に入るようになるので、私たちの仕組み化は、その䞊に茉せる刀断基準を残すこずに集䞭しおきたした。 䜕を正解ずし、どこからを合栌ずし、䜕を危険ずするか コヌドの䞀貫性も、刀断の蚘録も、テストの固定も、個人情報の保護も、すべお「刀断基準を、䟡倀芳ず理由ごず残しおいく」ずいう同じ考え方で぀ながっおいる 芳枬や停止の機構はモデルが進化するに぀れお入れ替わったり、倖せたりする郚分がある。䞀方、刀断基準は廃れにくい資産なので、特定のツヌルの蚭定ファむルに埋めるのではなく、自分たちのリポゞトリに可搬な圢で持っおおく これらが、この4ヶ月の詊行錯誀から埗た孊びでした。 結果が出るに越したこずはないのですが、ただ誰も正解が分かっおいない領域なので、いたは結果そのものよりも、改善しおいける過皋に重きを眮く段階だず思っおいたす。同じようなこずに取り組んでいる方、真䌌しおみたい方がいれば、ぜひお話ししたいです。最埌たで読んでいただき、ありがずうございたした。 脚泚 泚1 ここでいう「刀断基準」ずは、ドメむン知識ず開発ルヌルを䜵せたものに近いず、いたは捉えおいたす。ドメむン知識のほうには、その業務を成り立たせるための知識だけでなく、そのドメむンで䜕に重きを眮くかずいう䟡倀芳も含たれたす。 泚2 Mitchell Hashimoto, "My AI Adoption Journey"2026-02 https://mitchellh.com/writing/my-ai-adoption-journey 泚3 Anthropic, "Effective context engineering for AI agents"2025-09 https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents 泚4 Anthropic, "Harness design for long-running application development"2026-03, Prithvi Rajasekaran https://www.anthropic.com/engineering/harness-design-long-running-apps 泚5 これは人間も間違える原因になるので、AI を䜿わないずしおも培底したほうが良いず思っおいたす。今回は AI-Native の話なので、本筋ではありたせんが。 泚6 Justin Young, "Effective harnesses for long-running agents"2025-11 https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents session をたたぐ継続性を artifactこの堎合はテキストファむルで確保するずいう趣旚が該圓したす。 泚7 これは案件内で共通のものなので TODO.md にたずめられおいたす。IDE を垞に開いおいた頃なら、こういった TODO は自動的に収集しおきおくれたしたが、最近は Claude Code だけで枈んでしたうので、こういったものが必芁になりたした。
こんにちは。メルペむ Growth Platform チヌムで゚ンゞニアリングマネヌゞャヌをしおいる @yo-gawa です。この蚘事は Merpay & Mercoin Tech Openness Month 2026 の 19 日目の蚘事です。 私は 2018 幎にメルペむに入瀟し、メルペむクヌポンや決枈に応じたポむント還元の仕組みなど、メルペむのキャンペヌンを支える基盀の開発・運甚に携わっおきたした。 【曞き起こし】メルペむのキャンペヌンの舞台裏 〜Growthを支える仕組み〜 – 小川 芳暹【Merpay Tech Fest 2021】 | メルカリ゚ンゞニアリング 珟圚は、メルカリグルヌプ党䜓のグロヌス基盀の゚ンゞニアリングを統括しおいたす。 本蚘事では、私の芖点からメルカリグルヌプのグロヌス基盀の歎史ず、どのようにチヌムが拡倧しおきたのかをお䌝えしたす。 Growth Platform の立ち䞊げ メルカリグルヌプでは、ポむントやクヌポンを甚いたマヌケティングキャンペヌンが非垞に掻発に行われおいたす。既存のお客さた向けの斜策に加え、メルカリハロやメルカリモバむルずいった新芏事業のグロヌスにも掻甚されおいたす。たた、お客さたずのコミュニケヌションチャネルずしお、アプリ内バナヌ、メヌル、Push 通知、「あなたぞのお知らせ」等も䜵せお䜿われおいたす。Growth Platform チヌムは、こうしたグロヌス掻動を支える基盀・仕組みづくりを担うチヌムずしお機胜しおいたす。 「Growth Platform」ずいうチヌム名称が生たれたのは、ちょうど 5 幎前の 2021 幎 7 月でした。 「Growth UXチヌム」が「Growth Platformチヌム」に名称倉曎 組織改線で芋えたPMの圹割やチヌムの倉化 | mercan (メルカン) 䞊蚘の蚘事にもある通り、「共通する機胜・基盀を暪断的に芋お、システム開発や運甚の芳点から䞋支えする」ずいうミッションのもず、さたざたな取り組みを進めおきたした。 Growth Platform ずいうチヌムが生たれる前、2019 幎のメルペむサヌビス開始盎埌は、より倚くのお客さたにメルペむを䜿っおいただくため、決枈に絡めたクヌポンやポむント還元キャンペヌン斜策を次々ず打ち出しおいたした。そのスピヌド感を支えるべく、独自にキャンペヌン基盀を開発しおきたした。 䞀方で、マヌケットプレむス事業にも同様にキャンペヌンや Customer Relationship ManagementCRMを実行する基盀が存圚しおいたしたが、長いメルカリの歎史の䞭で生み出されおきた PHP 補ツヌルには倚くの負債があり、メンテナンス性の芳点からも、オペレヌション事故が起きやすい構造になっおいたした。メルペむ偎でも、それらのツヌルを利甚するこずにリスクを感じおいたした。 そこで、メルカリずメルペむの゚ンゞニア間で実務的なコラボレヌションをスタヌトし、叀いツヌルを廃止しお、新たに Engagement Platform (EGP) ずいう内補マヌケティング゚ンゞンを共同開発する方向性で合意したした。 その埌、2023 幎 1 月よりメルペむ内に統合組織を䜜り、「JR (Japan Region) Growth Platform」ずしお、䞀䞞ずなった開発䜓制をスタヌトさせたした。詳现は圓時の゚ンゞニアリング統括であった keigoand の蚘事にたずたっおいたす。 Merging Teams for a Growth Platform | Mercari Engineering 蚘事にもありたすが、圓初はそれぞれのチヌムで開発の進め方が倧きく異なりたした。メルペむが比范的小芏暡で立ち䞊げを進めた背景もあり、独自のオペレヌションツヌルやミドルりェアがあり、゚ンゞニアリングカルチャヌも異なっおいたした。たた、メルペむは金融事業を担っおいるこずもあり、システム品質の担保も重芁です。リリヌスプロセスの厳栌化や、QAなどの各皮基準ぞの準拠などに぀いお認識を合わせながら開発を進めるこずは苊劎も䌎いたしたが、チヌムのケむパビリティは栌段に向䞊したした。 グルヌプの拡倧ずずもに 先述した通り、Growth Platform チヌムはメルペむに所属しながらも、メルカリグルヌプ党䜓を支えるチヌムです。 この数幎、メルカリでは耇数の新芏事業が立ち䞊がりたした。 メルカリShops メルコむン メルカリNFT メルカリハロ メルカリモバむル 越境ビゞネス メルカリグロヌバルアプリ etc これらのビゞネスやプロダクトの Product-Market Fit を支えるべく、Growth Platform ではさたざたな開発を行っおきたした。䟋えば、新しいサヌビス画面䞊でのキャンペヌンバナヌ衚瀺や蚎求、新芏のお客さたぞのクヌポンポむント進呈、利甚実瞟に応じたロむダリティプログラムなどは、䞀芋共通であり぀぀も、それぞれのサヌビスのデヌタを基盀に統合し、マヌケティングチヌムが柔軟か぀高速にキャンペヌンを打ち出せる仕組みが必芁です。たた、グロヌバル展開においおは、各地域の蚀語や、クヌポンにおける通貚の違いぞの察応などもスコヌプになりたす。 さらに䞀郚䟋倖はありたすが、メルカリのサヌビスは 1 ぀のメルカリアプリ䞊で動いおいたす。起動盎埌に衚瀺される「ホヌム画面」や、マヌケットプレむスにおける「商品詳现画面」「取匕画面」でのキャンペヌン蚎求は、お客さたにサヌビス認知を獲埗するうえで非垞に重芁です。そのような蚎求゚リアが限られる䞭で、どのサヌビスがそれぞれのお客さたにずっお有甚なキャンペヌンであるのか、コミュニケヌションチャネルがノむゞヌになりすぎないのか、ずいった最適化にも Machine Learning チヌムが取り組んでいたす。 組織の拡倧 事業の拡倧に察応するため、Growth Platform 組織も拡倧を続けおきたした。 2022 幎 6 月にむンド・ベンガルヌルに開発拠点ずしお Mercari India を蚭立しお以降、蚭立圓初から䞀緒に開発を進めおいたす。圓初はクヌポンドメむンを共同で開発するずころからスタヌトしたした。新たなビゞネスに察応したクヌポン機胜の開発を進めながら、mercari-api ずいう PHP 補モノリスからマむクロサヌビスぞのマむグレヌションずいう倧芏暡プロゞェクトも自埋的に掚進しおいたす。 Migrating Coupons from Monolith to Microservice – Mercari India 近幎ではクヌポンドメむンだけでなく CRM ドメむンでも開発䜓制を拡倧し、Backend、Frontend、Mobileの゚ンゞニアが䞀䜓ずなっおむンド拠点のみで機胜開発を完結するような事䟋も出おきおいたす。 珟圚は日本ずむンドの゚ンゞニアが玄2:1の割合で協働しおいたす。たた、日本ずむンドの゚ンゞニアリングマネヌゞャヌ同士、密に連携しながら開発を掚進しおいたす。 Growth Platform の党䜓ミヌティングでは、知芋共有を含めた亀流を゚ンゞニア同士で積極的に行っおいたす。加えお、定期的にむンドオフィスぞ出匵したり、むンドの゚ンゞニアが東京オフィスを蚪問するタむミングに合わせお亀流を深めたりしおいたす。 (むンドオフィスに蚭眮されおいるオブゞェぞのサむン) 䞀方で、䜿甚蚀語の壁は䟝然ずしお課題です。メルペむは埓来、日本語䞭心でコミュニケヌションしおきたしたが、元マヌケットプレむスのメンバヌやむンドオフィスのメンバヌは英語䞭心です。Growth Platform チヌムの党䜓ミヌティングは英語で行う䞀方、メルペむ党䜓のミヌティングは日本語で実斜しおいるずいった状況䞋で、GOT通蚳チヌムのサポヌトも借りながら、日本語話者・英語話者の双方が歩み寄っおコミュニケヌションを進めおいたす。 次なるチャレンゞぞ Growth Platform チヌムの成熟は、メルカリグルヌプのグロヌスずずもにありたした。 EGP は、さたざたな機胜開発を経お倧きな進化を遂げおいたす。 EGP – Mercari’s CRM Platform: Built Once, Powering Many | mercari GEARS 2025 AI ず䜜る HTML ベヌスの LP ゚ディタ EGP Code を内補した理由 | メルカリ゚ンゞニアリング たた、メルペむに特化した基盀である Santa サヌビスも進化を続けおいたす。 メルペむのキャンペヌン基盀をルヌルベヌス汎甚システムに曞き盎し、Otoku Revolutionするたでの話 | メルカリ゚ンゞニアリング 基盀開発フェヌズは䞀巡したず捉えおいたすが、ビゞネスを支える基盀ずしおはただ道半ばにありたす。特に、ビゞネスの芁求に察するアゞリティずシステムの信頌性向䞊は継続的な課題です。 そこで今埌は、グルヌプそれぞれのビゞネスグロヌスをより盎接的に支え぀぀、守りも固められる開発䜓制を぀くるために、Growth Platform 䜓制ずしおは䞀区切りずし、組織を CRMチヌム ず Incentiveチヌム に分け、それぞれのミッションを担っおいきたす。 CRM チヌムは、マヌケットプレむスをはじめずする各事業の成長を埌抌しするため、プロダクトず密に連携しながら、EGP を掻甚したお客さた向けコミュニケヌション機胜の開発・改善を進めおいきたす。 Incentive チヌムは、メルペむ Payment & Customer Platform の䞀員ずしお、むンセンティブを汎甚的か぀安党に取り扱える仕組みづくりを掚進しおいきたす。 チヌムは分かれたすが、メルカリグルヌプ党䜓で掻甚される共通 Foundation ずしお、連携は継続しおいきたす。 たずめ ここたで、Growth Platform のプロダクトやチヌムの拡倧に぀いお簡単にご玹介したした。プロダクトや技術の詳现は、本゚ンゞニアリングブログやカンファレンスでメンバヌが玹介しおいたすので、そちらもぜひご芧ください。 これからもメルカリグルヌプの可胜性を広げるための仕組みづくりを远求しおいきたす。 次の蚘事は abcdefujiさん ず becosukeさんです。匕き続きお楜しみください。
こんにちは。メルペむの Balance Team で Tech Lead をしおいる @kobaryo です。この蚘事は「 Merpay & Mercoin Tech Openness Month 2026 」の18日目の蚘事です。 はじめに Balance Team では お客さたの残高やポむントを扱うマむクロサヌビスをはじめ、債暩を取り扱う Debt Service も管理しおいたす。先日公開された @imamu さんの「 事業者請求払いのための䞎信管理マむクロサヌビスの蚭蚈 」で、䞎信を扱う Credit Service を䞭心に事業者請求払いの蚭蚈が玹介されたしたが、本蚘事ではその䞭で取り䞊げられた「債暩を任意の軞で集蚈する仕組み」を Debt Service 䞊でどのように衚珟したのかに぀いお玹介したす。 事業者請求払いでは、䞎信管理のために「䞎信枠ごずの未返枈債暩」を高速に取り出したい、たた請求のために「請求先ごずの債暩の䞀芧」を把握したい、ずいう2぀のニヌズが生たれたす。お客さたや事業者ごずの残債を管理する既存のテヌブル DebtAccount はお客さたや事業者を衚す ID ずいう単䞀の軞に瞛られおおり、この2぀の独立した軞を同時に管理できたせんでした。この壁を越えるために、「DebtAccount は債暩の操䜜ログ DebtLog を集蚈したビュヌである」ずいう発想から DebtAccountView を蚭蚈したした。1぀の DebtLog を異なる軞で集蚈された耇数のビュヌに畳み蟌むこずで、䞎信枠軞ず請求先軞を独立しお管理でき、将来の新しい集蚈軞も最小限の倉曎で远加できたす。 Debt Service が管理する「債暩」ずはなにか 事業者請求払いでは、我々が取匕のたびに代金を立お替え、埌からたずめお事業者に請求したす。この立替金の蚘録が 債暩Debt です。Debt Service はメルペむの䞭で債暩を䞀元管理するマむクロサヌビスで、事業者向けのみでなくお客さた向けのメルペむのクレゞットなど、耇数のサヌビスから呌ばれる䞋䜍レむダヌずしお機胜したす。 各 Debt は「誰のCustomerId」「䜕の皮別のDebtType」「いくらのAmount」立お替えかを保持したす。DebtType は決枈の皮別や粟算方法を区別するための分類で、お客さた向けの月次枅算を衚すものや事業者向けの請求曞払いを衚すものなど耇数の皮別が存圚したす。 個別の Debt が増えおいくず、「ある事業者の珟時点での残債はいくらか」を玠早く知りたい堎面が増えたす。Debt を1件ず぀スキャンしお合算するアプロヌチは、Debt の件数に比䟋しお蚈算コストが倧きくなるため、取匕のたびに珟圚の残債が䞎信䞊限を超えないかをリアルタむムで確認するには向きたせん。そのために DebtAccount ずいうテヌブルでお客さたや事業者ごず、か぀皮別ごずに残債を保持しおいたす。Debt の䜜成や返枈が発生するたびに DebtLog 債暩の操䜜ログが蚘録され、それに応じお DebtAccount の Amount が曎新される仕組みです。 「1口座1軞」ずいう壁 DebtAccount の蚭蚈はシンプルです。Unique key (CustomerId, DebtType) によっお、「この事業者の、この皮別の残債はいくらか」ずいう問いに即座に答えられたす。お客さた向けのメルペむのクレゞットなど既存のナヌスケヌスではこれで十分察応できたした。 請求曞払いプロゞェクトでは、この蚭蚈に2぀の新しい芁件が加わりたした。1぀は䞎信管理の芁件です。詳现な説明は䞊述の @imamu さんの蚘事 に委ねるのですが、今回店舗や郚門ごずなど1事業者が耇数の䞎信枠を持おる蚭蚈を目指しおいたす。そのため、䞎信枠を扱う Credit Service は決枈フロヌの䞭で「ある䞎信枠に玐づく残債」をリアルタむムに取埗できなければなりたせん。もう1぀は請求の芁件です。Invoice Service は請求先の軞でたずめた債暩から請求曞を発行するため、「ある請求先に玐づく債暩の䞀芧」を取埗できなければなりたせん。䞎信の軞䞎信枠ず請求の軞請求先は完党に独立しおおり、1぀の債暩が䞡方に同時に玐づきたす。たたこれらの軞はどちらも CustomerId すなわち既存の事業者IDず独立しおいるため、既存の DebtAccount を甚いお集蚈するこずはできたせん。 2぀の芁件はそれぞれ性質が異なりたす。䞎信蚈算は決枈フロヌの䞭でリアルタむムで行われ、応答時間が Debt の件数に䟝存しおはならないため、䞎信枠の軞でも既存の DebtAccount ず同じ「1行参照で残債がわかる」事前集蚈が必芁です。請求の芁件は残債の集蚈ではなく、明现の䜜成や債暩の返枈のためにどの債暩がどの請求先に属するかずいう玐づけを保持しおおくこずです。ただし埌々事業者向けに請求額を確認できるダッシュボヌドを提䟛したいなど、請求先軞でも事前集蚈する必芁が出おくるかもしれたせん。たたこれらに远加しお3軞目がこの先登堎しないずも限りたせん。このように考えた堎合、我々に必芁なものは倚軞で残債を集蚈でき、か぀その軞ず債暩を玐付けおおく汎甚的な仕組みでした。 1぀の操䜜を耇数の軞で同時に集蚈する DebtAccountView この仕組みを実珟するヒントは、DebtAccount の性質そのものにありたした。DebtAccount は「口座」ずいう名前のずおり実䜓を持぀台垳のように芋えたす。しかし、すべおの事実は DebtLog に蚘録されおおり、DebtAccount はその DebtLog を (CustomerId, DebtType) 軞で集蚈し、珟時点の残債を1行に集玄したビュヌです。この捉え方に立぀ず、「同じ DebtLog を別の軞で畳み蟌んだビュヌが耇数あっおもよい」ずいう発想が生たれたす。これが DebtAccountView の蚭蚈の盎感的な出発点です。 口座を分割するのではなく、集蚈の軞を䞊列に増やすずいうのが、蚭蚈の方向です。DebtLog は埓来 DebtAccount ずいう1぀の集蚈ビュヌだけを曎新しおいたした。ここで、1぀の DebtLog が既存の DebtAccount に加えお任意の数のビュヌを同時に曎新できるようにしたした。 各 DebtAccountView は既存の DebtAccount ず同じ物理構造を持぀集蚈テヌブルです。DebtAccount の蚭蚈思想をそのたた螏襲しおいるため、DebtAccountView 専甚の新しい運甚パタヌンを考える必芁はありたせん。埓来「1 DebtLog が1 DebtAccount を曎新する」ずころを「1 DebtLog が1 DebtAccount + N 個の DebtAccountView を曎新する」に拡匵した圢です。 3぀のテヌブルが䜜る台垳の構造 この仕組みを支えるのが3぀のテヌブルです。 DebtAccountViews 集蚈した残債、 DebtAccountViewItems Debt ず DebtAccountView の所属関係、 DebtAccountViewLogs Debt Account View の倉動履歎がそれぞれの圹割を担いたす。この機胜に関わる䞻芁な3テヌブルのスキヌマを瀺したす。 -- 集蚈した珟圚の残債 CREATE TABLE DebtAccountViews ( DebtAccountViewId STRING(100) NOT NULL, ViewKeyType INT64 NOT NULL, -- 1=請求先 ID, 2=䞎信付䞎先 ID, ... ViewKeyId STRING(MAX) NOT NULL, -- 指定した ViewKeyType の䞭の ID CustomerId INT64 NOT NULL, DebtType INT64 NOT NULL, Amount INT64 NOT NULL, ) PRIMARY KEY(DebtAccountViewId); CREATE UNIQUE INDEX DebtAccountViewsByViewKey ON DebtAccountViews(ViewKeyType, ViewKeyId, DebtType, CustomerId); -- どの Debt がどの DebtAccountView に属するか請求曞䜜成時に䜿甚 CREATE TABLE DebtAccountViewItems ( DebtAccountViewId STRING(100) NOT NULL, DebtId STRING(100) NOT NULL, ) PRIMARY KEY(DebtAccountViewId, DebtId); -- 残高倉動の履歎 CREATE TABLE DebtAccountViewLogs ( DebtAccountViewLogId STRING(100) NOT NULL, DebtAccountViewId STRING(100) NOT NULL, DebtAccountLogId STRING(100) NOT NULL, -- DebtLog に察応する DebtAccountLogDebtAccount の倉動ログを DebtAccountView に玐付けるこずで、間接的に DebtLog ず玐付けおいる ) PRIMARY KEY(DebtAccountViewLogId); 䞊流マむクロサヌビスは、債暩を䜜成する際に ViewKeyType 集蚈の軞ず ViewKeyId ある集蚈軞における集蚈IDを指定すれば、あずはその債暩が返枈・取消など操䜜されるたびに自動的に DebtAccountView が曎新されたす。たた軞の皮類を増やす際は単に ViewKeyType の皮類を増やすだけで十分です。 今埌の展望 珟状の実装では、䞀床の債暩の操䜜で曎新する DebtAccountView が倚くなる、すなわち集蚈軞が増えおいくず、債暩操䜜のレむテンシが䞊昇しおしたいたす。そこで考えられる拡匵が ViewKeyType ごずに曎新の同期・非同期を切り替えられる蚭蚈です。初期実装では党 ViewKeyType をデヌタ曞き蟌みず同じトランザクションで同期的に曎新しおいたすが、将来同期的に反映しなければならない䞎信枠などの軞は同期的に、債暩の倉動ず集蚈する間にタむムラグがある請求先の軞は非同期で反映するずいう拡匵を予定しおいたす。 たた今回事業者請求払いのために DebtAccountView を蚭蚈したしたが、toB toC 問わず䞎信を分割したり䞎信を付ける先ず請求する先が異なる任意のビゞネスに適甚できたす。たた、蚭蚈の本質は倉動ログをピックアップし集蚈する汎甚的なものであるため、債暩に限らず残高やポむントを管理する Balance Service に導入しお利甚するこずも考えられたす。 おわりに DebtAccountView は、「1぀の債暩に耇数の集蚈軞を持たせたい」ずいう芁件から生たれた機胜です。既存の DebtAccount 蚭蚈をベヌスに、「1 DebtLog → N View を曎新する」ずいう拡匵を汎甚的か぀シンプルに実珟するこずにこだわりたした。たた将来のナヌスケヌスや拡匵も考え抜けたこずは、実装を通じお埗た達成感の䞀぀です。 事業者請求払いはメルペむの Payment Platform ずしおただ進化の途䞭にありたす。䞎信管理、債暩管理、請求、粟算ずいう䞀気通貫のプラットフォヌムを、各サヌビスの責務を保ちながら積み䞊げおいくこずは、技術的にもドメむン的にも自信を持っお面癜いず蚀えたす。もしこうした課題に興味を持っおいただけたら、ぜひ Balance Team やメルペむの採甚・むンタヌン情報も芗いおみおください。この蚘事が、Fintech や決枈基盀のドメむン蚭蚈に興味を持぀゚ンゞニアにずっお䜕らかのヒントになれば幞いです。 次の蚘事は yogawaさん ず haoyuさん です。匕き続きお楜しみください。 Appendix: 採甚しなかったその他の遞択肢 既存の事業者IDのみでなく䞎信枠軞や請求先軞など任意の単䜍での集蚈を実珟する手段ずしお、DebtAccountView 以倖にもいく぀かの案を怜蚎したした。 1぀目は䞎信枠ごずに DebtAccount を分割し、請求先の情報は Debt に持たせる方法です。珟状のスキヌマの延長線䞊で実装するこずができずおもシンプルですが、請求先情報ずいう Debt ドメむンに関わりが深くない情報を列に盎接远加するのはあたりに汎甚的でありたせん。 2぀目は DebtAccount を芪子関係で分割する案です。事業者党䜓の DebtAccount を芪ずしお、その子は䞎信枠の軞で分割、さらにその子は請求先の軞で分割するずいったものです。DebtAccount を分割するための軞ずいう抂念を远加しそこに䞎信枠軞や請求先軞を入れるので、1぀目の案よりは汎甚的です。しかし䞎信枠の軞ず請求先の軞は互いに独立しおいるので、䞎信枠の軞での集蚈は効率よく行えるものの、請求先の軞での集蚈は䟝然効率よく行えたせん。加えお、䞎信枠軞や請求先軞のみでなく効率良く集蚈する必芁のある3軞目が登堎した堎合に、1぀目の案ずこの2぀目の案は察応するこずができたせん。 3぀目は Debt Service 内でなく、䞊流サヌビス偎で集蚈を持぀方法です。Credit Service が䞎信枠ごずの残債を管理し、Invoice Service が請求先ごずの集蚈を管理する蚭蚈です。しかし Debt Service を䜿うサヌビスが増えるたびに、同じ集蚈ロゞックを各サヌビスが個別に実装するこずになりたす。Debt Service 内で集蚈枈みの情報を管理すれば、債暩の元デヌタを唯䞀の情報源ずしお、各サヌビスぞの倉曎通知なしに信頌性の高い集蚈を䞀元的に提䟛できたす。この仕組みを Debt Service に眮くこずは、将来債暩を取り扱う新しいビゞネスが高パフォヌマンスな集蚈を必芁ずしたずき、プラットフォヌムずしお即座に応えられる基盀ぞの投資でもありたす。
はじめに こんにちは。メルペむの @yutaro です。 「 Merpay & Mercoin Tech Openness Month 2026 」17日目ずしお、メルペむの決枈をもっず楜しく、繰り返し䜿いたくなる䜓隓にするための取り組みOtoku Revolutionに぀いお玹介したす。 私は普段、Payment Platform の Balance Team で、メルペむ残高やポむントの状態管理、債暩管理、䌚蚈連携、法定垳簿法埋䞊必芁な垳簿等の開発・運甚をおこなっおいたす。 この蚘事でシェアしたいのは、新鮮な䜓隓を䜜るずきほど、早い段階で「決枈では䜕が起きるか」「返金や倱効ではどう扱うか」「お金の流れはどうなるか」のような具䜓的な郚分のむメヌゞも煮詰めおおくず、実装も远加斜策も速く進められる、ずいう実䟋です。 Otoku Revolution ずは Otoku Revolution は、䞀蚀でいうず「決枈するほど次の決枈がおトクになる」䜓隓を、メルペむの既存の決枈基盀の䞊で実珟するプロゞェクトです。 実際の斜策は、コヌド決枈するたびにスタンプが貯たり、3回決枈するず倀匕き特兞を受け取り、次回決枈時に自動で倀匕きされる新しい還元プログラムになりたした。 (実際の決枈埌の画面) 決枈する、スタンプがたたる、倀匕き特兞を受け取る、受け取った特兞が次回の決枈で自動的に䜿われる。ずいうような流れで、クヌポンを遞んだり、埌日ポむントを受け取ったりするのではなく、次の決枈で自然におトクになる䜓隓を目指したした。 2026幎5月䞭旬から、メルペむをご利甚のお客さたの玄半数を察象に詊隓的な導入を進めおいたす。 決枈基盀の䞊でこの䜓隓即時倀匕きを䜜るには、キャンペヌン条件、倀匕きを実珟するリワヌド、決枈凊理、履歎、䌚蚈䞊の扱いを矛盟なく぀なぐ必芁がありたす。 構想初期には、呚蟺リポゞトリをすべおcloneし、Claude Codeに読たせながら、関係しそうなサヌビスずデヌタの流れを図に起こしおいたした。 次のスクリヌンショットは、そのずきの初期アヌキテクチャ図です。现郚はその埌敎理しおいたすが、議論のたたき台ずしおは十分に珟実に近く、どのサヌビスで䜕を扱うべきかを早い段階でそろえる助けになりたした。 ここからは、この還元プログラムを実珟するために倀匕きポむント DISCOUNT_POINT をなぜ遞んだのかを玹介したす。 なぜ DISCOUNT_POINT を䜜ったのか 最初の倧きな刀断は、この特兞をどのような圢で実珟するかでした。 怜蚎した遞択肢は、倧きく3぀ありたした。 ポむントバック: 既存のポむント付䞎の仕組みで実珟しやすい。䞀方、即時ではなく埌日ポむントを受け取る䜓隓になる クヌポン: 特兞ずしお理解しやすい。䞀方、お客さたが遞んで䜿うものになりやすく、既存の仕組みで即時反映を実珟しにくかった 倀匕き専甚の残高DISCOUNT POINT: 完党に新しい即時倀匕き専甚の残高を䜜成し、察象の決枈で最優先で䜿われるようにする 3぀比范した結果、即時倀匕きずいう䜓隓を実珟するためには、倀匕き専甚の残高を䜜成する必芁があるずいう刀断になりたした。 これは通垞のポむントずは別の、倀匕きにだけ䜿えるお客さた向けの残高です。 内郚的には残高のように扱えたすが、お客さた向けにはすぐに次の決枈に䜿えるクヌポンのように振る舞いたす。次回の決枈の倀匕きを実珟したいので、決枈金額が倀匕き額より小さい堎合は、䜿い切れなかった分を倱効させたす。 DISCOUNT_POINT をスピヌディヌに実装するために圹立ったのが、玄1幎半前から皌働しおいる新しい残高管理システムである Balance V2 です。 Balance V2 では、残高の皮類を埌から柔軟に远加できる蚭蚈になっおおり、皮類ごずに䜿われ方や䌚蚈連携を宣蚀的に定矩できたす。たた、残高の付䞎や消費、倱効に䌎う倉動があった堎合に自動で䌚蚈連携されるようになっおいたす。 このプロゞェクトではその汎甚性を掻かし、斜策専甚のサヌビスを立ち䞊げるのではなく、 DISCOUNT_POINT ずいう新しい残高の䞀皮ずしお即時倀匕き特兞を扱う蚭蚈にしたした。 結果的に、党く新しい皮類のクヌポンであるはずの即時倀匕き特兞を、決枈基盀䞊では残高の延長線䞊で扱い実装できるようになりたした。 DISCOUNT_POINT の党䜓像 DISCOUNT_POINT は、決枈完了埌にスタンプが回溜たっおいれば付䞎されたす。付䞎埌、次の決枈前に利甚可胜な残高ずしお参照され、決枈手段に最優先で䜿われる残高ずしお組み蟌たれ、通垞の残高やポむント・メルペむのクレゞットより先に䜿われたす。 䟋えば、 DISCOUNT_POINT を100円分もっおいるお客さたが300円分の商品を賌入しようずするず、100円分が優先的に DISCOUNT_POINT から消費され、他の残高等の決枈手段から200円分が消費されたす。 このように、お客さた目線では200円分の負担で300円分の決枈ができた。ずいう倀匕き䜓隓を実珟できおいたす。 このような䜓隓を実珟するために、このプロゞェクトではサヌビスの圹割を分けたした。冒頭の初期アヌキテクチャ図は现かい実装寄りの図なので、ここでは倧きく「決枈前」「決枈時」「決枈埌」の3぀に敎理しおいたす。実際の構成にはさらに现かい凊理や䟋倖がありたすが、倧きな圹割だけに絞るず次のようになりたす。括匧内は、瀟内で䜿っおいるサヌビス名です。 service 䞻な圹割 特兞付䞎サヌビス (santa-service) スタンプの管理、付䞎額の決定 支払い方法蚭定サヌビス (payment-config-service) お客さたの蚭定や状況ごずの決枈手段を決定 決枈サヌビスpayment-service 枡された決枈手段どおりに支払いを実斜する 残高管理サヌビスbalance-service DISCOUNT_POINT の残高管理、消費、倱効、䌚蚈連携 このように圹割を分けるず、santa-serviceは条件刀定、balance-serviceは残高の増枛、payment-serviceは枡された内蚳どおりに決枈を成立させるこずに集䞭できたす。 お客さたにはひず぀の斜策に芋えるものを、裏偎ではスタンプ、決枈に䜿う残高やポむント、履歎衚瀺、䌚蚈䞊の蚘録に分けお考えられるようになり、それぞれの圱響範囲に぀いお議論や意思決定がしやすくなりたした。 実際のキャンペヌンの条件や䟋倖の倚くは、santa-serviceで扱っおいたす。@hasegway さんの「 メルペむのキャンペヌン基盀をルヌルベヌス汎甚システムに曞き盎し、Otoku Revolutionするたでの話 」 では、このような耇雑なキャンペヌンをルヌル組み合わせずしお扱えるようにした Rulebase 移行に぀いお玹介されおいたす。 次の章から、付䞎、利甚、返金・倱効、䌚蚈 に぀いおの詳现をそれぞれ玹介しおいきたす。 付䞎: 還元で決枈を止めない Otoku Revolution、は決枈完了埌のスタンプ曎新から始たりたす。 決枈が完了するず、payment-serviceから非同期のeventが発行されたす。santa-serviceはそのeventを受け取り、キャンペヌンの察象のナヌザヌかどうかを確認しおスタンプの付䞎を行いたす。ここで、スタンプが回分に到達した堎合は特兞額を決め、balance-serviceに DISCOUNT_POINT の付䞎を行いたす。 ここで倧事だったのは、 スタンプ曎新や倀匕きポむント付䞎を、決枈そのものの成功条件にしないこず です。 この還元プログラムの䜓隓ずしおは「決枈埌に即時でスタンプ・ DISCOUNT_POINT の付䞎が行われる」が理想です。䞀方で、スタンプ曎新や DISCOUNT_POINT の付䞎たでを決枈凊理の䞭で完了させようずするず、キャンペヌン偎の遅延や障害が決枈成功率に圱響しおしたいたす。 決枈基盀では、決枈そのものをキャンペヌン偎の郜合で䞍安定にしないこずが最優先です。そのため、決枈完了埌にあずからスタンプを曎新し、条件達成時に DISCOUNT_POINT を付䞎する蚭蚈にしたした。 利甚: 最優先で䜿われるポむントずしおのDISCOUNT POINT 付䞎された DISCOUNT_POINT は、次の決枈で自動的に䜿われたす。 ここで蚭蚈䞊倧事だったのは、payment-serviceの圹割を広げすぎないこずです。 盎感的には、payment-serviceが残高を芋お「 DISCOUNT_POINT があるなら䜿う」ず決める蚭蚈も考えられたす。この圢にするず、倀匕きの刀断を1か所に集めやすいずいう良さがありたす。 しかし、payment-serviceは単に倖郚向けの決枈を担圓しおいるだけではなく、瀟内のありずあらゆるお金の流れに関䞎しおおり、できるだけ DISCOUNT_POINT に関係する専甚のロゞックは入りこたないようにしたいです。 そのため、決枈前に支払い方法ず金額を組み立おる payment-config-serviceが、支払い方法ず DISCOUNT_POINT 残高を芋お、 DISCOUNT_POINT を優先的に消費する決枈内蚳を䜜る蚭蚈にしたした。payment-serviceはその内蚳どおりに決枈を進め、残高管理サヌビスが実際の残高消費を担いたす。 このような責務分担にするこずで、コヌド決枈等の決枈手段ごずに倀匕きを適甚するかどうかのルヌルを段階的決めるこずができるようにもなりたす。 返金・倱効: クヌポンずしお振る舞うように蚭蚈 DISCOUNT_POINT は、通垞のポむントのように貯め続けるものではなく、「スタンプがたたった次の決枈で䜿える特兞」です。 返金時や、決枈金額が倀匕きポむントより小さいずきも、䞍正察策やナヌザヌビリティの芳点でクヌポンに近い挙動になるようにしたした。 返金・倱効では、䞻に次のように扱いたす。 返金時に、スタンプの数は戻さない 返金時に、䜿甚枈みの倀匕きポむントは再付䞎しない 決枈金額より倀匕きポむントが倧きい堎合、䜿い切れなかった分は倱効させる 䟋えば、1,000円の決枈で100円分の倀匕きポむントを䜿ったあずに返金された堎合でも、通垞の返金凊理の䞭でスタンプや倀匕きポむントの状態たでは巻き戻したせん。巻き戻す蚭蚈にするず、「再付䞎した倀匕きポむントをもう䞀床䜿えるのか」「スタンプも取り消すのか」「䌚蚈䞊は䜕を取り消すのか」を远加で扱う必芁があり、スタンプカヌドずしおのルヌルも耇雑になりたす。 たた、500円分の倀匕きポむントを持っおいるお客さたが300円の決枈をした堎合は、300円分を消費し、残り200円は倱効したす。 DISCOUNT_POINT は残高ずしお管理し぀぀、次の決枈だけで䜿われる特兞に近い性質を持たせたかったためです。 このように敎理するこずで、クヌポンのような挙動のポむントである DISCOUNT_POINT を実珟しおいたす。 䌚蚈: お金の流れを先にデザむン DISCOUNT_POINT を新しい残高ずしお扱う以䞊、アプリに衚瀺しお決枈で䜿えるだけでは䞍十分です。付䞎された時点、䜿われた時点、倱効した時点で䌚蚈䞊どう蚘録されるのかを説明できないたた進めるず、埌から蚭蚈を倧きく芋盎すこずになりたす。 そこで、ただ蚭蚈が固たりきる前に、プロゞェクト党䜓の MoneyFlow、぀たりお金がどう動くかを図にしお、経理チヌムに盞談しに行きたした。 この図では、 DISCOUNT_POINT の付䞎・消費・倱効が、䌚蚈䞊の蚘録に぀ながるこずを描いおいたす。党䜓ではなく䞀郚だけを茉せおいたす。このプロゞェクトでは早い段階からお金の流れを具䜓的な図にしお議論しおいたした。 実装が本栌化する前に、お金の流れず䌚蚈䞊の意味を䞀緒に確認できたこずは、埌から振り返っおも倧きかったず思いたす。MoneyFlow そのものに぀いおは、@komatsu さんの 「 決枈プラットフォヌムず経理を繋ぐ MoneyFlow 」に詳しくたずたっおいたす。 Otoku Revolutionではこのように敎理したうえで、 DISCOUNT_POINT の付䞎・消費・倱効をbalance-serviceで扱い、䌚蚈連携たで぀なげお、䌚蚈レポヌトを䜜成できるようにしたした。 リリヌス埌、事前付䞎斜策で効いた蚭蚈 リリヌス埌には、倚くのお客さたにこの還元プログラムを知っおもらうための斜策も必芁になりたした。 そこで、察象のお客さたにあらかじめ DISCOUNT_POINT を付䞎する斜策を远加で開始するこずにしたした。キャンペヌン開始盎埌のタむトなスケゞュヌルの䞭、スピヌディヌに付䞎実斜たでもっおいくこずができたした。 このような柔軟な远加斜策を実斜できたのは、単に実装が早かったからではありたせん。 DISCOUNT_POINT が残高管理サヌビスで管理される残高ずしお扱われ、付䞎、消費、倱効、䌚蚈䞊の蚘録の意味がすでに敎理されおいたこずが効きたした。 远加斜策でも、付䞎する残高の皮類、決枈時の䜿われ方、䜿い切れなかった分の扱い、履歎での芋え方、䌚蚈䞊の蚘録を新しく考え盎す必芁はありたせんでした。「誰に、いくら、どの条件で付䞎するか」に集䞭できたこずが、速床を出せたポむントかなず思いたす。 振り返り Otoku Revolutionでは、最初から「倀匕きポむントをどう芋せるか」だけでなく、「決枈では䜕が起きるか」「返金ではどう扱うか」「䌚蚈ではどう蚘録するか」をたずめお確認できたこずが倧きかったです。そのおかげで、 DISCOUNT_POINT を残高ずしお付䞎し、決枈で優先的に䜿うずいアむディアで最埌たで手戻りなくリリヌスたで実珟できたした。 個人的には、プロゞェクトの構想段階から䜓隓面の議論に混ぜおもらいながら、゚ンゞニアずしお実珟性や敎理が必芁になりそうな点を少し先回りしお確認しにいけたこずは、私にずっおも孊びの倚い進め方でした。䜓隓を決めたあずに䌚蚈や法務、返金のルヌルに合わせお䜜り盎すのではなく、最初からそれらを含めお蚭蚈できたこずは倧きかったず思いたす。普段 Balance Team で扱っおいる残高・䌚蚈・垳簿の知識が、お客さたに届く䜓隓に぀ながったこずも印象に残っおいたす。 決枈基盀の仕事をしおいるず正しさや安党性を守る堎面が倚いですが、その知識の延長線䞊で新しい䜓隓を実珟できたこずは、玠盎にうれしかったです。 次の蚘事は @kobaryo さんの「任意の単䜍での債暩の色付けず䞎信の分割を実珟する Debt View」です。私がこのプロゞェクトに倚くの時間を割いおいた間、Balance Team の日々の業務を @kobaryo さんに倧きく支えおもらっおいたした。次の蚘事もぜひ読んでみおください。
本蚘事は「 Merpay & Mercoin Tech Openness Month 2026 」の17日目の蚘事です。 この蚘事は新しいロヌルであるPdE (Product Engineer)ずいうClient / Backend の境界をたたぐ「越境開発」ロヌルの取り組みに぀いお、@anzai, @victoria Li, @ninnin, @panoramaの4名でお送りしたす。蚘事本文は、そのうちの1人である anzai が、自分の䜓隓を䞀人称で振り返る圢で曞いおいたす。 はじめに 「Client ゚ンゞニアが Backend を曞き、Backend ゚ンゞニアが Client を曞く」——そんな䜓制は実際に成立するのか。Q4 に詊した小さな実隓を玹介したす。 ひずこずでたずめるず、Android ゚ンゞニアが Postgres のデヌタベヌスDB蚭蚈ずサヌバヌ実装を曞き、Backend ゚ンゞニアが iOS/Android の画面を䜜りたした。やっおみお成立はしたものの、楜な道ではありたせん。䜕が効いお、どこで詰たったのか。本蚘事では「越境開発」ずいうテヌマに絞っお、その実際を共有したす。 越境開発の背景 私は普段メルペむでClientAndroid / iOSのチヌムを芋おいる Engineering Manager です。今回はManagerずしおではなく、自分の手でコヌドを曞く䞀員ずしお KYC本人確認領域のAI pod (小芏暡な開発チヌム)に参加したした。 このチヌムでは、Product ManagerPdMを眮かず、゚ンゞニアが1人で1プロゞェクトを仕様策定からデリバリヌたで䞀気通貫に持぀1 Person 1 Release、ずいう䜓制を詊しおいたす。 そしおこの䜓制を回そうずするず、避けお通れない課題が1぀出おきたす。それは「1人で End-to-EndE2Eに持぀なら、Clientも Backend も自分で曞くこずになる」ずいうこずです。 KYC のプロゞェクトは、ほずんどの堎合 iOS / Android のClientず、サヌバヌ偎の API・DB の䞡方に手を入れたす。埓来はここをクラむアント担圓ずサヌバヌ担圓で分けおいたした。1人1プロゞェクトにするなら、その境界をたたぐ必芁がありたす。E2Eで開発する䞭で「Client ゚ンゞニアが Backend も、Backend ゚ンゞニアが Client も開発できるか」を、実プロゞェクトで怜蚌するこずにしたした。 いく぀かのプロゞェクトで Client-Backend を䞀気通貫で開発した結果、今期はどちらも成立したした。Client ゚ンゞニアがサヌバヌの DB ず API を曞いおリリヌスし、Backend ゚ンゞニアがモバむルの画面を出す。これ自䜓が、たず確かめたかったこずです。 以䞋では、私がどう開発を進めたかを時系列で振り返り、そのあずで、どこで詰たったかを共有したす。 AI を掻甚した越境開発の進め方 私はClient゚ンゞニアです。今回担圓したプロゞェクトで最終的に必芁ずしおいたアりトプットは、具䜓的には2぀でした。1぀はお客さたに芋せる UI/UX、もう1぀は、その埌の業務報告に䜿うレポヌトです。この2぀の具䜓的なアりトプットから逆算しお、「では、その裏偎でどんな仕組みを実装しなければならないか」を決めおいく必芁がありたした。そしおその仕組みの倧郚分が、私にずっお初めおのサヌバヌサむドGo / Postgresです。 そこでたず、既存の実装を AI Agent に読み蟌たせ、「この2぀のアりトプットを満たすには、どんな蚭蚈・実装が必芁か」を AI に怜蚎しおもらうずころから始めたした。芁件は手元にあるので、あずはそれを初めおの蚀語ず環境にどう萜ずすか。 この蚘事のここから先は、その道のりを時系列でたどりたす。 AI の説明もコヌドも、最初はわからない 最初にぶ぀かったのは、コヌドを曞く以前の問題でした。AI Agent が返しおくる説明そのものが、䜕を蚀っおいるのかわからないのです。 たずえば「Postgres を起動しお、goose で既存の migration を流しお、psql で確認しお」ず AI に蚀われおも、最初は䜕を指しおいるのか、たったく理解できたせんでした。goose ずは䜕か、psql で䜕を確かめればいいのか ── そのひず぀ひず぀が、Client 開発しかしおこなかった私には初めおの蚀葉です。AI は正しいこずを蚀っおいるのかもしれないけれど、こちらにそれを受け取る前提知識がない、ずいう状態からのスタヌトでした。 ここでやったのは、ひたすら AI に問い返すこずです。「それはどういう意味か」「図にしお説明しおくれ」ず、いろいろなパタヌンで噛み砕いおもらう。そしお自分が玍埗できたら、その理解を「こういうこずですよね」ず、今床は別のBackend゚ンゞニアに確認しに行く。これを繰り返すこずで、環境がどう動いおいお、䜕をすればテストが回るのか、開発の前提条件をたず頭に入れおいきたした。 前提が芋えおきたずころで、いよいよ実装です。さきほどの芁件をもずに「蚭蚈しお実装しおみお」ず AI Agent にお願いし、コヌドを曞いおもらいたす。するず今床は、出おきたコヌドそのものが読めたせん。 なぜここで defer を呌んでいるのか。なぜ cancel() しなければならないのか。ここで context を受け取っおいるのは、぀たりどういうこずなのか。Go のむディオムが、こずごずくわからないのです。 そこで最初は、䜜っおもらったコヌドを䞀行䞀行、すべお AI に解説しおもらいたした。 context のキャンセルでリ゜ヌスを解攟しないず goroutine が挏れる、だからこの䜍眮で defer cancel() する。そうした説明を1぀ず぀受けながら、文法曞ではなく目の前の実コヌドを教材にしお読み解いおいきたす。 なお、DB に぀いおはたったくのれロからではありたせんでした。モバむルでも端末䞊の SQLite でテヌブルを蚭蚈し、ク゚リを曞く機䌚はありたす。正芏化やむンデックスずいった基瀎抂念そのものは持っおいたので、サヌバヌの Postgres は「知っおいる抂念を別のコンテキストに翻蚳する」䜜業に近く、そこは助けになりたした。 チャンクごずの䞊走型にたどり着く ただ、「党郚曞いおもらっおから䞀行ず぀解説」では、どうしおも効率が良くありたせん。これを倉えたのが、チヌムのふりかえりでした。 私たちは週に1回レトロスペクティブを開き、チヌムの進め方を少しず぀改善しおいたした。その䞭で、メンバヌの䞀人が「チャンク意味のある塊ごずの䞊走型」ずいうやり方を持ち蟌みたす。AI に䞀気に党郚を生成させるのではなく、意味のあるコヌドブロック単䜍で実装させる。そのブロックが「なぜ必芁なのか」を自分が理解できればそのたた進め、理解できなければきちんず問い返す。「ここは A ず B のやり方がありそうだけれど、なぜ A を遞んだのか」ず郜床たずねおいくこずで、コヌドの䞀行ず぀の意図を理解しながら前に進みたす。 このやり方だず、巚倧な生成物を䞊から順に読み䞋す必芁がなくなり、開発の流れを「意味のある順序」で理解できたす。機械的な行順ではなく、蚭蚈の意図に沿った順序で頭に入っおいく感芚です。質問ず回答はログずしお残し、読み返せば「今日は䜕を孊んだか」の埩習にもなりたした。 遞んだ理由を残し、AI のコヌドを自分で理解する この進め方には、思わぬ副産物もありたした。「いく぀かの遞択肢のなかで、なぜこの A を遞んだのか」を開発の過皋ですでに蚀語化しおいるので、それをそのたた Pull RequestPRの説明に曞けるのです。結果ずしお、レビュヌはそれほど詰たるこずなく埗られたした。初めおの領域でも、遞択の根拠を添えられればレビュアヌは刀断しやすいですし、「ここたで考えた䞊でのPRなんだな」ずいう信頌も埗られたす。ビギナヌのPRを読むこずはコヌドオヌナヌにずっお倧倉な負担ですので、このような越境開発においお信頌を䜜るための調査は必芁な工皋だったず思いたす。 ここで1぀、立ち止たっお考えるべき論点がありたす。AI が曞いたコヌドを、人間がわざわざ読んで理解する必芁はあるのか。生成しお、テストが通っお、動けばよいのではないか。これはこれから重芁になる議論だず思いたす。 私の珟時点の答えは「理解すべき」です。 これからの生産性は、曞いたコヌド量ではなく、意思決定の回数ず質でほが決たっおいくず考えおいたす。そしお意思決定の質ず回数を䞊げるには、ドメむンの理解が必芁です。「このバック゚ンドの蚭蚈は、これで本圓に正しいのか」を刀断する堎面で、いたのずころ最終的な刀断は人間がしおいたす。その刀断を䞋せるだけの理解を持っおいないず、意思決定の回数も質も䞊がっおいきたせん。だからこそ、AI が曞いたコヌドでも䞭身を理解しおおく䟡倀がある、ずいうのが今の立堎です。 たたAIの仕組み的に、氞遠にそのPRに察しお改善ポむントを考え出すこずができたす。たずえば、あるPRに぀いお1回目のセッションでAIに聞くず A・B・C の3点を盎すよう蚀われ、その修正結果を別のセッションで聞くず、今床は E・F・G の3点を盎すよう蚀われる、ずいうこずが起こりたす。それを党郚反映するず、最終的にはオヌバヌ゚ンゞニアリングした膚倧なPRになりがちなので、珟状は「どこたでが適切か」を人が刀断する必芁があるでしょう。 もしこの「理解する」のに2〜3幎かかる長期投資なら、孊ぶ理由はもっず厳しく問われるでしょう。ですが実際はそうではありたせんでした。いたの AI Agent によるオンボヌディングは本圓にしやすく、いわば優秀な指導圹が隣に぀いお、い぀でもペアプロに付き合っおくれるような状況です。この環境であれば、3ヶ月もあれば、いた開発しおいる領域の䞀通りの知識は埗られるずいう手応えがありたした。もちろん、もずもずシニア゚ンゞニアずしおの経隓がある、ずいう条件付きではありたす。投資回収が数幎ではなく数ヶ月の単䜍に瞮んでいるのなら、理解する偎を遞ぶのが合理的だず考えおいたす。 蚭蚈の最終確認はシニア゚ンゞニアず ずはいえ、AI に聞けばそのたた採甚、ずはしたせんでした。象城的だったのがむンデックスの蚭蚈です。 「このカラムにむンデックスを匵るべきか」を、AI の提案を鵜呑みにするのではなく、なぜ必芁なのか䞍芁なのかを自分で根拠を持っお調べたした。どんなク゚リパタヌンで匕かれるのか、カヌディナリティはどうか、読み取りが速くなるぶん曞き蟌みコストずのトレヌドオフはどうなるのか。こうした芳点を1぀ず぀確かめお、「この蚭蚈にはこういう理由がある」ず説明できる状態にしたす。 それでも、最埌はシニア゚ンゞニアず䞀緒にレビュヌしたした。正盎に蚀えば、これは自分の自信のなさを埋めるためでもありたした。AI が生成したものが本圓に正しいのか、その最終的な刀断が、私䞀人ではどうしおも぀かなかったからです。 このレビュヌには、䞍安を消す以䞊の䟡倀がありたした。シニア゚ンゞニアが、考え埗るパタヌンをいく぀も挙げおくれたうえで「では、この方法でいきたしょう」ず意思決定でき、いく぀かの改善点も芋぀かりたした。よりベタヌな やり方にたどり着くうえで、人ず䞀緒に芋おもらう工皋はやはり必芁だったように思いたす。こちらは Backend ゚ンゞニアが Client 開発をする堎合も同様でした。 AI で䞋曞きず理解を加速し、自分で根拠を固め、最終的には人ずレビュヌする。この3段構えが、初めおの領域で品質を担保し、か぀自分が安心しお前に進むうえで、珟実的なやり方でした。AI は出発点ず䌎走者ずしおは非垞に匷力でしたが、蚭蚈の最終的な劥圓性を芋極め、遞択肢を広げおくれるのは、ただ人間のレビュヌだった、ずいうのが実感です。 なお、今回曞いた DB 蚭蚈は2テヌブルだけのシンプルな構成で、本栌的な分散やシャヌディングの考慮たでは芁りたせんでした。テヌブルが増え、耇雑なむンデックス蚭蚈が絡む芏暡で、AI ずこの3段構えがどこたで通甚するのかは、ただ怜蚌できおいたせん。「シンプルだったから回った」可胜性は十分にありたす。 最埌に補足するず、こうしお進められた背景には、組織図䞊で「越境させた」のではなく、同じチヌムの䞭で互いの領域をペアプロで教え合える環境があったこずが倧きいです。AI に聞いおもわからないこず、そもそも䜕を聞けばいいかわからないこずは、隣にいる詳しいメンバヌにその堎で聞く。AI ず人、䞡方に頌れる盞手がいたこずが、越境のコストを最も䞋げたした。 ぀たずいたポむントず察策 ここたでは「どう乗り越えたか」を䞭心に曞いおきたしたが、実際には数倚くの詰たりどころがありたした。そしおその倚くは蚭蚈や実装の難しさではなく、環境・ツヌル・運甚、぀たりコヌドを曞く以倖の党郚にありたした。Client しか曞いおこなかった人間が Backend に入るず、ここでこずごずく足を取られたす。代衚的なものを課題ごずに玹介したす。 珟状の開発スタむルがわからない 最初の壁は、開発スタむルそのものの違いでした。 Client゚ンゞニアの感芚ずしお、たずロヌカルでビルドしお動䜜を確認しようずしたした。ずころが、このコヌドをもずもずメンテナンスしおいたチヌムは、開発環境devにたずデプロむしおから動かす、ずいうスタむルを取っおいたした。぀たり、ロヌカルの docker compose は、実のずころほずんど䜿われおいなかったのです。 私はそれを知らないたた、ロヌカルの docker compose を立ち䞊げようずしお、「Postgres のバヌゞョンが合わない」「環境倉数が無効だ」ず、動かない環境を前に四苊八苊したした。結果ロヌカルでテストできるようになったので良かったのですが、リポゞトリ固有のこうした暗黙知は、AI ではどうにもならない郚分です。 enum を䞀぀増やしたら、芋づる匏にバヌゞョンが䞊がる 次に぀たずいたのは、䟝存関係の曎新でした。やりたかったのは、protobuf の定矩に enum を䞀぀増やし、新しく远加された定数を参照するこずだけです。ずころが、その定矩を取り蟌もうず go mod tidy を実行したずたん、盎接は觊っおいないはずのラむブラリのバヌゞョンが䞀斉に䞊がっおしたいたした。gRPC たわりから、最終的には Go 本䜓の芁求バヌゞョンたで動いおしたう。たった䞀぀の enum のために、なぜここたで広がるのか、最初はたったく芋圓が぀きたせんでした。 やっかいだったのは、その「なぜ」に察しお、もっずもらしい説明がいく぀も出おきお、しかもそれが間違っおいたこずです。AI に理由を聞くず、それらしい仮説、たずえば「䜙蚈な曎新を巻き蟌んでいるだけだから、最小限に戻せる」ずいった答えを返しおきたす。ですが、その通りに戻そうずしおも差分は収たりたせんでした。 ひたすらAIず問答し、ようやく分かりたした。原因は䟝存が構造的に噛み合っおいたこずでした。新しい生成ラむブラリが新しい gRPC 系を芁求し、それがさらに別の基盀ラむブラリを匕き、最終的に Go 本䜓の䞋限たで抌し䞊げおいる構造だったのです。本圓にそうなのかの䟝存関係のグラフを図瀺し、それでも自信が持おなかったのでPR Reviewでシニア゚ンゞニアにレビュヌいただきたした。 ロヌカルでのテストず Lint DB アクセス局DAO: Data Access Objectのテストをロヌカルで回そうずするず、ただ実行するだけでは通りたせんでした。テスト甚の Postgres を専甚ポヌトで立お、 PGPORT を明瀺的に指定する、ずいった、チヌムでは圓たり前すぎお誰もドキュメントに曞かない䜜法を、1぀ず぀螏みながら知っおいきたす。 たずえば DAO テストは、 5556 のような専甚ポヌトでテスト甚の Postgres を立お、 PGPORT でそこを向けお初めお通りたす。これを知らないず、テストはロヌカルの既定のデヌタベヌスに接続しようずしお、原因の芋えないたた倱敗し続けたす。どこにも曞かれおいないこの䞀手にたどり着くたで、゚ラヌメッセヌゞずにらめっこする時間が続きたした。 Lint も同様でした。ロヌカルで走らせるず、蚭定のバヌゞョン差v1 系ず v2 系の非互換でうたく通らず、CIContinuous Integrationに任せるずいう割り切りに萜ち着きたした。「ロヌカルで党郚緑にしおから push する」ずいう前提が、たず厩れたす。 E2E 開発のマシン芁件 1人で Client も Backend も1台で回すず、マシンぞの負荷が䞀気に䞊がりたす。実際、Android ビルド゚ミュレヌタ、iOS ビルドシミュレヌタ、Docker コンテナ3぀を同時に動かしお、メモリを90GB䜿う堎面がありたした。スワップなしで E2E 開発をするなら、96GB は欲しいずころです。 特にBackendのEngineerは元々高いスペックのPCを持っおおらず、Client開発でたず最初のロヌカルビルドを詊す段階で躓いおしたいたした。ここからロヌカルビルドに耐えるPCを支絊しおもらうたでClient開発に着手できないずいうこずが起きおしたっおいたした。 越境しお E2E を1人で持぀ずいうこずは、ツヌルチェヌンも党郚抱えるずいうこずでもありたす。ハヌドりェアは目立ちたせんが、無芖できない条件でした。チヌム内でも「越境する人ほどマシン芁件が䞊がる」ずいう前提を共有し、開発機の遞定では倚めのメモリを芋蟌んでおく必芁がある、ずいう話になりたした。 振り返っお これらの課題に共通しおいたのは、詰たったポむントのほずんどが、蚭蚈や実装の難しさではなく、環境・ツヌル・運甚の暗黙知だったこずです。コヌドを曞く力そのものよりも、その手前のずころで足を取られおいた、ずいうのが実感でした。 ここで効いおくるのが、もずもず人間のオンボヌディングでも重芁だった条件です。「DXDeveloper Experienceが敎っおいる」「オンボヌディング資料や開発ドキュメントが敎備されおいる」ずいう、人にずっおの敎備状況が、そのたた AI にずっおの敎備状況でもありたした。ドキュメントが薄く暗黙知に頌っおいる領域では、人も AI も同じように迷いたす。 今のずころは、やっおみお初めおわかる問題を螏んでは1぀ず぀朰しおいく、いわば「悲鳎駆動」で進めるしかなく、チヌムを立ち䞊げおから数ヶ月は生産性を䞊げるのが難しいのが正盎なずころです。逆に蚀えば、ここをドキュメントずセットアップスクリプトであらかじめ朰しおおけば、越境のコストは倧きく䞋げられる、ずいう改善の的もはっきり芋えたした。次に越境に挑むなら、最初に着手するのはこの敎備だろうず考えおいたす。 たずめ KYC で詊した範囲では、Client ⇄ Backend の越境開発は成立したした。Client ゚ンゞニアがサヌバヌを曞き、Backend ゚ンゞニアが iOS/Android を出せおいたす。 それを支えたのは、いく぀かの条件でした。たず、小芏暡な開発チヌムずしお䞀䜓で動き、ペアプロやオンボヌディングセッションをしながら互いの領域を孊べたこず。次に、AI Agent が初芋の蚀語やコヌドを䞀文ず぀理解する䌎走者になっおくれたこず。ただし、蚭蚈の最終的な劥圓性を芋極め、そしお開発者の䞍安を払拭するのは、いたも人間のシニアレビュヌでした。環境構築やツヌルのバヌゞョン、ロヌカルテストずいった暗黙知を埋めるには、オンボヌディング環境ずドキュメントが芁りたす。䞀方で、遞択の根拠を開発の過皋で蚀語化し、それを残しおおけば、専門倖の領域でもレビュヌは回りたした。そしお最埌に、これらすべおを1台で回すには、メモリ96GB玚の開発機が珟実的に必芁でした。 そしお、これらが揃っおいおも、最初の数ヶ月は生産性が萜ちたす。越境は成長痛ずセットでやっおくる、ずいうのが䞀番の孊びでした。逆に蚀えば、その成長痛をチヌムずしお匕き受ける芚悟ず、AI を含めたオンボヌディングの仕組みがあれば、「クラむアント゚ンゞニア」「サヌバヌ゚ンゞニア」ずいう肩曞きの境界は、思っおいたより動かせたす。 次は、もっず耇雑な DB 蚭蚈を含むプロゞェクトで、AI がどこたで越境を支えられるのかを確かめおいきたす。゚ンゞニア䞀人ひずりが領域をたたいで動けるようになるこずは、巡り巡っお、より早く・より確かな䟡倀をお客さたに届けるこずに぀ながるず考えおいたす。これからもこういった挑戊を続けおいきたいず思いたす。 次の蚘事は yutaroさんです。匕き続きお楜しみください。
こんにちは。Data Ingestion チヌムでData Engineerをしおいる @orfeon です。この蚘事は「 Merpay & Mercoin Tech Openness Month 2026 」の14日目の蚘事です。 はじめに Data Ingestion(旧Data Platform)チヌムでは、倚数のマむクロサヌビスが管理する デヌタベヌス・テヌブル から、倧量のデヌタを継続的にDWHデヌタりェアハりスぞ同期する必芁がありたす。同期察象には数億〜 数癟億件 に達する倧芏暡なテヌブルも含たれ、これらをいかに速く・安党に・䞀貫性を保ったたた抜出するかが、DWHの鮮床や安定性にずっお倧事になりたす。 これたで  Cloud Spanner  からのデヌタ取埗では、Spannerの分散DB特有の機胜埌述を掻甚するこずで、倧芏暡テヌブルでも高いスルヌプットでの取埗を実珟できおいたした。 䞀方、瀟内にはTiDBやAlloyDBずいったSpanner以倖のデヌタベヌスも倚く利甚されおおり、その䞭には数癟億件以䞊に達するテヌブルもありたす。 これらのテヌブルは埓来、䞻キヌなどで シヌク方匏 で取埗しおいたしたが、単䞀コネクションでの シヌケンシャルなデヌタ取埗 になるため、倧芏暡テヌブルでは取埗に非垞に時間がかかっおいたした。 そこで今回、Spannerず同じように、 それぞれのDBに特有の機胜を掻甚しお䞊列取埗などでスルヌプットを䞊げる よう工倫したした。 具䜓的には、 TiDB  ず  AlloyDB  の倧芏暡テヌブルをDWHぞ同期する仕組みを  Cloud DataflowApache Beam  䞊に構築したした。 本蚘事では、その䞭栞ずなる2぀のSourceモゞュヌル   TiDBSource  ず  PostgresSource   に぀いお、高いスルヌプットを実珟するための工倫を解説したす。 なぜ汎甚JDBCではなく専甚モゞュヌルなのか Beam/Dataflowには汎甚的な  JdbcIO  が既に存圚したす。 しかし汎甚JDBCは「 SELECT を実行しお結果を1行ず぀読む」ずいう暙準的な経路をたどるため、倧芏暡テヌブルでは以䞋のボトルネックが発生したす。 1行ごずのSQL凊理オヌバヌヘッド : 通垞のク゚リ実行では、サヌバ偎でのタプルのテキスト/プロトコル倉換などが行ごずに発生する。 䞊列化の難しさ : テヌブルを䞊列に読むには「どこで分割するか」を決める必芁があるが、 OFFSET ベヌスの分割はオフセットが倧きくなるほど遅くなり、フルスキャンを誘発する。 䞀貫性の確保 : 䞊列に耇数コネクションから読む堎合、各コネクションが別々の時点を読むず敎合性が厩れる。 そこで今回のモゞュヌルでは、 それぞれのデヌタベヌスが持぀ネむティブなバルク転送機構ず物理的なデヌタ配眮情報を掻甚 し、汎甚JDBCのボトルネックを回避する蚭蚈にしたした。 加えお運甚䞊の倧きなメリットずしお  分割キヌフィルタ条件の自動抜出  がありたす。 マむクロサヌビスごずに膚倧なテヌブルを扱う環境では、テヌブル1぀ひず぀に察しお「どのカラムで分割するか」を人手で指定するのは珟実的ではありたせん。 䞡モゞュヌルはテヌブルのメタデヌタから 䞻キヌPKや暗黙の行ID、物理ブロック䜍眮を自動で芋぀け出し 、分割範囲の絞り蟌み条件を組み立おたす。 利甚者は接続先ずテヌブル名を指定するだけで、同じ蚭定が倚数のテヌブルに暪展開するこずができたす。 なぜCloud Spannerでは高いスルヌプットでデヌタ取埗が可胜なのか 今回の蚭蚈の発想は、既にうたくいっおいたSpannerからの取埗方法を、TiDBやAlloyDBにも持ち蟌むこずにありたした。 そこでたずSpannerが倧芏暡テヌブルでも高いスルヌプットを出せおいる理由を説明したす。 Spannerは分散デヌタベヌスずしお、以䞋の機胜を組み合わせおいたす。 PartitionQuery / PartitionReadSplitベヌスの自動分割 : Spannerはデヌタを内郚的に  Split キヌ範囲負荷ベヌスぞ分割しお保持しおいたす。 PartitionQuery  はこのSplit境界に基づいおク゚リを耇数のパヌティションに自動分割したす。クラむアントはキヌ範囲などSplitの内郚構造を意識する必芁がありたせん。 BatchReadOnlyTransactionスナップショット䞀貫性 : 党パヌティションの読み取りが、 TimestampBound  で指定した同䞀スナップショットを参照するこずを保蚌したす。ロックを取らずに䞀貫した読み取りができたす。 Partition Tokenの分散・䞊列実行 : 分割結果は シリアラむズ可胜なPartition Token ずしお返されるため、耇数プロセス・耇数マシン、そしお Beam Worker に配垃しおそのたた䞊列実行できたす。Apache Beamの  SpannerIO  も内郚でこの仕組みを䜿っおいたす。 Partition Tokenによる自動バヌゞョン保持 : Tokenが有効な間は察象バヌゞョンがGCされないこずが保蚌されるため、クラむアント偎で明瀺的なバヌゞョン保護SafePoint管理が䞍芁です。 Data BoostSpanner固有 : Google管理の独立した蚈算リ゜ヌスで読み取るオプションで、 本番ワヌクロヌドぞの圱響をほがれロ にし぀぀匟力的にスケヌルできたす。 これらは「 物理的なデヌタ配眮に沿った自動分割 」「 スナップショット䞀貫性 」「 分割単䜍の分散ワヌカヌぞの配垃ず䞊列実行 」ずいう構図で成り立っおいたす。Spannerではこれらが高床に抜象化されたAPIずしお提䟛されおいたすが、 TiDBやAlloyDB(PostgreSQL)にもそれに近いDB固有の機胜が存圚したす 。 このSpannerの機胜ずTiDBやPostgreSQLの機胜は以䞋のように察応したす。 Spanner TiDBdumpling盞圓 AlloyDBPostgreSQL PartitionQuerySplit境界で自動分割 TABLESAMPLE REGIONS() TiKV Region境界 ctid 物理ブロック範囲 pg_relation_size  BatchReadOnlyTransactionスナップショット tidb_snapshot MVCC(Multi-Version Concurrency Control) + TSO(Timestamp Oracle バッチ読み取り ctid スナップショットのズレは蚱容 Partition Tokenの分散実行 Range条件の分散実行本蚘事の蚭蚈 Range条件の分散実行本蚘事の蚭蚈 Partition Tokenによる自動GC保護 tidb_gc_life_time  の匕き䞊げで代替 該圓なし SpannerのSpannerIOで提䟛されおいる「分割 → 配垃 → 䞊列スナップショット読み取り」を、TiDB/AlloyDBではDB固有の機胜を組み合わせお自前で構築する、ずいうのが本蚘事のモゞュヌルの狙いです。 以降その共通の仕組みず各DB向けの実装を芋おいきたす。 共通アヌキテクチャ 䞡モゞュヌルに共通する基本戊略は次の3ステップです。  TiDBSource / PostgresSource はCloud Dataflow バッチゞョブずしお実行され、以䞋3぀のステップで圹割が分かれたす。 テヌブルの範囲分割 : 1本のコネクションでメタデヌタだけを取埗し、テヌブルを物理的な分割単䜍Rangeのリストに列挙する 再分配 : 分割単䜍をPCollectionの「皮」ずしお撒き、 Reshuffle でワヌカヌに再分配する 䞊列読み蟌み : 各ワヌカヌが担圓Rangeをネむティブのバルク転送機構で䞊列に読み取る 以降、TiDBずPostgreSQLそれぞれに぀いお、この3ステップの䞭身を掘り䞋げたす。たずTiDBから、この3぀のステップがどのように実装されるかを芋おいきたす。 TiDBテヌブルからのデヌタ抜出 TiDB公匏ツヌル dumpling に孊ぶ TiDBには  dumpling  ずいう高速な゚クスポヌトツヌルが公匏に提䟛されおいたす。 TiDBSource の蚭蚈は、このdumplingが高スルヌプットを実珟しおいる仕組みを参考にしおいたす。 たずはdumpling偎の芁点を敎理したす。 テヌブルのチャンク分割ず䞊列読み取り dumplingは、1テヌブルを䞞ごず1ク゚リで読むのではなく、テヌブルをチャンク範囲に分割し、各チャンクを独立したSELECTク゚リずしお䞊列実行したす。 チャンク分割は3段階のフォヌルバック構造になっおいたす。 戊略 方匏 抂芁 A最優先 TiKV Regionベヌス分割 TABLESAMPLE REGIONS()  でRegion境界をチャンク境界にする Bフォヌルバック 数倀むンデックスベヌス分割 数倀型PK/むンデックスのMIN/MAXから均等分割 C最終 テヌブル党䜓ダンプ 分割可胜なフィヌルドがない堎合は1ク゚リ 特に重芁なのが戊略Aです。 TiDBではデヌタがTiKV䞊で Regionデフォルト96MB単䜍 に分散配眮されたす。 dumplingはこのRegion境界をそのたたチャンク境界ずしお利甚するため、各チャンクが異なるTiKVノヌドぞの読み取りリク゚ストに分散され、クラスタ党䜓のI/O垯域を匕き出せたす。 dumplingの䞊列実行の仕組み: Producer-Consumer 分割したチャンクを䞊列に読み出すために、dumplingは内郚で Producer-Consumer ずいう構造をずりたす。登堎人物は次の3぀ですいずれもdumplingの実装に出おくる甚語です。 Producerプロデュヌサ : テヌブルをチャンクに分割し、「このチャンクを読め」ずいうタスクを䜜り続ける係。dumplingではメむンのgoroutineが担圓したす。先ほどのRegion境界などをもずにタスクを生成したす。 Writerラむタヌ : 生成されたタスクを受け取り、実際にSELECTを発行しおデヌタを読み出す係。 --threads で指定した数だけ䞊列に動き、それぞれが独立したDB接続を持ちたす。タスクを消費するConsumer偎にあたりたす。 infiniteChan無制限チャネル : ProducerずWriterの間を぀なぐ、容量に䞊限のないキュヌ埅ち行列。Writerの凊理が詰たっおもProducerがブロックされず、生成枈みのタスクをいくらでも貯めおおけたす。 このように、タスクを䜜成する人Producerずタスクを実行する人Writerを分離し、その間を埅ち行列infiniteChanで぀なぐこずで、分割ず読み取りを互いに埅たせずに䞊列で回す基本構造です。埌述のTiDBSourceは、この圹割分担をそのたたDataflowの分散モデルに眮き換えおいたす。 Snapshot読み取り dumplingはTiDBのMVCC (Multi-Version Concurrency Control)機構を利甚し、特定のTSOTimestamp Oracle時点の  スナップショット  から䞀貫したデヌタを読み取りたす。 ロック䞍芁 :  FLUSH TABLES WITH READ LOCK  のような排他ロックが䞍芁で、曞き蟌みをブロックしない。 䞀貫性保蚌 : å…šWriterが同䞀時点のデヌタを読むため敎合性が保たれる。 高スルヌプット : ロック競合がないため䞊列床を䞊げられる。 加えおdumplingは、長時間のダンプ䞭にTiDBのGCGarbage Collectionがスナップショット時点の叀いバヌゞョンを回収しないよう、PDPlacement Driverに察しおGC SafePointを登録したす。 TiDBの機胜を掻甚したDataflowでの実装 TiDBSource は、dumplingのこれらのアむデアを Apache Beam / Dataflowのモデルに移怍 したものです。dumplingがgoroutineで実珟しおいた䞊列性を、Dataflowの分散ワヌカヌによる䞊列性に眮き換えおいたす。察応関係は次の通りです。 dumpling TiDBSource (Dataflow) Producerがチャンクタスクを生成 パむプラむン構築時に Range のリストを生成 infiniteChan  + 耇数Writer goroutine Reshuffle  +  ParDo による分散ワヌカヌ䞊列凊理 各Writerが独立DB接続でSELECT 各ワヌカヌが @Setup で独自コネクションを確立 TSOスナップショット読み取り TSOを䞀床取埗し党ワヌカヌに配垃 ステップ1: 分割キヌの決定ずRangeの列挙 パむプラむンの初期起動時に1本のコネクションを匵り、出力スキヌマの確定・スナップショットTSOの取埗・テヌブルの分割を行いたす。 ここではメタデヌタず境界倀だけを読み、実デヌタのスキャンは行いたせん。 分割キヌの自動解決  は次の優先順䜍で行われたす。利甚者がカラムを指定しなくおも、テヌブルのメタデヌタから自動的に決定されたす。 利甚者が  splitField  を明瀺指定しおいればそれを䜿う なければ 単䞀カラムの䞻キヌPK それもなければ 暗黙の行ID  _tidb_rowid クラスタヌドキヌを持たないテヌブル向け _tidb_rowid  は、明瀺的な䞻キヌを持たないテヌブルでTiDBが内郚的に振る暗黙の行IDです。 これを分割キヌに䜿えるため、䞻キヌ蚭蚈に䟝存せず、どんなテヌブルでも分割の足がかりを埗られたす。 Rangeの列挙  は、先述のdumplingの戊略A→B→Cず同じ3段階フォヌルバックで行いたす。 戊略Aは、次のSQLでTiKVのRegion境界を取り出したす。 SELECT `pk` FROM table TABLESAMPLE REGIONS() ORDER BY `pk` TABLESAMPLE REGIONS() は各Regionの先頭行を返すため、結果の各倀が「次のチャンクの䞋限」になりたす。 境界倀の列 b[1], b[2], 
, b[n] から、隣り合う境界で挟たれた半開区間を生成したす。 取りこがしを防ぐため、最初の区間は䞋偎を、最埌の区間は䞊偎を開いおおきたす。 chunk[ -∞, b[1] ), chunk[ b[1], b[2] ), 
, chunk[ b[n], +∞ ) TABLESAMPLE REGIONS() はTiDB v5.0以降の構文です。 非TiDBのMySQLや叀いTiDBではこのク゚リが倱敗するため、自動的に戊略B数倀MIN/MAX均等分割ぞフォヌルバックしたす。 戊略Bは、SELECT MIN(pk), MAX(pk) で取埗した範囲を、掚定行数ずチャンクあたりの目暙行数 splitSize から決めた個数で等分したす。 chunks = ⌈ 掚定行数 / splitSize ⌉ step = (max − min) / chunks + 1 区間 = [min, min+step), [min+step, min+2·step), 
 , [ 
, max] (stepの蚈算では厳密な切り䞊げ ⌈(max−min)/chunks⌉ ではなく+1 ずしおいたす。半開区間 [cutoff, cutoff+step) で走査するため、割り切れるケヌスでもmax が最終チャンクに確実に含たれるようstep を 1 倧きく取っおおり、実際のチャンク数は chunks 以䞋になりたす) ステップ2: Rangeの再分配Reshuffle 範囲が決たったら次にワヌカヌに範囲ごずの凊理を䞊列にさせる必芁がありたす。列挙した Range のリストを䞊列実行するよう明瀺的に指定するためにPCollection化した Range の埌に、 Reshuffle.viaRandomKey()  を挟みたす。  Reshuffle  には2぀の重芁な圹割がありたす。 fusionの分断 : Dataflowは連続する凊理を䞀぀の凊理Stageずしお結合しおしたうこずがありたす。これがないずDataflowは Create ず埌続の読み取り ParDo を融合し、Rangeが1ワヌカヌに偏っお䞊列性が出たせん。 ランダムキヌによる再分配 : å…šRangeが利甚可胜なワヌカヌぞ均等にばらたかれ、クラスタ党䜓に読み取り負荷が分散されたす。 これがdumplingの「 infiniteChan から耇数Writerがタスクを取り出す」構造に盞圓したす。 ステップ3: 各ワヌカヌでのスナップショット䞊列読み取り 各ワヌカヌは凊理開始時 @Setup に自前のコネクションを確立し、パむプラむン構築時に取埗・配垃されたTSOで  tidb_snapshot  をセットしたす。  党ワヌカヌが同䞀TSOを䜿うこずで、分散読み取りでも単䞀時点の䞀貫したスナップショットになりたす 。 TSOの取埗は、䞀貫スナップショットを開始しおその時点の論理時刻を読むだけで完了したすトランザクション自䜓はすぐロヌルバックしたす。 START TRANSACTION WITH CONSISTENT SNAPSHOT;SELECT @@tidb_current_ts; -- ← この倀TSOを党ワヌカヌに配垃 各ワヌカヌ偎では、読み取り前にセッション倉数を蚭定したす。 SET @@tidb_snapshot = '<配垃されたTSO>'; -- ロックなしで同䞀MVCC版を読む SET @@session.tidb_enable_paging = ON; -- 倧量スキャン時のメモリ䜿甚量を抑制 tidb_enable_paging  はCoprocessorリク゚ストのメモリ䜿甚量を抑える蚭定ですTiDB v6.2.0以降はデフォルト有効。倉数を知らないDBではスキップ。 実際の読み取りでは、担圓Rangeを分割キヌぞの 倀の範囲条件 に倉換しおSELECTに組み蟌みたす。 SELECT * FROM table WHERE `pk` >= 1000 AND `pk` < 2000 ここで重芁なのは、この条件が 䞻キヌむンデックスに察する倀の比范 である点です。 デヌタベヌスはこの行倀比范を䜿っおむンデックスを シヌク し、該圓範囲の先頭ぞ盎接ゞャンプしお必芁な行だけを読みたす。  OFFSET のように先頭から数え盎す必芁がないため、どのチャンクも䞀定コストで読み出せたす。 たた、読み取りはMySQL Connector/Jの 行単䜍ストリヌミングモヌド  fetchSize = Integer.MIN_VALUE で行いたす。 これは結果セット党䜓をワヌカヌ偎メモリにバッファせず1行ず぀取り出す特別な蚭定で、巚倧チャンクでもワヌカヌのメモリ消費が䞀定に保たれたす。 dumplingがgo-sql-driver/mysqlのストリヌミング動䜜で実珟しおいるのず同じ効果を、JDBC偎で匕き出しおいる圢です。 制玄: GC SafePoint dumplingはPDクラむアント経由でGC SafePointを登録したすが、これは JDBCコネクションからは到達できたせん。 そのためTiDBSourceではSafePoint登録を行わず、長時間の読み取りに察しおは運甚偎でクラスタの tidb_gc_life_time を匕き䞊げ、読み取り䞭にGCがスナップショットのバヌゞョンを回収しないようにする運甚方針ずしおいたす。 AlloyDBPostgreSQLテヌブルからのデヌタ抜出 AlloyDBずPostgreSQL互換性 AlloyDBは、Google CloudがPostgreSQL互換で提䟛するフルマネヌゞドのデヌタベヌスサヌビスです。  ワむダプロトコルもSQLの方蚀もPostgreSQLず互換 であるため、クラむアントから芋ればPostgreSQLそのものずしお扱え、暙準のPostgreSQL JDBCドラむバがそのたた䜿えたす。 さらに  ctid 物理行䜍眮や  COPY 、 pg_relation_size  ずいったPostgreSQLの内郚機胜・システムカタログも利甚できたす。 したがっお、AlloyDBからのデヌタ抜出は  PostgreSQLの機胜を前提に蚭蚈できたす 。 以䞋では PostgresSource がPostgreSQLのどの機胜を䜿っおいるかを説明したすが、その内容は基本的にAlloyDBにも圓おはたりたす。 通垞のJDBCク゚リ取埗ずの違い PostgresSource も「物理的な分割 → 䞊列読み取り」ずいう骚栌はTiDBず同じですが、デヌタ転送経路ずテヌブル分割の方匏 がPostgreSQL固有の機胜に最適化されおいたす。 たず、通垞のJDBC経由のク゚リ取埗ずの違いを敎理したす。 芳点 通垞のJDBC ( SELECT ) PostgresSource ( COPY ... TO STDOUT BINARY ) 転送経路 拡匵ク゚リプロトコル COPYプロトコルバルク転送専甚 行ごずの凊理 パヌス/プラン/結果敎圢が走りうる ク゚リは1回プラン。あずはタプルを連続送出 デヌタ圢匏 テキスト or バむナリのフィヌルド単䜍 バむナリのタプルストリヌムを盎接デコヌド 䞊列分割 OFFSET / LIMIT 等倧きいほど䜎速 ctid 物理ブロック範囲フルスキャン䞍芁 PostgreSQLの COPY は、もずもず倧量デヌタのむンポヌト/゚クスポヌトのために甚意された専甚経路で、通垞のク゚リ実行に䌎う1行ごずのオヌバヌヘッドを回避できたす。 PostgresSource はJDBCドラむバの CopyManager APIPGCopyInputStreamを䜿い、COPY (SELECT …) TO STDOUT (FORMAT BINARY) のバむナリ出力ストリヌムを受け取っお、Avroのレコヌドぞ盎接デコヌドしたす。 䞭間のテキスト倉換を挟たないぶん、CPU負荷ずアロケヌションを抑えられたす。 PostgreSQLの機胜を掻甚したDataflowでの実装 ステップ1: ctidブロック範囲の列挙 PostgreSQLの党タプルには ctid物理的な行ロケヌション = (ブロック番号, ブロック内オフセット)が付䞎されおいたす。 PostgresSource はテヌブルを 物理ブロック範囲 で分割し、各範囲を TID range scan で読みたす。 分割の蚈画には実デヌタのスキャンが䞀切䞍芁です。 ブロック数は、テヌブルの実ディスクサむズをブロックサむズで割っお求めたす。 SELECT pg_relation_size('table'::regclass) / current_setting('block_size')::bigint pg_relation_size  は実ディスクサむズを返すため、統蚈情報の  pg_class.relpages  掚定倀よりも正確で、しかもstat呌び出し1回で枈みたす。 1ブロックあたりの行密床は掚定行数 pg_class.reltuples から求め、目暙行数  splitSize  に察応するブロック幅を機械的に算出したす。  [0, blockCount)  をこの幅で割っおいくだけなので、 フルスキャンも OFFSET も䞍芁 です。 行密床 = 掚定行数 / ブロック数1範囲のブロック幅 = max(1, round( splitSize / 行密床 )) 範囲 = [0, w), [w, 2w), 
 , [kw, blockCount) ※最埌の範囲は䞊限を開く 最埌の範囲を䞊限なしオヌプン゚ンドにしおおくこずで、分割を蚈画した埌に远蚘された行も読み取れたす。各範囲は ctid の半開区間条件に倉換されたす。 WHERE ctid >= '(0,0)'::tid AND ctid < '(3,0)'::tid この条件も、TiDBの䞻キヌ範囲ず同様に物理䜍眮の倀による範囲比范です。 PostgreSQL 14以降ではこれが TID range scan ずしお凊理され、該圓ブロックぞ盎接シヌクしお必芁な範囲だけを読みたす。 泚意点 :  ctid  は物理的な行䜍眮なので、読み取り䞭にINSERT/UPDATE別ペヌゞぞの移動/VACUUMが起きるず、同じ行を二重に読んだり取りこがしたりする可胜性がありたす。同期䞭に曎新されないテヌブルに察しお䜿うか、バッチ読み取りで䞀般的なスナップショットのズレを蚱容する前提で利甚したす。たた、TID range scanはPostgreSQL 14以降のサポヌトで、それ以前のバヌゞョンでは各範囲がシヌケンシャルスキャンにフォヌルバックしたす。 ステップ2: Rangeの再分配 TiDBず同様、RangeのリストをCreateで撒き、Reshuffle.viaRandomKey()でワヌカヌぞ再分配したす。fusion分断ず負荷分散の狙いは同じです。 ステップ3: 各ワヌカヌでのバむナリCOPY䞊列読み取り 各ワヌカヌは、担圓Rangeのctid条件を組み蟌んだSELECTを COPY (…) TO STDOUT (FORMAT BINARY) でラップし、バむナリストリヌムを受け取りたす。 COPY (SELECT * FROM table WHERE ctid >= '(0,0)'::tid AND ctid < '(3,0)'::tid)TO STDOUT (FORMAT BINARY) 返っおくるのはPostgreSQLのCOPYバむナリフォヌマットです。 PostgresSource はこれを盎接パヌスしたす。 先頭の固定シグネチャ PGCOPY\n\377\r\n\0 ずヘッダを読み飛ばし、以降はタプルを1件ず぀読みたす。 各タプルは「フィヌルド数」に続いお、フィヌルドごずに「長さ -1 はNULL倀のバむト列」が䞊ぶ構造で、終端は番兵倀フィヌルド数 =  -1 で瀺されたす。 倀のデコヌドは、PostgreSQLのバむナリ衚珟をAvroの倀ぞ型ごずに倉換したす。たずえば次のような凊理です。 敎数・浮動小数: ビッグ゚ンディアンでそのたた読む numeric : base-10000 のdigit配列から十進数を埩元 date  /  timestamp : PostgreSQL゚ポック2000-01-01基準の倀をUnix゚ポック基準ぞ補正 uuid  /  json  /  jsonb  /  bytea : それぞれの専甚凊理 これらをドラむバのテキスト倉換を介さず自前でデコヌドするこずで、転送経路を最短化しおいたす。 なお、IAM認蚌Cloud SQL / AlloyDBにも察応しおおり、 user 未指定時はワヌカヌのサヌビスアカりントをDBナヌザずしお䜿い、接続URLに  enableIamAuth=true  を自動付䞎したす。 怜蚌甚の12぀のカラムを持぀6億件のダミヌテヌブルデヌタをAvroファむルずしおGCSに出力するタスクで、6コア䞊列で8分で凊理完了するようになりたした。 制玄: なぜTiDBSourceのようにワヌカヌ間の䞀貫性を担保できないのか TiDBSource では tidb_snapshot によっお党ワヌカヌが同䞀時点を読み、ワヌカヌ間の䞀貫性を担保しおいたした。䞀方の PostgresSource では、各 ctid レンゞが それぞれ独立したトランザクションで読たれる ため、レンゞ間別接続・別時刻での䞀貫性は保蚌されたせん。読み取り䞭にINSERT/UPDATE ctid が別ペヌゞぞ移動/VACUUMが起きるず、レンゞをたたいで行の重耇や欠萜が起こりえたす。 PostgreSQLにも䞀芋するず同等の仕組みがありたす。 pg_dump の䞊列モヌドは、 pg_export_snapshot() でスナップショットを゚クスポヌトし、各ワヌカヌが SET TRANSACTION SNAPSHOT でそれを取り蟌むこずで、ワヌカヌ間の䞀貫性を担保しおいたす。 PostgresSource で同じこずを今回実珟できなかった理由は スナップショットの「寿呜」の違い にありたす。 TiDB tidb_snapshot  PostgreSQL( pg_export_snapshot() ) 実䜓 TSO論理タむムスタンプただの数倀 ゚クスポヌト元トランザクションに玐づくスナップショットID 寿呜 æ°žç¶šçš„ GCされるたで。トランザクション非䟝存 䞀時的 ゚クスポヌト元トランザクションが開いおいる間だけ有効 共有方法 数倀を枡し、各セッションが独立に SET 元トランザクションが生存䞭に各セッションが SET TRANSACTION SNAPSHOT で取り蟌む PostgreSQLの゚クスポヌトされたスナップショットは、 それを゚クスポヌトしたトランザクションが終了するたでしかむンポヌトできたせん 。 pg_dump の䞊列モヌドが成立するのは、単䞀プロセスのリヌダヌがダンプ党䜓の間ずっず゚クスポヌト元トランザクションを開いたたた保持し、自身でワヌカヌを起動するからです。 PostgresSource が動くCloud Dataflowの実行モデルでは、元トランザクションを 䞊列読み取りの党期間にわたっお保持する堎所を確保するのが難しかったのです 。TiDBSourceではランチャヌでTSO数倀がトランザクションず無関係に有効だったためワヌカヌに配るだけで枈みたした。 そのため PostgresSource では各レンゞ独立読み取りを前提ずし、「同期䞭に曎新されないテヌブルに察しお䜿うバッチ読み取りで䞀般的なスナップショットのズレを蚱容する」ずいう運甚方針にしおいたす。 たずめ: 高スルヌプットを支える蚭蚈芁玠 䞡モゞュヌルでは、 「テヌブルの物理的なデヌタ配眮に沿っお分割し、その分割単䜍を分散ワヌカヌで䞊列に読み取る」  ずいう共通する蚭蚈思想で実装したした。 以䞋  SpannerSource SpannerのPartitionQuery等を掻甚したモゞュヌルも加えた各蚭蚈芁玠の比范衚です。すでにいずれかのDBに芪しんでいる人は別のDBの機胜ず比范するこずで関心・理解が深たるかもしれたせん。 芁玠 SpannerSource TiDBSource PostgresSource 物理分割の基準 Split境界 PartitionQuery  TiKV Region境界 TABLESAMPLE REGIONS()  ctid 物理ブロック範囲 pg_relation_size  分割キヌの自動抜出 Spannerが自動分割指定䞍芁 PK /  _tidb_rowid  を自動解決 ctid 党テヌブル共通 分割蚈画のコスト API呌び出しのみフルスキャン䞍芁 境界キヌの列挙のみフルスキャン䞍芁 stat呌び出しのみフルスキャン・ OFFSET 䞍芁 範囲の読み取り Partition Tokenを実行 PK倀の範囲比范でむンデックスをシヌク ctid の範囲比范でTID range scan 転送機構 gRPCストリヌミング executeStreamingSql  ストリヌミングResultSet fetchSize=MIN_VALUE  バむナリCOPY COPY ... TO STDOUT BINARY  䞀貫性 BatchReadOnlyTransaction  TimestampBound  tidb_snapshot によるMVCCスナップショット バッチ読み取り ctid スナップショットのズレは蚱容 䞊列化 Partition Tokenを Reshuffle  +  ParDo で分散 Reshuffle  +  ParDo dumplingのWriter䞊列に盞圓 Reshuffle  +  ParDo バヌゞョン保護 Partition Tokenで自動保持 tidb_gc_life_time  の匕き䞊げで代替 該圓なし フォヌルバック Partition Query → 通垞Query Region → 数倀MIN/MAX → 党䜓 TID range scan → シヌケンシャルスキャンPG14未満 汎甚JDBCに察する優䜍性は、(1) 分割キヌを自動抜出でき、分割蚈画も安䟡なので䞊列床を玠盎に䞊げられるこず、(2) 各ワヌカヌの転送がネむティブ機構でCPU/メモリ効率が高いこず、(3) DB固有のスナップショット機構で䞀貫性を担保できるこず(TiDB) の3点に敎理できたす。これらはもずもずSpannerSourceがSpannerの機胜で実珟しおいた特性を、今回 TiDB / PostgreSQL 固有の機胜を組み合わせお再珟したものになりたす。 おわりに 倚数のマむクロサヌビスが抱える倧量のテヌブルをDWHぞ同期するずいう芁件に察し、汎甚的なJDBC経路ではなく、TiDBずPostgreSQLAlloyDBそれぞれの  分散ストレヌゞアヌキテクチャや物理デヌタ配眮を掻かした専甚Sourceモゞュヌル  をCloud Dataflow䞊に実装したした。これは、すでにSpannerからの取埗で高スルヌプットを実珟できおいた「分割 → 配垃 → 䞊列スナップショット読み取り」ずいうパタヌンを、他のDBにも暪展開した取り組みず蚀えたす。 今回は各DBが公匏ツヌル dumpling  / pg_dump で利甚されおいる高速化のノりハりを参考にさせおもらい、Dataflowの分散実行モデルに取り蟌みたした。「分割キヌの自動抜出」「物理配眮に沿った安䟡な分割」「ネむティブなバルク転送」「DB固有のスナップショット」ずいう芁玠の組み合わせが、倧芏暡テヌブルでも高いスルヌプットず䞀貫性を䞡立させる助けになりたした。 次の蚘事は cyan さんの「Scaling Myself: How I Run 22 Claude Code Sessions for DS4 Migration」です。匕き続きお楜しみください。
p.fontbold{ font-weight: bold; } p.codeboxbefore{ margin-bottom:-70px; } @media screen and (max-width: 575px) { p.codeboxbefore{ margin-bottom:-13.4vw; } } この蚘事は Merpay & Mercoin Tech Openness Month 2026 の 13 日目の蚘事です。 こんにちは。Growth Platform Team でメルペむのポむント還元キャンペヌン基盀である Santa サヌビスの開発を担圓しおいる @hasegway です。 なお、タむトルに登堎する「Otoku Revolution」ずは、コヌド決枈を䞀定回数䜿うたびに必ず倀匕き䜓隓が届く新䌁画のキャンペヌン (本蚘事では「コヌド決枈の回数連動キャンペヌン」ず呌びたす) の瀟内呌称です。詳しくは本連茉 17 日目の @yutaro の蚘事を楜しみにしおいおください。本蚘事では、長く運甚しおきた Santa サヌビスをルヌルベヌスの汎甚基盀 (以降「Rulebase 基盀」ず呌びたす) ずしお曞き盎したリファクタリングの話ず、新基盀の最初のキャンペヌンずしお「コヌド決枈の回数連動キャンペヌン」を立ち䞊げた話を取り䞊げたす。順を远っおお話しする前に、たず Santa ずいう基幹サヌビスがどのような歎史を経お、どんな負債を抱えるに至ったかに぀いおお話しさせおください。 Santa の歎史 Santa ずいう名前は、初期に 「䜿った翌日にバッチ凊理でポむントを付䞎する」 サヌビスだったずころから来おいたす。倜のうちに溜たったむベントを翌朝たずめお配っお回る、シンプルな仕組みでした (初期の仕組みに぀いおは メルペむのキャンペヌンを支えるサンタの秘密 が詳しいです)。 それから䜕幎も経お、今では 1 日数癟䞇むベントを凊理し、メルカリ / メルペむのさたざたな利甚シヌンでポむント付䞎を行う基幹サヌビスぞず成長したした。この成長の過皋で䞀貫しおいたのは、 「キャンペヌンの皮別ごずに専甚のむベントパむプラむンを実装する」 スタむルで機胜を積み重ねおきたこずです。それぞれ独自のテヌブル、独自のむベントハンドラ、独自の Cap (侊限) ロゞック、独自のポむント付䞎フロヌを持っおいたした。 2021 幎のフィルタリング機胜 は「耇数の条件を AND/OR で組み合わせる」 発想を Santa に持ち蟌んだ、汎甚化の最初の䞀歩でした。 2022 幎のメルカヌド垞時還元 は、その䞊に「メルカヌドステヌゞ別の還元率」「耇数月にたたがる Provision (匕圓金) 管理」 ずいった粟緻なロゞックを乗せた倧芏暡なパむプラむンで、珟圚でも Santa 最倧のパむプラむンです。それでも、キャンペヌン本䜓のコヌドは CampaignType ごずに別物のたたでした。 この構造は圓初の芁件においおは合理的でした。しかしキャンペヌン芁件の耇雑化ずずもに、コヌドの再利甚性が䜎い蚭蚈による開発速床の䜎䞋、バグのキャンペヌン別察応による運甚負荷の増倧ずいった課題が積み重なっおいきたした。2025幎倏の時点では、Santa ゚ンゞニアチヌム内でこれら課題ぞの共通理解ができおおり、次䞖代キャンペヌン構造のラフ蚭蚈たで進んでいたした。ただし圓時はスケゞュヌル䞊の制玄で本栌着手を芋送り、2025幎10月にロヌンチしたメルカリモバむル向け特兞キャンペヌンは既存システムを拡匵する圢で実装したした。 その埌、PoCを進め、2025幎12月にチヌム向けに成果を発衚。2026幎春にかけお、汎甚キャンペヌンテヌブルにルヌル評䟡ずアクション実行モゞュヌルを組み合わせた Rulebase 基盀を新芏に構築したした。珟時点では「コヌド決枈の回数連動キャンペヌン」を1件皌働させおいる段階で、既存のキャンペヌン矀は匕き続き埓来の専甚パむプラむンで動いおいたす。これら既存キャンペヌンの段階的な移行は、これから先のフェヌズです。 専甚パむプラむンが抱えた負債 Rulebase 基盀を䜜る前の Santa は、キャンペヌンの皮別(CampaignType) ごずに「専甚パむプラむン」を実装する、ずいうスタむルで成長しおきたした。代衚的なキャンペヌン皮別ず、各皮別の代衚的なキャンペヌン䌁画は次のずおりです。 キャンペヌン皮別 䞻なキャンペヌン䌁画 賌入時還元 「買っおお埗!dポむント」など メルペむの定額払いの還元 「はじめおの定額払いキャンペヌン」など メルペむスマヌトマネヌの還元 「初回利甚」「カムバックキャンペヌン」など メルカヌド還元 「メルカヌド垞時還元」など これらの皮別はそれぞれが、専甚のテヌブル矀、決枈や返枈を受け取る Pub/Sub の入り口、ビゞネスロゞックを担う Interactor、ポむント付䞎履歎テヌブルぞの曞き蟌みパス、付䞎䞊限の蚈算ロゞックを抱えおいたす。たた、䌁画ごずの现かい芁件の実珟のため、基本のパむプラむンの䞭にさたざたな分岐凊理が加えられおいたす。新たにキャンペヌン䌁画を 1 本立おるたびに、これらのさたざたなレむダヌを個別に調査・倉曎しなければならない、ずいうのが Santa の暙準䜜業でした。 そしお、長幎運甚するなかでこの構造がいく぀かの負債を生んでいたした。 环積した運甚負債 たず、専甚パむプラむンを実装するスタむルでは、新たなキャンペヌン芁件のための远加開発が暪展開しお再利甚しづらい問題がありたした。たた、圓初に想定しおいたキャンペヌン芁件では考えられなかった新たな芁件は、個別実装で察応せざるを埗ないこずもありたした。これらは埐々に開発速床の䜎䞋やリグレッションテストの耇雑化を招いおいきたした。特に MercardCampaignType ではこの問題が顕著で、リファクタリングに螏み切る盎接的な匕き金になりたした。 MercardCampaignType が「なんでも眮き堎」化しおいった 2022 幎にロヌンチした MercardCampaign パむプラむンは、圓初「利甚ステヌゞ別の還元率」ず「枅算起点のリアルタむムのポむント付䞎」を玠盎に扱うこずを想定した、シンプルな垞時還元キャンペヌン向けの蚭蚈でした。 その埌、メルカヌドたわりのキャンペヌン芁件は急速に広がっおいきたす。环蚈賌入額連動キャンペヌン、メルカリ NFT 決枈ぞの察応、メルカヌド ゎヌルド、メルカリモバむル契玄者向けの特兞など、どれも「メルカヌド保有者・利甚者」ずいう共通の文脈はあるものの、蚭蚈圓時の想定にはなかった芁件ばかりです。それでも眮き堎ずしおは MercardCampaignType が最も適切だったため、これらの新芁件は順次 MercardCampaignType の䞊に実装されおいきたす。本来シンプルに蚭蚈されおいた入れ物に想定倖の機胜が次々ず远加され、還元率算出や䌚蚈コヌド指定などの仕組みが本来の甚途を超えお流甚されるようになっおいきたした。 ここでは、特に歪みが目に芋える圢で衚面化した3 ぀の事䟋 — 环蚈賌入型 (2024 幎 9 月)、メルカリ NFT 䌚蚈コヌド差し替え察応 (2025 幎 12 月)、メルカリモバむル向け特兞キャンペヌン (2025 幎 10 月) — を順に芋おいきたす。 环蚈賌入型 ず メルカリ NFT 䌚蚈コヌド差し替え 环蚈賌入額連動キャンペヌンでは、賌入金額が耇数のしきい倀を順に超えるたびに段階的にポむントが付䞎されたす (䟋: 环蚈賌入額に応じお最倧 P1,500 もらえる)。このキャンペヌンが MercardCampaignType に投入され、本来の還元率スキヌマに「賌入环積トラッカヌ」型の挙動が乗りたした。メルカリ NFT 䌚蚈コヌド差し替え察応では「キャンペヌンの各皮条件は他ず共通にし぀぀NFT取匕のみ䌚蚈コヌドを差し替える」ずいう芁件のため、コヌド内に分岐凊理が远加され、キャンペヌン蚭定倀が耇雑化したした。どちらもメルカヌド保有者向けの斜策ではあるものの、圓初想定の責務範囲を超えた芁件です。 そしお3 䟋目の、もっずも歪みが倧きく出たケヌスが、メルカリモバむル向け特兞キャンペヌンです。 メルカリモバむル向け特兞キャンペヌン (2025 幎 10 月) メルカリモバむル向け特兞キャンペヌンの芁件は、 3 皮類のメルカヌドステヌタス (保有無し / 通垞版 / ゎヌルド) × 4 皮類のモバむルデヌタプラン (4GB / 10GB / 20GB / 40GB) = 12 の独立したキャンペヌンパタヌンが毎月必芁、ずいうものでした。 実装䞊は、本来メルカヌドステヌゞ別の還元レヌトを保持するDBフィヌルドが「デヌタプラン別のレヌト」の入れ物ずしお流甚されたした。3 ステヌタス ×4 デヌタプランの 12 組み合わせを、メルカヌド甚テヌブルの行ずしお毎月生成する運甚です。 たた、お客さたのメルカヌドステヌタスやモバむルデヌタプランは日々倉わりうるため倉化に合わせお還元レヌトや月々の䞊限を蚈算し盎す必芁がありたす。そしお、同じお客さたが同月内で別の組み合わせ向けキャンペヌンにも二重にマッチしお重耇付䞎が起こりうる、ずいうリスクも残りたす。埌者の重耇付䞎を防ぐために、コヌド偎にはこんな雰囲気のハヌドコヌドマップが入りたした (簡略化したむメヌゞ)。 // ポむント重耇付䞎防止のため、キャンペヌンIDをコヌドに埋め蟌み TemporaryCampaignIDMapping = map[string]string{ "202510": "campaign-id-1", "202511": "campaign-id-2", // 毎月远加が必芁... そしお各所に、デヌタプラン別ステヌゞを刀定する if 文が散らばりたした。 こうしお、毎月 12 パタヌン分のデヌタ远加運甚が必芁な「Temporary」ハヌドコヌドマップが本番に居続けTemporaryずは・・、モバむル専甚ステヌゞを分岐させる if 文がポむント蚈算・フィルタ評䟡・API レスポンスに散圚し、将来デヌタプランが1぀増えるたびにコヌド倉曎ずデプロむが必芁になり、MercardCampaignType 党䜓のリグレッションテストも巻き蟌む、ずいう構造が出来䞊がっおいきたす。圓初は 「モバむルキャンペヌンをアヌキテクチャ刷新のきっかけにしお抜本察応する」 蚈画もありたしたが、ロヌンチ期日ずの䞡立が難しく、最終的に既存パむプラむンを拡匵する刀断を取りたした。圓時の制玄䞋では合理的な遞択ですが、根本的な構造課題は持ち越し、運甚負荷は増えおいたす。 3 事䟋ずもビゞネス文脈では筋が通っおいる䞀方、「メルカヌド還元の入れ物」が「メルカヌド呚蟺キャンペヌン党般の入れ物」ずしお䜿われ、MercardCampaignType のスキヌマず責務範囲が抌し広げられおきたのが圓時の状態で、そのひずみは無芖できない倧きさになっおいたした。 Rulebase 基盀の蚭蚈 このリファクタリングそのものは前から怜蚎しおいたものの、ロヌンチ責任ずの䞡立が難しく、本栌着手は半幎寝かせおいたす。その間も内郚で PoC は進め、本実装で固めた方針は「キャンペヌンの挙動を、専甚コヌドから蚭定デヌタぞ」ずいうシンプルなものです。 より具䜓的には、 「どのようなきっかけで動くか」 (TriggerType)、 「どのような条件でマッチさせるか」 (RuleCondition ず、その評䟡を担う RuleEvaluator)、 「䜕をするか」 (ActionExecutor) ずいう3 ぀の軞を、できるだけ atomic な (再利甚可胜なサむズの) 郚品ずしお定矩し、その組み合わせで倚様なキャンペヌン芁件に察応する、ずいうのが基本的な発想です。埓来のように「メルカヌドキャンペヌン専甚のロゞックを曞き䞋ろす」のではなく、Trigger / Condition / Action を小さな郚品ずしお甚意し、キャンペヌン定矩はその組み合わせずしお曞く、ずいう発想です。専甚パむプラむン時代ずの根本的な違いはここにありたす。䞀床実装した Condition や Action を別の CampaignType から蚭定倀だけで呌び出せたり、動的な条件分岐や繰り返し条件を1 ぀のキャンペヌン定矩の䞭で衚珟できたりする胜力も、ここから生たれたす。 党䜓像 チヌム内発衚でも、次の察比を䜿っお説明したした。 As-Is (メルカヌド専甚ハンドラの内郚に if が積たれおいる) func (h *MercardCampaignHandler) Execute(event Event) { if user.Stage == StageA { if user.Status == "Active" { if !h.HasReward(user.ID, event.ID) { points = amount * 0.03 h.RewriteRewardHistory(user.ID, event.ID) } } } else if user.Stage == StageB { if user.Status == "Gold" { points = amount * 0.10 if h.HasReward(user.ID, event.ID) { h.RewriteReward(user.ID, event.ID, points) } } } } To-Be (キャンペヌン定矩は JSON デヌタ、評䟡゚ンゞンは汎甚) { "rule_id": "mobile-std-4gb", "conditions": [ {"type": "user_attribute", "params": {"stage": "Standard", "plan": "4GB"}}, {"type": "period", "params": {"start": "2025-10-01", "end": "2025-10-31"}}, {"type": "payment_attribute", "params": {"transaction_type": "code_payment"}} ], "action": { "type": "ADD_POINTS", "params": {"rate": 0.05, "currency_points": 60, "monthly_cap": 200} } } この JSON を Spanner に氞続化したスキヌマが次の3 テヌブルです。Campaigns 配䞋に CampaignRules、その配䞋に RuleConditions を INTERLEAVE IN PARENT で䞊べる構造になっおいたす。 -- 倧枠の宣蚀: 期間・CampaignType・キャンペヌン固有蚭定 (JSON) Campaigns( CampaignID, CampaignType, StartAt, EndAt, Metadata, ... ) -- 1 キャンペヌン内の耇数ルヌル: 䜕をトリガに、どう集蚈し、どんなアクションを取るか CampaignRules( CampaignID, RuleID, TriggerType, CalculationType, ActionType, ActionParams (JSON), Priority, Enabled ) INTERLEAVE IN PARENT Campaigns -- 1 ルヌル内の耇数条件: AND/OR グルヌプで合成 RuleConditions( CampaignID, RuleID, ConditionID, ConditionType, ConditionParams (JSON), ConditionGroup ) INTERLEAVE IN PARENT CampaignRules これに察応する評䟡゚ンゞン (Rule Evaluation Engine) を新蚭し、以䞋のような4 局構造の EvaluationData を入力ずしお走らせたす。 Layer 内容 Event Data 受信した Pub/Sub むベント Rule & Campaign DB から読んだ CampaignRule + RuleConditions User Data お客さたの属性 (カヌド皮類、利甚履歎など) Providers 倖郚サヌビスぞの DI ハンドル むベントが届いおから付䞎たでの流れは次のずおりです。 Condition/Rule ず Action は、新しい皮別が必芁になったずきに察応する実装を远加しおおくこずで、以降のあらゆるキャンペヌン定矩から再利甚できる仕組みになっおいたす。新芏キャンペヌンの立ち䞊げ自䜓は、すでにカタログに揃っおいるものの組み合わせで実珟できるものであれば、コヌド倉曎を䌎わずに SQL の INSERT で反映できたす。 3 ぀の軞の䞭身 ここからは、前述した3 ぀の軞が Rulebase 基盀の䞭でそれぞれどう蚭蚈されおいるかを順に芋おいきたす。 TriggerType — どのようなきっかけで動くか CampaignRules テヌブルの TriggerType 列が、各ルヌルが「どのむベントに反応するか」 を衚したす。 TriggerType は倖郚むベントず1察1になるよう定矩しおおり、Pub/Sub から届いたメッセヌゞを内郚ドメむンのモデルに正芏化したうえで、合臎する TriggerType を持぀ルヌル矀を CampaignRules から匕き圓お、条件マッチングを担う2 段目のハンドラ局に匕き枡すずころたでが、この軞の責任範囲です。条件評䟡や副䜜甚はここでは扱わず、埌段に切り出しおいたす。 RuleCondition ず RuleEvaluator — どのような条件でマッチさせるか CampaignRules に玐づく RuleConditions テヌブルには、評䟡したい条件が1行1 ä»¶ 䞊んでいたす。各レコヌドは次の3 ぀で構成されたす。 ConditionType は、その条件がどんな皮類の刀定をするかを瀺す分類で、埌段でどの ConditionEvaluator にディスパッチするかを決めたす。 ConditionParams は、その ConditionType に枡す具䜓的なパラメヌタで、皮別ごずに必芁な匕数が違うため、固定スキヌマではなく JSON で柔軟に保持しおいたす。 ConditionGroup は、耇数の条件を AND ず OR で組み合わせるためのグルヌピングラベルで、これを䜿うこずで A AND (B OR C) のような耇合的な論理匏を、フラットな行デヌタで衚珟できるようにしおいたす。 たずえば「ある期間内で、お客さた属性 B か C のいずれかにマッチしたら成立」 ずいう A AND (B OR C) の条件は、RuleConditions テヌブルに次のように 3 行で䞊びたす。 ConditionID ConditionType ConditionGroup グルヌプの意味 A period NULL 単独で AND B user_attribute g1 グルヌプ g1 内で OR C payment_attribute g1 グルヌプ g1 内で OR 評䟡゚ンゞンの入力は、先に挙げた4 ぀のレむダヌの情報を1぀に束ねた EvaluationData です。ConditionEvaluator 偎からは「これさえ読めば刀定に必芁な倀はそろっおいる」 状態で参照できるようにしおありたす。PoC ではここにキャンペヌン固有の蚈算結果も持たせる案を怜蚎しおいたしたが、本実装では「条件評䟡のフェヌズずアクション実行のフェヌズで責務を分けるべき」ず刀断し、 EvaluationData は条件評䟡に必芁な情報だけに絞っおいたす。 評䟡゚ンゞン本䜓は、ConditionType ごずの個別刀定を担う ConditionEvaluator ず、ルヌル 1 件分の真停をたずめる RuleEvaluator の 2 段構成です。 䞋段の ConditionEvaluator は、ConditionType ごずに 1 ぀ず぀実装が甚意されおおり、 EvaluationData を読み取っおその条件 1 件分の真停を返したす。刀定は副䜜甚を持たず、倖郚 API 呌び出しや DB 曞き蟌みは起こりたせん。 䞊段の RuleEvaluator は、その䞊に乗っおルヌル 1 件分の評䟡を組み立おたす。具䜓的には、(1) RuleCondition の各行をその ConditionType に応じた ConditionEvaluator に振り分け、(2) 各行が返した真停を ConditionGroup のセマンティクス (NULL は単独 AND、同じ倀どうしは OR、別の倀どうしは AND) で AND/OR 合成し、(3) ルヌル 1 件分の最終的な真停ず、どの条件がどう寄䞎したかの内蚳を返したす。返るのは真停ず内蚳だけで、蚈算結果や副䜜甚は含めたせん。 新しい評䟡軞が必芁になったずきは、察応する ConditionEvaluator を実装しお ConditionType の enum に登録したす。䞀床カタログに加われば、以降のキャンペヌン定矩は RuleConditions の 1 行ずしおその軞を蚭定倀ベヌスで呌び出せたす。 ActionExecutor — 䜕をするか マッチしたルヌルに察応する Action を、 ActionType ごずの Executor が実行したす。䞊限蚈算、ポむント付䞎ステヌタスの遷移、ポむント台垳ぞの曞き蟌み、倖郚ぞのむベント発行ずいった副䜜甚は、ここで起こりたす。Condition / Rule 偎は副䜜甚を持たない蚭蚈なので、倖郚に䜜甚するロゞックはこの局に集玄されたす。新しい Action 皮別が必芁になったずきは、察応する Executor を実装しお ActionType の enum に登録したす。䞀床カタログに加われば、以降のキャンペヌン定矩は CampaignRules.ActionType ず ActionParams を指定する圢で、その Action を汎甚的に呌び出せたす。 3 軞を支える共通ヘルパヌ Executor の責務は、Action ごずの副䜜甚そのもの (DB 曞き蟌み、倖郚 API 呌び出し、PointStatus の遷移など) です。䞀方で、ポむント蚈算ず Cap (侊限) 適甚、PointStatus / ProvisionStatus のラむフサむクル管理、倖郚マむクロサヌビスに枡す冪等キヌの生成、蚭定倀テンプレヌトの展開ずいった「Action 皮別をたたいで毎回必芁になる暪断的な凊理」は、3 軞ずは別レむダヌの共通ヘルパヌに切り出しおいたす。各 Executor は、自分の Action に応じお必芁なヘルパヌだけを必芁なずきに呌び出す圢にしおありたす。実装したヘルパヌはいく぀かありたすが、代衚䟋を 2 ぀挙げたす。 PointLifecycleManager (PointStatus / ProvisionStatus のオヌケストレヌション) ポむント付䞎にた぀わるラむフサむクルをたずめお扱うヘルパヌです。 お客さたぞのポむント付䞎状態 (PointStatus) ず、 䌚蚈䞊の匕圓状態 (ProvisionStatus) は、それぞれ独立したステヌトマシンずしお衚珟しおいたす。 䞊が PointStatus で、 planned で台垳に予定を立お、倖郚の付䞎 API が成功するず confirmed 、埌凊理たで終わるず completed に進みたす。 planned 盎埌にキャンセルされた堎合は cancelled 、倖郚呌び出しが倱敗した堎合は failed に倒れる、ずいうのが䞻な遷移です。䞋が ProvisionStatus で、匕圓が立っおいない not_linked から、匕圓が玐づいた linked を経お、最終的に revoked (匕圓凊理が確定した状態) に遷移するのが䞻軞です。 旧メルカヌドパむプラむンでは、PointStatus の遷移ず ProvisionStatus の遷移がそれぞれポむント付䞎凊理偎ず匕圓凊理偎に分散しお実装されおいお、䞡者がどう連動しおいるかの芋通しが悪くなっおいたした。Rulebase 基盀では、䞡方のステヌトマシンを PointLifecycleManager 配䞋に切り出し、 CompletePoint / ReversePoint / CreateProvision / UpdateProvision / RevokeProvision の各 Action から必芁なずきに呌び出す圢にしおありたす。これによっお、耇数月にたたがる匕圓が必芁なメルカヌド系のキャンペヌンも、匕圓が䞍芁なシンプルなキャンペヌンも、同じ郚品の組み合わせでラむフサむクルを衚珟できたす。 TemplateExpander (蚭定倀テンプレヌトの展開) 旧システムには汎甚的な文字列テンプレヌトの仕組みがなく、たずえば䌚蚈コヌドを決枈皮別ごずに分けお積むような芁件が出おくるず、䌚蚈コヌドのパタヌン数だけキャンペヌンレコヌドを別に切るしかありたせんでした。本来 1 ぀のキャンペヌンずしお扱いたいものをパタヌン数だけ重耇登録する必芁があり、運甚負荷の原因ずしお積み䞊がっおいた郚分です。 これを汎甚化するために甚意したのが TemplateExpander です。キャンペヌン定矩のなかに {user_id} / {campaign_id} / {payment_count} ずいったプレヌスホルダヌを曞いおおくず、実行時に EvaluationData から取り出した実倀に眮き換えたす。䌚蚈コヌド (たずえば merpay_xxx_campaign-{campaign_id}-{user_status} ) や、ハッシュのシヌド文字列 ( {user_id}:{campaign_id}:{payment_count} ) などがその利甚䟋です。新しいパタヌンが必芁になったずきも、蚭定マスタ偎のテンプレヌト文字列を差し替えれば、コヌド倉曎や远加レコヌドなしに同䞀キャンペヌンの䞭で扱えたす。 最初の実装事䟋: コヌド決枈の回数連動キャンペヌン ここたでに䜜った汎甚基盀の「入れ物」を䜿った最初の移行ですが、感芚的には「リスクが䜎く、運甚負荷の高いずころ」 から始めたくなりたす。新しめで蓄積デヌタの少ないものほど移行リスクが䞋がり、運甚負荷が高いほど移行の効果が出やすいからです。圓初はメルカリモバむル向けキャンペヌンを最初の移行察象に据える予定でした。元々これをアヌキテクチャ刷新のきっかけにする案も挙がっおいたしたし、皌働開始から日が浅く蓄積デヌタが少ない䞀方で 12 パタヌンの毎月運甚で運甚負荷が高い、ずいうたさにスむヌトスポットの条件に圓おはたっおいたためです。 ただ、ちょうどそのタむミングで、新芏䌁画ずしお「コヌド決枈の回数連動キャンペヌン」 の話が立ち䞊がりたす。新芏䌁画であれば、垞時皌働しおいる既存パむプラむンを止めずに茉せ替える、ずいうコストを払わずに、最小構成で「蚭定倀ベヌスでキャンペヌンを組み立おる」 こずの怜蚌ができたす。結果ずしお、最初の事䟋は移行ではなくれロからの立ち䞊げに振り盎し、本䌁画のキャンペヌンを Rulebase 䞊で盎接立ち䞊げる圢で進めたした。既存のメルカリモバむルなどの移行は、先のフェヌズに持ち越しおいたす。 この新芏䌁画は、N 回利甚するごずに付䞎が発火するシンプルな仕組みで、お客さたから芋るず「䜿い続けるほど、確実に倀匕きが返っおくる」䜓隓になりたす。 これをRulebase䞊で組むにあたっお必芁だったのは 环蚈カりントず呚期報酬を扱う ActionType  COUNT_AND_REWARD を 1 ぀だけ远加するこずだけでした。あずは 既存の ConditionType (期間 / お客さた属性 / 決枈属性) の組み合わせで実装できた点です。Rulebase 䞊で「ルヌル評䟡ずアクション実行を最倧限再利甚し、なるべく蚭定倀だけで組み立おる」圢を、最初に怜蚌できたケヌスになりたした。 仕組み自䜓はシンプルです。お客さたの゚ントリ状況を「お客さた属性条件」で芋お、察象決枈を「決枈属性条件」で絞り蟌んだうえで、 COUNT_AND_REWARD Executor がカりンタをむンクリメントしたす。カりンタが芏定回数に達するずポむントを付䞎しおカりンタをリセットし、これをキャンペヌン期間䞭ずっず繰り返す、ずいう流れです。デヌタずしおは、Campaigns 1 行、CampaignRules 1 行、RuleConditions 数行、ずいうシンプルな構造で衚珟できたす (簡略化したむメヌゞ)。 // Campaigns { "campaign_id": "...", "campaign_type": 9, // InfinitePayment "start_at": "2026-04-01", "end_at": "2026-09-30", "metadata": { ... } } // CampaignRules (1 ä»¶) { "trigger_type": "PaymentCharge", "action_type": "COUNT_AND_REWARD", "action_params": { "trigger_count": 3, "reward_currency_points": 100 } } // RuleConditions (3 ä»¶: 期間 / ゚ントリ状況 / 決枈皮別) { "condition_type": "period", "params": { ... } } { "condition_type": "user_attribute", "params": { "attribute": "entry_status", "promotion_key": "..." } } { "condition_type": "payment_attribute", "params": { "attribute": "transaction_type", "value": "code_payment" } } 実装䞊の新芏远加は COUNT_AND_REWARD Executor ず、カりンタを保持する 2 ぀のテヌブル (珟圚のカりントずログ) くらいです。他は基盀の汎甚郚品をそのたた組み合わせお完結したした。 補足ずしお、この回数連動キャンペヌンの意矩は「単玔なキャンペヌン掟生がやりやすくなった」こずではありたせん。SQL INSERT で䌌たキャンペヌンを増やすこず自䜓は、埓来の専甚パむプラむン時代でもそれなりにできおいたした。Rulebase 基盀で新しく可胜になったのは、CampaignType をたたいだ Rule・Action の蚭定ベヌス再利甚です。䞀床実装した Condition や Action は、別の CampaignType のキャンペヌンからも蚭定倀の組み合わせで呌び出せたす。回数連動キャンペヌンで䜿った COUNT_AND_REWARD も、他のキャンペヌンが「环積回数で発火する」芁件を持おば、コヌドを曞き足さずに蚭定だけで䜿い回せたす。 同じ仕組みは、動的な条件分岐を 1 ぀のキャンペヌン蚭定で衚珟するこずにも転甚できたす。たずえばメルカリモバむル向けキャンペヌンでは「3 ステヌタス × 4 デヌタプラン」を 12 個の独立キャンペヌン定矩ずしお毎月準備しおいたしたが、Rulebase なら属性条件・繰り返し条件・䞊限条件を組み合わせお 1 ぀のキャンペヌン蚭定の䞭で衚珟できたす。「N 回ごずに発火」のような呚期的な振る舞いも、 COUNT_AND_REWARD を Executor 偎に持぀こずで汎甚パヌツずしお扱えたす。今埌の新䌁画では、既存のルヌル・アクションの組み合わせで衚珟できる範囲が広がっおいるかぎり、れロからの実装ではなく「蚭定倀だけで䜜っお詊す」ずころから入れる、ずいうのが新基盀の最倧のメリットです。 䜙談: ランダムなのに、䜕床匕いおも同じ金額 仕様ずしおは 「芏定回数に到達したら、耇数の候補金額から重み付きランダムで 1 ぀を匕き圓おる」 ずいう芁件がありたす。玠盎に math/rand で抜遞しおしたうず、Pub/Sub の at-least-once 配信䞋では同じ PaymentCharge が再配信されたずきに 1 回目ず 2 回目で別の金額が遞ばれおしたうこずがありたす。PointID ベヌスの冪等性チェックは通っおいるのに、2 回目の詊行から芋える金額が初回付䞎額ずずれる、ずいうケヌスが起きうる構造です。 そこで抜遞は乱数ではなく決定論的ハッシュで行いたした。 user_id ・キャンペヌン識別子・ payment_count を組み合わせた文字列をシヌドに、SHA-256 でハッシュ化したものから重み付きで候補を 1 ぀遞びたす。アルゎリズムの抂略は次のずおりです (簡略化したむメヌゞ)。 // seed の䟋: "12345:campaign-abc:3" (user_id : campaign_id : payment_count) seed, _ := expander.Expand(params.DeterministicReward.SeedFormat) h := sha256.Sum256([]byte(seed)) v := binary.BigEndian.Uint64(h[0:8]) // 先頭 8 バむトを uint64 ずしお取り出す var totalWeight uint64 for _, rv := range variations { totalWeight += rv.Weight } target := v % totalWeight // 重みの合蚈で割った䜙り (これが候補遞択甚の倀) var cumulative uint64 for i, rv := range variations { cumulative += rv.Weight if target < cumulative { return rv, i // 环積重みで圓たった候補を遞択 } } お客さたから芋た「䜿うたびに違う金額が返っおくる」䜓隓はそのたたに、同じ (user_id, campaign_id, payment_count) の組み合わせに察しおは䜕床 retry が走っおも、別プロセスから読たれおも、同じ金額が䞀意に確定したす。 そしお、シヌドさえ揃えば抜遞結果は確定倀なので、Pub/Sub のむベント凊理完了を埅たずに「今回付䞎される金額」を蚈算できたす。決枈成功盎埌の API レスポンスやフロント゚ンド偎で「今回は ○ ポむントです」ず確定衚瀺を返すこずができ、埌段で UserPoints が曞かれたあずに金額が倉わっお芋える、ずいった䞍敎合の心配もありたせん。at-least-once ず weighted random を䞡立させるための仕組みが、お客さたぞの早い衚瀺にもそのたた䜿える圢になっおいたす。 QA 環境の改善に助けられた話 今回の QAではいく぀かの環境パタヌンを切り替えお実斜する必芁があり、工数ボリュヌムに䞍安を感じおいたした。ちょうど良いタむミングで今たで Santa サヌビスでは実珟できおいなかった「むベント駆動郚分専甚の QA 耇補環境」をチヌムメンバヌが䜜りきっおくれたこずで、䞊行しお QA を実斜できるようになり、倧倉助かりたした。その詳现は本連茉 8 日目の @mikupo の蚘事 で詳しく解説されおいたす。 おわりに 今回のリファクタリングでは、「キャンペヌン定矩をコヌドからデヌタぞ」 ずいう方針のもず、3 テヌブル + 評䟡゚ンゞンに再構成したした。ロヌンチ責任ずの䞡立で半幎寝かせおいたリファクタリングの機䌚を諊めずに掎んで「入れ物」を䜜り切っお本番でキャンペヌンをひず぀皌働させたこずで、システムに今埌の新芁件に぀いおの受け皿を䜜るこずができたした。 ただし、回数連動キャンペヌン自䜓は本蚘事執筆時点ではロヌンチしたばかりで、ただ掟生キャンペヌンの実䟋はありたせん。蚭定だけで掟生が立ち䞊がる䞖界の本栌怜蚌は、これからの新䌁画を通じお行っおいくフェヌズです。加えお、メルカヌド垞時還元などの既存のパむプラむンもただ皌働しおおり、Temporary マップも本番に残ったたたです。垞時皌働するキャンペヌンシステムでは、入れ物を䜜る難しさよりも、止めずに茉せ替えるタむミングず手順の蚭蚈こそが、ここから先の本題になりたす。 今回の蚘事は以䞊になりたす。なにか参考になるこずがあれば幞いです。 次の蚘事は orfeon さんの「TiDB / AlloyDB の倧芏暡テヌブルを高速にBigQueryni同期するための工倫」です。匕き続きお楜しみください。
DBRE(DataBase Reliability Engineering)チヌムの@coyamaずIDP(IDentity Platform)チヌムの@taskです。 メルカリでは2026幎5月14日から2026幎5月15日たで開催されたクラりドネむティブ䌚議にスポンサヌずしおブヌス出展したした。2日間で125名にクむズぞ参加いただき、想定以䞊に“認蚌”や“マむクロサヌビス芏暡”ずいった話題で倚くの議論が生たれたした。本蚘事では、ブヌスの展瀺内容やクむズやアンケヌトの結果に加えお、来堎者ずのやり取りや感想を玹介したす。 メルカリブヌスの展瀺 メルカリの技術面の取り組みを参加者に認識いただくために、有志の゚ンゞニアが䞭心ずなりブヌスを蚭蚈したした。メルカリのブヌスでは䞻に以䞋を展瀺したした。 メルカリの技術スタックのクむズ/アンケヌト メルカリのアヌキテクチャ倉遷やKubernetesクラスタでのパケットキャプチャに関するポスタヌ AI SecurityのLLM Key Serverに関するスラむド クむズ/アンケヌトに回答いただいた方には、メルカリのストラップやボヌルペン、マスキングテヌプをプレれントしたした。メルカリのストラップは、参加者から「メルカリらしいノベルティ」ずいうコメントもあり奜評でした。 メルカリのアヌキテクチャ倉遷のポスタヌでは、以䞋の転換点に぀いお展瀺をしおいたした。 デヌタセンタヌからパブリッククラりドぞの移行 アプリケヌションのKubernetesぞのデプロむ モノリシックアヌキテクチャからマむクロサヌビスアヌキテクチャぞの移行 マむクロサヌビスアヌキテクチャの課題ずモゞュラヌモノリスの取り組み 「モノリシックアヌキテクチャからマむクロサヌビスアヌキテクチャに移行する際に、どうシステムを分割すべきか」や「マむクロサヌビスアヌキテクチャの課題は䜕か」ずいった議論ができたした。たた、他瀟でもメルカリず類䌌した課題に盎面しおいるこずを改めお認識したした。 ブヌスの展瀺内容に関連した資料は以䞋に公開されおいたす。 SRE芖点お゙振り返るメルカリのアヌキテクチャ倉遷ず普遍的な考え – Speaker Deck It’s Not Always the Network (But Here’s How to Prove It): Kubernetes Packet Capture for SREs | USENIX LLM Key ServerによるLLM APIぞの安党で䟿利なアクセス提䟛 | メルカリ゚ンゞニアリング メルカリのテックスタックに関するクむズ 今回のクむズは、メルカリが日々向き合っおいるサヌビス党䜓やテックスタックに぀いお興味を持っおもらうべく、党4問で構成したした。特定のディヌプなむンフラ技術に寄るのではなく、広めのプラットフォヌム゚ンゞニアリングに関する話題に぀いお広くカバヌし぀぀、ナヌザが実際に目にするプロダクト寄りの問題も含めおみたした。 その結果、広めのテックスタックをカバヌした䞭〜高皋床の問題セットになりたした。 そしお、クラりドネむティブ䌚議䞭にお2日間で125名の回答をいただき、分垃は以䞋の通りでした。䞭倮倀は2点で、4点満点を取ったのはわずか9名のみだったため、なかなか手応えのあるクむズになっおいたず思いたす。 たた、それぞれの回答の分垃は以䞋の通りでした。 出題した問題の䞭で、特に泚目を集めたのが以䞋のログむン認蚌方法に関する問題です。 メルカリで利甚されおいるログむン認蚌方法の䞊䜍3぀を䜿甚頻床の高い順にあげおください。 What are the top three login authentication methods used in Mercari, ranked from most to least used? Google+SMS > Password+SMS > Facebook Password+SMS > Passkeys > Google+SMS Password+SMS > Apple > Passkeys Passkeys > Password+SMS > Email Link これはクむズ䜜成時の情報なのですが、この回答に぀いお「䞀般的な Web サヌビスをむメヌゞするず、パスワヌドや゜ヌシャルログむンが䞊䜍を占めるず思いがちなので意倖だった」「パスキヌの普及率が意倖ず高いのが面癜い」ずいったコメントが倚かったです。普通はこうだろうずいう先入芳で答えるず間違えおしたう問題だったので、メルカリが技術で攻めた良い事䟋なのかもしれたせん。 たた、こちらのログむン認蚌方法に぀いお、メルカリは 2023 幎からパスキヌログむンの普及率拡倧を掚進しおいるため、最新のメトリクスによるず Passkeys > Password+SMS > Google+SMS に順䜍が倉わっおいたす。 メルカリ、すべおのログむンに 生䜓認蚌「パスキヌ」を導入 | 株匏䌚瀟メルカリ たた、他にも管理されおいるマむクロサヌビス数に関する問題に぀いおもコメントをいただくこずが倚かったです。 メルカリの microservices-terraform リポゞトリでは、倚数のサヌビス矀がInfrastructure-as-Codeずしお管理されおいたす。その管理䞋にあるサヌビスの総数はいく぀でしょうか The microservices-terraform repo manages Infrastructure-as-Code for a large portfolio of services. What is the total number of services managed in this repo? 100 – 250 services 250 – 500 services 501 – 1000 services more than 1000 services 特に、「想定よりも倚くのマむクロサヌビスを抱えおいるのに驚いた」「倚くのマむクロサヌビスを抱える䞊での新たな課題は䜕か」ず蚀ったコメントが倚かったです。こちらの倉遷に぀いおは SRE芖点お゙振り返るメルカリのアヌキテクチャ倉遷ず普遍的な考え – Speaker Deck でも觊れられおいる通りで、こちらの資料を肎にブヌスにおけるディスカッションが起きたのが面癜い点でした。 いずれにせよ、どのクむズにおいおも新しいディスカッションや雑談のネタになったため、このようなメルカリ独自のトピックにおける広めのクむズ蚭定は狙い通りでした。 Cloud Native Kaigiでのブヌス出展を終えお 今回のクラりドネむティブ䌚議では、本圓に倚くの方にメルカリブヌスぞお立ち寄りいただきたした。セッションの合間の䌑憩時間にはブヌス前が熱気に包たれる堎面もあり、運営メンバヌ䞀同、クラりドネむティブ・コミュニティの圧倒的な熱量を盎接肌で感じるこずができたした。 (coyama) メルカリからもプラットフォヌム゚ンゞニアリングに関わる耇数のチヌムのメンバヌが参加しおいたした。そのため、参加者から寄せられた幅広い質問に察応できる䜓制で、2日間を終えるこずができたした。䟋えば、DBREに関する質問では、「メルカリのテックブログでTiDB Auto Scalerの蚘事を読んで参考になった」ずいう声をきっかけに、トラフィックパタヌンに぀いお議論するこずができたした。たた、セキュリティに関する質問に぀いおは、セキュリティ゚ンゞニアに回答しおもらうこずで、うたく圹割分担ができおいたした。耇数のチヌムからメンバヌが集たるこずでプラットフォヌム゚ンゞニアリングやSREに関する幅広いコンテンツを提䟛できたのは良かったず思いたす。 (task) ブヌス運営を通しお特に印象的だったのは、今回の「テックスタッククむズ」が単なる゚ンタメで終わらず、 そこからディヌプな技術的ディスカッションぞず発展したこず です。 䟋えば、正答率が䜎かったTerraformのMonorepoに関する問題をきっかけに、「実際、数癟のサヌビスが盞乗りしおいる状態で、CIの実行速床やデプロむの安党性はどう担保しおいるんですか」「うちの䌚瀟でもプラットフォヌム基盀をどう切り出すかで悩んでいお  」ずいった、珟堎の゚ンゞニアならではのリアルな悩みや知芋の亀換が、ブヌスのあちこちで自然発生しおいたした。 問題の難易床に「うわっ、ガチなや぀だ 笑」ず頭を抱え぀぀も楜しんでくださる参加者の皆さんの姿や、「メルカリのプラットフォヌムっお、ここたでプロダクトの䜓隓パスキヌ等に螏み蟌んで䜜り蟌たれおるんですね」ずいう驚きの声は、日々倧芏暡なシステム基盀ず向き合っおいる私たちにずっお、䜕よりのモチベヌションになりたした。 瀟倖の優秀な゚ンゞニアの方々ず盎接お話しし、フィヌドバックをいただけたこずは、チヌムにずっおも非垞に倧きな刺激ずなりたした。 改めお、ブヌスに足を運んでくださった皆様、そしお難問クむズに挑戊しおくださった125名の猛者の皆様、本圓にありがずうございたした メルカリでは、今回出題したような「プラットフォヌムからプロダクトたで」を跚ぐような倧芏暡で耇雑な技術課題に、䞀緒に立ち向かっおくれる仲間を絶賛募集しおいたす。 「今回のクむズの内容、もっず詳しく聞いおみたい」「自分ならもっず良いアヌキテクチャにできる」ず興味を持っおくださった方、ぜひ以䞋のリンクからカゞュアルにお話ししたしょうお埅ちしおいたす 株匏䌚瀟メルカリ 採甚情報 7/8(æ°Ž)14:00- Mercari AI Career Fes 2026 – connpass