社交应用的数据库设计和优化考虑因素

5
通常情况下,我有一个简单的应用程序,允许用户上传照片并关注其他人。因此,每个用户都将拥有类似于“墙”或“活动源”的东西,他或她可以查看来自朋友(他或她关注的人)上传的最新照片。
大多数功能很容易实现。然而,当涉及到历史活动源时,由于性能原因,事情很容易变得混乱。
我在这里遇到了以下困境: 我可以轻松地将活动源设计为数据库中的规范化部分,这将节省我的写入周期,但在为每个用户选择这些结果时,复杂度会极大增加(针对在一定时间段内上传的每张照片,选择一定数量的上传者,我正在关注 / 针对每个我关注的人,选择他的照片)
一种优化选项是引入一系列阈值约束条件,例如基于其最后上传日期对我关注的人进行排序,甚至排除某些人以节省周期,并且对于每个用户,仅选择最近上传的5张照片。
第二种方法是引入完全非规范化的活动源模式,其中每行代表一个关注者的通知。这意味着每次我上传照片时,DB都会将n行放入此“下拉桶”中,n表示我关注的人数,即需要大量写入周期。但如果我有这样的表,可以很容易地应用一些优化技术,例如巧妙的索引以及修剪比一定时间段早的条目(队列)。
然而,第三种方法是一种更少规范化的模式,其中服务器端应用程序将从数据库中卸下一些复杂性。我看到一些社交应用程序(如friendfeed)严重依赖于在DB中存储序列化对象,例如JSON对象。
我肯定还没有完全掌握可扩展的DB设计技巧,因此我相信还有很多东西我错过了或需要学习。如果有人能给我指点迷津,我将不胜感激。

我对数据库优化不是很擅长,但看起来你可能需要一个非关系型数据库(可以看看Cassandra和MongoDB)。实际上,在这种情况下它们似乎真的更快。 (想想Facebook,使用Cassandra作为主要数据库管理系统:D) - ArtoAle
有没有一本关于设计可扩展数据库(用于社交应用和大型多人在线游戏)的好书? - xantrus
只是好奇想知道,在设计这种类型的应用程序时,除了可扩展的数据库和数据检索之外,您是否还遇到其他问题。您选择使用哪个框架和编程语言来开发这种类型的应用程序?实际上,我曾经问过类似的问题:http://stackoverflow.com/questions/4842276/designing-a-social-networking-website-db-and-front-end - ag112
5个回答

14
如果您的应用程序成功了,那么很可能会有更多的读操作而不是写操作——我只上传一次照片(写入),但是每当我的朋友刷新他们的动态时,他们都会阅读它。因此,您应该优化快速读取,而不是快速写入,这指向了去规范化模式的方向。
问题在于,如果您拥有大量用户,则创建的数据量可能会迅速失控。非常大的表对数据库查询不利,因此存在潜在的性能问题。(还有足够的存储空间的问题,但这更容易解决)。
如果像您建议的那样,在一定时间后删除行,则这可能是一个很好的解决方案。随着您的增长并遇到性能问题,可以减少那段时间(到一定程度)。
关于存储序列化对象,如果这些对象是不可变的(写入后不会更改)且您不需要对其进行索引或查询,则这是一个好选择。请注意,如果您去规范化了数据,则可能意味着为活动源使用单个表。在这种情况下,我认为存储二进制大对象(BLOBs)几乎没有多少好处。
如果您选择使用序列化对象方式,请考虑使用一些NoSQL解决方案,如CouchDB-它们更好地优化了处理这种数据,因此原则上您应该在相同的硬件设置下获得更好的性能。
最后,有建议要注意的一点:经验告诉我们构建一个可扩展的应用程序很困难,需要花费更多时间。在您开始担心如何为这些百万用户提供服务之前,您应该先考虑如何将数百万用户引导到您的应用程序。当您成功到一定程度时,可以重新设计和重建您的应用程序。

4
先获取数百万用户再考虑扩展,而不是构建可扩展但仅有少数人使用的应用程序,这种方法值得支持。 - Kris C

7

您可以采取许多选项

  • 增加更多硬件,内存、CPU--进入云托管
  • 24GB内存听起来如何?大部分重要的数据库信息都可以放在内存中。
  • 选择一个具有可扩展SSD的主机。
  • 在应用程序中使用基于事件的系统编写所有用户的“历史记录”。 所以它会像这样:id,user_id,event_name,date,event_parameters'--例如:1,8,CHANGED_PROFILE_PICTURE,26-03-2011 12:34,<id of picture>最重要的是,这个表将在内存中。不再需要担心写入性能。 记录过去了,即3天后,它们可以清除到另一个表(非内存)中,并包含在查询结果中,如果用户选择回到那个时候。 通过在一个表中拥有所有这些内容,您可以消除执行多个查询和SELECT以构建此信息的必要性。
  • 考虑使用INNODB用于历史/源表。

好资源阅读


2
我越来越多地了解NoSQL解决方案并看到人们推荐它们,但是没有人提到这种选择的缺点。对我来说最明显的是缺少事务处理 - 想象一下如果您不时丢失几条记录(有报道称这种情况经常发生),那将会怎样。
但是,令我惊讶的是,没有人提到MySQL被用作NoSQL的情况 - 这里有一些阅读材料
最终,无论您选择什么解决方案(关系型数据库还是NoSQL存储),它们都以类似的方式进行扩展 - 通过在网络上分片数据(当然,还有更多选择,但这是最明显的选择)。由于NoSQL做得更少(没有SQL层,因此CPU周期不会浪费在解释SQL上),所以它更快,但也可能会达到极限。
正如Elad已经指出的那样 - 从一开始就构建可扩展的应用程序是一个痛苦的过程。更好的做法是花时间专注于使其流行,然后再将其扩展出去。

2

我建议您首先使用规范化的模式,这样可以快速而简洁地编写代码。然后使用非事务性(无锁定)读取来获取信息,确保使用游标以便在返回结果时处理结果,而不是等待整个结果集。由于听起来这些信息并没有任何特别重要的影响,所以您不需要担心锁定或其他通常会让您避免事务性读取的问题。


2
这些问题是为什么当前使用NOSql解决方案的原因。我在我的以前的项目中所做的非常简单。我不会在内存存储器中保存仅包含纯粹feed'id的用户->墙用户->历史记录(我最喜欢的是redis)。所以在每次插入时,我都会在数据库中进行一次插入操作和(n*读取优化)插入操作在内存存储器中。我设计内存存储器来优化我的读取。如果我想要过滤用户历史记录(或墙)的视频,我将feedid推送到列表中,例如user::{userid}::wall::videos。
当然,你也可以完全在memstores中构建系统,但有两个系统各自发挥其所长是很好的。
编辑: 查看这些应用程序,以获得一个思路:

http://retwis.antirez.com/

http://twissandra.com/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接