面试官:在电商支付系统中,如何有效避免用户重复支付?请详细阐述你的设计思路。
应试者:防止重复支付是电商支付系统的核心设计挑战之一。我的解决方案主要从以下几个维度考虑:
在支付流程中,我们需要为每笔交易生成全局唯一且可追溯的幂等标识:
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
}
面试官:能详细解释一下你提到的多层幂等性保障吗?每一层具体是如何实现的?
应试者:多层幂等性保障是一种分层防重复提交的策略:
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
);
这种多层设计的优势:
面试官:如果在高并发场景下,这套机制可能会引入性能瓶颈,你有什么优化建议吗?
应试者:高并发场景下的性能优化是一个非常关键的话题。我的优化建议包括:
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 高质量内容试读👇: https://portal.yunosphere.com
欢迎关注我,经常分享有用的 Go 知识 / 面试 / 创业经历 / 其他编程知识 👇
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.