--- todos: - id: "remove-prewallet-check" content: "Phase 1: 删除 executeBetWalletTransfer 中 getWallet 预检,改由 wallet bet 返回映射余额不足" status: pending - id: "defer-ledger-query" content: "Phase 1: finalizeSuccessfulTransfer 去掉同步 queryBizLog,markWalletSuccess(0) + 异步 ledger 回填" status: pending - id: "wallet-return-ledger" content: "Phase 2: slot-wallet update 响应增加 ledger_id,POP 直接写入 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/controller/CashController.php) 本身很薄,性能问题在 [`slot-pwa/app/pop/logic/CashLogic.php`](slot-pwa/app/pop/logic/CashLogic.php)。 - POP 协议要求 **同步返回最新 `balance`**,且 **钱包扣款/派奖必须在响应前完成**,否则厂商会重试或判失败。 - 相比 jdb/quick/gasea(只做 wallet + Redis 幂等 + 异步流水),POP 额外引入了 **callback_log、provider_tx、game_round** 三套分表状态机,单次成功回调大约 **6~10 次 DB 写 + 2~3 次 wallet HTTP**。 - **已有异步**:用户交易流水(`TransactionLogService::log` → `pwa_transaction_log` worker)、局终事件(`GameRoundEventService::publishFinalSettled`)、试玩活动(`TrialRewardNotifyService` MQ publish)。 因此:**可以队列化的是「不影响 POP 响应正确性的旁路写/追踪」**;**不能队列化的是幂等、钱包、局状态校验**。 --- ## 当前同步链路(成功路径 BET) ```mermaid 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`](slot-pwa/app/quick/service/CashService.php):**无 callback_log / provider_tx / game_round**,wallet 成功后只发 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`](slot-pwa/app/service/game/ProviderTxCompensationService.php) | | 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 路径双查钱包:** ```686:711:slot-pwa/app/pop/logic/CashLogic.php $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:** ```829:839:slot-pwa/app/pop/logic/CashLogic.php $ledgerQuery = $this->walletGatewayService->queryBizLog( $transferContext->uid(), $finalizeContext->walletRequestId, ProviderTxService::resolveWalletBizType($finalizeContext->txType) ); $walletLedgerId = (int) ($ledgerQuery['ledger_id'] ?? 0); $this->providerTxService->markWalletSuccess(..., $walletLedgerId); ``` - 钱包 `update` 响应 [`WalletEntity`](slot-pwa/app/entity/WalletEntity.php) **不含 `ledger_id`**,故又调 `queryBizLog`,**再多 1 次 HTTP**。 - 两条路(二选一或组合): - **A(推荐)**:扩展 [`slot-wallet`](slot-wallet/app/api/logic/WalletLogic.php) `update` 响应带 `ledger_id`,POP 直接写入,去掉热路径 `queryBizLog`。 - **B(低改动)**:热路径 `markWalletSuccess(ledger_id=0)`,通过现有 `ProviderTxWalletCompensate` 或新建轻量 MQ consumer 异步回填 `wallet_ledger_id`(与 reward_grant 文档中 queryBizLog 补偿模式一致)。 ### 2. 多次分表状态机 UPDATE(中等收益) 单次回调对 `callback_log`、`provider_tx` 分别多次 `UPDATE`(parse → in_progress → wallet_calling → success;middleware 还有 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` 去掉同步 `queryBizLog`;`markWalletSuccess(ledger_id=0)` + 触发异步回填(复用 `ProviderTxCompensationService` 或新增 `provider_tx_ledger_backfill` 队列)。 3. 补充 Feature 测试:余额不足、幂等重复、wallet 成功但 ledger 延迟回填。 ### Phase 2 — 跨服务优化(需 slot-wallet 配合) 1. `POST /api/wallet/update` 响应增加 `ledger_id`(bet/win 写入后返回)。 2. slot-pwa 优先读响应字段,补偿任务作兜底。 ### Phase 3 — DB/观测优化(可选) 1. 合并 callback_log / provider_tx 多次 UPDATE。 2. 对 `modifyTransferInOut` 加分段耗时 metrics(middleware / provider_tx / round / wallet / finalize),用数据验证 Phase 1/2 收益。 --- ## 预期收益(量级) - Phase 1:BET 成功路径 **减少 1~2 次 wallet HTTP**(通常 20~80ms/次,视网络与 wallet 负载)。 - Phase 2:WIN/FINAL 成功路径再 **减少 1 次 queryBizLog**。 - 队列化旁路(ledger 回填、统计):**不缩短 POP 感知 RTT 的主矛盾**,但降低峰值时 wallet/DB 叠加压力。 **不能指望**:把 callback_log / provider_tx / game_round 全部异步后 POP RTT 接近 quick/jdb——这三张表是 POP 架构的有意同步成本,用于幂等、审计、局聚合。