当前位置:首页 > 科技  > 软件

高度可扩展系统中的性能优化策略

来源: 责编: 时间:2023-12-12 17:02:28 141观看
导读译者 | 刘汪洋审校 | 重楼在现代数字化环境下,单纯构建一个具备基本功能的系统已无法满足更高的应用需求。我们需要开发在高负载环境下能够稳定且高效扩展的系统。众多开发者和架构师的实践证明,系统可扩展性的提升往往

译者 | 刘汪洋Yu228资讯网——每日最新资讯28at.com

审校 | 重楼Yu228资讯网——每日最新资讯28at.com

在现代数字化环境下,单纯构建一个具备基本功能的系统已无法满足更高的应用需求。我们需要开发在高负载环境下能够稳定且高效扩展的系统。Yu228资讯网——每日最新资讯28at.com

Yu228资讯网——每日最新资讯28at.com

众多开发者和架构师的实践证明,系统可扩展性的提升往往伴随着独特的挑战。即使是微小的效率问题,在放大到百万倍的负载下,也可能导致系统陷入瘫痪。那么,怎样才能确保你的应用程序在任何负载下都能快速响应呢?Yu228资讯网——每日最新资讯28at.com

本文将详细介绍构建可扩展系统时的性能优化策略。我们会探讨一些适用于各种代码库的通用策略,无论是前端还是后端,也不论使用何种编程语言。这些策略不仅限于理论层面;它们已在全球一些最具挑战性的技术环境中经过实际应用和验证。作为 Facebook 团队的一员,我亲自参与了将这些优化技术应用于多个项目中,包括 Facebook 的轻量级广告创建体验和 Meta 商务套件。Yu228资讯网——每日最新资讯28at.com

因此,无论你是在打造下一个大型社交网络、企业级软件套件,还是仅仅想要优化个人项目,我们在此讨论的策略都将成为你工具箱中的宝贵资产。现在,让我们开始探索吧。Yu228资讯网——每日最新资讯28at.com

预取

预取是一种基于预测用户行为的性能优化技术。设想用户正在与应用程序交互,系统能够预测用户的下一步操作,并提前获取相关数据。这种方法能够创造一种无缝体验:当数据被需要时,它几乎能够即刻被获取,从而使应用程序显得更加迅速和响应灵敏。主动在需求出现之前获取数据能够显著提升用户体验,但如果过度使用,可能会导致资源浪费,如带宽、内存甚至处理能力的浪费。Facebook 在其需要依赖机器学习的复杂操作中大量使用预取,例如在“好友建议”功能中。Yu228资讯网——每日最新资讯28at.com

何时进行预取?

预取涉及在用户明确表达需求之前,主动向服务器发送请求以检索数据。尽管这看起来很有吸引力,但开发者必须确保在效率和资源使用之间取得平衡。Yu228资讯网——每日最新资讯28at.com

A.优化服务器响应时间(后端代码优化)

在实施预取之前,首先应确保服务器响应时间已经得到优化。后端代码优化可以通过以下方式实现更佳的服务器响应时间:Yu228资讯网——每日最新资讯28at.com

  • 精简数据库查询,以缩短检索时间。
  • 确保复杂操作能够并发执行。
  • 减少重复的 API 调用,避免重复获取相同的数据。
  • 剔除不必要的计算过程,以避免减慢服务器响应。

B.确认用户意图

预取的核心是对用户下一步操作的预测。然而,预测有时可能不准确。如果系统为用户从未访问的页面或功能预获取数据,就会造成资源的浪费。因此,开发者应采用机制来评估用户意图,例如跟踪用户行为模式或检查用户的活跃参与度,以确保数据仅在有高概率被使用的情况下被获取。Yu228资讯网——每日最新资讯28at.com

如何实现预取

预取可以在任何编程语言或框架中实现。以 React 为例,来展示预取的实现方法。Yu228资讯网——每日最新资讯28at.com

考虑一个简单的 React 组件。该组件一旦完成渲染,就会触发一个 AJAX 调用来预先获取数据。当用户点击该组件中的按钮时,第二个组件会使用这些预先获取的数据:Yu228资讯网——每日最新资讯28at.com

import React, { useState, useEffect } from 'react';import axios from 'axios';function PrefetchComponent() {  const [data, setData] = useState(null);  const [showSecondComponent, setShowSecondComponent] = useState(false);  // 组件渲染完成后立即预取数据  useEffect(() => {    axios.get('https://api.example.com/data-to-prefetch')      .then(response => {        setData(response.data);      });  }, []);  return (    <div>    <button onClick={() => setShowSecondComponent(true)}>Show Next Component  </button>{showSecondComponent && <SecondComponent data={data} />}  </div> );}function SecondComponent({ data }) {  // 在这个组件中使用预取的数据  return (    <div>    {data ? <div>Here is the prefetched data: {data}</div> : <div>Loading...</div>}</div>);}export default PrefetchComponent;

在上述代码示例中,PrefetchComponent组件在渲染之后立刻进行数据获取。当用户点击按钮时,SecondComponent组件会展示,使用的是之前预先获取的数据。Yu228资讯网——每日最新资讯28at.com

记忆化

在计算机科学中,“不要重复自己”原则是优秀编码习惯的核心。此原则也是性能优化的有效手段,正是记忆化技术的基础。记忆化建立在这样一个观点上:重复执行某些操作可能会消耗大量资源,尤其是当这些操作的结果不经常发生变化时。那么,为什么要重复执行已经完成的工作呢?Yu228资讯网——每日最新资讯28at.com

记忆化通过缓存计算结果来提升应用程序的性能。当同一计算再次被请求时,系统会先检查结果是否已在缓存中。如果已缓存,就直接从缓存中提取结果,省去了实际计算的步骤。从本质上讲,记忆化涉及到对之前结果的存储(由此得名)。这对于计算成本高且经常被同样的输入调用的函数来说尤为有效。这就好比一个学生解决了一个复杂的数学问题,并在书的边缘记下了答案。如果未来的考试中出现了同样的问题,学生可以简单地查看书边的笔记,而不必重新解决这个问题。Yu228资讯网——每日最新资讯28at.com

何时使用记忆化?

记忆化并非适用于所有情况。在某些场景下,记忆化可能会导致更多的内存消耗。因此,正确识别何时使用这种技术至关重要:Yu228资讯网——每日最新资讯28at.com

  • 数据变化不频繁时: 对于那些输入一致时返回结果也一致的函数,尤其是计算密集型的函数,使用记忆化是理想选择。这确保了在随后相同的调用中不会浪费一次计算的努力。
  • 数据不太敏感时: 在考虑使用记忆化时,安全性和隐私问题也是不可忽视的重要因素。虽然缓存所有内容看似诱人,但并不总是安全的。例如,支付信息、密码及其他个人详细信息这类数据永远不应缓存。然而,像社交媒体帖子的点赞数和评论数这类较为无害的数据,可以安全地进行记忆化以提升性能。

如何实现记忆化

在 React 中,我们可以利用 useCallback 和useMemo等钩子来实现记忆化。让我们来看一个简单的例子:Yu228资讯网——每日最新资讯28at.com

import React, { useState, useCallback, useMemo } from 'react';function ExpensiveOperationComponent() {    const [input, setInput] = useState(0);    const [count, setCount] = useState(0);    // 模拟一个计算开销很大的操作    const expensiveOperation = useCallback((num) => {        console.log('Computing...');        // 模拟耗时长的计算        for(let i = 0; i < 1000000000; i++) {}        return num * num;    }, []);    const memoizedResult = useMemo(() => expensiveOperation(input), [input, expensiveOperation]);    return (        <div>            <input value={input} onChange={e => setInput(e.target.value)} />            <p>Result of Expensive Operation: {memoizedResult}</p>            <button onClick={() => setCount(count + 1)}>Re-render component</button>            <p>Component re-render count: {count}</p>        </div>    );}export default ExpensiveOperationComponent;

在这个示例中,expensiveOperation函数模拟了一个计算密集型任务。我们使用useCallback钩子来确保在每次组件渲染时,这个函数不会被重新定义。此外,useMemo钩子被用来存储expensiveOperation的结果,这样,即使组件重新渲染,如果输入没有变化,就不会重复执行这个计算。Yu228资讯网——每日最新资讯28at.com

并行获取

并行数据获取是指同时获取多个数据集,而非逐个获取。这就好比在超市结账时,有多个收银员同时服务,而不仅仅是一个:顾客能更快得到服务,排队时间缩短,整体效率得到提升。在数据处理领域,鉴于很多数据集之间互不相关,因此并行获取能显著加快页面加载速度,尤其适用于检索复杂数据所需时间较长的场景。Yu228资讯网——每日最新资讯28at.com

何时使用并行获取?

  • 当各数据集独立且获取过程复杂时: 若所需获取的数据集之间无依赖关系,并且检索每个数据集耗时较长,此时并行获取能有效提高处理速度。
  • 后端应用广泛,前端使用需谨慎: 尽管在后端,通过提升服务器响应速度,并行获取能发挥显著效果,但在前端使用时需格外小心。过多的并行请求可能会加重客户端负载,影响用户体验。
  • 优先处理网络请求: 若数据获取涉及多个网络请求,最佳做法是优先处理一个主要请求,并在前端展示,同时在后台并行处理其他请求。这样做可确保最重要的数据首先被获取,同时其他次要数据也在后台并行地进行加载。

如何使用并行获取

在 PHP 中,随着现代扩展和工具的发展,实现并行处理变得更为简便。以下是一个使用concurrent {}代码块的基本示例:Yu228资讯网——每日最新资讯28at.com

<?phpuse Concurrent/TaskScheduler;require 'vendor/autoload.php';// 假设这些是一些从各种来源获取数据的函数function fetchDataA() {    // 模拟延迟    sleep(2);    return "Data A";}function fetchDataB() {    // 模拟延迟    sleep(3);    return "Data B";}$scheduler = new TaskScheduler();$result = concurrent {    "a" => fetchDataA(),    "b" => fetchDataB(),};echo $result["a"];  // Outputs: Data Aecho $result["b"];  // Outputs: Data B?>

在此示例中,fetchDataA 和 fetchDataB 分别代表两个数据检索函数。通过运用concurrent {}代码块,这两个函数可同时执行,从而缩短了获取这两个数据集的总耗时。Yu228资讯网——每日最新资讯28at.com

延迟加载

延迟加载是一种设计模式,其核心思想是仅在真正需要时才加载数据或资源。与预先加载所有内容不同,延迟加载只载入初始视图所需的必要内容,随后根据需求加载额外资源。这类似于一家餐厅仅在顾客点特定菜品时才开始烹饪,而非预先准备所有菜肴。例如,在网页中,模态框的数据只有在用户点击按钮打开模态框时才被加载。通过这种方式,可以将数据的获取推迟到实际需要的时刻。Yu228资讯网——每日最新资讯28at.com

如何实现延迟加载

有效实现延迟加载的关键在于,要确保在数据获取过程中向用户提供清晰的反馈,以优化用户体验。常见的做法是在数据检索时展示一个旋转的加载动画,这样用户就能明白他们的请求正在被处理,即便数据暂时还不可用。Yu228资讯网——每日最新资讯28at.com

React 中的延迟加载示例

以下是一个 React 组件中实现延迟加载的示例。此组件只在用户点击按钮以查看模态框内容时获取数据:Yu228资讯网——每日最新资讯28at.com

import React, { useState } from 'react';function LazyLoadedModal() {    const [data, setData] = useState(null);    const [isLoading, setIsLoading] = useState(false);    const [isModalOpen, setIsModalOpen] = useState(false);    const fetchDataForModal = async () => {        setIsLoading(true);                // 模拟一次 AJAX 获取数据的调用        const response = await fetch('https://api.example.com/data');        const result = await response.json();        setData(result);        setIsLoading(false);        setIsModalOpen(true);    };    return (        <div>            <button onClick={fetchDataForModal}>                Open Modal            </button>            {isModalOpen && (                <div className="modal">                    {isLoading ? (                        <p>Loading...</p>  // 这里可以使用旋转圈或加载动画                    ) : (                        <p>{data}</p>                    )}                </div>            )}        </div>    );}export default LazyLoadedModal;

在这个例子中,只有当用户点击“打开模态框”按钮后,才会开始获取模态框的数据。在此之前,不会发起不必要的网络请求。一旦开始获取数据,便会显示加载信息(或旋转器),以示用户请求正在处理。Yu228资讯网——每日最新资讯28at.com

结论

在当今快速的数字时代,响应时间的每一毫秒都十分重要。用户寻求快速响应,而企业无法承受让用户等待的后果。性能优化已成为提供优质数字体验的必要条件,而不仅仅是一种优化。Yu228资讯网——每日最新资讯28at.com

通过预取、记忆化、并行获取和延迟加载等技术,开发者能有效提升应用性能。虽然这些策略在应用和方法上有所不同,但它们共同的目标是确保应用程序能够尽可能高效和快速地运行。Yu228资讯网——每日最新资讯28at.com

重要的一点是,不存在一劳永逸的解决方案或“银弹”。每个应用程序都有其独特之处,性能优化应结合对应用程序需求的深入理解、对用户期望的认识,以及正确技术的有效应用。这是一个持续改进和学习的过程。Yu228资讯网——每日最新资讯28at.com

译者介绍

刘汪洋,51CTO社区编辑,昵称:明明如月,一个拥有 5 年开发经验的某大厂高级 Java 工程师,拥有多个主流技术博客平台博客专家称号。Yu228资讯网——每日最新资讯28at.com

原文标题:Performance Optimization Strategies in Highly Scalable Systems,作者:Hemanth MuraliYu228资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-43323-0.html高度可扩展系统中的性能优化策略

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 深入了解Java的GC原理,掌握JVM 性能调优!

下一篇: JS小知识,分享一些让我迷惑的前端面试题

标签:
  • 热门焦点
Top