Azure - C# 并发 - 最佳实践

Azure - C# Concurrency - Best Practices

我们正在使用 Microsoft Azure 抓取基于 Web 的 API。问题是要检索的数据太多(涉及 combinations/permutations)。

如果我们使用标准的 Web Job 方法,我们计算出处理我们想要获得的所有数据大约需要 200 年 - 我们希望我们的数据每周都被刷新。

来自 API 的每个 request/response 大约需要 0.5-1.0 秒来处理。请求大小平均为 20000 字节,平均响应为 35000 字节。我相信请求总数以百万计。

思考这个问题的另一种方式是:您将如何使用 Azure 进行 Web 抓取 - 并确保您不会超载(在内存 + 网络方面)VM 运行 上? (在这种情况下,我认为您不需要太多 CPU 处理)。

到目前为止我们已经尝试过的:

  1. 使用 Service Bus Queues/Worker Roles 扩展到 8 个小型 VM - 但这导致了很多网络错误的发生(必须有一些网络限制多少VM 可以处理的每个辅助角色)。
  2. 使用 Service Bus Queues/Continuous Web Job 扩展到 8 个小型 VM - 但这似乎工作得更慢 - 即使扩展,也没有给我们太多控制关于幕后发生的事情。 (我们真的不知道有多少虚拟机在运行)。

似乎这些东西是为 CPU 计算而构建的 - 而不是为了 Web/API 抓取。

澄清一下:我将我的请求放入队列中 - 然后由我的多个 VM 拾取以进行处理以获得响应。这就是我使用队列的方式。每个 VM 都按照 Microsoft 的规定使用 ServiceBusTrigger class。

  1. 拥有大量小型 VM 还是拥有少量大型 VM 更好?
  2. 我们应该查看哪些 C# classes?
  3. 尝试在 Azure 上执行此类操作时,技术最佳实践是什么?

我在抓取方面有一些经验,所以我会分享我的想法。

  1. 似乎这些东西是为 CPU 计算而构建的 - 而不是为了 Web/API 抓取。

它们是为动态缩放而构建的,鉴于您的任务并不是您真正需要的。

  1. 如何确保您不会使 VM 过载?

测量响应时间和错误率并调整代码以降低它们。

  1. 在这种情况下,我认为您不需要太多 CPU 处理。

取决于每秒传入的数据量以及您正在使用这些数据做什么。对快速传入数据进行更复杂的解析(如果您决定在同一台机器上进行解析)将很快耗尽 CPU。

  1. 8个小型VM导致出现大量网络错误(一定有网络限制)

VM 越小,它们获得的共享资源就越少。存在吞吐量限制,然后您的邻居与您共享实际硬件就会出现问题。通常,您的实例越小,您 运行 遇到的麻烦就越多。

  1. 是拥有大量小型 VM 还是拥有少量大型 VM 更好?

根据我的经验,较小的 VM 太残废了。但是,您的里程可能会有所不同,这完全取决于特定任务及其解决方案的实施。真的,你要在你的环境中衡量你自己。

  1. 我们应该看什么 C# 类?
  2. 尝试在 Azure 上执行此类操作时,技术最佳实践是什么?

对于高吞吐量抓取,您应该关注基础架构。您在不同的 Azure 数据中心会有不同的延迟,并且在不同的 VM 大小下网络 latency/sustained 吞吐量会有不同的体验,具体取决于谁与您共享硬件。最佳做法是尝试找到最适合您的方法 - 更改数据中心、VM 大小和其他实验。

Azure 可能不是解决此问题的最佳解决方案(除非您正在疯狂消费)。 8 个小型虚拟机每月 450 美元。这足以支付一台非托管专用服务器的费用,该服务器具有 256Gb 内存、40 个硬件线程和 500Mbps - 1Gbps(甚至高达数 Gbps 突发)的优质网络带宽,没有延迟问题。

根据您的预算,您将拥有一个 无法超载 的专用服务器。您将有足够多的 RAM 来处理异步固定(如果您决定使用异步),或者有足够的硬件线程用于多线程同步 IO,从而提供最佳吞吐量(如果您选择使用固定大小的线程池进行同步) .

旁注,根据 API 的具体情况,您的主要问题可能是 API 所有者,当您开始放太多东西时,它只会让您步履维艰API 端点上的压力。

实际上,网络抓取工具是我在 Azure 中使用 运行 一段时间了:-)

据我所知没有 'magic bullet'。在截止日期前收集大量资源非常困难。

它是如何工作的(最重要的事情):

  • 我使用工作者角色和 C# 代码作为代码本身。
  • 对于调度,我使用队列存储。我将爬行任务放在超时队列中(例如 'when to crawl then'),然后让爬虫将它们拉下来。您可以在队列大小上设置触发器,以确保在速度方面满足最后期限——我个人不需要它们。
  • SQL Azure 很慢,所以我不使用它。相反,我只使用 table 存储来存储抓取的项目。请注意,更新数据可能非常复杂。
  • 不要使用过多线程;相反,对所有网络流量使用异步 IO。
  • 此外,您可能还必须考虑额外的线程需要额外的内存(解析树可能会变得相当大)- 因此需要权衡取舍...我确实记得使用过一些线程,但实际上只有少数几个。

请注意,如果您现在使用线程方法,这可能确实需要您重新设计和重新实现完整的网络抓取工具。再一次,有一些好处:

  • Table 存储和队列存储很便宜。
  • 我目前使用一个 Extra Small VM 来抓取超过一千个网络资源。
  • 入站网络流量免费。
  • 因此,结果也很便宜;我敢肯定它比其他选择要少得多。

至于我使用的 类...好吧,那是一个有点长的列表。我将 HttpWebRequest 用于异步 HTTP 请求和 Azure SDK——但其余的都是手工制作的(而不是开源的)。

P.S.:这不仅适用于 Azure;其中大部分也适用于本地刮板。