项目
支付中台
对接微信支付宝接口
开发余额充值
开发退款
开发调账 seata处理
开发对账 后期采用redis set集合优化队长逻辑数据库连接过多
下单业务
openfeign- 远程调用
redis
sdiff 函数 取差集
对账
定时任务 当天9点执行对账 拉取昨天的数据进行对账
充值
充值 商品类型不用限制重复 需要限制重复下单
关单
graph TD
A["用户创建商品订单"] --> |"发送延迟消息,5分钟后消费"| B["消费者通过商品订单号查询数据库支付状态,如果是已支付不进行操作"]
B -->|"如果是未支付"| C["通过商品订单号查询关联的支付订单号,一一查询支付渠道状态,如果都没有支付成功进行关单,并且把支付订单调用第三方关单接口进行关单,关闭不仅要关闭本地的,还需要关闭第三方的订单(WX,AliPay)"]
组合支付
graph TD
A("先扣除余额,在扣除渠道")
A_A("扣除完余额后,若没扫码,退余额麻烦。扫码了但是需要等回调")
B("在渠道支付成功后,更新余额")
B_B("扫码了但是需要等回调,这时还有余额,用户又下单,抵扣余额,渠道再次支付,扣除失败 但是对渠道就不好处理了")
A --> A_A
B --> B_B
C("冻结余额,扫码后再解冻并扣除余额")
重复下单
还有事物@Transactional(timeout = 2, isolation = Isolation.READ_COMMITTED)
注意:锁外查询一次 锁内要再次查询
redis setnx (set if not exists) 解决重复下单问题
redis 加锁lua脚本
1 | if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then |
脚本说明:
- 如果redis设置成功,则返回1,并设置过期时间
- 如果redis设置失败,则返回0
redis 释放lua 脚本
1 | if redis.call('get', KEYS[1]) == ARGV[1] then |
脚本说明:
- 如果redis的值与传入的值匹配,则删除该键并返回成功
- 如果不匹配,则返回0表示释放失败
参数说明
- KEYS[1]:锁的 key(例如:distributed_lock:pay:123:alipay:ORDER001:createPayment)
- ARGV[1]:锁的 value(通常是 UUID,用于标识锁的持有者)
执行逻辑
- 获取锁的当前值:redis.call(‘get’, KEYS[1])
- 比较值是否匹配:检查当前锁的值是否等于传入的 ARGV[1]
- 匹配则删除锁:如果匹配,执行 redis.call(‘del’, KEYS[1]) 删除锁
- 不匹配返回0:如果不匹配,返回 0 表示释放失败
重复支付
graph TD
A[重复支付]
B[重复下单]
C[重复支付订单]
A --> B
A --> C
D["` 设置事物过期时间2s 2s后要么数据库里有数据 要么回滚
隔离级别设置提交读
`"]
B --> D
用户对一个商品订单要有唯一索引
一个用户对一个商品订单进行多次渠道支付要复用之前渠道支付的订单
graph TD
A["用户先用支付宝支付,扫码了但支付宝余额不够,取消支付宝支付"]
B["选择再次支付,进行微信支付,也返回了二维码"]
C["会创建新的支付订单"]
D["`判断支付订单表,该笔商品订单有没有其他渠道且待支付的订单
还需要主动查询支付渠道状态,如果返回待支付则进行关闭,如果已支付了
返回已支付,请勿重复支付
`"]
A --> B
B --> C
B --> D
性能优化
后期报表数据接口响应时间慢
优化支付对账逻辑,提升对账速度
引入设计模式优化代码结构,方便后期迭代
线上问题
JVM内存溢出问题
- 线上支付对账接口响应时间慢
- 线上支付对账接口响应时间慢,导致支付对账线程池满了
企业内部内存监控平台 监控gc次数 每次gc后内存的释放率 要求full gc一天不能超过2次
重复通知问题(幂等姓)
防重表加唯一索引
乐观锁
迭代周期
一个月2-3次
jvm 内存怎么设置
- Xms 设置初始堆大小
- Xmx 设置最大堆大小
- Xmn 设置年轻代大小
- Xss 设置每个线程的栈大小
- Xmx 和 Xms 一般设置为相同的值,避免堆大小
- XX:+UseG1GC 使用 G1 垃圾收集器
支付宝请求
请求的时候私钥加签
回调的时候私钥验签
JMeter 进行压力测试
平稳的时候50%以下。 老年代30 40 新声代10 20
极端情况 70 - 80