Why Each Payment Channel Needs Its Own Microservice: A Payment Center Design
The article analyzes the drawbacks of bundling multiple payment channels into a single service and presents a layered micro‑service architecture—splitting gateway, orchestration, channel, and storage layers—detailing the reasons for channel isolation, routing mechanisms, fee allocation, callback merging, data modeling, wallet accounting, and security considerations.
Many teams initially implement payment systems by placing all payment channels—WeChat, Alipay, wallet, and others—into a single microservice using if‑else or strategy patterns. While acceptable for early stages, this approach becomes costly as the business expands across countries, currencies, and dozens of payment providers, leading to SDK conflicts, release‑cycle mismatches, fault propagation, and inefficient scaling.
Overall Architecture
The proposed solution consists of four layers: an access layer (payment gateway), an orchestration layer (payment orchestration service), a channel layer (individual channel services), and a storage layer (payment ledger). Nine independent microservices implement this design, covering domestic WeChat and Alipay, multiple overseas aggregators, an internal wallet, and a management backend.
Why Isolate Each Payment Brand
SDK dependency conflicts: WeChat uses weixin-java-pay, Alipay uses alipay-sdk-java, and overseas aggregators rely on REST APIs with varied HMAC signatures. Different dependency trees and upgrade cadences increase conflict risk when bundled together.
Release cadence differences: WeChat may change APIs twice a year, Alipay quarterly, and overseas providers unpredictably. Separate services allow independent releases without redeploying the entire payment system.
Fault isolation: Failures in a third‑party API affect only the corresponding service instance, preserving overall payment success rates.
Traffic pattern variance: Domestic WeChat mini‑program traffic can spike tenfold during evenings, while overseas traffic remains steady. Independent services enable targeted scaling.
The trade‑off is increased operational complexity; however, when channel count exceeds five or cross‑border payments are involved, the benefits outweigh the costs.
Payment Gateway vs. Payment Orchestration Service
The payment gateway is the external entry point that validates parameters, performs signature checks, and routes requests to internal paths based on business line or scenario. It does not decide which payment channel to use.
The orchestration service is the system’s brain, handling channel routing, fee splitting, composite‑payment coordination, and callback aggregation. It determines whether an order should go through WeChat, Alipay, wallet, or a combination thereof.
Both layers coexist in large‑scale systems such as Meituan and JD, where they are treated as distinct components.
Design of the Orchestration Service
Channel routing uses the strategy pattern: each channel implements a handler bean registered in a Map. At runtime, the paymentChannel field selects the appropriate handler.
public PayChannelHandler getHandler(String channel) {
ChannelEnum channelEnum = ChannelEnum.valueOf(channel);
return handlerMap.get(channelEnum.getServiceName());
}Adding a new channel only requires implementing the handler and registering it as a bean.
Fee allocation follows a fixed priority: free‑card funds are used first, then wallet balance, and finally third‑party channels (WeChat/Alipay). This reflects business considerations—pre‑paid free‑card balances are platform assets, wallet balances are secondary, and external channels incur transaction fees.
Callback merging is the most complex part of composite payments. Each channel’s asynchronous callback updates its status in Redis; when all channels report success, a payment‑success message is sent via MQ. The following diagram illustrates the flow.
Data Model
The payment ledger uses a master‑detail structure. A TradeOrder record stores order‑level information (total amount, status, user, store). Each participating channel creates a TradeDetail record with channel‑specific amount, status, and external transaction ID.
// Master record: one per order
TradeOrder: tradeNo, outTradeNo, amount, payStatus, userId
// Detail record: one per channel
TradeDetail: tradeNo, payChannel, amount, payStatus, outTransNoThe state machine progresses from New (0) → Processing (1) → Success (2) / Failure (3), with an optional Reversal (4) after success.
Wallet and Accounting System
The wallet service implements double‑entry bookkeeping. Each transaction generates debit and credit entries to ensure balance. Accounts include personal wallets, sub‑accounts (free‑card), and platform revenue accounts, each with balance, frozen amount, currency, and overdraft flags.
Optimistic locking prevents concurrent update anomalies using a version column:
UPDATE customer_account
SET balance = ?, version = version + 1
WHERE id = ? AND version = ?A template‑method pattern defines the accounting skeleton; concrete subclasses handle consumption, recharge, refund, and reversal. Two accounting modes exist: real‑time (immediate balance update) and delayed (record only, batch settlement later).
Security Architecture
Gateway layer: VIP gateway validates signatures using client‑provided public keys, checks timestamps to prevent replay, and extracts user identity from JWT.
Channel layer: Each provider uses its own signature scheme (WeChat MD5, Alipay RSA, overseas HMAC‑SHA256). Callbacks are verified before processing.
Payment confirmation: Wallet‑deducting payments require password verification via the user center.
Configuration security: Sensitive keys and certificates are stored in Apollo configuration center and fetched at runtime, supporting multi‑merchant configurations.
Configuration Management
Configuration is organized into three layers: application (different client IDs), merchant (different merchant numbers, keys, certificates), and store (store‑specific merchant settings). The orchestration service selects the appropriate configuration based on store ID and channel, then initializes the SDK client for the channel.
Conclusion
The design balances “unified control” with “channel isolation.” A centralized orchestration layer enforces consistent business rules, while isolated channel services allow independent deployment, scaling, and fault containment. The architecture has proven effective across multiple countries and payment providers. The author suggests three future improvements: persisting pre‑order data instead of relying solely on Redis, replacing hard‑coded callback logic with a counter‑based pattern, and extracting a dedicated reconciliation module.
Design principle: be tolerant outwardly—accommodate diverse third‑party differences—while being strict inwardly—ensure every cent is traceable, reconcilable, and auditable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
samdeepthink
Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
