抢票系统详解

article/2025/9/24 11:54:49

转载自:https://blog.csdn.net/qq_37095882/article/details/102777226

秒杀抢购系统选型:

火车票秒杀系统如何在高并发情况下提供正常、稳定的服务呢?

我们知道用户秒杀流量通过层层的负载均衡,均匀到了不同的服务器上,即使如此,集群中的单机所承受的 QPS 也是非常高的。如何将单机性能优化到极致呢?

**要解决这个问题,我们就要想明白一件事:**通常订票系统要处理生成订单、减扣库存、用户支付这三个基本的阶段。

我们系统要做的事情是要保证火车票订单不超卖、不少卖,每张售卖的车票都必须支付才有效,还要保证系统承受极高的并发。

这三个阶段的先后顺序该怎么分配才更加合理呢?我们来分析一下:

下单减库存:

img

当用户并发请求到达服务端时,首先创建订单,然后扣除库存,等待用户支付。

这种顺序是我们一般人首先会想到的解决方案,这种情况下也能保证订单不会超卖,因为创建订单之后就会减库存,这是一个原子操作。

但是这样也会产生一些问题:

  • 在极限并发情况下,任何一个内存操作的细节都至关影响性能,尤其像创建订单这种逻辑,一般都需要存储到磁盘数据库的,对数据库的压力是可想而知的。
  • 如果用户存在恶意下单的情况,只下单不支付这样库存就会变少,会少卖很多订单,虽然服务端可以限制 IP 和用户的购买订单数量,这也不算是一个好方法。

支付减库存:

img

如果等待用户支付了订单在减库存,第一感觉就是不会少卖。但是这是并发架构的大忌,因为在极限并发情况下,用户可能会创建很多订单。

当库存减为零的时候很多用户发现抢到的订单支付不了了,这也就是所谓的“超卖”。也不能避免并发操作数据库磁盘 IO。

预扣库存:

img

从上边两种方案的考虑,我们可以得出结论:只要创建订单,就要频繁操作数据库 IO。

那么有没有一种不需要直接操作数据库 IO 的方案呢,这就是预扣库存。先扣除了库存,保证不超卖,然后异步生成用户订单,这样响应给用户的速度就会快很多;那么怎么保证不少卖呢?用户拿到了订单,不支付怎么办?

我们都知道现在订单都有有效期,比如说用户五分钟内不支付,订单就失效了,订单一旦失效,就会加入新的库存,这也是现在很多网上零售企业保证商品不少卖采用的方案。

订单的生成是异步的,一般都会放到 MQ、Kafka 这样的即时消费队列中处理,订单量比较少的情况下,生成订单非常快,用户几乎不用排队。

扣库存的艺术:

从上面的分析可知,显然预扣库存的方案最合理。我们进一步分析扣库存的细节,这里还有很大的优化空间,库存存在哪里?怎样保证高并发下,正确的扣库存,还能快速的响应用户请求?

在单机低并发情况下,我们实现扣库存通常是这样的:

img

为了保证扣库存和生成订单的原子性,需要采用事务处理,然后取库存判断、减库存,最后提交事务,整个流程有很多 IO,对数据库的操作又是阻塞的。

这种方式根本不适合高并发的秒杀系统。接下来我们对单机扣库存的方案做优化:本地扣库存。

我们把一定的库存量分配到本地机器,直接在内存中减库存,然后按照之前的逻辑异步创建订单。

改进过之后的单机系统是这样的:

img

这样就避免了对数据库频繁的 IO 操作,只在内存中做运算,极大的提高了单机抗并发的能力。

但是百万的用户请求量单机是无论如何也抗不住的,虽然 Nginx 处理网络请求使用 Epoll 模型,c10k 的问题在业界早已得到了解决。

但是 Linux 系统下,一切资源皆文件,网络请求也是这样,大量的文件描述符会使操作系统瞬间失去响应。

上面我们提到了 Nginx 的加权均衡策略,我们不妨假设将 100W 的用户请求量平均均衡到 100 台服务器上,这样单机所承受的并发量就小了很多。

然后我们每台机器本地库存 100 张火车票,100 台服务器上的总库存还是 1 万,这样保证了库存订单不超卖,下面是我们描述的集群架构:

img

问题接踵而至,在高并发情况下,现在我们还无法保证系统的高可用,假如这 100 台服务器上有两三台机器因为扛不住并发的流量或者其他的原因宕机了。那么这些服务器上的订单就卖不出去了,这就造成了订单的少卖。

要解决这个问题,我们需要对总订单量做统一的管理,这就是接下来的容错方案。服务器不仅要在本地减库存,另外要远程统一减库存。

有了远程统一减库存的操作,我们就可以根据机器负载情况,为每台机器分配一些多余的“Buffer 库存”用来防止机器中有机器宕机的情况。

我们结合下面架构图具体分析一下:

img

我们采用 Redis 存储统一库存,因为 Redis 的性能非常高,号称单机 QPS 能抗 10W 的并发。

在本地减库存以后,如果本地有订单,我们再去请求 Redis 远程减库存,本地减库存和远程减库存都成功了,才返回给用户抢票成功的提示,这样也能有效的保证订单不会超卖。

当机器中有机器宕机时,因为每个机器上有预留的 Buffer 余票,所以宕机机器上的余票依然能够在其他机器上得到弥补,保证了不少卖。

Buffer 余票设置多少合适呢,理论上 Buffer 设置的越多,系统容忍宕机的机器数量就越多,但是 Buffer 设置的太大也会对 Redis 造成一定的影响。

虽然 Redis 内存数据库抗并发能力非常高,请求依然会走一次网络 IO,其实抢票过程中对 Redis 的请求次数是本地库存和 Buffer 库存的总量。

因为当本地库存不足时,系统直接返回用户“已售罄”的信息提示,就不会再走统一扣库存的逻辑。

这在一定程度上也避免了巨大的网络请求量把 Redis 压跨,所以 Buffer 值设置多少,需要架构师对系统的负载能力做认真的考量。

总结回顾:

总体来说,秒杀系统是非常复杂的。我们这里只是简单介绍模拟了一下单机如何优化到高性能,集群如何避免单点故障,保证订单不超卖、不少卖的一些策略

完整的订单系统还有订单进度的查看,每台服务器上都有一个任务,定时的从总库存同步余票和库存信息展示给用户,还有用户在订单有效期内不支付,释放订单,补充到库存等等。

我们实现了高并发抢票的核心逻辑,可以说系统设计的非常的巧妙,巧妙的避开了对 DB 数据库 IO 的操作。

对 Redis 网络 IO 的高并发请求,几乎所有的计算都是在内存中完成的,而且有效的保证了不超卖、不少卖,还能够容忍部分机器的宕机。

我觉得其中有两点特别值得学习总结:

①负载均衡,分而治之

通过负载均衡,将不同的流量划分到不同的机器上,每台机器处理好自己的请求,将自己的性能发挥到极致。

这样系统的整体也就能承受极高的并发了,就像工作的一个团队,每个人都将自己的价值发挥到了极致,团队成长自然是很大的。

②合理的使用并发和异步

自Epoll 网络架构模型解决了 c10k 问题以来,异步越来越被服务端开发人员所接受,能够用异步来做的工作,就用异步来做,在功能拆解上能达到意想不到的效果。

这点在 Nginx、Node.JS、Redis 上都能体现,他们处理网络请求使用的 Epoll 模型,用实践告诉了我们单线程依然可以发挥强大的威力。

服务器已经进入了多核时代,Go 语言这种天生为并发而生的语言,完美的发挥了服务器多核优势,很多可以并发处理的任务都可以使用并发来解决,比如 Go 处理 HTTP 请求时每个请求都会在一个 Goroutine 中执行。

总之,怎样合理的压榨 CPU,让其发挥出应有的价值,是我们一直需要探索学习的方向。


http://chatgpt.dhexx.cn/article/bb8sBaQR.shtml

相关文章

程序员专用的抢票小助手,再也不用担心抢不到车票了。

作者:JackTian 微信公众号:杰哥的IT之旅(ID:Jake_Internet) 马上临近过年了,漂泊在远方的朋友,也都准备陆续抢过年回家的车票了,但是往年每次不管是十一假期还是年关,大家…

12306崩了,90%的人都用过这三款抢票工具

12306又蹦了 12306回应软件崩了:操作旅客过多,可尝试重装app或切换网络 有不少网友反映12306崩了,买票太难了。12306客服表示,可能是操作旅客过多,系统繁忙造成的,可尝试重新卸载安装客户端或切换网络。关…

Python 一百多行实现抢票助手

一. 代码使用PythonSplinter开发,Splinter是一个使用Python开发的开源Web应用测试工具,它可以帮你实现自动浏览站点和与其进行交互。 二. 安装好Python 3或2都可以,然后安装Splinter pip install Splinter 三. Splinter注意事项 1. Splinte…

分流抢车票软件

分流抢车票软件 下载地址 传送门 没积分的的可以私信取

抢票(python)

关注微信公众号: 程序工厂,不定期更新更新黑科技、脚本等资源 腾讯云服务器优惠购买链接: 1核2G云服务器首年88元:http://url.cn/5Z0ZWGI 阿里云服务器优惠购买链接: 服务器半年只需要54 https://www.aliyun.com/minisite/goods?userCo…

python实现云服务器上12306自动化抢票功能

本文将分为几大模块讲解python服务器上12306自动化抢票功能: 一、云服务器的安装与配置 1.1 云服务器与个人主机不同,不受时间、场所等条件的限制,将python代码运行在云服务器上可以实现真正意义上的解放。 1.2 这里,我选择阿里…

12306分流抢票软件 v1.13.21官方版 -抢票神器

软件介绍: 分流抢票,是以用户为中心、人性化的抢票软件。不做广告、不做推广、不携带病毒、不收集隐私信息,并接受各方技术评测,全心全意为用户打造一款属于自己的抢票软件!12306分流抢票器是能够提供给用户强大的自动…

12306GT多线程、分流免费抢票工具使用

大事记背景 我相信很多远游他乡的朋友每逢佳节都会遇到一个难题,就是购票难,这个难题有多难呢?经常在12306官网购票的小伙伴应该知道每个地方的放票时间是不一样的,但是逢年过节的那几天即使你在放票几分钟前一直盯着电脑屏幕或者…

分流抢票软件浅谈

其实,我不是很想写这篇文章的,因为现在有很多抢票的软件,即我们所说的第三方抢票软件,也有很多抢票的心得在网上,但是,我今天在微信晒了一个抢票成功的图片,就有很多人来问我,说要我分享这个软件,我在微信也看到一个师姐因抢不到票而哭,我就有了写下这篇文章的决心,…

免费的Windows抢票神器 – 12306分流抢票 – bypass

本页目录 分流抢票 官网要求操作 输入账号密码滑块登陆主界面绑定微信公众号后,可以获取消息 微信消息 年复一年的火车抢票大战,光靠我们人工抢是无法满足的,毕竟有很多第三方付费平台使用服务器间歇性抢票!更有甚者,第…

Bypass一款不错的分流抢票助手工具

前言 Bypass也就是12306分流抢票软件,是一款全程自动抢票,自动识别验证码,多线程秒单、稳定捡漏,支持多天、多车次、多席别、多乘客等功能。   下载 Bypass 使用方法 1.软件打开时,会有一个联网检测的过程。 2.输入你在中铁12306订票官网申请到的…

bypass分流抢票(火车、高铁)

1、双击运行Bypass.exe或者右键以管理员身份运行 2、输入账户、密码进行登录(该账户为12306的账户,如若没有则点击更多功能进行注册) 3、滑块登录 4、进行选择买票 5、设置支付选项(在这里可设置自动支付,也可在抢票成…

关于12306Bypass-分流抢票

原文地址为: 关于12306Bypass-分流抢票 12306Bypass-分流抢票-2013-15年 官网:http://www.12306bypass.com 分流抢票是一款完全免费的抢票软件,请抵制淘宝贩卖等诈骗行为 作者不会授权任何人去出售,更不会自己去出售&#xff0…

c语言scanf和printf区别,printf和scanf的区别是什么

printf和scanf的区别:1、printf是格式化的输出函数,scanf是C语言的输入功能;2、printf用于以规定格式将信息输出到标准输出设备,scanf是一种格式输入功能,即以用户指定的格式从键盘将数据输入到指定的变量中。 本文操作…

MongoDB和mysql的区别

一.什么是MongoDB MongoDB 是一个基于分布式文件存储的数据库。由 C 语言编写,是一个开源数据库系统。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富&#…

SDK和API的区别

SDK和API的区别 一、API的概念二、SDK的概念三、SDK和API的区别 在正式了解它们的区别之前,我们得先知道 SDK 和 API 分别是什么? 一、API的概念 我们先来看这样一张图: (图画的很烂就请不要在意了) API 的全称为 …

html div p区别,p标签和div标签的区别与用法

前面介绍过span与div区别,在html布局中p标签同样也是常用的标签,那p标签与div标签区别是什么,怎么选择使用与用法? 一、css属性区别 1、结构不同 div和p均是一对开始与闭合标签。 div以 开始,以 结束的一对标签。 p以 …

BeanFactory与ApplicationContext的区别

BeanFactory与ApplicationContext的区别? 一、BeanFactory和ApplicationContext 接口及其子类图 二、概述 BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。 BeanFactory: BeanF…

watch跟computed的区别

大家好,我是大帅子,今天给大家讲一下watch跟computed的区别,下面我们直接开始吧 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。 是否调用缓存:computed中的函数所依赖的属性没有发生变化,…

动态lacp和静态lacp区别_lacp静态与动态区别

lacp静态与动态区别是: 1、用户权限不同。动态lacp汇聚是一种系统自动创建/删除的汇聚,不允许用户增加或删除动态lacp汇聚中的成员端口。静态lacp汇聚由用户手工配置,不允许系统自动添加或删除汇聚组中的端口。汇聚组中必须至少包含一个端口。…