7

还有一个关于选择哪种 NoSQL 的问题。但是,我还没有找到有人要求这种类型的目的,消息存储......

我有一个 Erlang 聊天服务器,我已经在使用 MySQL 来存储朋友列表和“需要加入”信息。

我想存储消息(该用户没有收到,因为他离线......)并检索它们。

我已经预先选择了 NoSQL,由于它是面向 RAM 的范例,我不能使用像 MongoDB 这样的东西,并且无法像其他人一样进行集群。我想我的清单有 3 个选择:

  • Hbase
  • 里亚克
  • 卡桑德拉

我知道他们的模型完全不同,一个使用键/值,另一个使用 SuperColumns 和 co。

直到现在我还是偏爱 Riak,因为它是 Erlang 的稳定客户端库。

我知道我可以将 Cassandra 与 Thrift 一起使用,但 Erlang 似乎不太稳定(我没有得到很好的回报)

我现在对 HBase 一无所知,只知道它存在并且基于像 Cassandra 和 Riak 这样的 Dynamo。

所以这就是我需要做的:

  • 每个注册用户存储 1 到 X 条消息。
  • 获取每个用户存储的消息数。
  • 一次检索来自用户的所有消息。
  • 一次删除用户的所有消息。
  • 删除所有超过 X 个月的邮件

现在,我对那些 NoSQL DB 真的很陌生,我一直是 MySQL 爱好者,这就是为什么我问你这个问题,作为一个新手,有没有比我有更多经验的人可以帮助我选择哪个更好,并且会让我做我想做的一切而没有太多麻烦......

谢谢 !

4

3 回答 3

7

我不能代表 Cassandra 或 Hbase,但让我谈谈 Riak 部分。

是的,Riak 适合您的场景(我已经看到几家公司和社交网络将它用于类似目的)。

要实现这一点,您需要简单的 Riak Key/Value 操作,以及某种索引引擎。您的选择是(按偏好的粗略顺序):

  1. CRDT 集。如果您的 1-N 集合大小合理(假设每个用户的消息少于 50 条或其他),您可以将子集合的键存储在CRDT Set Data Type中。

  2. 里亚克搜索。如果您的集合很大,特别是如果您需要在任意字段上搜索您的对象,您可以使用Riak Search。它在后台启动 Apache Solr,并根据您定义的模式索引您的对象。它具有非常棒的搜索、聚合和统计、地理空间功能等。

  3. 二级索引您可以在eLevelDB 存储后端之上运行 Riak ,并启用二级索引(2i) 功能。

运行一些性能测试,以选择最快的方法。

至于架构,我建议使用两个存储桶(对于您描述的设置):一个用户存储桶和一个消息存储桶。

索引消息桶。(通过将搜索索引与其关联,或通过 2i 存储 user_key)。这使您可以执行所有必需的操作(并且消息日志不必放入内存中):

  • 每个注册用户存储 1 到 X 条消息- 一旦你创建了一个用户对象并获得一个用户密钥,每个用户存储任意数量的消息很容易,它们将直接写入消息存储桶,每条消息都存储适当的 user_key作为二级索引。
  • 获取每个用户存储的消息数量- 没问题。获取属于用户的消息键列表(通过搜索查询,通过检索您保存键的 Set 对象,或通过对 user_key 的 2i 查询)。这使您可以在客户端获得计数。
  • 一次检索来自用户的所有消息- 请参阅上一项。获取属于用户的所有消息的键列表(通过 Search、Sets 或 2i),然后通过多次获取每个键的值来获取这些键的实际消息(所有官方 Riak 客户端都有multiFetch能力,客户端-边)。
  • 一次删除用户的所有消息- 非常相似。获取用户的消息键列表,在客户端向它们发出删除。
  • 删除所有早于 X 个月的消息- 您可以在日期上添加索引。然后,检索所有早于 X 个月的消息密钥(通过搜索或 2i),并为它们发出客户端删除。
于 2012-10-21T19:43:13.607 回答
0

我根本无法与 Riak 交谈,但我会质疑你放弃 Mongo 的选择。只要您关闭日记功能并且不要完全饿死它以获取 RAM,那就很好了。

我对 HBase 了解很多,听起来它可以轻松满足您的需求。根据您拥有的用户数量,可能会过度杀伤力。它微不足道地支持诸如为每个用户存储许多消息之类的事情,并具有写入自动到期的功能。根据您构建架构的方式,它可能是原子的,也可能不是原子的,但这对您的用例来说并不重要。

缺点是正确设置它有很多开销。在建立 HBase 之前,您需要了解 Hadoop、让 HDFS 运行、确保您的名称节点是可靠的等等。

于 2012-04-23T18:38:02.193 回答
0

我建议使用 Riak 或 Couchbase 之类的分布式键/值存储,并将每个用户的整个消息日志序列化(转换为二进制 erlang 术语或 JSON/BSON)作为一个值。

因此,对于您的用例,它将如下所示:

  • 每个注册用户存储 1 到 X 条消息- 当用户上线时,生成一个有状态的gen_server,它从存储中获取并在启动时反序列化整个消息日志,接收新消息,将它们附加到它的日志副本,在会话结束时终止,序列化更改的日志并将其发送到存储。
  • 获取每个用户存储的消息数量——注销、反序列化、计数;或者可能将计数存储在单独的 k/v 对中。
  • 一次检索来自用户的所有消息- 只需将其从存储中提取。
  • 一次删除用户的所有消息- 只需从存储中删除值。
  • 删除所有超过 X 个月的邮件- 获取、过滤、放回。

明显的限制 - 消息日志必须适合内存。

如果您决定单独存储每条消息,如果您希望它们按时间顺序排列,则需要在分布式数据库中对它们进行排序,因此处理大于内存的数据集几乎没有帮助。如果需要的话-无论如何,您最终都会遇到一些更棘手的方案。

于 2012-04-25T12:08:22.983 回答