当我们谈高性能时,我们谈些什么?

简介: 网站越快,用户忠诚度更高; 网站越快,用户转化率越高。 简言之,速度是关键。 ——《Web 性能权威指南》 显然,高性能意味着“快”。但对快的定义,在不同的系统中,标准是不一样的。为了获得快的体验,通常我们需要平衡成本和收益等方面制定优化方法。
网站越快,用户忠诚度更高;

网站越快,用户转化率越高。

简言之,速度是关键。

——《Web 性能权威指南》

显然,高性能意味着“快”。但对快的定义,在不同的系统中,标准是不一样的。为了获得快的体验,通常我们需要平衡成本和收益等方面制定优化方法。

如果说“快”的标准不好把握的话,但我们都对类似这样的典型论述有一致的结论,比如:

内存是快的

U 盘是慢的

之所以对这些问题容易有统一的认知,是因为我们已经对需要度量的范围与标准有了较清晰的概念,我们不自觉地预设一些应该受到控制的变量,并将它们与其他某些事物做了对比。比如,在谈 U 盘慢时,往往指的是在同一台计算机上与硬盘、内存等其他存储方法作比较。

类似地,当我们谈论应用的性能时,也需要把应用所在的环境、处理的数据量等情况一同纳入考虑范围内。这些因素常常让速度的定义变得复杂。因此,在谈论高性能之前,我们首先需要对性能进行建模,确定合适的用于反映性能状况的指标,并据此制定明确在各项因素在各种情况下的性能目标。比如,在谈论 Web 应用程序的速度时,我们经常谈到 QPS、TPS 和响应时间等指标,而确定性能目标时,则往往要考虑数据量的多少、并发用户数目和网络带宽等情况。

在性能建模时,越细致、越全面的数据就越真实地反映出系统的状况,从而能为做出正确的决策提供更准确的依据。一般来说,网络、磁盘等 IO 设备、操作系统,以及应用程序运行时(如 CLR、JVM)往往都提供了丰富的性能数据。对于 Web 和云原生系统而言,设计良好的服务端框架(如 Kubernetes),以及对开发人员友好的浏览器(如 Chrome)等也都会提供相关的性能接口。

举例来说,如果考虑一个桌面应用程序,我们需要收集的指标有:

第一个界面出现的时间

第一个界面加载完毕的时间

某些典型事务处理时间

关闭窗口时的等待时间

从开始加载文件到能够编辑文件的时间

在制定性能目标时,我们要选用一些典型的用户机型进行模拟。在收集测试数据时,摆在面前的第一个问题是如何准确获得这么多种类时间?靠人肉掐秒表也是一种思路,不过还是显得太原始了一些。这时,我们需要在应用中添加一些性能埋点,并利用统一的工具收集这些数据(如操作系统提供的性能计数器)。

下面是利用 Windows 性能工具来查看 IO 操作在物理磁盘上执行的情况:

这些性能数据不但能够在制定科学的性能目标时提供帮助,更能够在系统的性能未达预期时,在第一时间展示出系统瓶颈所在。一段时间以来,当网站慢时,我总是能够通过 Chrome 开发人员工具提供的网络时间线和性能分析工具快速地发现问题所在,并且运用《高性能网站建设指南》等经典书籍中给出的切实的建议针对性地做出优化。

下面是一个 Chrome 浏览器中加载资源时的资源瀑布图:

有人说,所发现了问题时,就是解决了一半,对于一些容易解决的问题尤其如此。不过,一般来说,性能问题往往没那么容易解决——除非是程序的实现有明显的瑕疵(比如陷入了死循环)。相比于逻辑错误问题,解决性能问题一般需要具有一定经验的工程师才能胜任。

在优化应用程序的性能时,一般会由根据距离应用的远近,从外部到内部将优化分为这三个层次:

链路上的优化

结构性优化

应用内优化

链路上的优化指的是在用户操作发出之后、真正到达应用程序逻辑执行之前的过程期间执行的优化;结构性优化指的是对应用程序所处的环境、依赖的资源,以及应用本身的子系统间的关系等方面的优化;而应用内优化则指的是对应用内的实现方式(比如算法和数据结构)进行优化。

举例来说,下图是一个简单的 Web 系统的结构,用户的操作指令发出之后,需要经过互联网到达负载均衡服务器,最后到达两台应用服务器中执行运算逻辑,而应用依赖了读写分离的两个数据库。

在上述三种层次上,对系统的性能进行优化时,可以考虑以下措施:

(链路上)使用 DNS prefetch 技术减少域名查找时间

(链路上)增加负载均衡服务器的出口带宽

(结构性)增加一个新的应用服务器

(结构性)在应用服务器增加 CPU 核心数和内存

(应用内)用多线程技术把操作数据库和访问磁盘的操作同步进行

(应用内)消除应用加载数据时的 n+1 问题

一般来说,链路上和结构性方面的优化,对于使用各类编程平台实现的应用程序都一样适用。对于一个 Web 系统来说,HTTP 请求到达 Web 应用之前的所有优化,都属于这两类。时下,关于大流量、大并发系统的性能优化方法,人们已经讨论的很多了。不过,纵观那些优化方法,实际上也都可以从应用内的优化方法上看到类似的方法,可以认为这些优化思想大体是相通的。

从应用内部优化时,业务专家可以通过一些业务流程上的简化等方法来有效地改善应用程序的性能,例如,在某些情形下省略一些不必要的运算等。这类优化主要取决于业务规则的自身特点,难以统一地归纳出具体的经验。而在业务之外的优化方法,各种应用程序之间却是相通的。

通常,在应用内,要在业务流程之外进行性能优化,我们考虑以下方法:

并发与并行 也就是让程序同时做多件事,以及将一件事分为多个小块同时完成。 将按顺序执行(串行)的多个任务改为并行之后,处理时间从多个任务之和变成了多个任务中最慢的任务的时间。计算机系统中某个层次(如应用程序)的并行能力是由它的底层(如操作系统)的并发能力提供支持的。既然多核计算机早已普及,那么就没有理由不好好利用并行处理能力了。

异步 在计算机系统中,运算往往要比输入输出(IO)操作快得多,不少看起来很慢的系统经常是在空置地等待完成 IO 操作。异步化 IO 操作能让计算机不再等待 IO 完成,从而能最大化地利用系统的运算能力。

缓存 不论是运算,还是 IO 操作都是要耗费时间的。“利用空间换时间”经常是有效的优化方法:典型地,在运算斐波那契数列时,如果不是有通项公式,在不用缓存的情况下几乎不可能写出符合时间要求的算法。

精减与压缩 还是 IO 的问题。如果 IO 慢,就更不能让它执行不必要的操作了——比如多执行的 SQL、多加载的 JavaScript 文件等。经常,当数据量少了之后,由于需要处理的内容少了,还同时能够节省运算的时间。

技巧性优化 上面所述的几种方式,是在代码级别的“通用”方法。而面对具体的问题,经常会有一些技巧性优化方法。比如,采用更具针对性的数据结构,或已经证实更高效的算法,更利于运行时进行垃圾回收的代码风格等。

在上述这些方面的优化,在不同类型的应用程序里,有具体的表现形式;而在不同编程平台上,又可能有不同的实现。举例来说,在 Web 前端应用里,异步可表现为异步加载 JavaScript/CSS 文件和异步执行 Ajax;而在一个 Web 后端应用里,异步则表现为对文件、网络等操作的异步执行。如果具体到编程语言,Node.js 应用可能使用一个 nextTick 操作,而一个 ASP.NET 应用则使用一个 async 方法。需要参考其对应编程平台的优化经验进行实施。

最后,当我们掌握了优化性能的方法,也不意味着我们一定要用尽各种方法去优化我们编写的每一个应用程序。在编写代码过程中,优先选用更高性能的写法通常是有益的(例如,使用 HashSet 替换 List 来存储需要快速查找的集合)。另一方面,过早优化是所有开发人员都容易忽略的陷阱(例如,集合的元素并不多,又大量用于循环时用 HashSet 替换了 List)。几乎所有新的开发人员都听说过“字符串是不可变量,应该尽量使用 StringBuilder”、“反射的性能很糟糕,应该尽量避免使用”之类的经验之谈。单从字面来理解确实都是金玉良言,但作为一种优化手段,性能优化往往会要求应用程序遵守一些约束,这些约束有时会破坏代码的可读性,有时会改变编写代码的习惯,而这些往往意味着在更广的维度上给团队带来成本。

《.NET性能优化》

[美]萨沙·戈德斯汀(Sasha Goldshtein) 著

作者和其他三位 ThoughtWorks 同事一同翻译的《.NET 性能优化》一书已于近日出版,各大在线书店有售。本书详细解释了影响应用程序性能的 Windows、CLR 的内部结构,并为读者提供了衡量代码如何独立于外部因素执行优化的知识和工具。书中提供了大量的 C# 代码示例和技巧,将帮您最大限度地提高算法和应用的性能。

尽管成书于数年之前,书中所述的大多数经验仍适用于最新的 .NET 框架和运行时。它不光讲述适用于 .NET 平台的性能优化方法,还详细地讲解了性能度量的指标,以及普适性的性能优化的思路和原理。既授人以鱼,又授人以渔,是不可多得的上佳之作。

公众号读者可以通过扫码、点击链接等方式在异步社区购买 《.NET 性能优化》时,在结算时输入优惠码 d4c43c-e 即可获得10元现金优惠。也可通过亚马逊、京东和当当等网站自行购买

本文来源于陈计节的个人博客,作者:陈计节,作品《当我们谈高性能时,我们谈些什么?》点击查看原文链接

长按二维码,可以关注我们哟

每天与你分享IT好文。

在“异步图书”后台回复“关注”,即可免费获得2000门在线视频课程

异步图书福利送不停

邀请10名好友关注10天直接获取异步图书一本(点击文字获取活动详情哦)

点击阅读原文,购买.NET性能优化

阅读原文


相关文章
|
开发者
SyntaxError: cannot assign to literal错误
SyntaxError: cannot assign to literal错误
3104 1
|
10月前
|
程序员 API 调度
iOS|解决 setBrightness 调节屏幕亮度不生效的问题
在包含视频播放功能的 App 中,一种常见的交互是在播放器界面的左侧上下滑动调节屏幕亮度,右侧上下滑动调节音量。我们的 iOS App 里也是这样设计的,但最近在测试过程中,发现亮度调节不生效了。
440 76
|
8月前
|
人工智能 开发框架 安全
Serverless MCP 运行时业界首发,函数计算让 AI 应用最后一公里提速
作为云上托管 MCP 服务的最佳运行时,函数计算 FC 为阿里云百炼 MCP 提供弹性调用能力,用户只需提交 npx 命令即可“零改造”将开源 MCP Server 部署到云上,函数计算 FC 会准备好计算资源,并以弹性、可靠的方式运行 MCP 服务,按实际调用时长和次数计费,欢迎你在阿里云百炼和函数计算 FC 上体验 MCP 服务。
736 30
|
安全 测试技术
Fiddler是什么软件?如何配置使用?
【10月更文挑战第3天】Fiddler是什么软件?如何配置使用?
572 3
|
Python 计算机视觉
2024年Python最新利用python进行数学公式识别_python 识别图片中的数学公式,2024年最新字节跳动技术岗位面试
2024年Python最新利用python进行数学公式识别_python 识别图片中的数学公式,2024年最新字节跳动技术岗位面试
2024年Python最新利用python进行数学公式识别_python 识别图片中的数学公式,2024年最新字节跳动技术岗位面试
基于极大似然法和最小二乘法系统参数辨识matlab仿真,包含GUI界面
该程序对比了基于极大似然法和最小二乘法的系统参数辨识,输出辨识收敛曲线和误差。在MATLAB2022a中运行,显示了测试结果。核心代码涉及矩阵运算和循环,用于更新和计算系统参数。算法原理部分解释了辨识的目的是建立数学模型,并介绍了极大似然法(基于概率统计)和最小二乘法(基于误差平方和最小化)两种方法。
|
存储 算法 数据挖掘
重磅发布 | OpenSearch推出向量检索GPU图算法方案并支持GPU规格售卖
OpenSearch向量检索版推出了面向企业开发者的GPU图算法方案(CAGRA算法),支持客户直接购买GPU规格节点,是国内首家支持GPU规格的向量检索产品。
955 12
|
机器学习/深度学习 算法 数据挖掘
从零到精通:Scikit-learn在手,数据分析与机器学习模型评估不再难!
【10月更文挑战第4天】在数据科学领域,模型评估是连接理论与实践的桥梁,帮助我们理解模型在未知数据上的表现。对于初学者而言,众多评估指标和工具常令人困惑。幸运的是,Scikit-learn 这一强大的 Python 库使模型评估变得简单。本文通过问答形式,带你逐步掌握 Scikit-learn 的评估技巧。Scikit-learn 提供了丰富的工具,如交叉验证、评分函数(准确率、精确率、召回率、F1 分数)、混淆矩阵和 ROC 曲线等。
246 1
|
消息中间件 关系型数据库 MySQL
从零玩转Docker之docker-compose快捷部署中间件2
从零玩转Docker之docker-compose快捷部署中间件
1589 0
|
消息中间件 负载均衡 NoSQL
TencentOS Server 配置 docker / docker-compose 一键部署 redis,rabbitmq 容器
TencentOS Server (tlinux 3.1)配置 docker,compose 工具,并一键部署多容器(redis,rabbitmq)。TencentOS Server 是腾讯公司自主研发的定制化服务器操作系统。该系统集成了众多服务 器系列的优点,加入自主研发的软件,便于用户操作使用,提供全方位(内核及用户态)的 操作系统支持...
2672 0
TencentOS Server 配置 docker / docker-compose 一键部署 redis,rabbitmq 容器