极端分片:每个用户一个SQLite数据库

44

我正在开发一个介于电子邮件服务和社交网络之间的网络应用程序。我认为它有潜力在未来快速增长,因此我很关心可扩展性。

我决定为每个活跃用户创建一个单独的SQLite数据库:即每个“碎片”一个活跃用户,而不是使用一个集中式MySQL/InnoDB数据库,然后在需要时进行分区。

这样备份数据库将像每天将每个用户的数据库文件复制到远程位置一样容易。

扩展将像添加额外的硬盘以存储新文件一样容易。

当应用程序超出单个服务器范围时,我可以在文件系统级别使用GlusterFS连接服务器并无需更改应用程序;或者搭建一个简单的SQLite代理系统,允许每个服务器操作相邻服务器中的sqlite文件。

并发问题将很小,因为每个HTTP请求每次只会访问数千个文件中的一个或两个数据库文件,并且SQLite只会在读取时阻塞。

我打赌这种方法将使我的应用程序能够平滑扩展并支持许多酷炫而独特的功能。 我是否犯了错误? 我有遗漏什么吗?

更新 我决定采用不那么极端的解决方案,目前运行良好。我使用了一个固定数目的碎片-精确地说是256个SQLite数据库。每个用户都通过简单的哈希函数分配并绑定到一个随机碎片。

我的应用程序大多数功能只需要访问一个或两个碎片,但有一项特别需要在256个碎片中执行10到100个简单查询的功能,具体取决于用户。 测试表明,如果所有数据都缓存在RAM中,则大约需要0.02秒或更短时间。我认为这已经可以应对了!

更新2.0:我将应用程序移植到MySQL/InnoDB并能够获得类似于常规请求的性能,但是对于需要分片操作的那个请求,InnoDB会快4-5倍。因此,出于这个原因和其他原因,我放弃了这种架构,但我希望有人能够找到它的用途...谢谢。


这是一篇相当旧的帖子,你对Gluster的经验可能现在不太相关,但你最终是否尝试在glusterFS上使用sqlite? - jberryman
1
对于考虑研究这种架构的人,我建议看看开源Actordb;每个演员都是一个SQLite筒仓,使用Raft协议进行分布和复制 - http://www.actordb.com/ - Jerome WAGNER
8个回答

34
这种方法会失败的地方是,如果你需要进行所谓的“分片遍历”——即查找跨越许多不同用户的所有数据。这种特定的“查询”将必须通过编程方式完成,依次询问每个SQLite数据库,并且很可能是您网站上最慢的部分。在任何数据已被“分片”到单独的数据库中的系统中,这都是一个普遍问题。
如果所有的数据都是自包含的,则这种设计应该可以很好地扩展——使其成为有效设计的关键是要知道数据可能如何被使用,以及一个人的数据是否会与另一个人的数据互动(在您的情况下)。
您还需要注意文件系统资源——SQLite很棒、很快等等,但使用“标准数据库”(即MySQL、PostgreSQL等)会得到一些缓存和写入方面的好处,因为它们的设计方式不同。在您提出的设计中,您将错过其中的一部分优势。

3
这是一个很棒的答案。另一个需要考虑的因素是“规模经济”——将类似的数据保存在一起可以实现高效压缩,更好地利用磁盘空间(你可能已经在缓存评论中提到了),等等。 - SquareCog
我遇到了类似的问题。我正在使用Db4o,而Db4o基本上会将整个数据库加载到内存中进行查询。因此,我认为每个用户都有一个DB,并动态地将DB加载到内存中,而不是一次性加载一个巨大的DB,这样会更有效率。对此有什么想法吗? - jigzat

8
听起来像是一个维护噩梦。当所有这些数据库的模式发生变化时会发生什么?

模式更改可以动态地推出。 兼容的模式更改(例如添加列)可以在新应用程序代码启用该功能之前,每个用户一周内逐个推出。不兼容的更改可以在打开每个数据库文件时推出。无停机时间。 - Seun Osewa
1
在Fogbugz中似乎并不是问题,因为每个客户都有自己的SQL Server数据库... - Mike Woodhouse
如果您的模式迁移是自动处理的,那就没有问题。手动处理会很棘手;但是您可能希望使生产数据库的手动更新难以避免诱惑。 - Dickon Reed

5

http://freshmeat.net/projects/sphivedb

SPHiveDB是一个用于sqlite数据库的服务端。它使用JSON-RPC over HTTP来暴露一个网络接口以使用SQLite数据库。它支持将多个SQLite数据库合并为一个文件,也支持使用多个文件。它专门为极限分片模式而设计--每个用户一个SQLite数据库。


4
一个可能存在的问题是,每个用户都有一个数据库会非常低效地使用磁盘空间和内存,并且随着用户数量的增加,使用轻量级快速的数据库引擎的好处将完全丧失。
解决这个问题的一种可能方案是创建“minishards”,其中包含1024个SQLite数据库,每个数据库最多容纳100个用户。这比每个用户一个数据库的方法更有效,因为数据被更有效地打包。而且比Innodb数据库服务器方法更轻,因为我们使用的是Sqlite。
并发性也相当不错,但查询将不太优雅(shard_id 不好看)。你觉得呢?

3
如果你为每个用户创建一个单独的数据库,那么似乎你并没有设置关系...那么为什么要使用关系型数据库呢?

好问题。每个用户的数据库内部都存在关系。此外,SQLite允许您通过将一个数据库“ATTACH”到另一个数据库来执行与多个数据库中的表的连接。 - Seun Osewa

2
如果你的数据很容易分片,为什么不使用标准的数据库引擎呢?如果你扩展到足够大的规模,DB变成瓶颈时,将数据库分片,不同的用户在不同的实例中。效果相同,但你不会使用许多小型数据库。
实际上,你可能有至少一些共享数据并不属于任何单个用户,而且你可能经常需要访问一个以上用户的数据。这将导致任何系统出现问题。

2

我正在考虑使用相同的架构,因为我基本上想要将服务器端的SQLite数据库用作客户端的备份和同步副本。我的想法是使用Sphinx进行全文搜索来查询所有数据,并从所有数据的平面转储中运行Hadoop作业到Scribe,然后将结果公开为web服务。然而,这篇文章让我有些犹豫,所以我希望人们能继续发表自己的意见。


1

每个用户拥有一个数据库当然可以轻松地恢复单个用户的数据,但正如@John所说,模式更改需要一些工作。

这并不足以使其变得困难,但足以使其变得非平凡。


对于每个分片:锁定写入,更新存储和查询,解锁写入。 - undefined

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