


























简介: 本文详细介绍了大厂性能优化的10大顶奢方案,涵盖代码优化、缓存优化、异步优化、多线程优化、前端优化、微服务架构优化、硬件升级、数据库优化、过载保护优化以及度量与监控系统等方面。每部分不仅提供了理论知识,还结合实际案例和代码示例,帮助读者全面理解和应用这些优化策略。文章还特别强调了架构设计的重要性,指出架构师需要具备多方面的知识和技能,包括硬件、软件、网络协议、分布式知识等,以应对复杂的技术挑战。最后,作者尼恩分享了自己多年的经验,提供了丰富的技术资源和实战指导,助力读者在面试和工作中取得成功。
高并发下,如何设计秒杀系统?这是一个高频面试题。
在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、shopee、百度、网易的面试资格,遇到很多很重要的面试题:
如何做性能优化,有哪些方案?
你用过哪些 性能优化方案?
前几天 小伙伴面试 shopee,遇到了这个问题。但是由于 没有回答好,导致面试挂了。
小伙伴面试完了之后,来求助尼恩:遇到性能优化,该如何才能回答得很漂亮,才能 让面试官刮目相看、口水直流。
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典》V145版本PDF集群,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,后台回复:领电子书
下面给大家总结一下大厂 性能优化的10方案 , 组成一个《大厂 性能优化圣经》

代码优化是提升系统性能的重要手段,它涉及到编写高效、简洁且易于维护的代码。以下是对代码优化方案的详解:

首先,必须通过性能分析工具识别出代码中的瓶颈。这些工具可以帮助开发者了解程序的执行时间、内存使用情况以及热点函数等关键信息。
循环是程序中常见的性能瓶颈之一。优化循环包括减少循环次数、优化循环内部的计算以及使用更高效的数据结构。
比如说:将循环内的重复计算移到循环外部。
// 原始代码
for (int i = 0; i < n; i++) {
double x = pow(a[i], 2);
选择正确的算法对性能至关重要。例如,对于大数据集的操作,使用排序算法时,快速排序通常比简单排序更高效。
函数调用会引入额外的开销。在某些情况下,内联函数可以减少调用的开销,特别是在函数体较小的情况下。
有效的内存管理可以减少程序的内存占用和提高缓存利用率。避免内存泄漏、合理使用缓存以及减少内存分配和释放操作都是重要的优化手段。
在多核处理器上,利用并发和多线程可以显著提高程序的执行效率。合理分配任务、减少线程间的竞争以及同步开销是并发编程中的关键。
代码重构是改善现有代码设计而不改变其外部行为的过程。它可以帮助开发者去除重复代码、提高代码的模块化和可读性,从而间接提升性能。
消除代码中的冗余计算,
例如:
通过重新组织代码逻辑,可以完全避免无效循环,实例如下:
// 原始代码
for (int i = 0; i < n; i++) {
if (a[i] > threshold) {
process(a[i]);
}
}
// 优化后的代码
for (int i = 0; i < n; i++) {
if (a[i] <= threshold) continue;
process(a[i]);
}
充分利用编译器的优化选项,如开启高级优化等级,可以让编译器帮助我们进行一些代码优化。
最后,任何优化都应该通过性能测试来验证其效果。确保优化后的代码不仅在理论上更快,而且在实际运行中也能带来性能提升。


在架构设计中,缓存策略的合理运用可以显著提高系统性能。常见的缓存策略包括LRU(最近最少使用)、LFU(最少频繁使用)等,以及分布式缓存的使用,如Redis或Memcached。
多线程与分布式计算是性能优化中的重要策略,它们通过利用更多的处理器核心或分布计算任务到多个物理或虚拟机器上来提升系统的整体性能。
异步处理可以提高系统的响应性和吞吐量。
消息队列(如RabbitMQ、Kafka)在分布式系统中用于解耦服务,实现异步通信,提高系统的可扩展性和容错性。
先看第一个银弹: 缓存优化。
缓存是提升系统性能的关键技术之一,通过减少数据访问延迟和降低后端存储压力,显著加快数据检索速度。在现代应用架构中,缓存不仅用于提升用户体验,也是实现高并发处理的基础。
内存缓存利用服务器的RAM来存储热点数据,提供快速的数据访问能力。常见的内存缓存实现包括Ehcache、Memcached等。
分布式缓存通过多台服务器共享缓存数据,解决了单机内存限制的问题,并提供了更好的扩展性和可用性。例如,Redis和Hazelcast是流行的分布式缓存解决方案。
浏览器缓存利用客户端的存储能力,减少网络传输的数据量,加快页面加载速度。通过设置合适的HTTP头信息,如Cache-Control和Expires,可以控制浏览器缓存的生命周期。
内容分发网络(CDN)通过在网络边缘节点存储静态资源,使用户可以就近获取数据,从而减少延迟和带宽消耗。
合理选择缓存的粒度,可以平衡内存使用和访问速度。过细的粒度可能导致缓存碎片化,而过粗的粒度可能降低缓存效率。
缓存失效策略(如LRU、FIFO等)决定了哪些数据应该被移除缓存,以适应新的数据更新和访问模式。
缓存预热是在系统启动或低负载时段预先加载热点数据到缓存中,避免在高负载时发生缓存缺失。
在分布式系统中,保持缓存与后端存储的一致性是一个挑战。可以通过发布/订阅模式、消息队列等机制来实现缓存的同步更新。
在电商网站中,商品详情页、购物车等热点数据通过缓存策略减少数据库访问,提高系统响应速度。
社交媒体平台通过缓存用户动态、热门话题等数据,应对大规模的用户访问和数据请求。
金融服务应用缓存技术在交易处理、风险评估等场景中,以满足低延迟和高吞吐量的需求。
缓存策略的有效性需要通过持续的监控和调优来保证。监控指标包括缓存命中率、响应时间、内存使用率等,根据这些指标调整缓存大小、失效策略和数据更新频率。
通常情况下,我们需要在redis中保存商品信息,里面包含:商品id、商品名称、规格属性、库存等信息,同时数据库中也要有相关信息,毕竟缓存并不完全可靠。
用户在点击秒杀按钮,请求秒杀接口的过程中,需要传入的商品id参数,然后服务端需要校验该商品是否合法。
大致流程如下图所示:

根据商品id,先从缓存中查询商品,如果商品存在,则参与秒杀。
如果不存在,则需要从数据库中查询商品,如果存在,则将商品信息放入缓存,然后参与秒杀。
如果商品不存在,则直接提示失败。
这个过程表面上看起来是OK的,但是如果深入分析一下会发现一些问题。
具体的分析过程,请参考《尼恩的秒杀圣经》。

异步处理是一种编程模式,允许程序在等待特定操作完成时继续执行其他任务。这种技术可以显著提高应用程序的响应性和性能。
异步处理适用于多种场景,特别是在需要提升性能和用户体验的应用程序中。
多种编程语言和框架提供了实现异步处理的技术,包括回调函数、事件循环、Promise、Async/Await等。
为了充分利用异步处理的优势,开发者需要遵循一些最佳实践。
随着业务的发展,微服务应用的流量越来越大,使用到的资源也越来越多。
在微服务架构下,大量的应用都是 SpringCloud 分布式架构,这种架构,总体是全链路同步模式。
同步编程模式不仅造成了资源的极大浪费,并且在流量发生激增波动的时候,受制于系统资源而无法快速的扩容。
全球后疫情时代,降本增效是大背景。
如何降本增效?可以通过技术升级,全链路同步模式 ,升级为 全链路异步模式。
全链路同步模式架构图

需要 全链路、多层次、多维度进行 优化和改造。

异步处理可以显著提升性能,但也需要考虑到一些性能方面的细节。

多线程与分布式计算是性能优化中的重要策略,它们通过利用更多的处理器核心或分布计算任务到多个物理或虚拟机器上来提升系统的整体性能。
多线程技术允许程序中的不同部分同时执行,从而提高程序的执行效率和响应性。
Java 中可以使用 CompletableFuture 用于处理异步任务。它提供了一种灵活的方式来处理异步计算和多线程优化。
以下是一个使用 CompletableFuture 来并行下载文件的示例。
java复制代码import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
public class MultiThreadedDownloader {
CompletableFuture是否使用默认线程池的依据,和机器的CPU核心数有关。
场景一:当 (CPU核心数-1) 大于1时,才会使用默认的线程池,forkjoin 线程池 ForkJoinPool.commonPool()。
场景二:当 (CPU核心数-1)不大于 1时,也就是 单核或者双核,将会为每个CompletableFuture的任务创建一个新线程去执行。
换句话说,forkjoin 线程池 作为 CompletableFuture的默认线程池,只有在双核以上的机器内才会使用。
在双核及以下的机器中,会为每个任务创建一个新线程,这种场景,等于没有使用线程池,且有资源耗尽的风险。
另外,forkjoin 线程池 也有问题,这个默认线程池,池内的核心线程数,也为机器核心数-1。
也就意味着假设你是4核机器,那最多也只有3个核心线程,对于CPU密集型的任务来说倒还好,但是我们平常写业务代码,更多的是IO密集型任务/混合型任务,这就问题很大。
对于IO密集型、混合型的任务来说,机器核心数-1 的线程数量 其实远远不够用的,会导致大量的 任务在等待,导致吞吐率大幅度下降,即默认线程池比较适用于CPU密集型任务。
具体的线程数的设置,包括CPU密集型 、IO密集型任务/混合型任务 的线程数设置,具体的算法 请参见尼恩 的《JAVA 高并发核心编程 卷2》
1、CompletableFuture默认使用的线程池是 ForkJoinPool.commonPool(),commonPool是当前 JVM(进程) 上的所有 CompletableFuture、并行 Stream 共享的,commonPool 的目标场景是非阻塞的 CPU 密集型任务,其线程数默认为 CPU 数量减1,所以对于我们用java常做的IO密集型任务,默认线程池是远远不够使用的
2、CompletableFuture是否使用默认线程池的依据,和机器的CPU核心数有关。当CPU核心数-1>1时,才会使用默认的线程池,否则将会为每个CompletableFuture的任务创建一个新线程去执行。
也就是说,CompletableFuture的默认线程池,只有在双核以上的机器内才会使用。在双核及以下的机器中,会为每个任务创建一个新线程,等于没有使用线程池,且有资源耗尽的风险。
因此建议,在使用CompletableFuture时,务必要自定义线程池。
@Configuration
public class ThreadPoolConfig {

浏览器访问优化是提升用户体验的关键步骤。通过减少HTTP请求次数,合并CSS和JavaScript文件,以及利用浏览器缓存等策略,可以显著减少页面加载时间。
以秒杀场景为例。
秒杀详情页面是用户流量的第一入口,所以是并发量最大的地方。
如果这些流量都能直接访问服务端,恐怕服务端会因为承受不住这么大的压力,而直接挂掉。

秒杀详情页面绝大多数内容是固定的,比如:商品名称、商品描述、图片等。
为了减少不必要的服务端请求,通常情况下,会对活动页面做静态化处理。
用户浏览商品等常规操作,并不会请求到服务端。
为了性能考虑 动静分离,分离出下面的两大部分:
但只做页面静态化还不够,因为用户分布在全国各地,有些人在北京,有些人在成都,有些人在深圳,地域相差很远,网速各不相同。
如何才能让用户最快访问到活动页面呢?
这就需要使用CDN,它的全称是Content Delivery Network,即内容分发网络。

使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
CDN服务器就是内容分发网络,把资源内容放在了全国各地的各服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,一般都是到阿里云买CDN服务器。
尼恩提示:如果没有CDN,也可以放在Nginx中做动静分离。
内容分发网络(CDN)通过将内容缓存到离用户更近的节点,加快了静态资源的加载速度,提升了全球用户的访问体验。
反向代理服务器作为Web服务器的前置,可以提供额外的安全层,并通过缓存机制加速内容的分发。
通过将Web应用的各个组件分离到不同的域名下,可以提高浏览器的并发下载能力,加快页面渲染速度。
将前端应用拆分成多个服务,可以独立部署和扩展,提高应用的可维护性和可扩展性。

架构设计是性能优化中的关键环节,其核心原则包括模块化、单一职责、可扩展性和高内聚低耦合。
这些原则有助于构建一个易于维护、升级和扩展的系统。
微服务架构通过将单一应用程序划分为一组小的服务,每个服务运行在其独立的进程中,服务之间通过轻量级的通信机制进行交互。这种架构有助于提高系统的可维护性和可扩展性,同时也便于进行持续集成和持续部署。
我们可以将电商系统的微服务架构简化,成下图所示:

由图所示,我们可以简单的将电商系统的核心层分为:接入层、服务层和持久层。
接下来,可以一层一层的进行优化。
微服务架构 ≈ 模块化开发 + 分布式计算。
需要注意的是“微服务”与“微服务架构”是有本质区别的。“微服务”强调的是服务的大小,它关注的是某一个点。而“微服务架构”则是一种架构思想,需要从整体上对软件系统进行通盘的考虑。
微服务架构示意图:

常见的微服务组件及概念:
微服务架构的优点:
微服务架构的缺点:
不过,现在很多微服务的框架(比如 Spring Cloud、Dubbo)已经很好的解决了上面的问题。
服务网格(如Istio)提供了一种将服务间通信控制和安全性从应用程序代码中抽象出来的方式。
它支持服务发现、负载均衡、故障恢复、度量和监控等微服务治理功能,有助于提升系统的性能和稳定性。
2017 年底,非侵入式的 Service Mesh 技术从萌芽到走向了成熟。
Service Mesh 又译作“服务网格”,作为服务间通信的基础设施层。
如果用一句话来解释什么是 Service Mesh,可以将它比作是应用程序或者说微服务间的 TCP/IP,负责服务之间的RPC调用、限流、熔断和监控。
对于编写应用程序来说一般无须关心 TCP/IP 这一层(比如通过 HTTP 协议的 RESTful 应用),同样使用 Service Mesh 也就无须关系服务之间的那些原来是通过应用程序或者其他框架实现的事情,比如 Spring Cloud、OSS,现在只要交给 Service Mesh 就可以了。
Service Mesh 的来龙去脉:
Service Mesh 有如下几个特点:
Service Mesh 架构图:

目前流行的 Service Mesh 开源软件有 Linkerd、Envoy 和 Istio,而最近 Buoyant(开源 Linkerd 的公司)又发布了基于 Kubernetes 的 Service Mesh 开源项目 Conduit。
Service Mesh 开源项目简介:
关于微服务和服务网格的区别,尼恩的一些理解:

容器化技术(如Docker)可以将应用及其依赖打包在一起,确保应用在不同环境中的一致性。
容器编排工具(如Kubernetes)则提供了自动化部署、扩展和管理容器化应用的能力,有助于提升资源利用率和系统弹性。
这部分内容,请参见尼恩的 《第28章视频:K8S学习圣经》
为解决系统重复建设、能力复用性低的问题,启动了中台化建设步伐。
中台建设并非从零开始,前期已经积累了行业中多个场景的业务和技术的中台能力。因系统建设的复杂,亟需一个中台大脑站在全局视角进行公司中台能力的梳理和建设。
DDD建模流程、设计流程是 中台化架构 的绝配。 通过引入新的建模流程,完成 中台化的宏观分析和架构建模。
Tips:
在云服务厂商的支持下,集群架构已经能够支撑较大的用户流量了。云服务器、云数据库等云端基础服务的支撑能力,也比前些年要好了很多,升级扩容也方便了许多,已经足够满足一般规模下的系统性能需求了。所以,不要觉得业务量一上来,就立马要改系统架构,因为这反而可能带来不必要的麻烦。有时,直接通过升级云服务器/云数据库等的配置,就可以解决问题了。(通常来说,常规业务场景下,通过一些优化改造,顶住1万以内的QPS是没有太大问题的)。


具体请参见尼恩的《DDD学习圣经》
看看尼恩给小伙伴出的一个 经典的技术架构图,就知道有点干货了:


硬件升级是提升系统性能的重要手段之一,特别是在性能瓶颈由硬件限制导致的情况下,硬件升级可以带来显著的性能提升。
硬件升级可以直接影响应用的性能表现,特别是在处理大量数据和复杂计算时。
存储设备的性能直接影响数据的读写速度,升级到更快的存储设备可以显著提高系统的整体性能。
增加系统内存可以提供更多的数据缓存空间,减少因内存不足导致的页面交换(swap),从而提高系统响应速度。
CPU作为计算核心,其性能直接影响到处理速度。升级到更高性能的CPU可以加速计算任务的完成。
网络设备的性能同样影响数据传输效率,特别是在分布式系统中,高速网络设备可以减少数据传输时间。
对于图形密集型或需要GPU加速的应用,显卡的性能至关重要。
除了上述主要硬件外,还有其他组件的升级也会影响系统性能,如电源供应器(PSU)、散热系统等。
硬件升级需要考虑与现有系统的兼容性以及成本效益比,选择合适的硬件进行升级,以达到最优的性能提升效果。

索引是提升数据库查询性能的关键技术。合理的索引设计可以显著提高查询速度,减少数据检索时间。在索引优化中,应关注以下几点:
查询语句的优化是提升数据库性能的直接方式。优化查询包括:
缓存是减轻数据库负担的有效手段。通过缓存优化,可以:
硬件的性能直接影响数据库的处理能力。硬件优化包括:
合理的数据库配置可以提升系统性能:
先看看数据库瓶颈是什么?
1、IO 瓶颈
第一种:磁盘读 IO 瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的 IO,降低查询速度 -> 分库和垂直分表。
第二种:网络 IO 瓶颈,请求的数据太多,网络带宽不够 -> 分库。
2、CPU 瓶颈
第一种CPU 瓶颈:SQL 问题,如 SQL 中包含 join,group by,order by,非索引字段条件查询等,增加 CPU 运算的操作 -> SQL 优化,建立合适的索引,在业务 Service 层进行业务计算。
第二种CPU 瓶颈:单表数据量太大,查询时扫描的行太多,SQL 效率低,CPU 率先出现瓶颈 -> 水平分表。
不管是 IO 瓶颈,还是 CPU 瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值。

对于大数据量的数据库,分库分表是一种有效的优化手段:
比如: 可以按照水平、垂直两大维度进行拆分:
比如:可以按业务功能拆分数据库,如:用户数据、订单数据......等分别存储。
也可以,将同一表的数据按一定规则分散到多个表中,比如:
通过读写分离,可以将查询操作和更新操作分散到不同的数据库服务器:
读写分离旨在通过将读操作、和写操作分开,是一种常见的优化方案, 大致流程 如下图所示:

大致的原理,如下:
在MySQL中,通过索引重建、适当反范式化、批量执行等技术手段,可以显著提升SQL的执行效率。以下是详细的说明和示例代码。
1. 索引重建
重建索引可以提高查询性能,特别是在数据频繁变动导致索引碎片化的情况下。
示例代码
sql复制代码-- 重建指定表上的所有索引
ALTER TABLE table_name ENGINE=InnoDB;
2. 适当反范式化
适度的反范式化可以减少复杂的连接操作,从而提高查询效率。
示例代码
假设我们有一个标准化的数据库结构:
-- 用户表
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(100)
);
我们可以通过反范式化来提高查询性能:
-- 反范式化后的订单表
CREATE TABLE orders (
order_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
user_name VARCHAR(100),
order_total DECIMAL(10, 2)
);
3. 批量执行
批量执行可以减少SQL语句的开销,提高数据处理效率。特别是在插入大量数据时,使用批量插入能显著提高性能。
示例代码
-- 批量插入示例
INSERT INTO orders (user_id, user_name, order_total) VALUES
(1, 'Alice', 99.99),
(2, 'Bob', 49.99),
(3, 'Charlie', 19.99);
定期对数据库进行维护,包括:
通过监控和分析数据库性能,及时发现并解决问题:

过载保护架构是另一种确保系统稳定性和可靠性的机制,特别是在面对高流量或异常流量时。过载保护通常包括:
在设计链路保护和过载保护架构时,需要综合考虑系统的业务需求、性能指标、成本和复杂性等因素,以实现最佳的保护效果。

度量与监控系统是确保系统性能优化方案有效实施的关键环节。以下是对10大性能优化方案的度量与监控系统的详解:
确立度量指标是监控系统的第一步。需要根据性能优化方案的特点,选择合适的度量指标,如响应时间、吞吐量、资源利用率等。
选择合适的监控工具对于数据的准确收集至关重要。常用的监控工具包括但不限于Prometheus、Zabbix、Nagios等。
这个请参考尼恩的:Prometheus圣经的上下两部分
完整的PDF,请在 技术自由圈 公众号获取。
数据采集是度量性能的基础。通过自动化工具定期采集性能数据,并进行深入分析,以识别性能瓶颈。
实现实时监控,当性能指标超出预设阈值时,系统应能自动发出告警,以便及时采取措施。
通过可视化手段,如Grafana等工具,将监控数据以图表的形式展现出来,使性能状况一目了然。
建立性能基线,用于衡量性能优化前后的变化,评估优化方案的效果。
存储历史监控数据,用于长期趋势分析和问题回溯。
将度量结果应用于持续的性能优化过程中,形成闭环优化机制。
确保监控系统本身的稳定性和可靠性,避免因监控系统故障而影响性能优化工作。
定期对性能优化方案进行综合评估,结合度量与监控结果,不断调整和完善优化策略。
架构师是学问,也是艺术。
架构师学问,这里架构构师至少需要掌握网络知识,硬件,软件,架构理论、架构哲学等方方面面的知识:

1.硬件知识。CPU/硬盘/内存/物理网络
2.软件知识。操作系统/数据库/应用服务器...。
3.通讯协议。TCP/IP/HTTP/MQTT....。
4.分布式知识。
架构知识。 比如说尼恩的3高架构知识图谱。
架构哲学。 比如尼恩的架构师哲学。
意志坚强。但不偏执。
善于沟通。但不花言巧语。
尼恩写的一系列架构文章,已经帮助很多小伙伴拿到了大厂offer,大家也可以收藏起来, 作为 架构的参考资料。
3万长文 秒杀圣经 : 16大绝招,完成10Wqps秒杀架构
百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现
如何做性能优化? 以上的内容,如果大家能对答如流,如数家珍,基本上 面试官会被你 震惊到、吸引到。
最终,让面试官爱到 “不能自已、口水直流”。offer, 也就来了。
在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。
很多小伙伴刷完后, 吊打面试官, 大厂横着走。
在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。
另外,如果没有面试机会,可以找尼恩来改简历、做帮扶。
遇到职业难题,找老架构取经, 可以省去太多的折腾,省去太多的弯路。
尼恩指导了大量的小伙伴上岸,前段时间,刚指导一个40岁+被裁小伙伴,拿到了一个年薪100W的offer。
……完整版尼恩技术圣经PDF集群,请找尼恩领取
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。