云浮建设网站,长春网站排名推广,网站设计公司 国际,保定网站建设方案当您启动初始服务时#xff0c;通常会过度设计以考虑大量流量。但是#xff0c;当您的服务达到爆炸式增长阶段#xff0c;或者如果您的服务请求和处理大量流量时#xff0c;您将需要重新考虑您的架构以适应它。糟糕的系统设计导致难以扩展或无法满足处理大量流量的需求通常会过度设计以考虑大量流量。但是当您的服务达到爆炸式增长阶段或者如果您的服务请求和处理大量流量时您将需要重新考虑您的架构以适应它。糟糕的系统设计导致难以扩展或无法满足处理大量流量的需求可能会导致糟糕的用户体验甚至服务失败。 缓存在处理大量流量的服务中起着重要作用因为它可以快速将数据传递给用户。然而缺乏可扩展性这在早期服务中很容易被忽略如果缓存需要增加容量或进行物理移动可能会导致重大服务失败。 系统架构中的缓存 我在一家拥有大量流量的全球信使公司担任核心团队成员六年有很多机会思考这样的可扩展性。在本文中我将分享在我需要物理移动缓存并增加其容量的类似情况下如何可靠地迁移和改进缓存而不影响服务。 大规模消息服务中的缓存 消息服务中的常见流程 由于 Messenger 的全球性数据从许多国家/地区以各种形式传输包括文本、图像、视频、音频和二进制文件。如果你想分解这个过程它是这样的。 上游数据下游数据交货数据 在大规模服务中缓存请求/响应流 如果缓存每次在数据下游都检查数据源所在的存储那么数据的传递速度会很慢用户体验会很差。因此缓存检查并在数据下游传递用户数据因为为了用户体验必须快速传递数据。 系统架构可能会因各项服务的特殊因素而有所不同例如数据的性质和用户的服务模式。因此即使对于相同的服务设计也会根据流量的大小而有所不同因此灵活的设计很重要。我运行的平台是一个高流量服务所以我根据用户的服务使用模式不同地应用了缓存。 根据用户对服务的使用情况访问不同的数据 从数据利用的角度来看用户如何使用您的服务存在三种一般模式。 用户在上传数据后立即访问他们的数据。用户上传数据后他们不会立即访问数据但会频繁访问。用户上传数据后他们立即访问数据的频率就会降低。 如果一个缓存同样适用于所有这些情况它将会是低效和昂贵的这不是一个好的系统设计。根据用户的模式缓存应该足够灵活以应用于相同的服务。 在大规模服务中缓存请求/响应流 认识到上述情况可以按如下方式应用缓存。 对于可立即访问的数据在上游时将其推送到缓存中并使其在之后立即被命中。对于不能立即访问的数据如果尚未命中则在下载时将其从缓存中拉出。 当然在第二种情况下您可能会发现自己在第一次下载时访问存储这是按需的不会立即访问缓存。但是如果此后数据被频繁访问它会不断地命中缓存这将减少存储 I/O从而显着降低成本。 技术总是与Trade-off一起应用因此从架构师的角度来看它们是为成本、可靠性和用户体验而设计的。 缓存迁移 在实时产生大量流量的消息服务中缓存起着非常重要的作用。在这种情况下缓存服务器老化需要增加容量。为此我们首先需要整理现有设计中存在的问题并定义需要改进的功能。 软件设计问题 旧设计的问题是双重的。 具有难以缩放结构的哈希算法 首先现有哈希服务器的哈希算法是一种基于特定标识符以服务器数量为分母进行划分和哈希的结构如果哈希服务器数量发生变化则现有缓存的访问方式也会发生变化并且所有数据的命中率大幅下降。 因此需要重新定义缓存服务器的哈希算法来扩展缓存服务器的容量。 在役期间难以管理哈希服务器 第二个问题是缓存服务器不能实时自主控制即在服务中途如果缓存服务器发生变化或故障无需重启后端应用程序。 这两个问题的关键共同问题是缺乏可扩展性因此我们着手通过将可扩展性作为我们的首要任务以及实现它的操作来改进它们。 一致性哈希 为什么要使用一致性哈希 哈希算法有很多算法方法视情况而定。但是为了解决上述问题我们需要优先考虑可扩展性因此我们决定引入一种一致性哈希算法即使在扩展时也可以被同一节点访问。 那么什么是一致性哈希以及它的好处是什么 概念 一致性哈希概念 在分布式系统中Consistent Hashing 有助于解决以下场景。 为缓存服务器提供弹性伸缩。扩展一组服务器节点例如 NoSQL 数据库或缓存。 一致性哈希算法 我们的目标是设计一个缓存系统。 能够在一组“n”个缓存服务器上均匀分布请求的散列键。我们必须能够动态地添加或删除缓存服务器。添加或删除缓存服务器时需要在服务器之间进行最少的数据移动。 Consistent Hashing 可以解决水平可扩展性问题无需在每次向上或向下扩展时重新排列所有键或操作所有缓存服务器。 怎么运行的 一致性哈希的工作原理 创建散列键空间假设您有一个散列函数它生成范围 [0, ²³²-1] 内的整数散列值。我们将哈希空间表示为哈希环并假设在步骤 1 中生成的整数被放置在一个环中以便封闭最后一个值。我们会在密钥空间(Hash Ring)中放置一批缓存服务器并使用哈希函数将每个缓存服务器映射到环中的特定位置。例如如果您有四台服务器您可以使用散列函数来使用它们的 IP 地址的散列将它们映射到不同的整数。这决定了服务器的关键位置。在哈希环中添加或删除服务器时您无需操作缓存服务器。 它如何在生产环境中工作 生产环境中的一致性哈希 假设您已经在特定哈希环中部署了哈希密钥和服务器。 当系统触发哈希键时它将尝试在分配给它的最近服务器上查找数据。这种旋转或放置可以根据系统设计进行调整。这些缓存服务器中的每一个在系统设计中都被称为一个“节点”这里分别表示为A、B、C、D。它们按顺时针方向排列后面是密钥。 现在当系统收到有关“Cairo, Eygpt”的数据请求时它会首先在相应的节点(即“A”)中查找该信息。类似地对于键“英国伦敦和日本东京”最接近的相应位置或节点是顺时针方向的“D”因此它将与该特定节点交互以检索数据。 与传统的哈希不同当系统遇到服务器故障、添加或移除时请求或数据密钥会自动连接或分配到最近的服务器或节点。 在服务器出现问题或问题的情况下传统的散列方法不足以使用和处理网络上的请求。假设有固定数量的服务器并且密钥到服务器的映射是同时发生的。 添加服务器需要为新服务器重新映射和散列对象以及大量计算。另一方面一致性哈希中节点的非线性放置允许节点在系统发生变化时相互交互。 然而有时 Hash Ring 中所有节点的分布或负载不相等或不成比例从而导致分布不平衡。让我们仔细看看 Consistent Hashing 系统如何响应添加或删除服务器/节点的情况以及它如何确保系统不会变得不平衡。 热点 承载分布不均的数据请求负载的节点成为热点。为了解决这个问题系统工程师可以使用虚拟节点来启用哈希环将请求平均分配给所有活动节点。 在一致性哈希中添加和删除服务器 在一致性哈希中添加和删除服务器 当您将新节点添加到环中时例如在“Srushtoka Freddie”键之间。最初如上图所示处理两个键。现在在新服务器之后“Freddie”密钥的哈希或分配将被分配或映射到而不是。但是“Srushtika”键分配仍将映射到 . 在从环中删除现有服务器的情况下遵循相同的原则。因此哈希环可确保在添加或删除服务器或节点出现故障的情况下不影响整个过程。此外如果出现重新分配的情况与传统的散列机制相比它不会花费太多时间。 注意事项和好处 您有一个缓存服务器集群需要能够根据流量负载进行弹性扩展或缩减。例如一个常见的情况是在圣诞节或新年期间添加更多服务器以处理额外的流量。因此你需要有一套可以根据流量负载弹性伸缩的缓存服务器。 这就是一致性哈希在这种情况下大放异彩的地方在这种情况下您正在运行一个弹性缓存集群。让我们总结一下这样做的好处。 数据库或缓存服务器集群的弹性扩展更容易在服务器之间复制或分区数据分区数据允许均匀分布以减少热点启用系统范围的高可用性 可扩展的软件设计 随着哈希算法更改为一致性哈希您拥有易于扩展的现成缓存服务器形式但您需要做一些额外的准备以使用一组现成的缓存服务器替换或添加到现有的缓存集群。 要在不中断服务的情况下迁移缓存服务器并对现有集群进行更改您需要确保后端应用程序支持热重载这意味着它们可以在不重新启动服务的情况下读取和反映设置。如果您的服务基于大量流量您需要格外小心以确保它已准备好并能够处理此任务。 准备迁移 首先我们做了很多配置减法以便在不中断服务的情况下从后端应用程序添加或删除更改的缓存服务器。这个过程应该只针对应该由配置控制的信息并且这样做的原因应该是清楚和明确的。 迁移场景 上述设置完成后我们一路将场景分为成功的场景和失败的场景准备相应的应对。 大规模服务的成功缓存迁移场景 成功案例 根据地域等因素依次迁移各族缓存服务器。数据迁移到新配置的缓存集群完成新缓存集群的命中率接近100%。减少对现有缓存集群的请求命中率接近0%。在不重启服务的情况下使用设置移除旧的缓存集群所有数据请求现在都将由新配置的缓存集群传送。 大规模服务缓存迁移失败场景 故障场景 每个缓存服务器集群根据特定因素(例如区域)依次迁移。当数据迁移到新配置的缓存集群时它会与现有数据哈希混合导致数据中断。删除所有新的缓存集群并将请求回滚到仅现有的缓存集群。现有后端应用程序服务器或存储 I/O 由于使用率高而出现死锁。监控系统资源观察情况并比以前多添加 20-50% 的后端应用程序服务器。通过断路器临时限制一些请求以适应存储 I/O。系统稳定后执行分析以确定原因。 我们首先考虑了可行的方案和可能失败的方案并与我们自己和我们的团队成员一起审查它们以确保我们不会错过任何任务或案例。如果场景可行我们会列出我们需要的功能并一一实现。 迭代测试 如果您直接跳入缓存迁移而不测试依赖大量流量的服务那么它顺利进行的可能性非常低。即使你准备了很多场景和响应工程师也无法预料到每一种情况人总是会犯错误所以即使是小问题也很可能发生。 大规模服务中的迭代测试 因此在我开始在生产环境中迁移缓存之前我将测试分为两部分。 在开发环境中运行小型模拟以进行测试。在生产中请求最少的服务器集群上运行多个 Canary 测试。 对于以上两个测试我们设置了与生产环境相同的监控和告警系统。 开发环境中的仿真 我们在开发环境做小规模模拟的时候会根据mock数据产生流量让我们承受小规模的高流量也就是压力测试。但是这种模拟的缺点是无法测试与实际生产环境相同。 生产环境中的金丝雀测试 金丝雀测试 开发环境测试没有覆盖的是mock数据流量不是真实用户流量所以没有考虑生产环境缓存迁移时用户的时间events当时天气和其他背景因素。我们认为这些测试很难在开发环境中覆盖所以我们想通过在生产环境中运行多个金丝雀测试来弥补。 但是由于金丝雀测试是在生产环境中进行的会影响到服务所以我们选择了请求量最少的区域的一组服务器在请求量最少的时候进行测试。 迁移 我们把缓存迁移成功和失败的所有场景都写了出来为它们开发了特性并在小范围内测试了几次所以我们认为如果不出什么大事迁移就会顺利进行。事实上一旦我们在生产中这样做从旧缓存集群迁移到新缓存集群大约需要一个月的时间。花费这么长时间的原因是因为有一些流量可能是从各种客户端或遗留客户端代码遗留下来的。 由于新的缓存集群已经到位我们能够在正确的时间移除旧的缓存集群因为我们一直在监控和密切管理警报。另外为了通过缓存迁移保持稳定的服务我们着眼于降低失败率而不是以成功为目标因此我们有灵活的应对失败场景的计划。最终这个过程让我们在长达一个月的时间内顺利完成了缓存迁移没有出现任何问题。 结论 在本文中我们讨论了缓存对依赖大量流量的服务的影响这些服务设计中的可扩展性差距会导致什么以及我们在尝试扩展缓存时遇到的问题以及我们如何解决他们。 总的来说这些变化对于依赖大量流量的服务来说可能是非常沉重的负担所以你应该经常质疑自己的想法是否有错误。此外我们并没有仅仅实现缓存迁移的短期目标而是考虑了很多关于“我们可以用当前系统做出回应吗”的问题。或“我们可以扩展吗” 当将来出现类似的需求时。如果我们有缓存迁移的短期目标我们会简单地根据现有的哈希算法增加服务器的数量。 当您考虑大型服务的架构时您可能会遇到许多需要权衡取舍的情况。在这些情况下提前计划并着眼于减少可能会失败以实现目标的场景的数量而不是试图实现零碎的目标这可能是解决问题的有效方法。