Step into MongoDB II - Industry Sample

[快的打车][1]

  • 场景

    1亿多用户,超过300个城市里与300万司机取得了联系
    两类业务:快的出租车 & 快的一号专车
    司机与乘客每天高达6百万次的联系
    管理着将近5亿的订单
    支持着每秒钟数以万计的读写操作
    MongoDB每秒支持着5万个操作(读取和写入的比例约为80:20)
    数据库已经增长到5亿多文档,并且还在持续扩展中

  • 应用

    选择指标:性能(延迟、实时更新的速度),可扩展性,易用性
    LBS : MongoDB的地理空间索引及查询
    可扩展性,历史订单数据的存档:顾客每呼叫一辆出租车,行程的起点及终点、司机的身份以及费用等都会被存储在一条单一的记录中
    Redis 缓存
    MySQL 存储顾客运营及订单数据
    Hadoop 将数据从MongoDB和MySQL中拷贝到Hadoop上进行挖掘及分析
    使用Nagios来监测应用及数据库
    使用Java驱动来运行MongoDB2.6

[盛大大数据量项目中的应用][2]

Best Practices
Replica Set: one for primary, one for secondary, one for increamental back up with a arbiter

[电影票预定系统 design idea][3]

需求

每个场次,每个座位,都只有一个库存
每个订单所预定的座位有锁定状态,在支付前对应的作为不能被再次购买
订单涉及到的座位要不全成功,要不全失败
“全国”级的,数据容量不是太大问题,但性能上要支持水平扩展

描述信息文档结构

  • 影院描述

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    CinemaManager.cinema_detail{
    _id:ObjectId,
    name:String,
    city:String,
    location: [,], // [ 120.13, 30.16 ], coordinate
    comments:String
    }
    db.cinema_detail.ensureIndex({city:1, name:1}){
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 2,
    "numIndexesAfter" : 2,
    "ok" : 1
    }
    db.cinema_detail.ensureIndex({location: "2d"}){
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 3,
    "numIndexesAfter" : 4,
    "ok" : 1
    }
  • 影厅描述

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    CinemaManager.theater_detail{
    _id,
    cinema_id,
    name:String,
    seat:{
    row1:[],
    row2:[],
    row3:[],
    ...
    },
    comments:String
    }
    db.theater_detail.ensureIndex({cinema_id:1}){
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
    }
  • 影片描述

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    CinemaManager.movie_detail{
    _id,
    name:String,
    director:String,
    actors:[],
    comments:String
    }
    db.movie_detail.ensureIndex({name:1}){
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
    }

影片放映文档结构

放映信息包含放映时间段,放映影厅,票价。虽然Document结构可以做复杂的嵌套,但原则上期望Document尽量小,
利用数据Shard,性能优化。所以在movie_schedule的设计上每个影片的每场放映独立一个Document表达。

  • 描述
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    CinemaManager.movie_schedule{
    _id,
    cinema_id,
    movie_id,
    theater_id,
    start_time:
    end_time,
    comments:String
    }
    db.movie_schedule.ensureIndex({cinema_id:1, movie_id:1, theater_id:1}){
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
    }

交易系统

抽象的来看,售卖系统就是对上诉所有集合的一个整合,外加一套库存字段。
我们认为一场放映就是一个主商品,每个座位可以认为是这个商品的SKU,每个SKU都是1份。
通过Reference关系结合movie_schedule与theater_detail,注意这里引用了

1
2
3
4
5
6
7
8
9
10
11
{
_id: ,
movie_schedule_id:
theater_id: ,
seat: {
row1: [2, 2, 2, 2],
row2: [2, 2, 2],
row3: [2, 2, 2, 2],
row4: [2, 2, 2, 2, 2],
}
}

不仅是Reference的引用关系,还复制了theater_detail.seat字段,每个seat都有一个库存数字,
因为在MongoDB中一个Document的操作是可以保证原子的,不需要对Collection加任何锁。数字2并不是表示可以卖2次:

  • 数字2表示,可销售
  • 数字1表示,已锁定
  • 数字0表示,已售完

From

1
2
3