Files
cursor/plans/POP modifyFee-454dc363.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

9.1 KiB
Raw Permalink Blame History


todos:

  • id: "remove-prewallet-check" content: "Phase 1: 删除 executeBetWalletTransfer 中 getWallet 预检,改由 wallet bet 返回映射余额不足" status: pending
  • id: "defer-ledger-query" content: "Phase 1: finalizeSuccessfulTransfer 去掉同步 queryBizLogmarkWalletSuccess(0) + 异步 ledger 回填" status: pending
  • id: "wallet-return-ledger" content: "Phase 2: slot-wallet update 响应增加 ledger_idPOP 直接写入 provider_tx" status: pending
  • id: "merge-db-updates" content: "Phase 3可选: 合并 callback_log / provider_tx 多次 UPDATE并加分段耗时监控" status: pending isProject: false

POP modifyFee 性能分析与队列化建议

结论(直接回答)

是的,同步路径偏重,但不宜把「整单回调」丢进队列。

  • Controller slot-pwa/app/pop/controller/CashController.php 本身很薄,性能问题在 slot-pwa/app/pop/logic/CashLogic.php
  • POP 协议要求 同步返回最新 balance,且 钱包扣款/派奖必须在响应前完成,否则厂商会重试或判失败。
  • 相比 jdb/quick/gasea只做 wallet + Redis 幂等 + 异步流水POP 额外引入了 callback_log、provider_tx、game_round 三套分表状态机,单次成功回调大约 610 次 DB 写 + 23 次 wallet HTTP
  • 已有异步:用户交易流水(TransactionLogService::logpwa_transaction_log worker、局终事件GameRoundEventService::publishFinalSettled)、试玩活动(TrialRewardNotifyService MQ publish

因此:可以队列化的是「不影响 POP 响应正确性的旁路写/追踪」不能队列化的是幂等、钱包、局状态校验


当前同步链路(成功路径 BET

sequenceDiagram
    participant POP
    participant MW as ProviderCallbackLogMiddleware
    participant Logic as CashLogic
    participant DB as ShardDB
    participant Wallet as slot_wallet
    participant MQ as RabbitMQ

    POP->>MW: TransferInOut
    MW->>DB: insert callback_log
    MW->>Logic: modifyTransferInOut
    Logic->>DB: update callback_log parse/in_progress
    Logic->>DB: createOrGet provider_tx
    Logic->>DB: loadOrCreate game_round
    Logic->>DB: markProcessing / markWalletCalling
    Logic->>Wallet: getWallet (BET 余额预检)
    Logic->>Wallet: update bet
    Logic->>Wallet: queryBizLog
    Logic->>DB: markWalletSuccess + round update
    Logic->>MQ: TransactionLog (async)
    Logic->>DB: markProcessSuccess
    Logic->>POP: balance

对比 legacy slot-pwa/app/quick/service/CashService.php无 callback_log / provider_tx / game_roundwallet 成功后只发 MQ 写流水,同步面小很多。


同步步骤分类

步骤 位置 是否必须同步 说明
callback_log 收包落库 Middleware 建议保留同步 审计与 trace但可合并多次 update
provider_tx create-or-get resolveProviderTx 必须 幂等键,防双花;必须在 wallet 前
game_round load/create/validate RoundService 必须 后续 WIN/FINAL 依赖局状态
风控 evaluate + applyRisk handleTransferRiskEvaluation 必须(接入真实风控后) HOLD/REJECT 需在 wallet 前
getWallet 余额预检 executeBetWalletTransfer 可优化掉 wallet 本身会拒余额不足,多 1 次 RTT
WalletService bet/win invokeWalletBetOrWin 必须 响应 balance 来源
queryBizLog finalizeSuccessfulTransfer 可移出热路径 仅回填 wallet_ledger_id;已有补偿 ProviderTxCompensationService
game_round applyBet/Win/Final applyRoundUpdateAfterSuccess 必须 同局后续回调校验
Redis round 缓存 updateRoundStateInfo 可弱一致异步 有 DB fallback但异步需防乱序
TransactionLog TransactionLogService::log 已异步 worker 内还做 VIP/日报/big win
callback_log 终态 markProcessSuccess 可延迟 不影响 POP 响应;影响实时排障
UserProfit / RTP stat WalletService::bet/win 可异步 Redis 统计,非 POP 协议字段

主要性能瓶颈(按收益排序)

1. 冗余 wallet HTTP最高收益、最低风险

BET 路径双查钱包:

        $currentWallet = WalletService::getWallet($userInfo->uid, $userInfo->currency);
        if ($currentWallet->balance < $feeAmount) {
            // ... markRejected ...
        }
        // ...
        return $this->invokeWalletBetOrWin($walletCommand, true);
  • getWallet,再 updateWallet(bet)多 1 次完整 HTTP 往返
  • 建议:删除预检,直接 bet(),按 wallet 返回/错误码映射 CODE_INSUFFICIENT_FUNDS(与 legacy 一致)。

成功后二次查询 ledger

        $ledgerQuery = $this->walletGatewayService->queryBizLog(
            $transferContext->uid(),
            $finalizeContext->walletRequestId,
            ProviderTxService::resolveWalletBizType($finalizeContext->txType)
        );
        $walletLedgerId = (int) ($ledgerQuery['ledger_id'] ?? 0);
        $this->providerTxService->markWalletSuccess(..., $walletLedgerId);
  • 钱包 update 响应 WalletEntity 不含 ledger_id,故又调 queryBizLog再多 1 次 HTTP
  • 两条路(二选一或组合):
    • A推荐:扩展 slot-wallet update 响应带 ledger_idPOP 直接写入,去掉热路径 queryBizLog
    • B低改动:热路径 markWalletSuccess(ledger_id=0),通过现有 ProviderTxWalletCompensate 或新建轻量 MQ consumer 异步回填 wallet_ledger_id(与 reward_grant 文档中 queryBizLog 补偿模式一致)。

2. 多次分表状态机 UPDATE中等收益

单次回调对 callback_logprovider_tx 分别多次 UPDATEparse → in_progress → wallet_calling → successmiddleware 还有 insert。可考虑

  • 合并 markParseSuccess + markProcessInProgress 为一次写(需改 Model SQL
  • provider_tx 状态迁移合并processing + wallet_calling 若对排障非强依赖可合并)。
  • 注意:这是 DB 优化,不是 MQ队列化这些状态反而增加一致性复杂度。

3. 适合队列、且不影响 POP 响应的旁路

候选 做法 风险
wallet_ledger_id 回填 MQ / 定时补偿 低;审计字段短暂为 0
callback_log 终态写 响应后 defer 或 MQ 中;实时查 log 延迟
UserProfitService / GameUserRechargeRtpStatService 挪到 TransactionLog worker 低;统计延迟秒级
Redis round 缓存更新 响应后 MQ 中;需 uid+round 有序消费

不适合队列:

  • 整个 modifyFee / wallet bet-win厂商等 balance
  • provider_tx 幂等创建(必须先于 wallet
  • game_round 聚合更新(同局后续回调依赖)

与「全异步回调」方案的边界

若把 wallet 也异步化:

  • POP 无法立即拿到 balance → 协议不满足
  • 失败重试会与幂等、局状态、钱包状态产生 竞态,需大量补偿与对账

现有设计已采用更合理模式:同步关键路径 + 异步旁路流水、局终事件。POP 的问题是 关键路径上叠了审计表 + 多余 HTTP,而非「异步做得不够」。


建议实施顺序(若后续要改代码)

Phase 1 — 热路径减负(推荐先做,改动集中在 slot-pwa

  1. 去掉 BET 前 getWallet 预检,统一由 wallet 拒单。
  2. finalizeSuccessfulTransfer 去掉同步 queryBizLogmarkWalletSuccess(ledger_id=0) + 触发异步回填(复用 ProviderTxCompensationService 或新增 provider_tx_ledger_backfill 队列)。
  3. 补充 Feature 测试余额不足、幂等重复、wallet 成功但 ledger 延迟回填。

Phase 2 — 跨服务优化(需 slot-wallet 配合)

  1. POST /api/wallet/update 响应增加 ledger_idbet/win 写入后返回)。
  2. slot-pwa 优先读响应字段,补偿任务作兜底。

Phase 3 — DB/观测优化(可选)

  1. 合并 callback_log / provider_tx 多次 UPDATE。
  2. modifyTransferInOut 加分段耗时 metricsmiddleware / provider_tx / round / wallet / finalize用数据验证 Phase 1/2 收益。

预期收益(量级)

  • Phase 1BET 成功路径 减少 1~2 次 wallet HTTP(通常 20~80ms/次,视网络与 wallet 负载)。
  • Phase 2WIN/FINAL 成功路径再 减少 1 次 queryBizLog
  • 队列化旁路ledger 回填、统计):不缩短 POP 感知 RTT 的主矛盾,但降低峰值时 wallet/DB 叠加压力。

不能指望:把 callback_log / provider_tx / game_round 全部异步后 POP RTT 接近 quick/jdb——这三张表是 POP 架构的有意同步成本,用于幂等、审计、局聚合。