面试实录 —— 电商支付系统中,如何有效避免用户重复支付? | 程序员论坛-金年会app官方网
面试官:在电商支付系统中,如何有效避免用户重复支付?请详细阐述你的设计思路。
应试者:防止重复支付是电商支付系统的核心设计挑战之一。我的金年会app官方网的解决方案主要从以下几个维度考虑:
唯一性标识设计
在支付流程中,我们需要为每笔交易生成全局唯一且可追溯的幂等标识:
type paymentidentifier struct {
orderid string // 订单id
userid int64 // 用户id
transactionid string // 全局唯一事务id
createdat time.time // 创建时间
}
// 生成全局唯一事务id
func generatetransactionid() string {
// 使用雪花算法生成分布式唯一id
return snowflake.generate().string()
}
幂等性控制机制
核心实现思路:
type paymentservice struct {
// 分布式锁,防止并发冲突
locker distributed.locker
// 已处理交易的缓存
processedtransactions *sync.map
// 数据库连接
db *gorm.db
}
func (s *paymentservice) processpayment(ctx context.context, payment *payment) error {
// 1. 获取分布式锁
lock, err := s.locker.lock(payment.transactionid)
if err != nil {
return errors.wrap(err, "获取锁失败")
}
defer lock.unlock()
// 2. 检查交易是否已处理
if _, processed := s.processedtransactions.load(payment.transactionid); processed {
return errors.new("交易已处理")
}
// 3. 数据库层面的幂等性检查
var existingpayment payment
if err := s.db.where("transaction_id = ?", payment.transactionid).first(&existingpayment).error; err == nil {
return errors.new("重复交易")
}
// 4. 执行支付逻辑
if err := s.executepayment(payment); err != nil {
return err
}
// 5. 记录已处理交易
s.processedtransactions.store(payment.transactionid, true)
return nil
}
多层幂等性保障
- 客户端:生成唯一请求id
- 网关层:请求去重
- 服务端:事务幂等
- 数据库:唯一约束
面试官:能详细解释一下你提到的多层幂等性保障吗?每一层具体是如何实现的?
应试者:多层幂等性保障是一种分层防重复提交的策略:
客户端层
type paymentrequest struct {
requestid string // 客户端生成的唯一请求id
orderid string
amount decimal.decimal
paymentmethod string
}
func generateclientrequestid() string {
// 结合时间戳、随机数、设备id等
return fmt.sprintf("%s-%d-%s",
time.now().format("20060102150405"),
rand.int63(),
deviceid)
}
网关层限流与去重
type paymentgateway struct {
// 使用redis实现请求去重
requestcache *redis.client
// 限流器
ratelimiter *rate.limiter
}
func (pg *paymentgateway) validaterequest(req *paymentrequest) error {
// 限流检查
if !pg.ratelimiter.allow() {
return errors.new("请求过于频繁")
}
// 请求去重
cachekey := fmt.sprintf("payment:request:%s", req.requestid)
// 使用分布式缓存防重
if pg.requestcache.exists(cachekey).val() > 0 {
return errors.new("重复请求")
}
// 缓存请求,设置过期时间
pg.requestcache.set(cachekey, "1", time.minute*10)
return nil
}
服务端事务管理
func (s *paymentservice) processpayment(ctx context.context, req *paymentrequest) error {
// 开启数据库事务
tx := s.db.begin()
// 检查是否存在相同的事务
var existingtxn paymenttransaction
if err := tx.where("request_id = ?", req.requestid).first(&existingtxn).error; err == nil {
tx.rollback()
return errors.new("事务已存在")
}
// 创建新的支付事务
txn := paymenttransaction{
requestid: req.requestid,
status: "processing",
createtime: time.now(),
}
if err := tx.create(&txn).error; err != nil {
tx.rollback()
return err
}
// 执行实际支付
if err := s.executepayment(tx, req); err != nil {
tx.rollback()
return err
}
// 提交事务
return tx.commit().error
}
数据库唯一约束
-- 创建支付事务表
create table payment_transactions (
id bigint primary key auto_increment,
request_id varchar(64) unique not null, -- 唯一约束
order_id varchar(64) not null,
status enum('processing', 'success', 'failed') not null,
amount decimal(10,2) not null,
create_time timestamp default current_timestamp
);
这种多层设计的优势:
- 在请求的不同阶段提供重复提交保护
- 降低系统被恶意请求的风险
- 提供细粒度的请求管理机制
面试官:如果在高并发场景下,这套机制可能会引入性能瓶颈,你有什么优化建议吗?
应试者:高并发场景下的性能优化是一个非常关键的话题。我的优化建议包括:
缓存优化
- 使用本地进程缓存(如 freecache)
- 结合分布式缓存(redis)
- 对频繁访问的数据进行多级缓存
异步处理
func (s *paymentservice) asyncpaymentprocess(req *paymentrequest) {
// 使用消息队列异步处理支付请求
go func() {
// 投递到消息队列
err := s.messagequeue.publish("payment_topic", req)
if err != nil {
// 记录投递失败日志
log.error("消息投递失败", err)
}
}()
}
// 消息消费者
func (s *paymentservice) paymentconsumer() {
for {
msg := s.messagequeue.consume("payment_topic")
// 并发处理
go s.processpayment(context.background(), msg)
}
}
细粒度锁
type concurrentpaymentmanager struct {
// 使用分段锁减少锁竞争
shardedlocks []*sync.rwmutex
}
func (m *concurrentpaymentmanager) getlock(key string) *sync.rwmutex {
// 对key进行哈希,选择锁
return m.shardedlocks[hashcode(key) % len(m.shardedlocks)]
}
func (m *concurrentpaymentmanager) processpayment(req *paymentrequest) {
lock := m.getlock(req.requestid)
lock.lock()
defer lock.unlock()
// 处理支付逻辑
}
限流与熔断
type adaptiveratelimiter struct {
// 动态调整的令牌桶
limit *rate.limiter
}
func (rl *adaptiveratelimiter) adjust(currentload float64) {
// 根据系统负载动态调整限流阈值
if currentload > 0.8 {
rl.limit = rate.newlimiter(rate.limit(50), 100)
} else {
rl.limit = rate.newlimiter(rate.limit(100), 200)
}
}
监控与性能分析
- 实时性能指标监控
- 链路追踪
- 动态性能调优
面试官:最后,对于这样一个支付系统,你有什么架构level的思考?
应试者:支付系统不仅仅是技术实现,更是一个复杂的金融级系统。我的架构思考主要包括:
安全性
- 多重风控机制
- 加密与脱敏
- 异常交易识别
可用性
- 多机房部署
- 灾备与容灾
- 平滑降级策略
合规性
- 完善的审计追踪
- 金融合规检查
- 数据留痕
可观测性
- 分布式追踪
- 实时告警
- 故障快速定位
核心是在高性能、高可用、安全性之间找到平衡,构建一个既健壮又灵活的支付系统架构。
更多 go 高质量内容试读👇:
欢迎关注我,经常分享有用的 go 知识 / 面试 / 创业经历 / 其他编程知识 👇
- 公众号:gopheryes
- b 站:yunfuns
- 知乎、掘金、头条号:yunfun
- 小红书号:986261983
本作品采用《cc 协议》,转载必须注明作者和本文链接
公众号:gopheryes
花里胡哨,无法完全处理重复支付问题