Gin+Vue+微服务架构打造秒杀商城实战

最近在学习Gin+Vue+微服务架构开发秒杀系统,但在分布式锁和库存一致性处理上遇到了问题。想请教大家:

  1. Redis分布式锁在秒杀场景下如何避免超卖?
  2. 微服务间调用是用RPC还是消息队列更合适?
  3. Vue前端如何优化才能应对瞬时高并发请求?
    有没有实际项目经验的大佬分享一下架构设计细节和避坑指南?
2 回复

使用Gin+Vue+微服务架构实现秒杀商城,后端用Gin处理高并发请求,Vue构建前端界面,微服务拆分订单、库存等模块,结合Redis缓存、消息队列提升性能。适合学习分布式系统和高并发场景。


Gin + Vue + 微服务架构秒杀商城实战

系统架构设计

核心架构

  • 前端: Vue3 + Element Plus
  • 网关层: Gin框架实现API网关
  • 业务服务: 微服务架构
  • 数据层: MySQL + Redis集群

核心代码实现

1. Gin网关层

// main.go
package main

import (
    "github.com/gin-gonic/gin"
    "seckill-gateway/handler"
    "seckill-gateway/middleware"
)

func main() {
    r := gin.Default()
    
    // 中间件
    r.Use(middleware.RateLimit())
    r.Use(middleware.Auth())
    
    // 路由
    api := r.Group("/api")
    {
        api.POST("/seckill", handler.SeckillHandler)
        api.GET("/products", handler.GetProductsHandler)
    }
    
    r.Run(":8080")
}

2. 秒杀核心服务

// seckill_service.go
package service

import (
    "context"
    "errors"
    "github.com/go-redis/redis/v8"
    "gorm.io/gorm"
)

type SeckillService struct {
    redisClient *redis.Client
    db          *gorm.DB
}

func (s *SeckillService) ProcessSeckill(ctx context.Context, userId, productId int64) error {
    // 1. 库存预减
    stockKey := fmt.Sprintf("stock:%d", productId)
    currentStock, err := s.redisClient.Decr(ctx, stockKey).Result()
    if err != nil || currentStock < 0 {
        s.redisClient.Incr(ctx, stockKey) // 回滚
        return errors.New("库存不足")
    }
    
    // 2. 生成订单
    order := model.Order{
        UserID:    userId,
        ProductID: productId,
        Status:    "pending",
    }
    
    if err := s.db.Create(&order).Error; err != nil {
        s.redisClient.Incr(ctx, stockKey) // 回滚
        return err
    }
    
    // 3. 发送消息队列
    s.sendOrderMessage(order)
    
    return nil
}

3. Vue前端组件

<template>
  <div class="seckill-container">
    <el-card v-for="product in products" :key="product.id">
      <h3>{{ product.name }}</h3>
      <p>价格: {{ product.price }}</p>
      <p>库存: {{ product.stock }}</p>
      <el-button 
        type="danger" 
        :disabled="product.stock === 0"
        @click="handleSeckill(product.id)">
        立即抢购
      </el-button>
    </el-card>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { seckillApi } from '@/api/seckill'

const products = ref([])

const handleSeckill = async (productId) => {
  try {
    const result = await seckillApi.seckill(productId)
    if (result.success) {
      ElMessage.success('抢购成功!')
    } else {
      ElMessage.error(result.message)
    }
  } catch (error) {
    ElMessage.error('网络错误')
  }
}

onMounted(async () => {
  products.value = await seckillApi.getProducts()
})
</script>

关键技术点

1. 限流策略

// 令牌桶限流
func RateLimit() gin.HandlerFunc {
    limiter := rate.NewLimiter(100, 200) // 100qps
    return func(c *gin.Context) {
        if !limiter.Allow() {
            c.JSON(429, gin.H{"error": "请求过于频繁"})
            c.Abort()
            return
        }
        c.Next()
    }
}

2. 库存控制

  • Redis原子操作保证库存准确性
  • 预减库存+异步下单模式
  • 库存回滚机制

3. 服务发现

// 服务注册与发现
type Registry struct {
    services map[string][]string
}

func (r *Registry) Register(serviceName, address string) {
    r.services[serviceName] = append(r.services[serviceName], address)
}

部署架构

前端(Nginx) → Gin网关 → 服务注册中心
                    ↓
        秒杀服务 → 订单服务 → 用户服务
                    ↓
           Redis → MySQL

这个架构能够支持高并发秒杀场景,通过微服务拆分、缓存优化、限流降级等手段保证系统稳定性。

回到顶部