System Design笔记:在线售票系统设计

文章目录

    • 何为在线售票系统?
    • 系统目标和要求
      • 1、功能要求
      • 2、非功能性需求
      • 3、设计注意事项
      • 4、容量估算
      • 5、系统API
        • 1.SearchMovies
        • 2.ReserveSeats
      • 6、数据库设计
      • 7、高级设计
      • 8、细节模块设计
      • 9、流程
        • 服务器如何跟踪所有尚未预订的active预订?服务器如何跟踪所有等待的客户?
        • ActiveReservationService
        • WaitingUsersService
      • 10、并发性
      • 11、容错性
      • 12、数据分区

何为在线售票系统?

电影票预订系统为其客户提供了在线购买影院座位的能力。Eticketing系统允许客户浏览当前正在播放的电影并预订座位,随时随地。

系统目标和要求

1、功能要求

功能要求:

  • 1、我们的售票服务应该能够列出其附属影院所在的不同城市。
  • 2、一旦用户选择城市,服务应显示在该特定城市发布的电影。
  • 3、一旦用户选择了一部电影,服务应显示运行该电影的电影院及其可用放映时间。
  • 4、用户应该能够在特定电影院选择一场演出并预订门票。
  • 5、服务应能向用户展示影院大厅的座位安排。用户应该能够根据自己的喜好选择多个座位。
  • 6、用户应能区分可用座位和预定座位。
  • 7、用户应能在付款完成预订之前,将座位保留五分钟。
  • 8、如果座位有可能可用,例如,当其他用户持有的座位过期时,用户应该能够等待。
  • 9、等待的客户应以公平、先到先服务的方式进行服务。

2、非功能性需求

1、系统需要高度并发。

在任何特定时间点,同一座位都会有多个预订请求。服务应该优雅而公平地处理这一问题。

2、这项服务的核心是订票,即金融交易。

这意味着系统应该是安全的,并且数据库符合ACID。

3、设计注意事项

1。为简单起见,假设我们的服务不需要任何用户身份验证。

2、系统不处理部分客票订单。要么用户得到了他们想要的所有门票,要么什么也得不到。

3、公平是制度的强制性要求。

4、为了防止系统滥用,我们可以限制用户一次预订10个以上的座位。

5、我们可以假设,在人们期待已久的热门电影上映时,流量会急剧上升,座位很快就会挤满。该系统应具有可扩展性和高可用性,以跟上流量激增的步伐。

4、容量估算

1、流量估计

假设我们的服务每月有30亿次页面浏览量,销量为10%一个月一百万张票。

2、存储量估计

假设我们有500个城市,平均每个城市有10家电影院。如果每家电影院有2000个座位,平均每天有两场演出。

假设每个座位预订需要50字节(ID、NumberOfSeats、ShowID、MovieID、SeatNumber、SeatStatus、Timestamp等)存储在数据库中。我们还需要存储关于电影和电影院的信息;假设需要50字节。所以,要存储所有关于所有城市的所有电影院一天的放映:

500 cities * 10 cinemas * 2000 seats * 2 shows * (50+50) bytes = 2GB / day

要存储五年的数据,我们需要大约3.6TB。

5、系统API

我们可以使用SOAP或RESTAPI来公开服务的功能。以下可能是用于搜索电影节目和预订座位的API的定义。

1.SearchMovies

在这里插入图片描述

api参数讲解:

api_dev_key (string): 注册账户的API开发人员密钥。这将用于根据分配的配额限制用户。keyword (string): 要搜索的关键字city (string): 筛选电影的城市lat_long (string): 用来过滤的经纬度信息radius (number): 要搜索事件的区域半径 start_datetime (string): 用来筛选的电影的开始日期end_datetime (string): 用来筛选的电影的结束日期postal_code (string): 用来筛选的邮政编码includeSpellcheck (Enum: “yes” orno): 拼写检查建议results_per_page (number): 每页返回的结果数。 Maximum is 30. sorting_order (string): 对搜索结果进行排序. 
Some allowable values : ‘name,asc, ‘name,desc,date,asc,date,desc, ‘distance,asc, ‘name,date,asc, 
‘name,date,desc,date,name,asc,date,name,desc. 

下面是电影及其节目的示例列表,后台的Returns: (JSON)

[{"MovieID": 1,"ShowID": 1,"Title": "Cars 2","Description": "About cars","Duration": 120,"Genre": "Animation","Language": "English","ReleaseDate": "8th Oct. 2014","Country": USA,"StartTime": "14:00","EndTime": "16:00","Seats":[{"Type": "Regular""Price": 14.99"Status: "Almost Full"},{"Type": "Premium""Price": 24.99"Status: "Available"}]},{"MovieID": 1,"ShowID": 2,"Title": "Cars 2","Description": "About cars","Duration": 120,"Genre": "Animation","Language": "English","ReleaseDate": "8th Oct. 2014","Country": USA,"StartTime": "16:30","EndTime": "18:30","Seats":[{"Type": "Regular""Price": 14.99"Status: "Full"},{ "Type": "Premium""Price": 24.99"Status: "Almost Full"}]},]

2.ReserveSeats

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ljkgijqY-1655134117332)(https://secure2.wostatic.cn/static/p7qSP9rcbkEe3tTxkKPC3w/image.png)]

api参数讲解:

api_dev_key (string): same as above session_id (string): 用于跟踪此预订的用户会话ID。一旦保留时间到期,将使用此删除用户在服务器上的保留
身份证件movie_id (string): 要预定的电影show_id (string): 要预定的场次eats_to_reserve (number): 包含要保留的座位ID的数组

下面是api返回值:Returns: (JSON)

Returns the status of the reservation, which would be one of the following: 
1) “Reservation Successful” 
2) “Reservation Failed - Show Full,” 
3) “Reservation Failed - Retry, as other users are holding reserved seats”. 

6、数据库设计

我们要存储的数据:

1、每个城市可以有多家电影院。

2、每家电影院将有多个大厅。

3、每部电影将有多场演出,每场演出将有多个预订。

4、一个用户可以进行多次预订。

下面是UML表单图设计

在这里插入图片描述

7、高级设计

在上层,我们的web服务器将管理用户会话,应用服务器将处理所有票证管理,将数据存储在数据库中,并与缓存服务器一起处理预订。

在这里插入图片描述

8、细节模块设计

首先,让我们尝试构建我们的服务,假设它是从单个服务器提供的。

以下是典型的售票流程:

1.用户搜索电影。

2.用户选择一部电影。

3.向用户显示电影的可用放映。

4.用户选择一个场次。

5.用户选择要预订的座位数目

6.如果有所需数量的座位,则会向用户显示要选择的剧院地图座位。如果没有,用户将进入下面的“步骤8”。

7.一旦用户选择了座位,系统将尝试预订这些选定的座位。

8.如果无法预订座位,我们有以下选择:

  • 本场次已满座,向用户显示错误消息
  • 用户想要预订的座位不再可用,但还有其他座位可用,因此用户将返回影院地图以选择不同的座位。
  • 没有可用的座位可预订,但是进入选定状态的座位有些还没有支付,也就是预订池中有一些其他用户持有的座位尚未预订。用户将进入等待页面,在那里他们可以等待,直到所需的座位从预订池中释放出来。这种等待可能会导致以下选项:
    • 如果所需的座位数量可用,用户将被带到剧院地图页面,在那里他们可以选择座位。
    • 等待期间,如果所有座位都已预订成功,或者预订池中的座位数少于用户预定的座位数,则会向用户显示错误消息。
    • 用户取消等待并返回到电影搜索页面。
    • 在用户会话过期并返回到电影搜索页面后,用户最多可以等待一个小时。

9.如果成功预订座位,用户有五分钟的时间支付预订费用。付款后,预订被标记为完成。如果用户无法在五分钟内付款,则其所有预留座位将被释放,以供其他用户使用。
整个流程如下:

在这里插入图片描述

9、流程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

服务器如何跟踪所有尚未预订的active预订?服务器如何跟踪所有等待的客户?

我们需要两个守护程序服务,一个用于跟踪所有active预订并从系统中删除任何过期的预定;我们称之为ActiveReservationService。

另一项服务将跟踪所有等待的用户请求,一旦所需的座位数可用,它将通知(等待时间最长的)用户选择座位;我们叫它WaitingUserService吧。

ActiveReservationService

除了将所有数据保存在数据库中之外,我们还可以将本场次的所有预定保留在内存中,保存在类似于链接HashMap或TreeMap的数据结构中。

我们需要一个链接的HashMap类型的数据结构,允许我们跳转到任何预订,以便在预订完成后将其删除。

此外,由于我们将有与每个保留相关联的过期时间,哈希映射的头部将始终指向最旧的保留记录,以便在达到超时时可以过期保留。

为了存储每个场次的每个预订,我们可以有一个哈希表,其中“key”是“ShowID”,而“value”是包含“BookingID”和创建“Timestamp”的链接哈希表。

在数据库中,我们将预订存储在“Booking”表中,过期时间将在时间戳列中。

“Status”(状态)字段的值为“Reserved(1)”,一旦预订完成,系统会将“Status”(状态)更新为“Booked(2)”,并从相关节目的链接哈希表中删除预订记录。当预订过期时,除了从内存中删除外,我们还可以将其从预订表中删除或将其标记为“过期(3)”。

ActiveReservationsService还将与外部金融服务一起处理用户付款。无论何时预订完成,或预订过期,WaitingUsersService都会收到信号,以便为任何等待的客户提供服务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5f3G5DDs-1655134117341)(https://secure2.wostatic.cn/static/7inVUNt9VDx15YhDgmNAYZ/image.png)]

WaitingUsersService

就像ActiveReservationsService一样,我们可以将一个场次的所有等待用户保存在链接哈希映射或树映射的内存中。我们需要一个类似于链接HashMap的数据结构,这样当用户取消请求时,我们就可以跳转到任何用户,将其从HashMap中删除。此外,由于我们以先到先得的方式提供服务,链接HashMap的头部将始终指向等待时间最长的用户,因此每当有座位可用时,我们都可以以公平的方式为用户提供服务。

我们将有一个哈希表来存储每个节目的所有等待用户。“key”将是“ShowID”,“value”将是一个包含“userid”及其等待开始时间的链接HashMap。客户端可以使用长轮询来更新自己的预订状态。每当座位可用时,服务器都可以使用此请求通知用户。

在服务器上,ActiveReservationsService跟踪活动预订的到期时间(基于预订时间)。由于客户端将显示一个计时器(用于过期时间),该计时器可能与服务器有点不同步,因此我们可以在服务器上添加一个5秒的缓冲区,以防止出现中断的体验,这样客户端就不会在服务器之后超时,从而阻止成功购买。

10、并发性

如何处理并发性,以便没有两个用户能够预订同一个座位。我们可以在SQL数据库中使用事务来避免任何冲突。例如,如果我们使用的是SQL server,我们可以利用事务隔离级别锁定行,然后再更新它们。以下是示例代码:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;-- Suppose we intend to reserve three seats (IDs: 54, 55, 56) for ShowID=99
Select * From Show_Seat where ShowID=99 and ShowSeatID in (54, 55, 56) and
Status = 0 -- free-- if the number of rows returned by the above statement is three, we can-- update to return success otherwise return failure to the user.update Show_Seat ...update Booking ...COMMIT TRANSACTION;

“Serializable”是最高的隔离级别,可确保不受脏、不可重复和幻影读取的影响。这里要注意一件事;在一个事务中,如果我们读取行,我们会得到一个写锁,这样其他人就无法更新它们。

一旦上述数据库事务成功,我们就可以在ActiveReservationService中开始跟踪保留。

11、容错性

ActiveReservationsServiceWaitingUserService崩溃时会发生什么情况?

每当ActiveReservationsService崩溃时,我们都可以从“Booking”表中读取重新所有active预定。请记住,在预订之前,我们将“状态”列保留为“预定(1)”。

另一种选择是进行主从配置,以便在主服务器崩溃时,从服务器可以接管。

我们没有将等待的用户存储在数据库中,因此,当WaitingUsersService崩溃时,我们没有任何方法来恢复该数据,除非我们有主从设置。类似地,我们将对数据库进行主从设置,使其具有容错性。

12、数据分区

数据库分区:如果我们按“MovieID”进行分区,那么一部电影的所有放映都将在一台服务器上进行。对于非常热门的电影,这可能会在该服务器上造成大量负载。更好的方法是基于ShowID进行分区;这样,负载就可以分布在不同的服务器上。

ActiveReservationServiceWaitingUserService分区:

我们的web服务器将管理所有active用户的会话,并处理与用户的所有通信。我们可以使用一致性哈希根据“ShowID”为ActiveReservationService和WaitingUserService分配应用程序服务器

这样,特定场次的所有预订和等待用户都将由一组特定的服务器处理

让我们假设为了负载平衡,我们的一致哈希为任何场次分配三台服务器,因此每当预订过期时,持有该预订的服务器将执行以下操作:

1、更新数据库以删除预订(或将其标记为过期),并更新“Show seats”表中的座位状态。

2、从链接的HashMap中删除保留。

3、通知用户其预约已过期。

4、向所有等待该节目的等待用户的WaitingUserService服务器广播一条消息,以找出等待时间最长的用户。一致性哈希将告诉哪些服务器容纳这些用户。如果所需座位可用,则向等待时间最长的用户所在的WaitingUserService服务器发送消息,以处理其请求。

无论何时预订成功,都会发生以下情况:

1。持有该预订的服务器将向持有该节目等待用户的所有服务器发送一条消息,以便这些服务器可以终止需要比可用座位更多座位的所有等待用户。

2、在收到上述消息后,所有等待用户的服务器都会查询数据库,以确定现在有多少免费座位。在这里,数据库缓存将非常有助于只运行一次此查询。

3、让所有想预订比可用座位更多座位的等待用户过期。为此,WaitingUserService必须遍历所有等待用户的链接HashMap。

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

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

相关文章

Response.Write具体介绍

问题一&#xff1a; Response.Write 后连接Response.Redirect &#xff0c;则Response.Write无法显示&#xff0c;直接跳转入Response.Redirect 的页面。 解决方案&#xff1a; Response.Write("<script langugejavascript>alert(成功改动); window.location.hrefin…

SharePoint通过IP地址访问

问题&#xff1a;SP站点通过计算机名称可以访问&#xff0c;但不能通过IP地址访问 解决方案&#xff1a;打开SharePoint2010管理中心》应用程序管理》配置备用访问映射》编辑公用 URL 备用访问映射集&#xff1a;选择要映射的网站集 默认:http://计算机名 Intranet &#xff1a…

公有云与私有云的差别(转)

公有云与私有云的差别 发现每一个公司对私有云、公有云的定义都不一样&#xff0c;能够从公有云与私有云的差别上理解这个概念。下面转载网络上一个比較浅显的解释&#xff1a; 差别1&#xff1a;从云的建设地点划分&#xff0c;公有云——互联网上公布的云计算服务&#xff1b…

流媒体协议初探(MPEG2-TS、RTSP、RTP、RTCP、SDP、RTMP、HLS、HDS、HSS、MPEG-DASH)

目录一、综述需求分析协议定制二、MPEG2-TS协议三、RTSP协议、RTP、RTCP、SDPRTSPRTP、RTCP、SDP四、RTMP五、HLS、HDS、HSSHLSHDS和HSS六、MPEG-DASH协议具体内容应用七、流媒体服务器流媒体服务器的功能与挑战客户端支持协议支持应用场景应用特点扩展技术广告投放录屏其他一、…

eclipse偶尔会反映迟钝,直接无视其报错

比如&#xff0c;你在web.xml中配置了什么东西&#xff0c;在有的时候不一定就会立即被eclipse察觉到&#xff0c;即便你的配置正确了&#xff0c;甚至重启了几次服务器&#xff0c;它仍然给你报错 比如说&#xff0c;刚才我在web.xml中配置了一个taglib&#xff0c;并且tld文件…

Qos(Quality of Service)

QOS&#xff08;即Quality of Service&#xff0c;服务质量&#xff09;主要指网络环境下服务满足用户的程度&#xff0c;在视频服务的语境下也可认为是Quality of Streaming&#xff0c;即流媒体服务的质量。通常&#xff0c;QOS可以由一系列指标表达&#xff0c;如传输的速度…

Popline:帅气的浮动 HTML5 文本编辑器工具栏

Popline 是一个基于 HTML5 实现的富文本编辑器工具栏&#xff0c;设计灵感来自 PopClip &#xff0c;相比传统的文本编辑器工具&#xff0c;Popline 能够浮动在编辑的文本周围&#xff0c;操作起来十分方便。 您可能感兴趣的相关文章Metronic – 基于 Bootstrap 响应式后台管理…

C#反射Assembly 具体说明

1、对C#反射机制的理解 2、概念理解后&#xff0c;必须找到方法去完毕&#xff0c;给出管理的主要语法 3、终于给出有用的样例&#xff0c;反射出来dll中的方法 反射是一个程序集发现及执行的过程&#xff0c;通过反射能够得到*.exe或*.dll等程序集内部的信息。使用反射能够看到…

流媒体技术优化

文章目录1、下载策略优化CDN选择策略错误处理策略码率选择策略2、协议和架构优化HTTP2TCP变种拥塞控制QUIC架构流媒体协议的选择与分发体系架构的设计对优化起着关键作用。 HLS和DASH协议在点播和OTT直播服务中已逐渐占据主流&#xff0c;其思想主要是将视频转为不同码率并切为…

Android——android必看 各个控件属性(网上看到的文字,觉得挺好的,珍藏了)...

属性 值 说明 Android:orientation horizontal/vertical 设置布局水平还是垂直&#xff0c;默认是垂直 android:checked true/false 标记默认选中&#xff0c;如果是单选则选中最后一个 android:layout_gravity center/right/left/bottom/top 位置 android:gravity…

java中接口的定义与实现

1、定义接口 使用interface来定义一个接口。接口定义同类的定义类似&#xff0c;也是分为接口的声明和接口体&#xff0c;当中接口体由常量定义和方法定义两部分组成。定义接口的基本格式例如以下&#xff1a; [修饰符] interface 接口名 [extends 父接口名列表]{ [public] …

API设计笔记:pimpl技巧

pimpl pointer to implementation&#xff1a;指向实现的指针&#xff0c;使用该技巧可以避免在头文件暴露私有细节&#xff0c;可以促进API接口和实现保持完全分离。 Pimpl可以将类的数据成员定义为指向某个已经声明过的类型的指针&#xff0c;这里的类型仅仅作为名字引入&am…

C++必读书

C必读书 《Inside The C Object Model》 《Effective C》和《More Effective C》以及《Exceptional C》 《C面向对象高效编程(C Effective Object-Oriented Software Construction)》 《面向对象软件构造(Object-Oriented Software Construction)》 《设计模式(Design Patterns…

python socket编程实现的简单tcp迭代server

与c/c socket编程对照见http://blog.csdn.net/aspnet_lyc/article/details/38946915 server&#xff1a; import socketPORT 9999 BACKLOG 5 MAXLINE 1024listenfd socket.socket(socket.AF_INET,socket.SOCK_STREAM) listenfd.bind((,PORT)) listenfd.listen(BACKLOG)w…

API设计笔记:抽象基类、工厂方法、扩展工厂

文章目录抽象基类、工厂方法扩展工厂抽象基类、工厂方法 renderer.h #ifndef UNTITLED_RENDERER_H #define UNTITLED_RENDERER_H#include <string> class IRenderer { public:virtual ~IRenderer() {}virtual bool func1(const std::string& filename) 0;virtual …

《设计模式》-责任链模式

责任链模式是一种对象的行为模式【GOF95】。在责任链模式里&#xff0c;很多对象由每一个对象对其下家的用而链起来形成一条链&#xff0c;请求在这个链上传递&#xff0c;直到链上的某一个对象决定处理此请求。 发出请求的客户端并不知道链上的哪一个对象终处理这个请求&#…

ASPX的Timer位置没放正确,导致整页刷新,而不是UpdatePanel里的内容刷新。

提示&#xff1a;Timer应该放在UpdatePanel的ContentTemplate标签里&#xff0c;才行。放在外面的话&#xff0c;会导致整页刷新。转载于:https://www.cnblogs.com/xxxteam/p/3209522.html

高性能随机数:mt19937、uniform_int_distribution使用

// 例如要随机获取一个vector中的元素 // 先对vector nums进行插入数据 .... // 使用高性能随机数 mt19937 gen; // mt19937头文件是<random> 是伪随机数产生器&#xff0c;用于产生高性能的随机数 uniform_int_distribution<int> dis(0, nums.size() - 1); //uni…

【机器学习】EM最大期望算法

EM, ExpectationMaximization Algorithm, 期望最大化算法。一种迭代算法&#xff0c;用于含有隐变量(hidden variable)的概率参数模型的最大似然估计或极大后验概率估计&#xff0c;其概率模型依赖于无法观测的隐变量。 经常用在ML与计算机视觉的数据聚类领域。 EM应用&#xf…

ModuleNotFoundError: No module named ‘_ctypes‘报错解决

1、python3的安装与卸载 先删除现有的python3 https://codeantenna.com/a/Ys0TCtmqIJ 2、关于ctypes的报错问题解决 安装库后&#xff0c;重新编译python ModuleNotFoundError: No module named _ctypeshttps://www.jianshu.com/p/69681655309b 问题解决