前言
受到中文社区《电商参考架构第二部分:库存优化方法》启发,想到了去年做过类似的电影票预定系统,如果用MongoDB去做存储支撑,那应该是怎样架构的呢?本文的目的是为了更好的学习掌握MongoDB,所以某些设计上更偏向于功能的展示,在实际使用上要因地制宜的改变,合适才是最好的。
需求
电影票预定系统与电商系统非常类似,都可以抽象理解为商品的售卖。进一步的讲电影票系统是电商系统的一个库存特例场景:
- 每个场次,每个座位,都只有一个库存
- 每个订单所预定的座位有锁定状态,在支付前对应的作为不能被再次购买
- 订单涉及到的座位要不全成功,要不全失败
- “全国”级的,数据容量不是太大问题,但性能上要支持水平扩展
PS:实际上的理论TPS并不高,目前全国5000家影院,假设平均8个影厅,每个厅200个位置,每个影厅6个场次,早中晚各3个高峰,每个高峰1个小时。计算得出TPS大概是:5000 8 6 * 200/ 3 / 3600 = 4400 TPS;但是设计上我们还是要保证性能的可水平扩展,否则怎么体现MongoDB的特色呢?^-^
描述信息文档结构
影院描述信息
保存最基本的影院信息,包括地理信息,名称,_id为MongoDB由MongoDB自动分配
CinemaManager.cinema_detail
{
_id: <ObjectID>,
name: "<cinema name>",
city: "<city name>"
location: [<longitude>, <latitude>],
comments: "<detail message>"
}
例如:
rs0:PRIMARY> db.cinema_detail.insert({
"name" : "大时代电影院",
"city" : "杭州",
"location" : [ 120.13, 30.16 ],
"comments" : "IMAX 4K,有停车位"
});
因为影院信息的查询一般都是按照城市和名称,或者地理坐标检索,所以这里建立两个索引
Index1:城市+名称的复合索引,因为查询电影院时一般都会指定城市名
rs0:PRIMARY> db.cinema_detail.ensureIndex({city:1, name:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 2,
"ok" : 1
}
注意,这里使用的是复合索引,所以针对 city + name的查询,或者city的查询是有效的,只查找name字段是无法通过索引优化的。
Index2:地理坐标索引,用来应付"最近的电影院"类查询
rs0:PRIMARY> db.cinema_detail.ensureIndex({location: "2d"})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 3,
"numIndexesAfte