[Go]-抢购类业务方案

news2024/9/21 14:29:53

在这里插入图片描述

文章目录

    • 要点:
      • 1. 抢购/秒杀业务的关键挑战
      • 2. 技术方案
      • 3.关键实现点
      • 4.性能优化建议
      • 5.其他考虑因素
    • 细节拆分:
      • 1. **高并发处理**
      • 2.**限流与防护**
      • 3.**库存控制**
      • 4. **异步处理**
      • 5. **数据一致性**
      • 6. **常用架构设计**
      • 7. **代码示例**
      • 8. 进一步优化
      • 9. 注意事项

抢购类业务常用于促销活动,如热销白酒、大月饼、低价显卡、抢票,用户是想挤进去抢到东西,商家端是吸引更多的流量,但是东西就是固定数额,肯定不想被恶意刷单或者超卖等场景,
这就对系统有强烈要求,这类业务需要处理高并发请求,以确保系统的稳定性和公平性,同时避免超卖现象。

抢购类业务(如秒杀)是一种在限定时间内,以极低的价格向消费者提供少量商品的促销活动。

Go语言在此类业务中有相当的优势,内存消耗低,天生支持并发,还可以离线打包,做一些小工具很方便。

公司业务中,防止频繁搜索,爬虫等,会用到令牌桶,进行限流。

以下列举一些场景,和针对高并发的处理方式

要点:

1. 抢购/秒杀业务的关键挑战

  • 高并发处理: 秒杀活动通常会吸引大量用户同时下单,服务器需要处理大量并发请求。
  • 库存管理: 需要确保库存的准确性,避免超卖。
  • 事务处理: 要保证多个操作的原子性,确保数据一致性。

2. 技术方案

  • 缓存层: 利用Redis等缓存技术,将库存数据保存在缓存中,减少数据库的压力。
  • 消息队列: 通过消息队列(如RabbitMQ、Kafka等)来削峰填谷,将高并发请求排队处理,避免服务器被瞬间击垮。
  • 乐观锁/悲观锁: 使用数据库锁或乐观锁来保证库存的正确性和事务的完整性。

3.关键实现点

  1. Redis 原子操作:通过 Lua 脚本确保扣减库存和判断库存是否充足的操作在 Redis 中是原子性的。
  2. 并发模拟:使用 sync.WaitGroup 模拟多个并发用户抢购。
  3. 库存管理:Redis 的 decr 函数用于减少库存,并且确保不会超卖。

4.性能优化建议

  • 本地缓存:使用内存缓存(如 sync.Map 或 LRU 缓存)减少频繁的 Redis 访问。
  • 读写分离:对高并发的读操作可以通过缓存层或数据库读写分离架构优化。
  • CDN 加速:对于静态资源或非关键请求,可以通过 CDN 缓解服务器压力。

5.其他考虑因素

  • 防止重复抢购:可以通过 Redis 的 setnx 或数据库唯一索引避免用户多次抢购同一商品。
  • 分布式锁:在高并发场景下,可以通过 Redis 分布式锁或数据库锁确保多个实例对库存的操作不会冲突。
  • 请求日志和监控:记录用户请求日志和库存变化,便于监控和追踪问题。

细节拆分:

1. 高并发处理

抢购类业务通常伴随着大量并发请求。Go 语言的高并发处理能力让它在这种场景下非常适用。

  • goroutine 并发:Go 的 goroutine 可以轻松处理大规模并发。抢购时每个用户的请求可以用 goroutine 处理。

  • 限流:为了防止服务器超载,可以引入限流机制。常见的限流方式包括:

    • 漏桶算法:按固定速率处理请求,防止过多请求冲击系统。
    • 令牌桶算法:允许一定程度的突发请求,超出限额后将请求拒绝。

    Go 中可以使用第三方库如

    golang.org/x/time/rate
    

    实现限流。

2.限流与防护

防止大量恶意请求和超高并发打垮系统,通常会采取以下策略:

  • 接口限流:通过令牌桶算法、漏桶算法或 Redis 实现接口限流,控制每秒允许的请求数量。
  • IP 限制:限制同一个 IP 的请求频率,防止 DDoS 攻击。
  • 用户限流:对于每个用户设置抢购次数的限制,防止恶意刷单。

3.库存控制

抢购业务中,库存的控制非常关键,不能超卖或少卖。常用的方法有:

  • 本地缓存库存:在抢购开始时将库存加载到应用层内存中进行扣减,以提高响应速度。用完库存后,再同步更新到数据库中。
  • 分布式锁:在多个应用实例之间控制库存时,可以使用分布式锁来保证同一时间只有一个实例操作库存,防止超卖。可以通过 Redis 的 SETNX 实现分布式锁,或使用诸如 Etcd、Zookeeper 等注册中心自带的锁机制。
  • 乐观锁:通过数据库字段(如版本号或库存数量)进行更新时的版本控制来防止超卖。MySQL 支持通过 UPDATE 操作中的 WHERE 条件来进行版本检查。
  • **Lua脚本:**Redis 可以用来存储库存数据,并且通过 Lua 脚本实现原子性操作,避免超卖的情况。Redis 的高性能特性也非常适合高并发场景。
  • 预减库存:当用户发起抢购请求时,先在 Redis 中预减库存,确保高并发情况下不会超卖。
  • 最终库存确认:抢购成功后,再将最终的订单写入数据库,并从 Redis 中同步更新实际库存。如果用户未成功下单,Redis 中的库存会回滚。

4. 异步处理

抢购业务中,许多操作可以异步化处理,如订单生成、库存核减、用户通知等。

  • 消息队列:可以将用户的抢购请求推入消息队列(如 Kafka、RabbitMQ),后续再异步处理订单生成和库存扣减。这样可以避免数据库的直接冲击,提高系统的稳定性。
  • 异步任务队列:针对抢购结束后的订单处理和支付,可以使用异步任务队列(如 Celery)来处理非实时任务。

5. 数据一致性

为了确保数据在高并发下的一致性,需要控制并发修改的顺序和处理好数据库事务。

  • 事务机制:在处理订单时,可以通过数据库的事务机制来保证库存扣减和订单生成的一致性。
  • 分布式事务:在分布式架构下,通过 TCC (Try-Confirm-Cancel) 模式、2PC (Two-phase Commit) 或 SAGA 模式来保证分布式系统中的事务一致性。
  • 分布式锁:如果多台服务器处理抢购订单,可以通过 Redis 分布式锁来保证同一时刻只有一台服务器操作库存数据,防止并发操作造成超卖。

6. 常用架构设计

抢购类业务的架构通常包括以下几部分:

  1. 前端限流:通过 Nginx 等代理服务器进行限流,过滤掉部分请求。
  2. 服务端限流:使用 Redis、令牌桶等方式在服务端进一步限流,防止请求压力过大。
  3. 库存预加载:将库存放入 Redis 或本地内存中进行预处理,以提高响应速度。
  4. 异步处理:将订单生成、库存扣减、用户通知等操作异步化处理,提升抢购效率。
  5. 数据持久化:最终将抢购结果持久化到数据库中,并同步更新库存信息。

7. 代码示例

以下是一个简单的Go实现,用Redis管理库存,并处理用户的抢购请求:

package main

import (
    "fmt"
    "github.com/go-redis/redis/v8"
    "context"
    "sync"
)

var ctx = context.Background()

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    // 初始化库存数量
    rdb.Set(ctx, "item_stock", 100, 0)

    // 模拟并发抢购
    var wg sync.WaitGroup
    for i := 0; i < 200; i++ {
        wg.Add(1)
        go func(userID int) {
            defer wg.Done()
            err := purchaseItem(rdb, userID)
            if err != nil {
                fmt.Printf("User %d failed to purchase: %s\n", userID, err)
            } else {
                fmt.Printf("User %d successfully purchased the item.\n", userID)
            }
        }(i)
    }
    wg.Wait()
}

// 处理抢购请求
func purchaseItem(rdb *redis.Client, userID int) error {
    // 乐观锁机制,减少库存
    err := rdb.Watch(ctx, func(tx *redis.Tx) error {
        stockStr, err := tx.Get(ctx, "item_stock").Result()
        if err != nil {
            return err
        }

        stock, err := strconv.Atoi(stockStr)
        if err != nil || stock <= 0 {
            return fmt.Errorf("Out of stock")
        }

        // 使用事务保证库存减少的原子性
        _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
            pipe.Decr(ctx, "item_stock")
            return nil
        })
        return err
    }, "item_stock")

    return err
}

这个示例采用乐观锁,当然也可以采用Lua脚本配合Redis扣减库存(为了防止库存超卖,通常会使用 Redis 的原子操作 来实现库存扣减)

// Redis 脚本实现原子扣减库存
local inventory = redis.call('GET', KEYS[1])
if (tonumber(inventory) <= 0) then
    return 0
end
redis.call('DECR', KEYS[1])
return 1

8. 进一步优化

  • 防止重复下单: 利用Redis的SETNX命令可以防止用户重复下单。
  • 分布式锁: 在分布式系统中,使用Redis的分布式锁机制,确保只有一个请求能修改库存。
  • 动态限流: 利用令牌桶等算法对并发请求进行限流,防止流量瞬间过载。

9. 注意事项

  • 幂等性: 秒杀系统中,每个操作必须是幂等的,以防止因网络延迟或重试机制造成数据的不一致。
  • 数据库优化: 针对热点数据表的读写,需要做好索引优化、分库分表等设计。

通过这些手段,能够有效地提高抢购类业务的性能和稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2111610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙(API 12 Beta6版)图形加速【OpenGL ES平台内插模式】超帧功能开发

超帧内插模式是利用相邻两个真实渲染帧进行超帧计算生成中间的预测帧&#xff0c;即利用第N-1帧和第N帧真实渲染帧预测第N-0.5帧预测帧&#xff0c;如下图所示。由于中间预测帧的像素点通常能在前后两帧中找到对应位置&#xff0c;因此内插模式的预测帧效果较外插模式更优。由于…

android studio 模拟器 loadlibrary failed with 126:找不到指定的模块

loadlibrary failed with 126:找不到指定的模块 解决方法 解决方法&#xff1a;设备管理器-> 显示适配器-> 禁用 AMD Redeon 重启AndroidStudio

【学习笔记】 陈强-机器学习-Python-Ch14 支持向量机

系列文章目录 监督学习&#xff1a;参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归&#xff08;SAheart.csv&#xff09; 【学习笔记】 陈强-机器学习-Python-…

示波器在嵌入式中的作用和使用

你是否在开发嵌入式系统时&#xff0c;遇到过调试电路和信号分析的困难&#xff1f; 在嵌入式开发中&#xff0c;硬件调试和信号分析是必不可少的环节&#xff0c;而示波器作为一种强大的工具&#xff0c;能够帮助我们深入了解信号特性并解决难题。那么&#xff0c;如何正确使用…

Aigtek功率放大器可以驱动哪些传感器设备

功率放大器是一种电子设备&#xff0c;主要用于将输入信号增强到更高的功率级别并驱动各种负载。在传感器应用中&#xff0c;功率放大器可以用来驱动多种传感器设备&#xff0c;下面将介绍几个常见的应用场景。 光学传感器&#xff1a;光学传感器是一类基于光学原理工作的传感器…

Django发送邮件

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 Django 5框架Web应用开发_夏天又到了的博客-CSDN博客 本文学习怎么使用Django发送邮件。 尽管使用Python的smtplib模块发送电子邮件…

Flutter集成Firebase中的Remote Config

远程配置&#xff08;Remote Config&#xff09;的功能 动态配置参数&#xff1a;Remote Config 允许您在不更新应用程序的情况下&#xff0c;实时更改应用程序的参数&#xff0c;如文本、颜色、布尔值等条件化参数&#xff1a;您可以基于用户的特定条件&#xff08;例如用户地…

ADC——模数转换器

一、转换流程 在处理器中主要进行ADC 1、AD转换流程 &#xff1a;采样、保持、量化、编码 通过比较器获得的电信号转换数字信号&#xff0c;根据自己需求&#xff0c;如果要求速率就可以使用较多的比较器&#xff0c;不要求速率考虑成本就可以使用较少的比较器&#xff0c;将最…

【Oracle篇】全面理解优化器和SQL语句的解析步骤(含执行计划的详细分析和四种查看方式)(第二篇,总共七篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

828华为云征文 | Flexus X实例CPU、内存及磁盘性能实测与分析

引言 随着云计算的普及&#xff0c;企业对于云资源的需求日益增加&#xff0c;而选择一款性能强劲、稳定性高的云实例成为了关键。华为云Flexus X实例作为华为云最新推出的高性能实例&#xff0c;旨在为用户提供更强的计算能力和更高的网络带宽支持。最近华为云828 B2B企业节正…

AFSim仿真系统---向导参考指南 (1)

向导参考指南 向导参考指南列出了包含在向导中的功能&#xff0c;并按各种类别进行了组织。 启动 命令行选项 1 命令行参数 - 向导 用法&#xff1a; wizard.exe [ <file_name.txt> ][ <project_file.afproj> ]{ -console } <file_name1.txt> <file_n…

QT:QWidget 控件属性的介绍

控件属性介绍 &#x1f334;enabled 状态属性&#x1f334;geometry 几何属性示例一&#xff1a;改变控件尺寸示例二&#xff1a;更变控件位置window frame 的影响 &#x1f334;windowTitle 窗口标题&#x1f334;windowIcon 窗口图标&#x1f334; qrc机制&#x1f334;windo…

DevExpress WinForms v24.1新版亮点:功能区、数据编辑器全新升级

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…

CMAQ 5.4 输入与输出数据

CMAQ 5.4 输入与输出数据 参考 CMAQ输入文件.https://github.com/USEPA/CMAQ/blob/main/DOCS/Users_Guide/CMAQ_UG_ch04_model_inputs.md CMAQ输出文件.https://github.com/USEPA/CMAQ/blob/main/DOCS/Users_Guide/CMAQ_UG_ch07_model_outputs.md 目录 文章目录 CMAQ 5.4 输…

企业如何组建安全稳定的跨国通信网络?

组建一个安全稳定的跨国通信网络对于现代企业来说至关重要&#xff0c;尤其是当企业在全球范围内运营时。以下是一些关键步骤和考虑因素&#xff1a; 需求分析&#xff1a; 确定企业的具体通信需求&#xff0c;包括带宽要求、延迟敏感度、数据类型&#xff08;如语音、视频、文…

Sobel边沿检测

前言 Sobel边沿检测是一种用于图像处理的边缘检测技术。它通过计算图像的梯度来识别图像中的边缘。Sobel算子是一种常用的边缘检测滤波器&#xff0c;它利用两个卷积核来分别检测水平和垂直方向的边缘。Sobel边沿检测在很多图像处理应用中都很有用&#xff0c;比如图像分割、目…

SpringBoot 集成 PDFBox 实现电子签章

Apache PDFBox 是一个开源的 Java 库&#xff0c;用于处理 PDF 文档。它提供了一系列强大的功能&#xff0c;包括创建、渲染、拆分、合并、加密、解密 PDF 文件&#xff0c;以及从 PDF 中提取文本和元数据等。PDFBox 支持 PDF 1.7 标准&#xff0c;并且兼容大多数现代 PDF 格式…

为何iPhone 16系列的发布对苹果至关重要?

即将发布的iPhone 16系列对苹果来说将是至关重要的时刻&#xff0c;特别是在快速发展的AI智能手机市场背景下。随着Android制造商在集成先进AI功能方面领先一步&#xff0c;苹果正处于一个关键的转折点——赶上竞争对手不仅仅是选择&#xff0c;而是必须完成的任务。 AI竞赛&am…

java设计模式(行为型模式:状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式)

6&#xff0c;行为型模式 6.5 状态模式 6.5.1 概述 【例】通过按钮来控制一个电梯的状态&#xff0c;一个电梯有开门状态&#xff0c;关门状态&#xff0c;停止状态&#xff0c;运行状态。每一种状态改变&#xff0c;都有可能要根据其他状态来更新处理。例如&#xff0c;如果…

SpringCloud集成ELK

1、添加依赖 <dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>6.1</version> </dependency>2、在logback-spring.xml中添加配置信息&#xff08;logback-sp…