12306用什么数据库-12306泄漏数据下载 bt
标签
PostgreSQL, 12306, 春节, 一票难求, 门禁广告, 数组, 范围类型, 抢购, 排他约束, 行情分析, 广告查询, 火车票
背景
春节马上就要到了,又是火车票销售的旺季。 抢票的问题还存在吗?
还记得10年前春节前买火车票,要在出票前一天搬个小板凳排队。 热门线路,排队一晚也未必能买到票。
随着互联网的发展,几年前建立了12306网上购票系统,可以在电脑上购票,但不要以为在电脑上就可以买票。
记得12306刚上线的时候,12306网站经常打不开,无法支付。
为什么?
原因很简单。 春节期间,在线购票人数可能达到数亿,而且售票日期为同日同时,这意味着12306将同时接待数亿用户的访问。
处理能力和实际访问要求更差,结果是网站打不开,系统不稳定。
后来12306想出了开通不同线路和时间段的方法,试图错开不同线路用户访问12306网站的时间,但这种方式一开始效果并不明显,也不是所有用户都知道吧(像你今天通知暂时不上班,但还是有用户会来单位),所以大部分用户还是专心一点访问12306网站。
随着硬件的发展和技术的演进,12306系统越来越成熟,稳定性和响应速度也越来越好。
据说很多商家也开通了云抢票服务,本质上就是让你不打12306系统,提前把需求收集起来。 当票被释放时,这些系统将排队并合并购买。 这个方法可以减少12306访问并发。
抢火车票是一个很有意思的话题,对IT人员的智商和IT系统的健壮性,尤其是数据库的功能和性能都是一个挑战。
接下来,我们来看看难点和解决方法。
1.铁路售票系统-西游记开始
铁路售票系统最基本的功能包括
查询余票、余票统计、购票、车次变化、退票、改签、中转乘车规划 等。
每个需求都有自己的特点,比如
1.查询剩余门票。 用户在购票前,通常会在目的地查看剩余的车票。 这是一个高度并发的操作。 同时需要统计剩余票数,需要强大的CPU支持实时查询。
2.买票。 购票不同于查询。 买票会改变库存,所以是对数据库的更新操作。
而且,买票可能会发生冲突。 比如很多人要买同一趟车的车票,就会发生冲突。 谁会卖给他们?
需要考虑锁冲突,尽量让不同的人并行购票,或者合并多个购票请求,减少数据库更新操作。
3、对于中转乘车,当用户需要购买的始发站和目的站都没有车票时,需要计算中转乘车计划。
比如北京到上海没有直达车,要不要换车? 什么时候转移,转移到哪里就成了问题。 简单来说,就是买票的人自己考虑。
如果再高级一点,可以让12306给你推荐路线,这涉及到数据库的路径规划功能。
我们来一一分析这些需求的特点。
1 查看剩余门票
1.普通剩余票查询需求
如果你想买从北京到上海的火车票,你通常会查看哪些车次还有余票。
查询的过滤条件可能有很多,比如
1.1. 上车站、下车站、中转站
1.2. 列车类型(高铁、高铁、直达、特快、普通客运……)
1.3. 出发日期和时段
1.4. 到货日期、期间
1.5. 座位类型(硬座、硬卧、...站票)
1.6. 过滤掉没有剩余车票的火车
在展示给用户的时候,还需要考虑如何排序(是按出发时间排列,还是按票价排列12306用什么数据库,还是按剩余票数排列?),如何分页。
眼见为实
查询余票通常不是实时的,也不一定准确,可能是后台异步统计的结果。
即便是实时统计的结果,在高并发抢票期,你看到的信息也可能很快对你失效。
比如你看到某趟车还有100张票,很可能等你付款的时候已经卖完了。
所以在高峰期,余票信息的参考价值不大,大家不要混淆。
2、查询余票还有一个更高级的需求是路径规划和自动适配(根据用户输入的中转站)
这个功能以前可能没有,但总有一天会曝光,尤其是在票很紧的情况下。
比如从北京到上海,就没有直达车了,系统可以帮你查询一次换乘,二次换乘,N次换乘。 (当然,转的越多越复杂)。
从中转的角度,实际上已经涉及到路径规划的技术。
如何转让就是时间最短,价格最低,转让次数最少等等。 (还涉及到换乘的输入要求(比如用户要求在一线城市换乘,或者必须换乘高铁))。
关于路径规划,可以参考PostgreSQL pgrouting,支持多种路径规划算法,支持算法的自定义扩展。
简直是居家出行杀人的必备良药。
《聊聊双十一背后的技术——物流、动态路径规划》
主人小心,有怪物。 . .
1. 大多数用户都有选择综合症。 一般来说,用户在选择合适日期的合适火车票之前可能会查询很多次。
查询量比较大,尤其是春节期间。
2.为了显示剩余票数,需要进行统计,会消耗较多的CPU和IO资源。
3.路线规划,帮助用户选择最佳的换乘路线,是对数据库功能的考验,大部分数据库都没有这个功能。
2 剩余投票统计
对于售票系统来说,查询剩余票数其实就是一个统计操作。
与简单的查询相比,统计操作不仅会消耗更多的 IO,还会消耗更多的 CPU 资源。
想象一下,有几亿人(其实没那么多,可能几十万就够了)去查剩余的票,即使机器不挂,机器所有的资源也会全力运行,而CPU 产生的热量可能在几分钟内就足够了。 稍微煮鸡蛋。
为了减少实时查询余票的开销,通常采用分时统计的方式来更新最新的统计信息。
当用户查询剩余票数信息时,查询到的是统计结果。 我已经分析了剩余的选票。 剩下的票是不可信的,所以有一定的延迟其实是允许的。
现在不能煮鸡蛋了,因为把上亿个统计请求变成一个统计请求,世界是不是一下子就安静了?
我们可以在12306首页看到剩余票数的行情数据
主人小心,有怪物。 . .
1.需要统计剩余的票信息,查询会消耗较多的CPU和IO。
由于剩余的选票是不可信任的,所以实际上允许一定的延迟。 优化方式为异步统计,用户查询统计结果。
3张门票
与查询剩余车票相比,购票是从请求次数来分析的,比查询请求次数要少,因为一般来说,用户在选择合适日期的合适车次的车票之前,可能会查询很多次。
但是由于购票是一个事务,每个事务都会产生一个写操作,而这个事务并不是一个无限库存的事务,因为库存是有限的,所以设计的关键是降低粒度,减少锁冲突,以及减少数据扫描量。
其他需要考虑的因素包括
1. 同一辆火车上的同一个座位可能会在不同维度上多次出售
1.1 时间维度,比如出发日期
1.2 空间维度,起点不同
2.票价
票价一般与座位绑定,按区间计费。
另一个要求是尽可能卖票,减少空座。
比如北京到上海的车路过(天津、徐州、南京、无锡、苏州),如果有人买了天津到南京的路段,剩下没买的路段要继续买。
如果北京到上海的火车,苏州到上海的车票都是用户买的,其他座位都不卖,铁哥会不会哭晕在厕所里?
或者某趟列车的大量座位被中途上车的用户购买,是否会减少全程可购买的车票数量?
这种情况之前就存在过,对于铁哥的成本来说也是一个不小的考验。
主人小心,有怪物。 . .
1、为了减少票务系统写锁冲突,比如同一个座位,尽量不要出现因为一个session在更新,其他session需要等待的情况。
(比如用户A买了北京到天津的公交车,用户B买了天津到上海同一趟火车的同一个座位,那么应该设计一个合理的merge操作(比如数据库内核改进)或者锁等待从设计中避免)
其实就是把座位的空间维度(从哪里到哪里)、自身的属性(座位号)、时间维度(出发日期)解耦,放到多条记录中,这样就可以在购买时同一时间。
因为目前数据库中最小的锁是行锁(一次只允许一个session更新单行记录,其他的都阻塞,等待释放锁),也许随着技术的发展,会演变成列锁,或者列锁中的元素(例如数组,JSON)。
4 增删改车
春节来临,一些热门线路通常要加班。
以及车次的增删改查。
在设计数据库时应考虑到这一点。
主人小心,有怪物。 . .
车次的变化会牵动全身。 比如剩余票数统计会相应变化,查询系统也会相应变化。
还有初始化信息的准备。 例如,为了加快购票速度,可以提前准备好车次的数据(可能每个座位一个记录)。 参考第三个要求的解释。
5 对账要求
可以通过支付宝、去哪儿、携程、铁路老板售票窗口、银行代理窗口、客运代理等多种渠道售票。
涉及实际销售信息和资金交易的对账要求。
通常这个操作是延迟第二天对账。
6 退改签要求
退票、改票也是比较普遍的需求,尤其是现在APP普及,退票、改票非常方便。
这导致用户可能会先买好一点的,尤其是春节期间,用户无法提前知道什么时候请假回家,所以先买几张不同日期的票,然后再退票或改票提前。
改签和退票涉及位置恢复(对于数据库来说,可能是更新数据),改签也涉及与购票相同的过程。
7 取票
这个很简单,就是根据用户ID查询已购买和未打印的票。
8种其他需求票
学生票、团体票、卧铺票、站票
这尤其适用于站票。 站票有上限。 需要控制一列火车的站票数量。
站票也有起点和终点之分,但有些用户可能买不到终点站的票,会先买一段,再补上,或者一直上车不下车,下车后再补上。
先上车再补车费
这种方法极其恶劣,但是很多人都是这样做的,未婚先孕,现在的年轻人。 . . .
通常考虑容积率,避免站票过多。
如果你不受控制地卖站票,你可能无法坐下。
猴哥,师父被妖怪抓走了
1. 大多数用户都有选择综合症。 一般来说,用户在选择合适日期的合适火车票之前可能会查询很多次。
查询量比较大,尤其是春节期间。
2.为了显示剩余票数,需要进行统计,会消耗较多的CPU和IO资源。
3.需要进行路线规划,帮助用户找到符合条件(时间最短、行程最短、指定中转站、最便宜、或最少站票)等条件的换乘路线。
妈妈再也不用担心买不到票了。
4.需要统计剩余的票信息,查询会比较消耗CPU和IO。
由于剩余的选票是不可信任的,所以实际上允许一定的延迟。 优化方式为异步统计,用户查询统计结果。
5.为了减少票务系统写锁冲突,比如同一个座位,尽量不要出现一个session在更新,其他session需要等待的情况。
(比如用户A买了北京到天津的公交车,用户B买了天津到上海同一趟火车的同一个座位,那么应该设计一个合理的merge操作(比如数据库内核改进)或者锁等待从设计中避免)
其实就是把座位的空间维度(从哪里到哪里)、自身的属性(座位号)、时间维度(出发日期)解耦,放到多条记录中,这样就可以在购买时同一时间。
因为目前数据库中最小的锁是行锁(一次只允许一个session更新单行记录,其他的都阻塞,等待释放锁),也许随着技术的发展,会演变成列锁,或者列锁中的元素(例如数组,JSON)。
6、车次变更会牵动全身。 比如剩余票数统计会相应变化,查询系统也会相应变化。
还有初始化信息的准备。 例如,为了加快购票速度,可以提前准备好车次的数据(可能每个座位一个记录)。 参考第三个要求的解释。
基于以上痛点和需求分析,设计时应尽量避免锁等待,避免实时剩余票查询,避免空座。
2. 猴子请来的救助者是谁?
经过前面的分析,铁路售票系统最关键的业务场景已经描述完毕,设计痛点也已经说明,那么如何才能设计出一个合理的系统来满足亿万人群的抢票需求呢?
在西游记的每一集中,孙悟空大人都被妖怪抓走,总能找到救援人员来救他。
我们也需要救援人员,救援人员快来。 . . .
PostgreSQL 是世界上最先进的开源数据库,几乎适用于任何场景。
有许多功能可以用来加快开发效率并满足架构要求。
对于铁路售票系统,可以使用哪些保命法宝?
1.看招数,法宝1,变位型
使用 varbit 存储每个座位大道站点是否已为每次乘车售出。
例如,G1921次列车从北京到上海,途经天津、徐州、南京和苏州。 包括起点站在内,共6站。 然后用6位来表示。
'000000'
如果我要买天津到徐州,这个值改成(下一站的BIT不用设置)
'010000'
这个位置也可以卖北京到天津,徐州到码头的任何一站。
剩余车票统计也很方便,可以根据BIT对整个车次进行汇总计算。
统计任意站组合的剩余票数(北京-天津、北京-徐州、北京-南京、北京-苏州、北京-上海、天津-徐州、天津-南京、......、苏州-上海)
udf_count(varbit) returns record
统计指定起点剩余车票(起点:北京,终点:南京;返程为京宁剩余车票)
udf_count(varbit, start, end) returns record
针对以上两个需求,开发相应的聚合函数就可以了,其实就是对一些指定范围的bitands进行计数操作。
通过法宝1,解决了统计剩余票的需求和售票不缺口的需求。
2.看招数,法宝2,阵法
用一个数组存储每列火车的始发站和经过站。
使用数组存储的好处是可以通过数组的GIN索引快速检索到有哪些列车可用。
比如查询北京到南京的火车班次。
select 车次 from 全国列车时刻表 where column_arr @> array['北京','南京'];
这个SQL是可以索引的,效率很高。 每秒请求几十万不成问题。
法宝2解决高并发请求查询符合要求的列车信息。
3.观看花样,法宝3,跳过锁定
此功能是跳过锁定的行。 比如用户买北京到南京的车票,其实就是一个UPDATE ... SET BIT操作。
但很有可能其他用户也在购买,可能会出现锁冲突。 为了避免这种情况,可以skip locked,跳过lock conflicts,直接找别的座位。
select * from table
where column1='车次号' -- 指定车次
and column2='车次日期' -- 指定发车日期
-- and mod(pg_backend_pid(),100) = mod(pk,100) -- 提高并发,如果有多个连接并发的在更新,可以直接分开落到不同的行,但是可能某些pID卖完了,可能会找不到票,建议不要开启这个条件
and column4='席别' -- 指定席别
and getbit(column3, 开始站点位置, 结束站点位置-1) = '0...0' -- 获取起始位置的BIT位,要求全部为0
order by column3 desc -- 这个目的是先把已经卖了散票的的座位拿来卖,也符合铁大哥的思想,尽量把起点和重点的票卖出去,减少空洞
for update
skip locked -- 跳过被锁的行,老牛逼了,不需要锁等待
limit ?; -- 要买几张票
神器3解决了一群人来抢票时,同一趟车的座位冲突问题。
4.看戏,法宝4,游标
如果要查询大量记录,可以使用游标来减少重复扫描。
5.看招数,法宝5,路径规划
如果用户选择了直达公交,且没有车票,它可以自动计算如何换乘,并根据用户的公交站点和目的地选择最佳路线。
参考pgrouting,符合物流的动态路径规划要求。
《聊聊双十一背后的技术——物流、动态路径规划》
6、看招数,法宝6、多核并行计算
开源还支持多核并行计算。 在生成余票统计时,为了提高生成速度,可以增加更多的CPU进行并行计算,快速得到余票统计。
比如你策划一本书,你已经做好了大纲,同时找了100个作者,这100个作者可以根据你布置的工作同时开始写作,很快就可以完成这本书。
在传统情况下,只有一个作者可以为你写一本书。 就算找到100个作者,其他99个也只能是免费的,或者只能写另外99本书。
7.看招数,法宝7,资源隔离
PostgreSQL是进程模型,因此可以控制每个进程的资源开销,包括(CPU、IOPS、MEMORY、网络)。 在铁路售票系统中,查询和售票是最关键的需求。 使用这种方法,您可以确保关键业务有足够的资源顺利运行。
这个思路和双十一镖局是一样的。 双十一期间,一些不必要的业务将被关闭,以保证主业的资源和顺畅的运行。
8.看招数,法宝8,分库分表
铁路数据已经达到了海量数据的水平,显然一台机器不可能存储所有的铁路数据。
那么该怎么办? 铁路数据可以分区存储在不同的主机上。
PostgreSQL有多种分库分表方案,如plproxy、pgpool-II、pg-xl、pg-xc、citus等。
9.看招数,法宝9,递归查询
铁路具有非常典型的上下文相关特征。 例如,一列火车经过N个车站,全国铁路组成一个庞大的铁路网。
递归查询可以根据某个节点递归向上或向下查找相关站点。
比如哪些车可以直达北京,哪些车可以中转北京,或者查看从北京到拉萨可以走哪些路线和路线。
10.看招数,法宝10,MPP,收工
为了不断提升12306的体验,铁哥还需要进行数据挖掘,比如今年春运应该增加哪些线路的车次,每天增加的车次,哪些线路可以减少春节前开行送用户回家。
这些问题可以通过基于过去运输数据的挖掘计算来回答。
基于PostgreSQL的MPP产品有很多,如Postgres-XL、Greenplum、Hawq、REDSHIFT、paraccl等。
使用PG可以很好的与这些产品集成12306用什么数据库,并保持语法一致。
降低数据分析的开发成本。
10件法宝一出,师傅又回来了。
别担心,还有更强大的。 阿里云在PostgreSQL的基础上做了很多改进。 例如,12306 系统具有特殊的定制功能。
3. 阿里云PostgreSQL varbit和数组增强介绍
在铁路售票系统中,有几个需求需要用到位和数组的特殊函数。 这些特殊功能目前在社区版本中不可用。 阿里云RDS PostgreSQL对此做了增强,如下。
1.剩余票数统计
计数指定的位范围 = 所有 0 计数
不指定范围,查询任意组合中所有位范围=0的个数
2.购票
指定要过滤、取出的位位置,并设置对应的位值
根据数组值获取其位置下标。
回头看之前写的两篇文章,也是使用varbit的应用场景,目的相同
《基于阿里云RDS PostgreSQL构建实时用户画像推荐系统》
《门禁广告销售系统需求分析与PostgreSQL数据库实现》
PostgreSQL的bit和array功能已经很强大了,阿里云RDS PostgreSQL的bitpack也是一个新的功能,需要用户在实际应用中细化。 大家一起来给阿里云提要求吧。
创建一个属于中国人的PostgreSQL。
概括
本文从铁路售票系统的需求出发,分析了售票系统的一些痛点以及设计数据库时需要注意的事项。
PostgreSQL的10大特性以及阿里云对PostgreSQL的改进可以很好的满足铁路票务系统的需求。
1、使用varbit存储每列火车的每个座位路线站是否已经售出。 解决了统计剩余票数的需求,以及售票无间隙的需求。
2.用数组存储每列火车的始发站和经过站。 数组类型支持索引,解决了高并发请求查询符合条件的列车信息的需求。
3.利用跳票锁定功能,解决了一群人来抢票时,同一趟车的座位冲突问题。
4.使用pgrouting路径规划功能解决智能推荐游乐设施需求。
同时,还可以应用于金融风控、刑事侦查、社会关系分析、网络分析等诸多场景。
有兴趣的话,网上有很多分析PostgreSQL、pgrouting、Neo4j的文章。 PostgreSQL 甚至比 Neo4j 更适合图场景。
5.多核并行计算,让更多的CPU帮你同时工作,比如快速异步剩余票统计。
6、减少空座的发生,保证更多人能买到满票。 (买票时,如果是中途票,尽量选择已经售出的中途票)
7、基于各个进程的资源隔离,可以提高稳定性。
8、连接HybridDB(基于GP\HAWQ)MPP系统,语法一致,可以支持iron
满足了道路系统的数据挖掘需求,节省了开发成本。
阿里云长期提供PostgreSQL、HybridDB(基于Greenplum、HAWQ)的服务和支持。
另外还准备了很多技术大餐分享给大家,感谢大家观看。