深入解析:写入瓶颈到削峰填谷:基于 Redis 与 MySQL 的高并发写入工程化方案

1. 方案背景与目标

1.1 为什么需要优化高并发写入?

在高并发场景下(如 注册、登录、提交订单、IoT 设备上报),直接写入数据库会导致:

  • 数据库连接池耗尽(如 MySQL 的 max_connections被打满)。
  • 事务锁竞争(如行锁、表锁导致请求阻塞)。
  • 磁盘 I/O 和 CPU 压力激增(如 InnoDB 日志刷盘、索引维护)。
  • 接口响应变慢(P99 延迟飙升,用户体验下降)。

目标:通过 Redis 缓冲 + 批量入库 + 最终一致性,将瞬时高并发写入 平滑削峰,提升系统吞吐量(QPS),同时保证数据最终不丢失。

2. 整体架构设计

2.1 核心流程

  1. 客户端 提交写入请求(如注册信息)。
  2. Gin 接口层
    • 幂等校验(防止重复提交,如用 Redis SETNX 对 phone加锁)。
    • 快速写入 Redis 队列(如 LPUSH reg_queue,JSON 格式存储请求数据)。
    • 立即返回(代表请求已接收,后续异步处理)。
  3. 批处理 Worker(独立 Goroutine):
    • 定时/定量触发(如每 100ms 或每 500 条数据)。
    • 从 Redis 拉取批量数据(如 BRPOP reg_queue 50ms)。
    • 去重 & 合并(按业务唯一键,如 phone去重)。
    • 批量写入 MySQL(使用 INSERT ... ON DUPLICATE KEY UPDATE)。
    • 成功后清理 Redis 消息(或标记为已处理)。
  4. 结果查询(可选):客户端通过 request_id轮询或回调获取最终状态。

2.2 关键组件

组件作用技术选型
Redis缓冲队列、幂等去重、结果缓存Go-Redis(官方库)
MySQL最终数据存储GORM / database/sql
批处理 Worker定时/定量拉取 Redis 数据并入库Goroutine + Channel
GinHTTP 接口层Gin Framework

3. 详细实现(Go + Gin 代码示例)

3.1 1. 幂等校验(防止重复提交)

目标:同一 phone10 秒内 只能提交一次,避免重复写入 Redis 和数据库。

// redis_dedup.go
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
"time"
)
var rdb *redis.Client
func initRedis() {

rdb = redis.NewClient(&redis.Options{

Addr:     "localhost:6379", // Redis 地址
Password: "",               // 无密码
DB:       0,                // 默认 DB
})
}
// TryAcquireDedup 尝试获取幂等锁(10 秒过期)
func TryAcquireDedup(ctx context.Context, phone string) bool {

key := fmt.Sprintf("reg:dedup:%s", phone)
// SET key "1" NX EX 10 → 如果 key 不存在则设置,并设置 10 秒过期
ok, err := rdb.SetNX(ctx, key, "1", 10*time.Second).Result()
if err != nil {

fmt.Printf("Redis SETNX 失败: %v\n", err)
return false
}
return ok
}

在 Gin 接口层调用

// main.go
r := gin.Default()
initRedis() // 初始化
posted @ 2025-11-28 12:35  gccbuaa  阅读(13)  评论(0)    收藏  举报