Web应用程序服务器优化课程



哈Ha! 我叫Alexey Pristavko,我是DataLine网站项目总监。 我今天的文章是关于如何解决或防止Web应用程序后端性能问题的。

这将集中于如何优化遭受可伸缩性,性能或可靠性等长期问题困扰的Web应用程序。
任何有兴趣的人-欢迎大家切入!

术语学


让我们从术语开始。 说到Web项目或Web系统的性能,我主要指的是后端和服务器组件。 在浏览器中加载页面时发生的事情是完全不同的故事,很可能将专门撰写单独的文章。

  • 应用程序性能的度量标准每秒处理的请求数(RPS)及其执行速度(TTFB-到第一个字节的时间)。
  • 因此,通过系统可伸缩性,我们意味着增加RPS的机会池。

现在关于可靠性。 这里有必要分开两个概念:容错和灾难容忍。

  • 故障恢复能力 -如果一台或多台服务器无法在所需参数范围内继续工作,则系统发生故障的能力。
  • 具有完全备份冗余(所谓的第二级)并且能够在没有数据中心之一的情况下完全失效的情况下工作的系统被认为是抗灾难的

同时,容灾系统是故障安全系统。 容灾但不容错的系统仅在一个“肩膀”上继续工作的情况是很正常的。 但是,如果其中一台服务器发生故障,则系统也会发生故障。

现在我们已经弄清了关键概念并更新了当前的术语,是时候直接进入优化和生活技巧的基础了。

从哪里开始优化




如何理解从哪里开始优化? 在急于优化之前,请深呼吸并花时间研究该应用程序。

确保绘制详细的图表。 在其上显示应用程序的所有组件及其关系。 检查完此方案后,您可以发现以前不明显的漏洞和潜在的故障点。



“什么? 在哪 什么时候? -优化查询


要特别注意同步请求。 让我提醒您,当我们在同一线程中发送请求并等待响应时,这些请求就是这样的。 这是当另一侧发生问题时严重刹车的原因所在。 因此,如果您可以减少同步请求的数量或将它们替换为异步请求,请执行此操作。

以下是一些技巧,可帮助您跟踪请求:

  • 为每个传入请求分配一个唯一的标识符。 Nginx有一个内置变量$ request_id。 将标识符传递到后端的标头中,然后写入所有日志。 因此,您可以方便地跟踪请求。
  • 将请求的结束不仅记录到外部组件,还要记录它的开始。 因此,您可以测量外部呼叫的实际持续时间。 例如,由于网络问题或DNS制动,它可能与您在远程系统上看到的有很大不同。

因此,收集了数据。 现在让我们分析问题点。 定义:

  • 最多的时间在哪里?
  • 最多的请求来自哪里?
  • 最长的请求来自哪里?

结果,您将获得系统中最有趣的部分以进行优化的列表。

提示:如果有一点“收集”了很多小查询,请尝试将它们组合成一个大查询以减少开销。 长查询的结果通常在缓存中有意义。

我们明智地缓存


优化时,应遵循一些一般的缓存规则:

  • 缓存离使用者越近,作业越快。 对于应用程序,“最近”的位置将是RAM。 对于用户,他的浏览器。
  • 高速缓存可加快数据获取速度并减少源上的负载。

如果十台Web服务器进行相同的数据库查询,则集中式中间缓存(例如Redis中的缓存)将提供更高的命中百分比(与本地缓存相比),并减少数据库的总体负载,这将显着改善整体状况。

提示1:使用Edge Side Includes在Nginx一侧完成页面的组件缓存。 它非常适合微服务/ SOA体系结构,并减轻了整个系统的负担,从而大大提高了响应速度。

技巧2:跟踪高速缓存中对象的大小,命中率以及写入/读取卷。 对象越大,处理时间就越长。 如果您写入缓存的次数比读取的次数多或比读取的次数多,那么这样的缓存不是您的朋友。 值得删除或考虑提高其有效性。

提示3:尽可能使用自己的数据库缓存。 正确的配置可以加快工作速度。

负载曲线


我们传递给负载配置文件。 如您所知,主要有两种类型:OLAP和OLTP。

  • 对于OLAP (在线分析处理),每秒花费的流量非常重要。
  • 对于OLTP (在线事务处理),关键指标是响应速度,毫秒计时。

通常,将这两种类型的负载分开是有效的。 至少,您将需要对数据库以及系统的其他组件进行单独的调整。

提示:通常使用OLAP类型处理来自管理面板的读取请求。 为该任务创建数据库和Web服务器的单独副本,以卸载主系统。

资料库




因此,我们自然而然地进入了最困难的优化阶段之一,即数据库优化。

让我提醒您一个一般规则:数据库越小,它的运行速度越快。 在提高速度方面,数据库的组织至关重要。

如果可能,将历史数据 ,应用程序日志和常用数据存储在不同的数据库中。 更好的是,将它们发布在不同的服务器上。 这不仅会延长主数据库的寿命,而且还会提供更多空间来进行进一步优化,例如,在某些情况下,它将允许对不同的负载使用不同的索引。 同样,负载的“均匀性”简化了数据库服务器的调度程序和查询优化程序的寿命。

再说一次规划的重要性


为了避免在真正不需要优化的地方感到困惑,请根据任务选择硬件。

  • 对于少量但频繁的请求,最好采用更多处理器内核。
  • 对于繁重的请求-更少的内核和更高的时钟速度。

尝试将数据库的工作量放入RAM。 如果这不可能或有大量写请求,那么该考虑将数据库转移到SSD上了。 它们将大大提高磁盘的处理速度。

缩放比例




上面,我描述了在不增加物理资源的情况下提高应用程序性能的关键机制。

现在,我们将讨论如何选择扩展策略并提高弹性。

有两种类型的系统扩展:

  • 纵向 -资源的增长,同时保持实体的数量;
  • 水平 -实体数量增加。

长高


让我们从选择垂直扩展策略开始。

首先,考虑增加系统功率 。 如果您的系统在一台服务器上运行,则必须在增加当前服务器的容量或购买另一台服务器之间做出选择。

第一种选择似乎更简单,更安全。 但是,如果再购买一台服务器并获得较大的容错能力以提高生产力,那将是更具远见的。 我在文章开头谈到了这一点。

如果您的系统有多台服务器,并且选择增加现有服务器的容量或购买更多服务器,请注意财务方面。 例如,一台功能强大的服务器可能比两台50%的“更弱”服务器昂贵。 因此,合理地考虑第二个折衷方案。 同时,在拥有大量服务器的情况下,性能,功耗和全机架成本的比率至关重要。

长大


水平缩放是有关容错和群集的故事。 通常,我们拥有一个实体的实例越多,整个解决方案的容错性就越高。

您想扩展的第一件事可能是应用程序服务器 。 这样做的第一个障碍是使用集中式数据源进行工作的组织。 除了数据库,它也是会话数据和静态内容。 这是我建议您执行的操作:

  • 要存储会话,请使用Couchbase,而不是通常的Memcached,因为它使用相同的协议,但是与memcached不同,它支持群集。
  • 所有静态变量 (尤其是大量图像和文档)都单独存储并使用Nginx提供服务,而不是从应用程序代码中获取。 这将为您节省流量成本并简化基础架构管理。

“收集”数据库


难以扩展数据库。 有两种主要的技术:分片和复制。 考虑他们。

复制过程中,我们将完全相同的数据库副本添加到系统中,同时分片 ,逻辑上分开的部分,分片。 同时,非常希望与每个分片的复制(复制)并行进行分片,以免失去容错能力。

请记住:数据库集群通常由一个接管写入流的主节点和几个用于读取的从属节点组成。 从容错的角度来看,这比单个服务器要好一些,因为整体的容错能力是由系统中最不稳定的元素决定的。

如果在没有确认每个服务器上的记录的情况下,具有两个以上数据库向导(环形拓扑)的方案经常会出现不一致的情况。 如果其中一台服务器发生故障,将很难恢复群集中数据的逻辑完整性。

提示:如果您不希望拥有多个主服务器,请考虑在没有主服务器的情况下至少一个小时运行系统的体系结构。 万一发生事故,这将使您有时间更换服务器,而不会导致整个系统停机。

提示:如果需要保留两个以上的数据库主数据库,建议您考虑使用NoSQL解决方案,因为其中许多解决方案都具有内置机制,可将数据置于一致状态。

在追求容错能力的过程中,请不要忘记复制只能确保您不会遭受物理服务器故障 。 由于用户错误,它不会保存在逻辑数据损坏中。

切记:任何重要数据都必须备份并存储为独立的,不可编辑的副本。

而不是结论


最后,一些备份性能提示:

提示1:从单独的数据库副本中提取数据,这样就不会使活动服务器超载。

提示2:手头上还有一个额外的,稍微滞后的数据库时间副本。 万一发生事故,这将有助于减少数据丢失量。

在不分析当前情况并了解您想要实现的目标之前,切勿盲目使用本文介绍的方法和技术。 您可能会遇到“过度优化”,结果系统的速度只会提高10%,而容易受到事故的影响则要高50%。

仅此而已。 如果您有任何疑问,我将很乐意在评论中回答。

Source: https://habr.com/ru/post/zh-CN414515/


All Articles