2

假设我有一张表(我们称之为BigTable),每天可以体验5,000,000 次插入(可能有同样多的 SELECT)。插入的每一行大约为 50kb。

这些每日 INSERT 平均分配给 5 个客户端(该表有一个名为 的 FK ClientID)。永远不需要跨多个客户端选择或连接数据。

随着这张表的增长,我担心数据库性能,所以我想出了两个解决方案。

解决方案 1:

  • 分区BigTable依据ClientID
  • 将每个分区存储在服务器上的单独硬盘上(使用 Azure 博客存储)。
  • 将 1 个月前的所有数据(存档数据,但仍需要可查询)分区到另一组 READONLY 分区中。

本质上,这意味着它们自己的存储设备上的以下分区:

  • 主要(所有数据不包括BigTable
  • ClientA BigTable(每天 5,000,000 行 / 5 个客户 x 30 天 = 30,000,000 行)
  • ClientB BigTable(30,000,000 行)
  • ClientC BigTable(30,000,000 行)
  • ClientD BigTable(30,000,000 行)
  • ClientE BigTable(30,000,000 行)
  • 客户A的BigTable档案
  • 客户B的BigTable档案
  • ClientC的BigTable档案
  • ClientD的BigTable档案
  • ClientE的BigTable档案

存档表中的行数将为 (5,000,000) x (DB 天数) - (30,000,000)。这仍然是一个巨大的表格,但只会用于绘制奇怪的报告。

SQL Server 将托管在 14GB、8 核的 Azure VM 上。

解决方案 2:

另一种选择是为每个客户端托管单独的数据库。这意味着每个人都将拥有自己的专用 SQL Server 机器。归档数据仍会进行分区。

由于数据的物理分离,此选项不是最佳选择。必须管理对多个数据库的更新可能会带来很大的问题。为每个客户端建立单独的数据库连接也是开发人员的考虑因素。

有人可以就这些选项提出建议吗?

4

3 回答 3

5

由于您使用 [azure] 和 [sql-server] 对此进行了标记,因此我假设您正在尝试在 Windows Azure 中执行此操作。如果是这种情况,那么 a) 客户端分区不一定是一个好主意,并且 b) SQL 可能不是最适合您的问题的(完整)。

在构建可扩展架构时,分区策略不应该基于特定的东西,比如“客户端”,而是更随意的东西。原因很简单——除非客户端有独立的理由,例如不希望他们的数据与其他数据混合,或者每个客户端有不同的 SLA,否则选择“客户端”作为分区可能不会呈现最佳结果。如果你 80% 的业务是由单个客户端生成的,那么你的问题还没有解决,仍然需要维护n 个单独的数据库来应对边际负载。

每天 500 万次数据库插入并不是一个很大的数字,但对于托管在 Azure IaaS 或 Azure SQL 数据库中的 SQL Server 来说可能是一个很大的数字——由于底层商品硬件的性能。在确定如何对 SQL 进行分区之前,请先问自己两个问题。首先,您希望从数据中获得哪些用途和性能特征?(它必须立即保持一致吗?您可以异步处理数据吗?)其次,您是否将这些特征与其他数据存储技术进行了对比?您是否考虑过表存储(或 Redis 等非 MS 解决方案)?

在尝试了几个选项后,您可能会发现:

  • 有时,SQL 可以很好地存储某些数据。
  • 大部分处理可以异步完成,因此插入的峰值性能无关紧要(在 24 小时内进行 5 百万次插入不是问题)。
  • SQL 可能不适合长期存储。
  • 使用 map-reduce 可以有效地查询旧数据,而不是 SQL 查询。

例如,我有一个以一秒为间隔跟踪车辆的应用程序。它的目标是 100,000 辆汽车,但其架构能够在不更改任何代码或数据库的情况下扩展到数百万辆。但从中期来看,它必须每天处理 7200 万次插入。所有这些都在一个小于 10GB 的 Windows Azure SQL 数据库和一大堆表存储上运行。这样做的原因是,虽然我想归档所有数据(7200 万行),但我不需要复杂的 SQL 查询访问它,所以它很高兴地位于表存储中。我在 SQL 中存储的是数据的摘要。所以在我的例子中,我只对车辆的旅程感兴趣(起点和终点位置,行驶距离等),这意味着我每天每辆车只有两到三行我需要的 SQL — 大大减少了数据库的负载。此外,我的瓶颈在于数据的收集,因此我立即将数据添加到(Windows Azure)队列中——并担心在单独的工作负载中汇总数据。

这个答案可能有点长,但是是为了让你更仔细地思考你的数据模型,而不是仅仅试图思考如何用 SQL 来解决问题。有关更多详细信息,请查看CALM中的数据模型。

于 2013-02-18T16:33:16.560 回答
3

给您的一些想法: 1) 使用 Azure 表而不是 SQL。有 PartitionKey = ClientID。每个表可以是 200TB 并支持 20k IOPS。每个分区是 2k IOPS,因为客户端在逻辑上是分开的,你会得到一个自然的负载平衡(Azure load balances by Partition)。这也将使您不必运行/管理 XL VM 24x7(即便宜得多)。存储成本将是相同的,因为 VM 的数据驱动器无论如何都由 Azure 存储提供支持。每天 500 万次插入仅为约 60/秒,因此会有很大的增长空间。这在 b/c 中尤其如此,您正在执行相当简单的插入/选择并且不会跨越客户端边界。

2)如果你想做一个每个客户端的数据库,我会选择 SQL Azure。配置速度要快得多,每个数据库都是一个单独的缩放单元(这将防止一个客户端为其他客户端创建问题)。您还可以根据客户端更改动态更改数据库。

3)如果你想要一个单一的单体数据库,我会在 VM 上使用 SQL Server。创建多个数据驱动器并将它们安装为条带集。对于 XL VM,最多可以映射 16 个驱动器。这会将数据库的最大大小限制为 16TB,因此您需要有一些机制来老化/归档/垃圾收集。

于 2013-02-18T18:52:39.783 回答
1

您不仅需要考虑访问性能,还需要考虑灾难恢复性能。仅在活动月份,每个客户端的容量为 6TB,我强烈建议将客户端保存在单独的数据库中。

如果您有一个不错的 Continuos 集成和自动部署过程,那么保持数据库模式同步应该不是什么大问题。

于 2013-02-18T14:47:50.867 回答