假设我们有以下示例JSON事件数据:
{
"eventId":"eb1363c3-6bf7-4a42-9daa-66270b922367",
"timestamp":"2014-10-28T09:12:22.628Z",
"ip":"1.2.3.4",
"device":{
"type":"mobile",
"os":{
"name":"iOS",
"version":"7.1.1"
},
"name":"iPhone 4/4s",
...
},
"eventType":"AddedProductToCart",
"store":"US",
"product":{
"sku":"ABC123",
"name":"Yellow Socks",
"quantity":1,
"properties":{
"foo":"bar",
"bar":1
}
...
},
"user":{
"id":123456,
"name":"jeff",
"type":"registered"
...
}
}
虽然将始终提供“eventId”和“timestamp”,但数组的结构可能会有所不同并且不同。大约有30-40个唯一的eventTypes,都具有不同的事件属性。大多数事件数据都有嵌套结构。
存储这些事件属性的最佳方法是什么?我查看了MongoDB,DynamoDB和一个名为EventStore(http://geteventstore.com)的项目。显然我也考虑过MySQL,但我想知道它在我们的用例中会如何表现。
数据的存储只是第一部分。在此之后,我们应该能够使用如下的复杂查询来查询我们的数据库/事件存储(并且不仅仅通过索引ID检索):
select all events where eventType is "AddedProductToCart" and timestamp > 2 weeks ago
-> should return all "AddedProductToCart" from 2 weeks ago until now
select all events where device.OS.name is "iOS" and device.OS.version is "7.1.1"
-> should return all events from iOS 7.1.1
等
我们预计每月约有1000万个活动。这相当于平均每秒3-4次写入,并且可能更像每秒30-40次写入峰值/最坏情况。存储不应该是一个问题 - 每个事件的总大小可能不会超过1或2kb(这相当于每100万个事件1-2GB)。
查询部分应该是PHP,最好是。例如,DynamoDB有一个PHP的SDK,这肯定会促进我们的
对此我们最好的解决方案是什么?写作应该是快速的,我们的查询也应该是可以接受的。简而言之,我们正在寻找一个低成本的数据存储来轻松存储然后检索( - 不仅使用索引查询,还使用嵌套JSON中的事件属性查询)我们的数据。
感谢您提出任何建议,如果需要更多信息来正确回答这个问题,我很乐意提供更多信息。
答案 0 :(得分:2)
亚马逊的DynamoDB提供完全托管(自动扩展),持久且可预测的解决方案。
根据您期望的流量和数据量来判断,DynamoDB的25个写/读容量单位和25 GB的免费等级基本上免费为您的运营提供服务。
每个写入容量单位相当于写入1KB的数据,因此如果您希望每秒写入3KB的2KB数据,则需要配置8个WCU。此外,DynamoDB的性能极其可预测,具有快速的单位数毫秒延迟。有关免费套餐的更多信息,请查看http://aws.amazon.com/dynamodb/pricing/。
就您的数据集而言,对于非文档对象,使用全局二级索引查询相对简单。
以下是PHP SDK中的一个示例。
$twoWeeksAgo = date("Y-m-d H:i:s", strtotime("-14 days"));
$response = $dynamoDB->query(array(
"TableName" => <Table Name>,
"KeyConditions => array(
"EventType" => array(
"ComparisonOperator" => ComparisonOperator::EQ,
"AttributeValueList" => array(
array(Type::STRING => "AddedProductToCart")
)
),
"Timestamp" => array(
"ComparisonOperator" => ComparisonOperator:GE,
"AttributeValueList" => array(
array(Type::STRING => $twoWeeksAgo)
)
)
)
));
您可以查询&#34; Device.OS.Name&#34;和&#34; Device.OS.Version&#34;通过扫描,但根据您要进行的查询类型,您应该考虑一些优化。
如果您正在寻找adhoc查询,则可以进行并行扫描调用,然后在嵌套属性上使用ConditionalExpression应用ScanFilter。通过并行扫描,您可以优化工作台上读取容量单位的消耗以及操作速度。有关并行扫描的更多信息,请查看http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScan.html#QueryAndScanParallelScan。
或者,如果您要选择要查询的属性,请考虑将某些字段设置为顶级属性或将它们移动到各自的单独表中,将必要的属性(即os.name到osname)展平并具有后引用到您的原始项目(主要适用于您的文档,如&#34;设备&#34;)。通过这样做,您可以在这些属性之上添加索引并快速有效地查询它们。此外,在预先公布在线索引时,您应该能够在必要时添加和删除索引以满足您的要求。
如果您想进一步详细讨论此问题或就使用DynamoDB提出一般性问题,请随时通过私信与我联系。
由于
答案 1 :(得分:1)
MongoDB是一个不错的选择。它可以轻松处理write / s(mongod
在我的笔记本电脑上看到更多动作。)
您提到的查询是基本的。例如:
db.collection.find({"device.OS.name":"iOS","device.OS.version":"7.1.1"})
和(缩短了可读性)
db.collection.find({"eventType":"AddedProductToCart",timestamp:{$gte: ISODate(iso8601String)}})
如果索引设置正确,那些应该是闪电般快速的。您甚至可以使用TTL索引自动删除特定时间之前的事件。
对于数据分析,您同时拥有map / reduce和MongoDB极其强大的聚合框架。
让我们来看看缺点。虽然使用MongoDB进行扩展相对容易,但由于某些原因,人们认为具有自动数据分发的复制分片集群与MongoDB的其余部分一样易于管理。关键字是相对容易(将它与使用MySQL的复制数据分区或 - 主帮助我们 - Oracle)相比,但它仍有一些陷阱。
可以在不使用MMS的分片环境中进行时间点恢复,但是您必须知道自己在做什么,因为同步分片的各个备份非常棘手。
无论您选择哪个数据库,我强烈建议您与相关专家联系。生产数据是基本的,没有数据库应由非专业人员计划和维护。