9

我的任务是从 Azure 表存储下载大约 1 亿行数据。这里重要的是速度。

我们使用的过程是从 Azure 表存储下载 10,000 行。将它们处理成 Sql Server 的本地实例。在处理行时,它一次从 Azure 表中删除 100 行。这个过程是线程化的,有 8 个线程一次下载 10,000 行。

唯一的问题是根据我们的计算。下载和处理我们存储的大约 1 亿行大约需要 40 天。有谁知道完成这项任务的更快方法?

一个附带问题:在下载过程中,Azure 将发回没有任何数据的 xml。它不会发回错误。但它发送这个:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="azure-url/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <title type="text">CommandLogTable</title>
  <id>azure-url/CommandLogTable</id>
  <updated>2010-07-12T19:50:55Z</updated>
  <link rel="self" title="CommandLogTable" href="CommandLogTable" />
</feed>
0

其他人有这个问题并有解决办法吗?

4

6 回答 6

16

除了禁用 Nagling的建议之外,还有一篇关于提高 Azure 表存储性能的非常好的帖子。实际上提高 ADO.NET 反序列化的速度Sqwarea (使用Lokad.Cloud框架构建的大型在线多人游戏)提供了 10 倍的加速。

但是,表存储可能不是大型存储场景(超过数百万条记录)的最佳解决方案。延迟是这里的杀手锏。为了解决这个问题,我已经成功地使用了基于文件的数据库存储,其中更改在本地完成(没有任何 CLAP 的网络延迟)并通过将文件上传回提交到 BLOB(Lokad在这里强制执行并发和横向扩展) .CQRS App Engine for Windows Azure)。

一次向 SQLite 数据库插入 1000 万条记录(在事务中,每条记录由 2 个字段索引,并且通过 ProtoBuf 序列化任意无模式数据)平均总共只需要 200 秒。上传/下载生成的文件 - 平均大约 15 秒。按索引随机读取 - 瞬时(前提是文件缓存在本地存储中并且 ETag 匹配)。

于 2010-07-13T03:44:56.750 回答
7

至于你的附带问题,我希望你得到一个“延续令牌”。如果您使用的是 .NET 存储客户端库,请尝试将 .AsTableServiceQuery() 添加到您的查询中。

至于你的主要问题,展开查询是你能做的最好的事情。听起来您正在从本地计算机(而不是在 Windows Azure 中)访问存储。如果是这样,我想你可以通过向 Windows Azure 部署一个小服务来加快速度,该服务从表存储中获取数据(更快,因为数据中心内的带宽更高,延迟更低),然后压缩结果并将它们发送回您的本地计算机。XML Windows Azure 表发回有很多开销,因此将其剥离并捆绑行可能会节省大量传输时间。

于 2010-07-12T20:11:48.867 回答
2

除了有关带宽限制的建议外,您还很容易遇到存储帐户限制,因为每个表分区被限制为每秒大约 500 个事务。

进一步:部署了优化(Nagle 算法),实际上可以减慢小读取(例如您的 1K 数据读取)的速度。这是一篇关于禁用 Nagling 的博客文章,这可能会显着加快您的读取速度,尤其是如果您直接在 Azure 服务中运行而没有 Internet 延迟。

于 2010-07-12T23:58:37.790 回答
2

获取数据的最快方法(亚马逊支持但 Azure 尚不支持)是向他们发送 USB 磁盘(甚至是 USB 记忆棒),让他们将数据放入磁盘并将其发送回给您。

另一种选择是在创建数据时使用 AppFabric 服务总线将数据导出到另一个系统,而不是等待一次全部下载。

于 2010-07-30T20:49:33.730 回答
1

最有可能的是,您的限制因素是网络带宽,而不是处理。如果是这样的话,你唯一真正的希望就是扩展:更多的机器运行更多的线程来下载数据。

顺便说一句,Azure 不是公开了一些“导出”机制来消除手动下载所有行的需要吗?

于 2010-07-12T20:08:04.570 回答
1

这里的重要因素是数据如何跨分区分布。跨越分区边界的查询将在每个需要重新提交的边界处返回 - 即使所讨论的分区有 0 行。如果数据是 1 Partition = 1 Row,那么它会很慢,但你可以将线程数增加到 8 以上。如果数据在 n 个分区 = m 行中,那么下面的想法应该会加快你的速度。

假设您有多个分区并且每个分区都有一定数量的行,最快的方法是启动尽可能多的线程(如果您使用.Net PLINQ 或 Parallel.ForEach(partition) 或 QueueWorkItem())并让线程扫描其分区中的所有行、处理、发布到 SQL 并在返回之前删除。

考虑到所涉及的延迟(10 毫秒)和多次往返,即使使用 8 个线程,您也可能没有您想象的那么忙。此外,您没有提及您使用的是哪个 VM,但您可能想要分析不同的大小。

或者,另一种方法是利用队列和一些“n”个工作人员。对于每个分区(或一组分区),将一条消息放入队列中。让工作人员从队列中拉出(多线程)并查询/处理/发布/重复。您可以根据需要启动尽可能多的工作人员,并将其分布在更多的数据中心(即更高的吞吐量等)。

于 2010-07-15T00:47:09.187 回答