在假期期间,几乎的人回到家乡去玩耍几乎遇到了问题:抓住火车票!尽管在大多数情况下可以预订门票,但门票当时没有门票。我相信每个人都会经历过。尤其是在春节期间,您不仅使用12306,而且还考虑“ Zhixing”和其他票房 - 抓票软件。在此期间,该国数亿人正在抢票。“ 12306服务”受QP的影响,该QP无法超过这个世界上任何尖峰系统。数以百万计的并发是正常的!作者专门研究了“ 12306”的服务器体系结构,并在其系统设计中学习了许多亮点。在这里,我们与您分享并模拟一个示例:如何同时获得10,000次火车票,该系统提供了正常的系统来提供正常的系统以提供正常的配置,稳定服务。Github代码地址
较高的系统体系结构将通过分布式簇部署。该服务的上层具有一层负载平衡,并提供多种灾难恢复方法(双重打火机,节点容错的容忍度,服务器灾难准备等),以确保系统的高可用性。配置策略与不同的服务器平衡。BELOW是一个简单的示意图:
1.1上述负载平衡的引入介绍了对服务器的用户请求,以通过三个层压负载平衡。简要介绍了以下三个负载平衡:
1.2证明Nginx的加权旋转查询NGINX实现负载通过上游模块平衡。加权旋转查询的配置可以为相关服务添加相应的服务。当配置时,可以根据服务器的性能和负载容量设置相应的负载。以下是加权旋转负载的配置。我将在本地监视上收听端口3001-3004,分别配置1、2、3和4:
我在本地/etc/hosts目录中配置了www.load_balance.com的虚拟域名地址,然后使用GO语言打开四个HTTP端口监视服务。以下是监视3001端口的GO程序。其他只需要修改修改端口:
我将请求的端口日志信息写到https://www.shouxicto.com/article/stat.log文件,然后使用AB压力测试工具进行压力测试:
统计日志中的结果端口3001-3004分别获得了100、200、300、400,这与我在nginx.nginx中的重量的比例非常一致。NGINX的Upsteam模块。这是Nginx上游机构的负载平衡
回到我们首先提到的问题:火车票尖峰系统如何在高并发条件下提供正常和稳定的服务?
从上面的简介中,我们知道用户的尖峰流量通过负载层平衡,均匀地与不同的服务器平衡。即便如此,群集中的立场很高的QP也很高。如何优化极端的单元性能?要解决这个问题,我们需要了解一件事:通常是三个基本阶段预订系统必须处理生产订单,扣除库存和用户付款。我们要做的是确保火车票务订单不超过超过例外的超过超过例外。销售,大量销售,必须支付每笔出售的每张售票才能有效,并且必须对系统产生影响很高的并发状况。如何分配这三个阶段的三个阶段的顺序更合理?让我们分析:
2.1当用户达到到达服务器的请求时,首先创建订单,然后扣除库存并等待用户付款时,将订单减少放置。该订单是我们想到的第一个解决方案。在这种情况下,我们可以确保订单不会超卖,因为它将在创建订单后减少库存。这是一个原子操作,但这也会引起一些问题。首先是在限制的情况下,任何内存操作的详细信息都会影响性能,尤其是创建订单的逻辑。通常,有必要将其存储到磁盘数据库中。第二个是,如果用户有恶意订购,则只有库存只能在不付款的情况下放置,并且会出售更少的订单。尽管服务器可以限制IP和用户的采购订单的数量,但这不是一个好方法。
2.2减少付款。如果用户正在等待用户支付订单,则第一种感觉不会少卖。当库存减少到零时,许多用户发现他们抓取的订单无法支付。这是So -call的“超级销售” Essencenor,可以避免并发操作数据库磁盘io
2.3考虑到上述两个方案的预测清单,我们可以得出结论,只要创建订单,我们必须经常操作数据库IO。因此,是否有一个解决方案不需要直接操作数据库IO?这是预先定位的库存。首先扣除库存,以确保其不超卖,然后作为用户订单生成,以便响应用户的速度会更快地;那么如何确保大量销售?如果用户获得订单并且不付款,该怎么办?我们都知道这些订单现在有有效期。例如,如果用户在五分钟内不付款,则该订单将无效。订单失败后,将添加新的库存。这也是许多在线零售公司确保出售许多产品的解决方案。订单的产生是异步的。通常将其放在即时消费者队列中,例如MQ和KAFKA。当订单量相对较小时,订单非常快,用户几乎不需要排队。
从上面的分析可以看出,预先描述库存的计划是最合理的。我们进一步分析了推论库存的细节。这里仍然有很大的优化空间。库存在哪里存在?如何确保高高和合并库存,并可以快速响应用户请求?
对于低单机器,我们意识到推论库存通常是这样的:
为了确保扣除库存的原子量并生成订单,需要使用交易处理,然后应使用库存判断和库存。最后,交易已提交。在整个过程中都有许多iOS,并且数据库的操作被阻止。该方法根本不适合高平行的尖峰系统。
接下来,我们优化单个扣除库存的解决方案:本地扣除库存。我们根据先前的逻辑分配一定数量的清单,直接在内存中分配一定数量的清单,直接在内存中减少库存,然后根据先前的逻辑创建订单异步异步。- 改进后的系统是这样的:
这样,避免了数据库的频繁IO操作,并且只有内存中的操作才大大提高了站立的能力 - 仅能抵抗。但是,数以百万计的用户请求无论如何都无法抗拒。尽管NGINX处理网络请求使用EPOLL模型,但C10K的问题长期以来一直在行业中解决。但是,在Linux系统下,所有资源都是文件,并且网络请求是相同的。大量文件描述符将使操作系统立即失去响应。我们提到了上述NGINX的加权平衡策略。我们也可以假设100W用户请求的金额与100台服务器保持平衡,因此单个机器的复杂性要小得多。然后,每台机器的本地清单中的每一个库存都是100台火车票,以及在该机器上的总库存100台服务器仍为10,000。
问题随之而来。在高并发状态下,我们仍然无法保证系统的高可用性。如果在这100个服务器上有两三台无法执行或其他原因的机器。订单量,这是下一个容忍度计划。服务器不仅必须在本地减少库存,而且还必须远程减少库存。通过远程统一减少库存的操作,我们可以根据每台机器的多余的“缓冲库存”,根据机器的负载以防止机器在计算机中放下机器。LET分析以下架构图:
我们使用REDIS存储统一库存,因为Redis的性能很高,声称单个机器QP可以抵抗10W并发。当地还原库存后,如果当地有订单,我们将要求远程库存REDIS和REDIS和REDIS库存。本地减少库存和远程减少库存成功,然后返回用户成功的提示。Superb。当机器中的机器停机时,每台计算机上都有一张保留的缓冲票,而市区机器上的剩余门票可以仍然可以在其他机器上弥补,以确保大量销售。缓冲投票设置如何?从理论上讲,缓冲区越多,系统中的机器数量越耐市区,但是大型缓冲区设置将对redis产生一定的影响。尽管REDIS内存数据库具有很高的能力来抵抗并发能力,该请求仍将接收互联网io。实际上,在获取机票的过程中,REDIS的请求数是本地库存和缓冲库存的总量,因为当本地库存不足时,系统将直接返回用户“已售罄的信息提示“将不再遵循统一扣除清单的逻辑。这也避免了巨大的网络请求挤压Redis,因此设置了多少缓冲区,并且需要通过系统负载来加载架构师。
GO语言是同时设计的本地人。我使用GO语言向您展示单手机票的特定过程。
4.1初始化GO软件包中的INIT函数,主函数在主函数中执行。在此阶段,主要进行了一些准备工作。我们需要做的准备工作是:本地库存的初始化,初始化的远程redis存储统一库存的哈希键值,初始化redis连接池;另外,您还可以使用阅读锁或其他方法(例如Redis)来避免资源竞争,但是使用渠道更有效。这是GO语言的理念:不要通过共享记忆进行通信,而是通过通信共享内存。REDIS库使用Redigo,以下是代码实现:
4.2本地扣除库存和统一扣除库存本地扣除库存逻辑非常简单。用户请求过来,添加销售,然后比较销售量是否大于本地库存。布尔值:
请注意,共享数据的操作是使用锁实施的,但是由于本地扣子库存和统一的扣子库存是原子操作,因此使用顶层的频道实现了它。均匀地扣除了库存操作,因为redis是单读单读的单线读取。,我们需要从中实现数据,编写数据并计算某些序列步骤。我们必须与LUA脚本合作以包装命令,以确保操作的原子量:
我们使用哈希结构来存储总库存和总销售信息。当用户要求它时,它将确定总销售量是否大于库存,然后返回相关的布尔值。在开始服务之前,我们需要初始化Redis的初始库存信息:
4.3响应用户信息,我们打开HTTP服务并在一个端口上进行监视:
我们已经完成了上述所有初始化工作。接下来,HandleReq的逻辑非常清楚。判断票是否成功并返回用户信息是一件好事。
如前所述,当我们扣除清单时,我们必须考虑竞争条件。我们使用该频道避免并发读写,确保请求的有效订单执行。我们将接口的返回信息写给https://www.shouxicto.com/article/article/stat.log文件,以促进压力测试统计数据。
4.4单机械服务压力测试打开服务,我们使用AB压力测试工具进行测试:
以下是我当地低Mac的压力测试信息
根据指标,我们可以每秒处理4000多个请求。普通服务器是多核配置。1W+的请求没有问题。查看日志发现,在整个服务过程中该请求是正常的,流量均匀,REDIS正常:
总体而言,尖峰系统非常复杂。在这里,我们只是简要介绍了如何优化高性能的立场,如何避免单点失败,以确保订单不超卖,许多卖出许多策略,以及完整的订单系统还具有订单进度。它是从总库存和库存信息定期显示给用户的。用户在订单的有效期内不付款,释放订单,补充库存等等。
我们已经实现了高并发抓票的核心逻辑。可以说,系统设计非常聪明,并且DB数据库IO的操作巧妙地避免了。它已经完成,并有效保证它不会超卖,很多销售,并且可以容忍某些机器的停机时间我认为其中两个特别值得学习并总结: