💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# Tumblr:哈希处理每秒 23,000 个博客请求的方式 > 原文: [http://highscalability.com/blog/2014/8/4/tumblr-hashing-your-way-to-handling-23000-blog-requests-per.html](http://highscalability.com/blog/2014/8/4/tumblr-hashing-your-way-to-handling-23000-blog-requests-per.html) ![](https://img.kancloud.cn/c1/3f/c13f19c8d55f861933f3c2cf7deff6f5_240x82.png) *这是 Tumblr 的 SRE 工程师 [](http://michael.tumblr.com/) [Michael Schenck](http://michael.tumblr.com/) 的特邀帖子。* 在 Tumblr,博客(或 Tumblelog)是我们互联网上访问量最高的面孔之一。 tumblelogs 最方便的方面之一是其高度可缓存的特性,这是奇妙的,因为 Tumblr 网络为我们的用户提供了很高的视图/发布比率。 就是说,扩展边界代理层(更不用说缓存层)对满足所有这些请求是必需的,这并非完全简单。 本文介绍了负责博客服务的外围部分的体系结构,这是我们流量更大的外围端点之一。 这是我们的方法。 ### 统计信息 * 共有 278 名员工,团队中有 6 名员工负责 Tumblr 的所有外围(Perimeter-SRE),包括一名经理。 * 超过 2800 台服务器中,不到 20%的服务器用于博客服务功能 * 每秒(峰值)超过 23,000 个博客请求 * 每秒(峰值)超过 6,500 个博客缓存清除事件 * 超过 1.96 亿个博客 * 超过 930 亿个帖子 ### 平台 * [HAProxy](http://www.haproxy.org/) * [清漆](https://www.varnish-cache.org/) * [鸟](http://bird.network.cz/) ### 我们在哪里-基于地图的分区 在早期,我们只需要一台活动和一台备用代理服务器以及清漆节点。 两者都很容易管理,监视和高度可用。 但是,由于要满足所有用户请求,因此将达到容量限制,并且由于流行而导致停机前,必须准备好下一步步骤(即使不是理想的部署)。 ### 超出单个代理节点 超出单个 活动 代理服务器的数量非常普遍,并且通常涉及 DNS。 像循环 A 记录这样基本的东西可能会满足您的需求,但通常值得花额外的钱进行健康检查 GSLB 配置(即使您只有一个地理位置)。 DNS 的缺点是,尽管名称服务器将以相当均匀的速率对每个 IP 进行响应,但不能保证每个查找都将用于相同数量的请求。 用户 A 可能在一分钟内向解析的 IP 发出 10 个请求,而机器人 B 可能在同一分钟内发出 100 个请求。 如果您有两个 IP,则用户 A 获得一个 IP,而机器人 B 获得另一个 IP,而它们是仅有的两个发出请求的客户端,那么您的一个代理的请求速率是另一个的 10 倍。 较低的 TTL 可以减轻此影响,以便 30 秒 TTL 可以平衡两个代理之间的那 110 个请求。 在最初的 30 秒内,用户 A 将转到代理 P1,而机器人 B 将转到代理 P2。 然后,他们的下一个解决方案可能会交换 IP,以便用户 A 将其请求发送到代理 P2,而机器人 B 将其请求发送到代理 P1。 在该分钟窗口结束时,每个代理将处理大约 60 个请求。 TTL 较低的缺点是查找更多,因此 DNS 成本较高(但 DNS 通常是您较便宜的第三方服务之一)。 ### 超出单个清漆节点 虽然 DNS 可以为您增加代理层的时间,但是缩放清漆要复杂一些。 即使您使用单个清漆节点的容量限制围绕请求并发进行,您也不希望简单地在循环中添加两个清漆节点。 这降低了缓存命中率,清除了更多的资源/时间,并且实际上并没有增加缓存的工作量(仅复制它)。 超出单个清漆节点的最简单迭代是 静态分区 。 这涉及确定您的唯一标识符,并在两个清漆节点之间划分此空间。 对于 Tumblelogs,这是博客的主机名。 由于 DNS 不区分大小写,因此您只需要担心 40 个字符即可。 字母数字(a-z 和 0-9)和四个允许的字符(-_。〜)。 因此,对于两个清漆节点,博客主机名在这两个缓存节点之间被分割(在第一个字符上)。 ### 均匀分布的分区-通过一致的哈希 前面的两个示例(DNS 循环和静态分区)都是朝着正确方向迈出的一步,但是在分区方面却提供了非常粗糙的粒度。 在足够小的规模上,这种粒度不一定是有问题的,但是随着您的流量开始增长,方差变得更加明显。 结果,减少最不热和最热节点处理的流量差异变得越来越重要。 这就是一致性哈希真正可以发挥作用的地方。 ### 分区代理流量 如果您的服务器所处的环境可以影响服务器前面的路由器,用户和代理服务器之间的路由器的路由表,那么您可以利用等价的多 -路径路由(ECMP)。 ECMP 使您能够将代理视为同一哈希环中的多个切片,然后在这些切片之间映射请求者。 这是通过通知到特定目标 IP(高可用性 IP)的多个路径(代理服务器)的路由基础结构来实现的。 然后,ECMP 将对请求源进行哈希处理,以确定哪个代理应接收此请求会话的数据包。 典型的 ECMP 实现提供第 3 层(仅 IP)和第 3 + 4 层(IP:端口)哈希选项。 第 3 层意味着来自特定 IP 的所有请求将转到特定的代理,这可能有助于调试,但与使用单个 NAT IP 的大型网络不平衡。 第 3 + 4 层通常提供最佳的分发,但是调试特定的客户端变得更具挑战性。 有多种方法可以 通知 路由器多个路径,但是我建议使用 OSPF 或 iBGP 进行动态路由通告。 一个人只需要在环回接口上侦听高度可用的 IP,启用内部路由以及将自己的 IP 作为下一跃点广告到该高度可用的 IP。 我们发现 BIRD 提供了一种轻巧可靠的方式来执行来自代理的路由广告。 ### 划分清漆流量 Tumblelog 通过其完全限定的域名(FQDN)进行标识,因此,博客的所有 URI 路径将始终在该博客 FQDN 下找到。 Tumblelog 的大部分是 tumblr.com 的子域,例如 [engineering.tumblr.com](http://engineering.tumblr.com/) ,但是我们也支持用户携带自己的自定义域名 。 考虑各种 FQDN 时,很明显,TLD 的变体数量最少,然后是域名(特别是由于绝大多数是 tumblr.com),然后是子域。 因此,我们最重要的位出现在可变长度字符串的最左侧。 ### 了解问题域 ![](https://img.kancloud.cn/c9/7c/c97ca97abc4a7fb1d4db8d83bcc708cc.png) * 完美-演示将散列函数应用于我们的测试数据集时,其散列函数是否为 完美 * constant_hdr-主机标头上的一致性哈希(最佳现实结果) * constant_hdr_use_domain_only-基本域名(即 tumblr.com 或 foo.net)上的一致性哈希,只有两个阵营 tumblr.com 和所有其他域名 * mapbased_firstchar-将主机标头的第一个字符映射到清漆节点(我们的原始静态分区实现) * mapbased_hdr-基于主机标头的映射 虽然一致的散列显然是 tumblelog FQDN 的最平均分布的领先者,但是我们接着确定散列函数是否合适。 默认情况下,HAProxy 使用 SDBM 哈希函数。 但是,在进一步研究后,通过比较 SDBM,CRC,MD5,DJB2 等,我们确定 DJB2 提供了更好的分布。 这导致我们向 HAProxy 提交了补丁,以使哈希函数可配置(有关更多信息,请参见“感谢”部分)。 ### 比较静态分区和一致性哈希 ![](https://img.kancloud.cn/6b/69/6b695dc747e46bb0812d61540286562f.png) 这显示了在移至最佳匹配哈希函数之前和之后,每个清漆节点每秒请求之间的方差变化。 ### 其他注意事项 ### 节点增长 在任一模型中,节点增长将意味着键空间移位,从而导致缓存失效。 在一致的哈希模型中,预测将失效的键的百分比要容易得多。 基本上为 1 / N(N 是添加新节点之前的缓存节点数)。 使用静态分区模型,除非您对要从中获取键空间的节点的请求进行分析,否则最糟糕的情况是小于或等于键上键的总百分比。 您从中获取键空间的节点。 ### 节点故障 使用静态分区时,除非您提供故障转移选项,否则单节点故障将导致无法访问 1 / N 密钥。 HAProxy 确实允许您拥有一个备用节点,但是现在您可以决定了。 每个密钥空间有 2N 个缓存节点(一个活动,一个备用)或共享的备用节点。 一种极端情况是 浪费 占硬件的 50%,其中频谱的另一端(所有活动节点之间共享 1 个备用节点)意味着两个故障节点导致备用 支持其他活动节点的密钥空间的 2 倍。 使用一致的哈希,将自动处理节点故障。 删除一个节点后,将移动 1 / N 个键(导致 1 / N 个键无效),并且每个剩余的活动节点的键空间均匀增加。 ### 正在清除缓存 将清除请求发送到单个清漆节点很容易,但是从多个清漆节点清除也应该很容易。 不必使代理服务器和清除服务器保持同步,最简单的方法是通过同一代理服务器发送所有清除请求。 拒绝来自非本地 IP 空间的清除尝试非常重要,以防止任何恶意的批量清除。 ### 获得的经验教训 * 您知道尚未回答的问题的答案。 面对扩展挑战时,请不要忽视您已经在其他地方使用的模式。 * 通过简单扩展。 在短期内可能会增加复杂性以克服可伸缩性挑战,但最终会赶上您。 * 了解您的哈希函数。 您使用的哈希函数与决定如何处理哈希值同样重要。 * 降级,不失败。 建议您的代理人监视自己达到后端的能力。 如果不能,则不要停止发布路由,而只是发布非优先级路由(例如,使用 OSPF 会增加路径成本)。 这样,如果所有后端都无法正常运行,您仍然可以提供错误页面,而不是无法访问。 ### 谢谢 ## * [Blake Matheny](http://tumblr.mobocracy.net/) 和 [Andrew Terng](http://andrew.tumblr.com/) 进行了散列函数比较并为 HAProxy 创建了补丁。 * [Bhaskar Maddala](http://maddalab.tumblr.com/) 与 HAProxy 社区合作,以获取 [此功能已添加到 HAProxy 1.5 版本](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4.2-hash-type) 。 * [Arnoud Vermeer](http://blog.arnoudvermeer.nl/) 和 [Aaron Prat](http://aaronprat.tumblr.com/) 与 ECMP / OSPF 流量分配有关。 ## 相关文章 [ * [关于 HackerNews](https://news.ycombinator.com/item?id=8132473) * [雅虎以 10 亿美元的价格收购了 Tumblr 架构](http://highscalability.com/blog/2013/5/20/the-tumblr-architecture-yahoo-bought-for-a-cool-billion-doll.html) * [Tumblr Architecture-150 亿页面浏览量一个月,比 Twitter 难扩展](http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html) 对于任何混乱,我们深表歉意,共有 278 位 Tumblr 员工。 负责 Tumblr 所有外围(Perimeter-SRE)的团队由 6 人组成(包括一名经理)。 本文介绍了负责博客服务的外围部分的体系结构,这是我们流量更大的外围端点之一。 对于那些不了解哈希的人来说,它会使您变得 O(1)复杂,并且比对普通 b 树数据库的搜索要快。 令人惊讶的结果,我想这就是您扩展 tumblr 之类的方式的原因:) 非常有趣的文章。 但是有一个问题:您提到 BIRT 是 IP 平衡器,尽管 Haproxy 也是平衡器,但是对于 TCP / HTTP 级别,不是 IP。 那么负载均衡人员到底是谁呢? 感谢您分享这个幕后或“后台”视图。 “ 1.96 亿个博客”数量巨大,接近 1000 亿个帖子表明这些博客已被实际使用,而不是像其他平台那样,通常一旦注册就此后一直处于闲置状态。 从网络工程的角度来看,这非常有趣。 我猜想您的 HAProxy 框上正在运行 BIRD,然后将散列的流量平衡到 Varnish? 是否还可以通过 Varnish 服务器从您的边缘路由器提供网络图? 谢谢!