投行交易与风控系统的消费侧幂等架构设计与实战

1.背景和痛点

1.1 资金操作敏感性场景

核心需求:

  1. 交易唯一性:资金类操作必须保证全局唯一执行
  2. 计算原子性:风控指标计算需具备事务性特征
  3. 审计追溯:所有操作需保留完整幂等轨迹

1.2 业务损失统计


二、技术挑战与架构设计

2.1 分布式环境技术难点

// 典型错误实现:非原子化幂等检查
public void processPayment(String txId) {if (!redis.exists(txId)) {  // 竞态条件风险点executePayment(txId);redis.set(txId, "DONE", 3600);}
}
// 问题:高并发时多个线程同时通过检查

2.2 分层架构设计

核心接口定义

public interface IdempotentService {boolean acquireLock(String key, int expireSeconds);void releaseLock(String key);boolean checkAndMarkProcessed(String key);
}

三、核心实现方案

3.1 复合幂等键生成

/*** 生成组合式幂等键(交易号+操作类型+版本号)* 示例:TX20230615123456_TRANSFER_v2*/
public class IdempotentKeyGenerator {public String generateKey(IdempotentRequest request) {return String.join("_", request.getTransactionId(),request.getOperationType().name(),"v" + request.getVersion());}
}

3.2 分布式锁+状态标记

/*** Redis原子化幂等实现* 采用Redisson分布式锁+状态标记二阶段方案*/
public class RedisIdempotentService implements IdempotentService {private final RedissonClient redisson;private final RBatch batch;public boolean checkAndMarkProcessed(String key) {RLock lock = redisson.getLock(key + "_LOCK");try {// 第一阶段:获取分布式锁if (lock.tryLock(5, 30, TimeUnit.SECONDS)) {RBucket<String> bucket = redisson.getBucket(key);// 第二阶段:状态检查与标记if (bucket.get() == null) {batch.getBucket(key).set("PROCESSING", 300, TimeUnit.SECONDS);return true;}return false;}throw new LockAcquireException("获取锁超时");} finally {lock.unlock();}}
}

3.3 数据库兜底校验

-- 幂等记录表设计
CREATE TABLE idempotent_record (idempotent_key VARCHAR(128) PRIMARY KEY,biz_type VARCHAR(32) NOT NULL,status ENUM('PROCESSING','SUCCESS','FAILED') NOT NULL,created_time TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3),updated_time TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),INDEX idx_biz_status (biz_type, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

四、实现难点与解决方案

4.1 并发场景下的状态管理

// DCL双重检查锁模式优化
public boolean checkWithDoubleLock(String key) {// 第一层快速检查(无锁)if (redis.get(key) != null) {return false;}// 第二层精确检查(带锁)RLock lock = redisson.getLock(key + "_LOCK");try {if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {if (redis.get(key) == null) {redis.set(key, "PROCESSING", 300);return true;}return false;}throw new LockTimeoutException();} finally {lock.unlock();}
}

4.2 异常状态恢复机制

// 状态补偿定时任务
@Scheduled(fixedDelay = 60000)
public void fixProcessingStates() {// 查询超过5分钟未完成的记录List<String> staleKeys = redis.keys("PROCESSING_*").stream().filter(key -> redis.getTimeToLive(key) > 240).collect(Collectors.toList());staleKeys.forEach(key -> {if (db.checkTxStatus(key) == TxStatus.SUCCESS) {redis.set(key, "SUCCESS", 3600);} else {redis.delete(key);}});
}

五、验证与测试方案

5.1 单元测试用例

@Test
public void testConcurrentCheck() throws InterruptedException {int threadCount = 100;CountDownLatch latch = new CountDownLatch(threadCount);AtomicInteger successCount = new AtomicInteger();String key = "TX_TEST_123";IntStream.range(0, threadCount).forEach(i -> new Thread(() -> {if (idempotentService.checkAndMarkProcessed(key)) {successCount.incrementAndGet();}latch.countDown();}).start());latch.await(10, TimeUnit.SECONDS);Assert.assertEquals(1, successCount.get());
}

5.2 集成测试场景

@SpringBootTest
public class IdempotentIntegrationTest {@Autowiredprivate PaymentService paymentService;@Testpublic void testPaymentIdempotence() {String txId = "TX_" + System.currentTimeMillis();// 第一次请求paymentService.processPayment(txId);Assert.assertEquals(1000, getAccountBalance());// 重复请求try {paymentService.processPayment(txId);Assert.fail("应抛出幂等异常");} catch (IdempotentException e) {Assert.assertEquals(ErrorCode.DUPLICATE_REQUEST, e.getCode());}Assert.assertEquals(1000, getAccountBalance());}
}

六、实施效果与优化方向

6.1 生产环境指标对比

指标实施前实施后
重复交易发生率0.15%0.0002%
异常恢复时间>30分钟<60秒
系统吞吐量损失18%3.2%
审计通过率89%100%

6.2 持续优化方向

  1. 存储层优化:探索RocksDB替代Redis存储幂等记录

    // RocksDB存储示例
    try (Options options = new Options().setCreateIfMissing(true)) {RocksDB.loadLibrary();try (RocksDB db = RocksDB.open(options, "/data/idempotent")) {db.put(key.getBytes(), "PROCESSING".getBytes());}
    }
    
  2. 动态策略调整:基于历史数据自动优化锁超时时间

    public void autoAdjustLockTimeout() {double avgProcessTime = getAvgProcessTime();int newTimeout = (int) (avgProcessTime * 3);config.setLockTimeout(newTimeout);
    }
    
  3. 跨集群同步:实现多机房幂等状态同步

    // 基于CDC的跨机房同步
    @Bean
    public DebeziumEngine<ChangeEvent> idempotentSyncEngine() {return DebeziumEngine.create(Connect.class).using(config.asProperties()).notifying(this::handleChangeEvent).build();
    }
    

结语

在金融级系统中实现幂等性,需要从业务特征出发进行针对性设计。本文提出的复合键方案、分布式锁+状态机模式、多级存储校验等实践,经过生产验证可有效解决重复处理问题。建议在实施时重点关注:

  1. 锁粒度与性能的平衡
  2. 异常场景的完备处理
  3. 监控体系的建设
  4. 定期演练验证机制

技术没有银弹,只有持续打磨优化,才能构建出符合金融业务要求的可靠系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76986.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

odoo-046 视图显示的 name 数据库中存储的不一样

文章目录 一、问题由来二、排查经过1. 问 deepseek2. 验证3. 新问题 三、 总结四、补充&#xff08;翻译模型 ir.translation 中 src 和 value 字段详解&#xff09; 一、问题由来 客户有多个公司&#xff0c;使用多个数据库。他们有时需要同步不同数据库之间的数据的需求。在…

充电宝项目:规则引擎Drools学习

文章目录 规则引擎 Drools1 问题2 规则引擎概述2.1 规则引擎2.2 使用规则引擎的优势2.3 规则引擎应用场景2.4 Drools介绍 3 Drools入门案例3.1 创建springboot项目 引入依赖3.2 添加Drools配置类3.4 创建实体类Order3.5 orderScore.drl3.6 编写测试类 4 Drools基础语法4.1 规则…

HTML、CSS 和 JavaScript 常见用法及使用规范

一、HTML 深度剖析 1. 文档类型声明 HTML 文档开头的 <!DOCTYPE html> 声明告知浏览器当前文档使用的是 HTML5 标准。它是文档的重要元信息&#xff0c;能确保浏览器以标准模式渲染页面&#xff0c;避免怪异模式下的兼容性问题。 2. 元数据标签 <meta> 标签&am…

基于CNN+ViT的蔬果图像分类实验

本文只是做一个简单融合的实验&#xff0c;没有任何新颖&#xff0c;大家看看就行了。 1.数据集 本文所采用的数据集为Fruit-360 果蔬图像数据集&#xff0c;该数据集由 Horea Mureșan 等人整理并发布于 GitHub&#xff08;项目地址&#xff1a;Horea94/Fruit-Images-Datase…

Ubuntu24.04安装libgl1-mesa-glx 报错,软件包缺失

在 Ubuntu 24.04 系统中&#xff0c;您遇到的 libgl1-mesa-glx 软件包缺失问题可能是由于该包在最新的 Ubuntu 版本中被重命名为 libglx-mesa0。以下是针对该问题的详细解决方案&#xff1a; 1. 问题原因分析 包名称变更&#xff1a;在 Ubuntu 24.04 中&#xff0c;libgl1-me…

webpack vite

​ 1、webpack webpack打包工具&#xff08;重点在于配置和使用&#xff0c;原理并不高优。只在开发环境应用&#xff0c;不在线上环境运行&#xff09;&#xff0c;压缩整合代码&#xff0c;让网页加载更快。 前端代码为什么要进行构建和打包&#xff1f; 体积更好&#x…

如何在爬虫中合理使用海外代理?在爬虫中合理使用海外ip

我们都知道&#xff0c;爬虫工作就是在各类网页中游走&#xff0c;快速而高效地采集数据。然而如果目标网站分布在多个国家或者存在区域性限制&#xff0c;那靠普通的网络访问可能会带来诸多阻碍。而这时&#xff0c;“海外代理”俨然成了爬虫工程师们的得力帮手&#xff01; …

数据仓库分层存储设计:平衡存储成本与查询效率

数据仓库分层存储不仅是一个技术问题,更是一种艺术:如何在有限的资源下,让数据既能快速响应查询,又能以最低的成本存储? 目录 一、什么是数据仓库分层存储? 二、分层存储的体系架构 1. 数据源层(ODS,Operational Data Store) 2. 数据仓库层(DW,Data Warehouse)…

YOLO学习笔记 | 基于YOLOv8的植物病害检测系统

以下是基于YOLOv8的植物病害检测系统完整技术文档,包含原理分析、数学公式推导及代码实现框架。 基于YOLOv8的智能植物病害检测系统研究 摘要 针对传统植物病害检测方法存在的效率低、泛化性差等问题,本研究提出一种基于改进YOLOv8算法的智能检测系统。通过设计轻量化特征提…

高级语言调用C接口(二)回调函数(4)Python

前面2篇分别说了java和c#调用C接口&#xff0c;参数为回调函数&#xff0c;回调函数中参数是结构体指针。 接下来说下python的调用方法。 from ctypes import * import sysclass stPayResult(Structure):_pack_ 4 # 根据实际C结构体的对齐方式设置&#xff08;常见值为1,4,…

springboot启动动态定时任务

1.自定义定时任务线程池 package com.x.devicetcpserver.global.tcp.tcpscheduler;import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotatio…

pytorch框架认识--手写数字识别

手写数字是机器学习中非常经典的案例&#xff0c;本文将通过pytorch框架&#xff0c;利用神经网络来实现手写数字识别 pytorch中提供了手写数字的数据集&#xff0c;我们可以直接从pytorch中下载 MNIST中包含70000张手写数字图像&#xff1a;60000张用于训练&#xff0c;10000…

WPF 使用依赖注入后关闭窗口程序不结束

原因是在ViewModel中在构造函数中注入了Window 对象&#xff0c;即使没有使用&#xff0c;主窗口关闭程序不会退出&#xff0c;即使 ViewModel 是 AddTransient 注入的。 解决方法&#xff1a;不使用构造函数注入Window&#xff0c;通过GetService获取Window 通过注入对象调用…

用户管理(添加和删除,查询信息,切换用户,查看登录用户,用户组,配置文件)

目录 添加和删除用户 查询用户信息 切换用户 查看当前的操作用户是谁 查看首次登录的用户是谁 用户组&#xff08;对属于同个角色的用户统一管理&#xff09; 新增组 删除组 添加用户的同时&#xff0c;指定组 修改用户的组 组的配置文件&#xff08;/etc/group&…

PyTorch学习-小土堆教程

网络搭建torch.nn.Module 卷积操作 torch.nn.functional.conv2d(input, weight, biasNone, stride1, padding0, dilation1, groups1) 神经网络-卷积层

MVCC详细介绍及面试题

目录 1.什么是mvcc&#xff1f; 2.问题引入 3. MVCC实现原理&#xff1f; 3.1 隐藏字段 3.2 undo log 日志 3.2.1 undo log版本链 3.3 readview 3.3.1 当前读 ​编辑 3.3.2 快照读 3.3.3 ReadView中4个核心字段 3.3.4 版本数据链访问的规则&#xff08;了解&#x…

企业级Active Directory架构设计与运维管理白皮书

企业级Active Directory架构设计与运维管理白皮书 第一章 多域架构设计与信任管理 1.1 企业域架构拓扑设计 1.1.1 林架构设计规范 林根域规划原则&#xff1a; 采用三段式域名结构&#xff08;如corp.enterprise.com&#xff09;&#xff0c;避免使用不相关的顶级域名架构主…

android11 DevicePolicyManager浅析

目录 &#x1f4d8; 简单定义 &#x1f4d8;应用启用设备管理者 &#x1f4c2; 文件位置 &#x1f9e0; DevicePolicyManager 功能分类举例 &#x1f6e1;️ 1. 安全策略控制 &#x1f4f7; 2. 控制硬件功能 &#x1f9f0; 3. 应用管理 &#x1f512; 4. 用户管理 &am…

Java学习手册:Java线程安全与同步机制

在Java并发编程中&#xff0c;线程安全和同步机制是确保程序正确性和数据一致性的关键。当多个线程同时访问共享资源时&#xff0c;如果不加以控制&#xff0c;可能会导致数据不一致、竞态条件等问题。本文将深入探讨Java中的线程安全问题以及解决这些问题的同步机制。 线程安…

PyTorch核心函数详解:gather与where的实战指南

PyTorch中的torch.gather和torch.where是处理张量数据的关键工具&#xff0c;前者实现基于索引的灵活数据提取&#xff0c;后者完成条件筛选与动态生成。本文通过典型应用场景和代码演示&#xff0c;深入解析两者的工作原理及使用技巧&#xff0c;帮助开发者提升数据处理的灵活…