7

不能完全无状态的大型网站如何在 Web 层实现极高的可扩展性?

像 eBay 和 Amazon 这样的网站不能完全无国籍,因为它们有购物车或类似的东西。将购物车中的每件商品编码到 URL 中是不可行的,将每件商品编码到 cookie 中并在每次连接时发送也不可行。所以亚马逊只是将会话 ID 存储到正在发送的 cookie 中。所以我知道 eBay 和 Amazon 的 web 层的可扩展性应该比 google 搜索引擎的可扩展性要困难得多,在那里一切都可以被编码到 URL 中。

另一方面,eBay 和亚马逊的规模都非常大。有传言说 eBay 上有大约 15000 个 J2EE 应用服务器。

这些站点如何处理这两者:极端的可扩展性和有状态?由于站点是有状态的,因此进行简单的 DNS 平衡是不可行的。所以人们会假设这些公司有一个基于硬件的负载均衡器,比如 BigIP、Netscaler 或类似的东西,这是该站点的单个 IP 地址背后的唯一设备。此负载均衡器将解密 SSL(如果已编码)、检查 cookie 并根据该 cookie 的会话 id 决定哪个应用程序服务器持有该客户的会话。

但这不可能工作,因为没有单个负载均衡器可以处理数千个应用程序服务器的负载?我想即使是这些硬件负载平衡器也无法扩展到这样的水平。

此外,负载平衡正在为用户透明地完成,即用户不会被转发到不同的地址,但仍然全部集中在 www.amazon.com 上。

所以我的问题是:是否有一些特殊的技巧可以实现网络层的透明分片(而不是通常所做的数据库层)?只要不检查 cookie,就无法知道哪个应用程序服务器正在持有此会话。

编辑:我意识到只需要透明度,如果需要对网站进行爬虫和书签。例如,如果该站点只是一个 Web 应用程序,例如飞机或火车票预订系统,那么将用户重定向到不同 URL 后面的特定 Web 服务器集群应该没有问题,例如 a17.ticketreservation.com。在这种特定情况下,只使用多个应用程序服务器集群是可行的,每个集群都位于自己的负载均衡器后面。有趣的是,我没有找到使用这种概念的网站。 编辑:我发现这个概念在highscalability.com上讨论过,讨论指的是 Lei Zhu 的一篇名为“Web 2.0 应用程序的客户端负载平衡”。Lei Zhu 使用交叉脚本来透明地进行客户端负载平衡。

即使有一些缺点,如书签、xss 等,我确实认为这对于某些特殊情况听起来是一个非常好的主意,即几乎没有内容的 Web 应用程序,不需要被蜘蛛或书签(例如机票预订系统或类似的东西)。那么就不需要透明地进行负载平衡了。

可能存在从主站点到服务器的简单重定向,例如从 www.ticketreservation.com 到 a17.ticketreservation.com 的重定向。从那里用户停留在服务器 a17。a17 不是服务器,而是集群本身,通过它可以实现冗余。

初始重定向服务器本身可以是负载平衡器后面的集群。这样,可以实现非常高的可扩展性,因为 www 后面的主要负载均衡器只在每个会话开始时被命中一次。

当然,重定向到不同的 url 看起来非常讨厌,但是对于单纯的 Web 应用程序(无论如何都不需要蜘蛛、深度链接或深度书签),这对用户来说应该只是一个视觉问题吗?

重定向集群可以轮询应用集群的负载并相应地调整重定向,从而实现平衡而不仅仅是负载分配。

4

4 回答 4

2

您可能必须在这些地方之一的工程团队中才能确定,但​​是有些人从两个地方的谈话和其他信息中做出了有根据的猜测:

易趣架构亚马逊架构

在当今世界中,仅一个负载均衡器本身就相当于过去几年的 DNS 循环。今天,您拥有诸如任播之类的东西,可以让您玩各种花样。您可以很确定 ebay 和 amazon 之类的公司确实使用负载均衡器,而且它们使用了很多。

当您考虑它的工作原理时,您可能需要进一步简化它,因为很多流量是无状态的。在对页面的单个请求中,可能有很多不需要了解状态的对象。通过从无状态系统(这是任播出现的地方)为它们提供服务,将这些对象从图片中剔除,请求的数量会急剧下降。

如果这不能让您达到单个负载均衡器可以处理负载的程度,那么下一步就是使用 IP 路由和/或地理 DNS 分解事务。像 ebay 和 amazon 这样大的网站将位于许多不同的数据中心,每个数据中心都有大量的互联网连接。您将来自互联网流行 quest-west 的所有内容发送到西海岸数据中心“quest”服务器,来自 att-west 的任何内容都被发送到西海岸数据中心“att”服务器,来自 quest-east 的任何内容然后发送到东海岸数据中心“任务”服务器等。这些系统中的每一个都可以是一个单独的负载均衡器,可以处理负载,一些负载均衡器每秒可以处理数十万个事务,甚至 SSL 加密。

于 2008-10-18T18:22:38.720 回答
2

您可能会发现以下论文很有用,该论文介绍了高可用性键值存储系统的设计和实现,亚马逊的一些核心服务使用该系统来提供“永远在线”的体验:

Giuseppe DeCandia、Deniz Hastorun、Madan Jampani、Gunavardhan Kakulapati、Avinash Lakshman、Alex Pilchin、Swami Sivasubramanian、Peter Vosshall 和 Werner Vogels,“<strong> Dynamo:亚马逊的高可用性键值存储”,第 21 届 ACM 研讨会论文集关于操作系统原理,华盛顿州史蒂文森,2007 年 10 月。

于 2008-10-18T18:51:32.140 回答
2

我不知道他们是怎么做到的,但这里有一些建议:

  • 为避免负载平衡器主机本身过载,请使用循环 DNS 或
  • 根据负载、设置、地理位置等将不同的客户端重定向到不同的集群地址

为了分配中间层负载,

  • 将中间层会话服务器的 ID 嵌入会话 ID cookie 中 - 正如其他人所建议的那样。这样,您点击哪个前端框就无关紧要了,它们可以添加/删除而不会产生任何影响。
  • 如果它足够重要,请在会话期间将客户端重定向到备用中间层服务器,以便可以将其删除以进行维护等。
  • 客户端在开始新会话时开始使用新委托的中间层服务器

分配后端数据库负载

  • 对每个帐户或每个用户的“实时”数据进行“常规”分片
  • 异步复制变化缓慢或相对静态的数据;用户可能会看到它已过时(但大多数情况下并不多)。中间层和 Web 服务器连接到它们自己位置的本地数据库
于 2008-10-20T13:26:06.777 回答
1

简单的。无状态的 Web 服务器是负载平衡的。保存会话数据的应用程序服务器(中间层)不是。Web 服务器可以使用您的会话 id cookie 来确定要联系的应用服务器。

Memcached 和 Microsoft 的 Velocity 是解决这一确切需求的产品。

编辑:Web 服务器如何知道要联系哪个应用服务器?这嵌入到会话 id 哈希中,通常可以按照您的喜好完成。它可能就像您的会话 id 是 server:guid 一样简单。不过, Memcached的基础是散列。

重要的是客户端必须能够以无状态方式确定要联系的应用服务器。最简单的方法是将它嵌入到密钥中,尽管注册表(可能在它自己的层上)也可以工作并且可以提供一些容错。

Edit2:回顾一些Ebay的采访,我可能对他们的实施细节有些错误。他们不做缓存,也不做中间层的状态。他们所做的是拥有一个按功能分区的负载平衡中间层(应用服务器)。因此,他们将拥有一个服务器池,用于例如查看项目。然后是另一个出售物品的池子。

这些应用服务器有一个“智能”DAL,它路由到分片数据库(按功能和数据进行分区,因此 Database1 上的用户 AL、Database2 上的用户 MZ、Items1 上的 Items 1-10000 等)。

它们在中间层没有状态,因为它们是按功能分区的。因此,正常的用户体验将涉及超过 1 个应用服务器池。假设您查看了一个项目 (ViewAppServerPool),然后去竞标一个项目 (BidAppServerPool)。所有这些应用服务器都必须保持同步,这需要分布式缓存来管理所有内容。但是,它们的规模是如此之大,以至于没有分布式缓存可以有效地管理它,单个数据库服务器也不能。这意味着他们必须对数据层进行分片,并且任何缓存实现都必须跨越相同的边界。

类似于我上面发布的内容,只是向下移动了一层。应用服务器决定联系哪个数据库,而不是让 Web 服务器确定要联系的应用服务器。只是,在 Ebay 的案例中,由于其分区策略,它实际上可能会攻击 20 多个数据库服务器。但是,无状态层也有一些规则用于联系有状态层。然而,Ebay 的规则比我上面解释的简单的“User1 在 Server10”规则要复杂一些。

于 2008-10-19T17:47:41.850 回答