фон
Наша система носит носитель и очень надежна, она тестировалась на нагрузку для обработки 5000 транзакций в секунду, и для каждой транзакции документ вставляется в единую коллекцию MongoDB (без обновлений или запросов в этом приложении, только). Это составляет ~ 700 млн. Документов в день, что является нашим эталоном.
Развертывание MongoDB еще не очерчено, у нас есть 1x replicaset с 1 master и 2 slaves, все из которых являются типами m2.2xlarge экземпляров на ec2. Каждый экземпляр поддерживается 1ТБ RAID0-полосой, состоящей из 8 томов (без PIOPS). Мы используем родной драйвер node -mongodb с собственным синтаксическим анализатором BSON С++ для оптимальной производительности записи и попытались соответствующим образом моделировать структуру документа.
Примечание
- Документы крошечные (120 байт)
- Документ включает в себя "ведро времени" (h [наш], d [ay], m [onth], y [ear]) вместе с полем "t [ime]"
- У нас есть индекс в коллекции для запроса с помощью "c [ustomer]" и "a", который является очень случайным, но не уникальным тегом
- Мы рассмотрели разделение данных на отдельные коллекции, хотя в этом примере все данные горячие.
- Мы также изучаем предварительную агрегацию, хотя это невозможно сделать в реальном времени.
требование
- Для отчетности нам нужно рассчитать количество уникальных "а" тегов в месяц вместе с их итогами клиентом за любой данный период.
- Отчет занимает около 60 секунд для запуска образца (полной коллекции) документов 9.5MM, хранящихся в течение 2 часов. Подробности ниже:
Документ
{
_id: ObjectID(),
a: ‘string’,
b: ‘string’,
c: ‘string’ or <int>,
g: ‘string’ or <not_exist>,
t: ISODate(),
h: <int>,
d: <int>,
m: <int>,
y: <int>
}
Индекс
col.ensureIndex({ c: 1, a: 1, y: 1, m: 1, d: 1, h: 1 });
запрос агрегации
col.aggregate([
{ $match: { c: 'customer_1', y: 2013, m: 11 } },
{ $group: { _id: { c: '$c', y: '$y', m: '$m' }, a: { $addToSet: '$a' }, t: { $sum: 1 } } },
{ $unwind: '$a' },
{ $group: { _id: { c: '$_id.c', y: '$_id.y', m: '$_id.m', t: '$t' }, a: { $sum: 1 } } },
{ $sort: { '_id.m': 1 } },
{
$project: {
_id: 0,
c: '$_id.c',
y: '$_id.y',
m: '$_id.m',
a: 1,
t: '$_id.t'
}
},
{ $group: { _id: { c: '$c', y: '$y' }, monthly: { $push: { m: '$m', a: '$a', t: '$t' } } } },
{ $sort: { '_id.y': 1 } },
{
$project: {
_id: 0,
c: '$_id.c',
y: '$_id.y',
monthly: 1
}
},
{ $group: { _id: { c: '$c' }, yearly: { $push: { y: '$y', monthly: '$monthly' } } } },
{ $sort: { '_id.c': 1 } },
{
$project: {
_id: 0,
c: '$_id.c',
yearly: 1
}
}
]);
результат агрегации
[
{
"yearly": [
{
"y": 2013,
"monthly": [
{
"m": 11,
"a": 3465652,
"t": 9844935
}
]
}
],
"c": "customer_1"
}
]
63181ms
Объяснение агрегации
{
"cursor" : "BtreeCursor c_1_a_1_y_1_m_1_d_1_h_1",
"isMultiKey" : false,
"n" : 9844935,
"nscannedObjects" : 0,
"nscanned" : 9844935,
"nscannedObjectsAllPlans" : 101,
"nscannedAllPlans" : 9845036,
"scanAndOrder" : false,
"indexOnly" : true,
"nYields" : 27,
"nChunkSkips" : 0,
"millis" : 32039,
"indexBounds" : {
"c" : [ [ "customer_1", "customer_1" ] ],
"a" : [ [ { "$minElement" : 1 }, { "$maxElement" : 1 } ] ],
"y" : [ [ 2013, 2013 ] ],
"m" : [ [ 11, 11 ] ],
"d" : [ [ { "$minElement" : 1 }, { "$maxElement" : 1 } ] ],
"h" : [ [ { "$minElement" : 1 }, { "$maxElement" : 1 } ] ]
}
}
вопросы
-
Учитывая высокую частоту вставок и нашу потребность в выполнении запросов агрегирования рангов с течением времени. Является ли практика времени хорошей практикой, учитывая, что приложение может вставлять 30MM-документы за один час?
-
Мы понимали, что MongoDB может запрашивать миллиарды документов за считанные секунды:
- Несомненно, наш запрос агрегирования по документам 9.5MM может вернуться через 1сек или около того?
- Используем ли мы правильную технику для достижения этого, а если нет, то где мы должны сосредоточить наши усилия на получении результатов отчета почти мгновенно?
- Возможно ли это без осколков на этом этапе?
-
Будет ли MapReduce (параллельно) лучше альтернативой?