那些不得不说的性能优化套路(一)

简介: 你有没有想过,为什么跨行转账要告诉你2小时内到账,而不是立即到账?为什么抖音那么多用户同时在使用,却很少出现崩溃的情况?电商网站是如何支撑住双十一全国人民买买买的?

你有没有想过,为什么跨行转账要告诉你2小时内到账,而不是立即到账?为什么抖音那么多用户同时在使用,却很少出现崩溃的情况?电商网站是如何支撑住双十一全国人民买买买的?


性能优化对一个产品的重要性不言而喻,它直接影响网站的用户留存率,APP在商店的评分和用户粘性。一个响应慢的应用,即便它功能再强大,也留不住用户。


性能优化对一个程序员同样非常重要——如果你是一个有追求的程序员的话。我们说,大多数人的职业生涯发展都应该是一个T字型,要在某一方面有深度,也要有广度。而性能优化,恰恰是一个既需要深度,又需要广度的话题。相信很多程序员都有一个成为架构师的梦,如果想要成为一个系统架构师,那性能优化是不得不学习了解的。


下面将从各个方面,把我知道的关于性能优化的各种“套路”介绍给大家,欢迎大家看完后留言交流探讨。


找到最慢的节点

我们谈性能时,一般来说有两个指标,一个是响应时间,一个是吞吐量。

说到响应时间,最直观的感受就是快与慢。打开一个网页需要多少毫秒、点击一个按钮需要等待多长时间、刷一个抖音视频需要加载多久?这些都是在说响应时间。

吞吐量指的是系统在单位时间能够承受的请求数量,反映是系统的承载能力。

下面列出一些常见的影响性能的地方。

网络传输

影响响应时间的因素有很多,我们可以通过一些监控去测试。但我可以很负责任的告诉你,在大多数场景,一次完整的网络请求中,最多的时间往往是消耗在网络传输上。

网络传输有很多种,比如服务端到客户端的请求和响应,还有服务端各个微服务之间的接口调用耗时,还有应用与数据库、应用与缓存、应用与消息中间件等等之间的网络传输。

当然,大多数时候,我们会把后端的一些东西尽量放在一个机房里面,这样可以直接走内网,网络传输时间不会很高。但相比于大多数应用代码的执行时间来说,这些网络传输也是一笔不小的消耗。

SQL查询

我们应用的数据可能会持久化在不同的地方,不管是关系型数据库、非关系型数据库、还是搜索引擎,一旦数据量上去了,如果没有做好性能优化,查询的时候很容易就耗费大量的时间。

最常见的就是SQL慢查询了,一旦产生了慢查询,轻则响应时间变慢,重则拖满线程池导致整个服务不可用。所以SQL查询也是我们经常会考虑到的性能优化方向。

线程等待

线程等待指的是线程同步造成的问题。现代服务器往往是多核的,我们通常会使用线程池来发挥多核服务器的优势。但使用多线程经常会遇到的问题就是线程的同步问题。

在高并发下,线程同步其实是一个很危险的操作。如果临界区的操作比较耗时,就会导致大量的线程等待、堆积,最终撑满线程池。比如上面提到的慢SQL就常常会导致这个问题。

所以我们在使用多线程的时候,一定要小心谨慎。尽量弄清楚它的原理,想办法避免或者更轻量级地上锁。比如Yasin前几天发的几篇关于ThreadLocal的文章,里面就介绍了在某些场景可以用ThreadLocal避免线程的同步。

多线程是一块比较大,也比较难的知识点,也是互联网大厂的入门门槛,面试必问,工作中也会经常用到。这里推荐我之前参与写作的一本关于多线程的开源电子书《深入浅出Java多线程》,在我的公众号“编了个程”回复“多线程”即可领取这本书的电子版。

Full GC

Full GC其实影响整个应用性能的概率比较小。但如果你的程序没写好,或者JVM参数没有设置好,造成了频繁Full GC或者Full GC时间过长,也是有可能会影响性能的。

对JVM有所了解的朋友都知道,Full GC会STW (Stop The World),这段时间程序会暂停,也就没法响应用户。

G1对Full GC做了优化,把单线程的Full GC变成了多线程并行Full GC。但如果Full GC频繁,仍然会影响应用的性能。

这里列一下Full GC频繁的原因,有兴趣的朋友可以自己再深入了解一下:

  • 老年代设置的空间太小
  • 永久代空间不足
  • 程序中写了很多大对象
  • 晋升老年代的代数阈值设置太小


高频优化思路

针对上面提到的几个最容易影响程序性能的点,下面介绍一些高频的性能优化思路,大多数都是针对网络传输的,从各种角度去减少网络传输的消耗。从这些思路入手,大概率可以很明显地提升性能,小伙伴们可以作为参考。

CDN

前面提到,一般来说,一个用户请求大多数时间是消耗在网络传输上的,尤其是客户端与服务端之间的网络传输。

CDN全称是“Content Delivery Network”,翻译过来叫内容分发网络。原理其实很简单,就是把资源分发到全国各地甚至是世界各地,使得用户可以就近取得资源,缩短网络传输的距离,降低延迟,所以可以很明显地提升响应速度和成功率。

CDN原理

所以CDN多是用于文件分发,比如网站的css、js、图片、视频等资源文件。曾经听过一句话:如果你的网站没有使用CDN,那么使用CDN基本上可以让你的网站性能得到大幅度提升

CDN一般是和OSS配合起来使用的。现在各大主流云厂商基本都提供了OSS和CDN的产品,我自己的个人网站是使用的七牛云,有10G的免费容量,比较适合于个人站长。

压缩

另一个优化网络传输消耗的思路就是压缩了。CDN的思路是让网络传输的距离更短,压缩的思路是让网络传输的内容更小。尤其适用于js/css等文本文件,压缩收益非常高,往往能节省很多的网络传输开销。

图片和视频当然也可以压缩,不过需要选择合适的压缩算法。比如我们用微信发送图片时,如果不点击“发送原图”,那图片就会被微信压缩,虽然可能没那么高清,但是文件小很多,使得用户可以更快收到图片,提升用户体验。

现在大多数网站都会使用nginx作为前端服务器或者负载均衡器,在nginx里面可以非常方便地启动gzip压缩功能:

server{
    gzip on;
    gzip_buffers 32 4K;
    gzip_comp_level 6;
    gzip_min_length 100;
    gzip_types application/javascript text/css text/xml;
    gzip_vary on;
} 

在浏览器打开“开发者控制台”,查看资源的网络请求,可以查看该资源是否启用了压缩算法。

使用gzip

注意:gzip压缩算法比较适用于html、js、css等文本文件,不适用于图片等二进制文件。对图片使用gzip压缩收益不高,反而可能会增加体积。

预加载

前面讲到了两个网络传输的优化思路。我们可以另辟蹊径:既然网络传输那么消耗时间,那我们偷偷在不忙的时候提前下载好不行吗?

大家可以做一个实验:刷抖音刷到一半,等一会儿,然后停掉自己的网络,再往下刷,可以发现还能刷好几个视频。

这就是因为抖音使用了预加载技术,当你在专心致志地看一个有趣的视频的时候,这个时候网络其实是空闲的,抖音就在悄悄下载后面几个视频,这样你就可以一直刷刷刷,用户体验就会很顺畅。

试想一下,如果不使用预加载,用户每次往下刷,都得等几秒钟把这个视频下载下来才能看,那自然用户体验极差。

当然了,预加载并不适用于所有场景。毕竟预加载是提前下载,并不是不下载。如果不是有特定的业务场景,其实也没必要使用预加载。不合理地使用预加载甚至有可能会影响正常的业务,还有可能造成数据不一致的问题。

慢SQL优化

很多应用后端会使用关系型数据库来持久化数据。如果数据量大了,索引设置不合理,就很有可能会产生慢SQL。

生产环境最好加上慢SQL监控和分析的工具。阿里出品的Druid就很不错。对很多中小型项目来说已经足够了。

慢SQL优化一般有几个思路。

  1. 先看是不是没有命中索引,如果没有命中,是否可以调整索引或者SQL语句?
  2. 看能不能从业务代码层面解决?
  3. 能不能在应用层面加缓存?
  4. 考虑是否需要分库分表?

索引这个东西大家应该或多或少都接触过或者听说过。分析索引需要有一定的数据库基础,这里推荐《高性能MySQL》这本书,对索引讲得比较清晰。我的个人网站yasinshaw.com上面也有我之前写的关于MySQL的系列文章:

搜索关键字MySQL

从业务层面解决也是可以思考的一个点。比如我之前优化过的一个慢SQL。优化前的做法是用count查询数据库还有多少数据,如果大于0,就delete掉这批数据,每次delete 3k条。结果每天数据库都有几十万条符合这个查询条件的数据,导致每次count查询都会耗费许多时间,即使走了索引,也得扫描几十行。而delete也因为数据量太大,执行时间超过1秒,收到告警。

long count = dao.count(condition);
while(count > 0) {
 dao.delete(condition);
    count = dao.count(condition);
}

优化思路也很简单,因为delete的时候会返回删除的行数。所以我们直接用这个数据来决定是否退出循环就行了,根本不需要count查询。同时把批量删除的行数从3k条修改为1k条,这样两个慢SQL问题就都解决了。

long deletedNumber = 0;
do {
    deletedNumber = dao.delete(condition);
} while (deletedNumber > 0)

缓存和分库分表会在下文做详细介绍,这里不赘述。

JVM调优和升级

频繁的GC会占用大量的JVM资源,还会浪费CPU的资源。所以如果是生产环境,推荐给JVM也加上监控和告警,这样能够随时观察JVM的状况是否健康。

尤其是对于Full GC,要格外注意,因为Full GC会Stop The World。前段时间我们有一个应用就是因为永久代空间不足,触发Full GC,而每次回收效果又不好,导致一遍又一遍地Full GC,影响应用的正常工作。

Java也在对JVM不断进行优化和升级,比如最新的ZGC,在大堆下性能表现优异。G1也非常不错,如果项目条件允许,建议使用稍微新一点的垃圾收集器。

目录
相关文章
|
算法 安全 数据安全/隐私保护
密码学基础-对称密码算法(Symmetric-key Algorithm)
密码学基础-对称密码算法(Symmetric-key Algorithm)
用html+javascript打造公文一键排版系统1:设计界面
用html+javascript打造公文一键排版系统1:设计界面
|
存储 容灾 关系型数据库
OceanBase 高可用性架构解析
【8月更文第31天】在大数据和云计算蓬勃发展的今天,数据库作为数据存储的核心组件,其稳定性和可靠性直接影响到整个系统的性能。OceanBase 是由阿里巴巴集团自主研发的一款分布式关系型数据库系统,旨在为大规模在线交易处理(OLTP)场景提供高性能、高可用性的解决方案。本文将深入探讨 OceanBase 是如何通过其独特的架构设计来确保数据的高可用性和容灾能力。
649 0
|
数据采集 传感器 大数据
利用大数据进行精准农业:技术与挑战
【6月更文挑战第6天】大数据技术正变革农业,推动精准农业发展。通过实时收集农田数据(如土壤条件、作物生长情况),运用数据分析预测病虫害,优化生产管理。示例代码显示了如何使用Python进行产量预测。然而,数据质量、整合、农民技术接受度及隐私安全等问题挑战重重。需强化数据管理,统一标准,提升农民数字素养,并保障数据安全。随着技术进步,大数据在精准农业的应用将更加广泛,助力农业高效可持续发展。
404 0
|
机器学习/深度学习 存储 人工智能
【ACL2024】阿里云人工智能平台PAI多篇论文入选ACL2024
近期,阿里云人工智能平台PAI的多篇论文在ACL2024上入选。论文成果是阿里云与阿里集团安全部、华南理工大学金连文教授团队、华东师范大学何晓丰教授团队共同研发。ACL(国际计算语言学年会)是人工智能自然语言处理领域的顶级国际会议,聚焦于自然语言处理技术在各个应用场景的学术研究。该会议曾推动了预训练语言模型、文本挖掘、对话系统、机器翻译等自然语言处理领域的核心创新,在学术和工业界都有巨大的影响力。此次入选标志着阿里云人工智能平台PAI在自然语言处理和多模态算法、算法框架能力方面研究获得了学术界认可。
|
开发框架 前端开发 JavaScript
电商商品数据库的设计和功能界面的处理
电商商品数据库的设计和功能界面的处理
|
弹性计算 运维 Kubernetes
阿里云ECS与混合云策略结合,提供云上云下无缝对接,提升业务灵活性和运维效率。
【7月更文挑战第3天】阿里云ECS与混合云策略结合,提供云上云下无缝对接,提升业务灵活性和运维效率。ECS支持多种计费模式和先进架构,保证低延迟计算。混合云融合公有云灵活性与私有云安全,实现资源最优配置。通过VPC互通、应用迁移、数据同步实践,确保安全合规,助力企业数字化转型。阿里云服务展示技术实力,支持企业在混合云时代抓住机遇。
486 3
|
SQL 大数据 分布式数据库
SQL与大数据的神秘力量:如何用高效SQL处理海量数据,让你的项目一鸣惊人?
【8月更文挑战第31天】在现代软件开发中,处理海量数据是关键挑战之一。本文探讨了SQL与大数据结合的方法,包括数据类型优化、索引优化、分区优化及分布式数据库应用,并通过示例代码展示了如何实施这些策略。通过遵循最佳实践,如了解查询模式、使用性能工具及定期维护索引,开发者可以更高效地利用SQL处理大规模数据集。随着SQL技术的发展,其在软件开发中的作用将愈发重要。
499 0
|
存储 安全 算法
静态路由与动态路由的区别及应用场景
【8月更文挑战第25天】
717 0