大厂性能优化 10大顶奢方案
尼恩说在前面
如何做性能优化,有哪些方案? 你用过哪些 性能优化方案?
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,后台回复:领电子书
大厂 性能优化的 10大方案
本文目录
- 大厂性能优化 10大顶奢方案
- 尼恩说在前面
- 大厂 性能优化的 10大方案
- 1. 代码优化
- 1.1 性能问题的识别
- 1.2 循环优化
- 1.3 算法优化
- 1.4 减少函数调用
- 1.5 内存管理
- 1.6 并发和多线程
- 1.7 代码重构
- 1.8 避免不必要的计算
- 1.9 编译器优化
- 1.10 性能测试
- 2. 缓存优化
- 2.1 常规优化的三大银弹
-1 缓存优化
-2 多线程优化
-3 异步优化
- 2.2 缓存的作用与重要性
- 2.3 常见的缓存实现方式
-2.3.1 内存缓存
-2.3.2 分布式缓存
-2.3.3 浏览器缓存
-2.3.4 CDN缓存
- 2.4 缓存策略的优化技巧
-2.4.1 缓存粒度控制
-2.4.2 缓存失效策略
-2.4.3 缓存预热
-2.4.4 缓存一致性
- 2.5 缓存的实际应用案例
-2.5.1 电商网站
-2.5.2 社交媒体平台
-2.5.3 金融服务
-2.5.4 缓存策略的监控与调优
-2.5.5 缓存的三大经典问题
- 3. 异步优化
- 3.1 异步优化的概念与优势
- 3.2 异步优化的应用场景
- 3.3 实现优化处理的技术
- 3.4 异步优化的最佳实践
- 3.5 全链路 异步
- 3.6 异步优化的性能考量
- 4. 多线程优化
- 4.1 多线程优化
- 4.2 示例代码
-总结一下,默认 ForkJoinPool.commonPool() 线程池缺点
- 4.3 实例2: CompletableFuture+ 自定义线程池
- 5. 前端优化
- 5.1 浏览器访问优化
- 5.2 CDN加速
- 5.3 反向代理
- 5.4 Web组件分离
- 5.5 前端服务化
- 6. 微服务架构优化
- 6.1 架构设计原则
- 6.2 微服务架构
- 6.3 服务网格与无入侵的微服务治理
- 6.4 容器化与编排
- 6.5 大型中台化架构
- 7. 硬件升级
- 7.1 存储设备升级
- 7.2 内存扩展
- 7.3 CPU升级
- 7.4 网络设备升级
- 7.5 显卡升级
- 7.6 其他硬件组件
- 8. 数据库优化
- 8.1 索引优化
- 8.2 查询优化
- 8.3 缓存优化
- 8.4 硬件优化
- 8.5 数据库配置优化
- 8.6 分库分表
- 8.7 读写分离
- 8.8 索引重建、适当反范式化、批量执行
- 8.9 定期维护
- 8.10 监控与分析
- 9. 过载保护优化
- 10. 度量与监控系统
- 10.1 度量指标的确立
- 10.2 监控工具的选择
- 10.3 数据采集与分析
- 10.4 实时监控与告警
- 10.5 可视化展示
- 10.6 性能基线的建立
- 10.7 历史数据的存储与对比
- 10.8 度量结果的应用
- 10.9 监控系统的可靠性与健壮性
- 10.10 性能优化方案的综合评估
- 总结:架构学问,也是艺术
- 说在最后:有问题找老架构取经
1. 代码优化
1.1 性能问题的识别
1.2 循环优化
// 原始代码
for (int i = 0; i < n; i++) {
double x = pow(a[i], 2); // 重复计算平方
y += x;
}
// 优化后的代码
double x;
for (int i = 0; i < n; i++) {
x = a[i] * a[i]; // 直接计算乘积,避免使用pow函数
y += x;
}
1.3 算法优化
1.4 减少函数调用
1.5 内存管理
1.6 并发和多线程
1.7 代码重构
1.8 避免不必要的计算
将重复使用的计算结果存储起来,避免在每次需要时重新计算。 通过重新组织代码逻辑,可以完全避免无效循环。
// 原始代码
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]);
}
1.9 编译器优化
1.10 性能测试
2. 缓存优化
2.1 常规性能优化的三大银弹
1 缓存优化
2 多线程优化
3 异步优化
2.2 缓存的作用与重要性
2.3 常见的缓存实现方式
2.3.1 内存缓存
2.3.2 分布式缓存
2.3.3 浏览器缓存
2.3.4 CDN缓存
2.4 缓存策略的优化技巧
2.4.1 缓存粒度控制
2.4.2 缓存失效策略
2.4.3 缓存预热
2.4.4 缓存一致性
2.5 缓存的实际应用案例
2.5.1 电商网站
2.5.2 社交媒体平台
2.5.3 金融服务
2.5.4 缓存策略的监控与调优
2.5.5 缓存的三大经典问题
3. 异步优化
3.1 异步优化的概念与优势
非阻塞操作:异步操作不会阻塞主线程,用户界面(UI)可以保持流畅,提升用户体验。 提高资源利用率:通过异步执行,系统资源得到更高效的利用,尤其是在I/O密集型操作中。
3.2 异步优化的应用场景
网络请求:在等待网络响应时,异步处理允许应用程序继续处理用户交互。 文件读写:处理大文件或慢速存储设备时,异步读写可以避免界面冻结。 数据处理:对大量数据进行处理时,异步执行可以避免长时间占用CPU资源。
3.3 实现优化处理的技术
回调函数:一种传统的异步处理方式,通过将函数作为参数传递给另一个函数来处理完成时的逻辑。 事件循环:Node.js等环境使用事件循环来处理异步事件,提高性能和可伸缩性。 Promise:现代JavaScript中用于异步编程的对象,提供了一种更易读和更易管理的方式来处理异步操作。 Async/Await:基于Promise的语法糖,允许以同步的方式编写异步代码,提高代码的可读性。
3.4 异步优化的最佳实践
错误处理:异步代码中的错误需要特别处理,确保程序的稳定性和可靠性。 避免回调地狱:深度嵌套的回调函数难以阅读和维护,应使用Promise或Async/Await来简化代码结构。 资源管理:确保异步操作中使用的资源(如数据库连接、文件句柄)在使用后正确释放。 测试:异步代码的测试需要特别注意,确保并发和时序问题得到妥善处理。
3.5 全链路 异步
3.6 异步优化的性能考量
减少等待时间:通过异步处理,可以减少程序的等待时间,提高整体的执行效率。 优化并发:合理控制并发数量,避免过多的并发导致资源竞争和性能下降。 监控和调优:使用性能监控工具来分析异步操作的性能,根据实际情况进行调优。
4. 多线程优化
4.1 多线程优化
线程管理:合理创建和管理线程,避免线程过多导致的上下文切换开销。 同步机制:使用互斥锁、信号量等同步机制来避免竞态条件和死锁。 线程池:使用线程池来重复利用线程资源,减少线程创建和销毁的开销。 任务分解:将大任务分解为可以并行处理的小任务,提高资源利用率。
4.2 示例代码
CompletableFuture
用于处理异步任务。它提供了一种灵活的方式来处理异步计算和多线程优化。CompletableFuture
来并行下载文件的示例。java复制代码import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
public class MultiThreadedDownloader {
// 要下载的文件列表
private static final List<String> URLs = Arrays.asList(
"http://example.com/file1",
"http://example.com/file2",
"http://example.com/file3",
"http://example.com/file4",
"http://example.com/file5"
);
public static void main(String[] args) {
// 创建一个包含下载任务的 CompletableFuture 列表
List<CompletableFuture<Void>> futures = new ArrayList<>();
// 遍历每个 URL,并为每个 URL 创建一个 CompletableFuture 任务
for (String url : URLs) {
futures.add(CompletableFuture.runAsync(() -> downloadFile(url)));
}
// 使用 allOf 方法等待所有任务完成
CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
// 当所有任务完成时,输出完成信息
allOf.thenRun(() -> System.out.println("All files downloaded."));
// 阻塞主线程,直到所有任务完成
allOf.join();
}
private static void downloadFile(String url) {
try {
URL website = new URL(url);
try (InputStream in = website.openStream()) {
Files.copy(in, Paths.get(url.substring(url.lastIndexOf('/') + 1)), StandardCopyOption.REPLACE_EXISTING);
System.out.println(url.substring(url.lastIndexOf('/') + 1) + " downloaded.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
具体的线程数的设置,包括CPU密集型 、IO密集型任务/混合型任务 的线程数设置,具体的算法 请参见尼恩 的《JAVA 高并发核心编程 卷2》
总结一下,默认 ForkJoinPool.commonPool() 线程池缺点
CompletableFuture
默认使用的线程池是 ForkJoinPool.commonPool()
,commonPool是当前 JVM(进程) 上的所有 CompletableFuture、并行 Stream 共享的,commonPool 的目标场景是非阻塞的 CPU 密集型任务,其线程数默认为 CPU 数量减1,所以对于我们用java常做的IO密集型任务,默认线程池是远远不够使用的CompletableFuture
是否使用默认线程池的依据,和机器的CPU核心数有关。当CPU核心数-1>1时,才会使用默认的线程池,否则将会为每个CompletableFuture的任务创建一个新线程去执行。4.3 实例2:CompletableFuture+ 自定义线程池
@Configuration
public class ThreadPoolConfig {
//参数初始化
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数量大小
private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT-1,4));
//线程池最大容纳线程数
private static final int maxPoolSize = CPU_COUNT * 2 + 1;
//阻塞队列
private static final int workQueue = 20;
//线程空闲后的存活时长
private static final int keepAliveTime = 30;
@Bean("asyncTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
//最大线程数
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
//等待队列
threadPoolTaskExecutor.setQueueCapacity(workQueue);
//线程前缀
threadPoolTaskExecutor.setThreadNamePrefix("asyncTaskExecutor-");
//线程池维护线程所允许的空闲时间,单位为秒
threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveTime);
// 线程池对拒绝任务(无线程可用)的处理策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
@RestController
@RequestMapping("/task")
public class CompletableTaskController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
@Qualifier("asyncTaskExecutor")
private Executor asyncTaskExecutor;
@RequestMapping("testOrderTask")
public String testOrderTask(){
List<CompletableFuture<List<Integer>>> futureList = Lists.newArrayList();
// 任务1,计算3秒
CompletableFuture<List<Integer>> task1 = CompletableFuture.supplyAsync(() -> {
sleepSeconds(3L);
return Lists.newArrayList(1,2,3);
}, asyncTaskExecutor);
futureList.add(task1);
// 任务2,计算2秒,得答案5
CompletableFuture<List<Integer>> task2 = CompletableFuture.supplyAsync(() -> {
sleepSeconds(1L);
return Lists.newArrayList(4,5,6);
}, asyncTaskExecutor);
futureList.add(task2);
// 任务3,计算3秒,得答案5
CompletableFuture<List<Integer>> task3 = CompletableFuture.supplyAsync(() -> {
sleepSeconds(2L);
return Lists.newArrayList(7,8,9);
}, asyncTaskExecutor);
futureList.add(task3);
// 写法1
List<Integer> newList = futureList.stream().map(CompletableFuture::join).flatMap(List::stream).collect(Collectors.toList());
return JSON.toJSONString(newList);
}
}
5. 前端优化
5.1 浏览器访问优化
减少HTTP请求:通过合并CSS和JavaScript文件,减少服务器请求次数,降低数据传输开销。 浏览器缓存利用:通过设置合理的Cache-Control和Expires头部,使得浏览器能够缓存静态资源,减少重复加载时间。 启用压缩:服务器端启用Gzip等压缩算法,减少传输数据量,加快加载速度。
5.2 CDN加速
静态化
处理。静态 秒杀页面资源:一个html文件,包括 css、js和图片等,内容包括秒杀产品的介绍,详情,参数等等。静态秒杀静态资源文件提前缓存到CDN上,让用户能够就近访问秒杀页面。 动态秒杀的exposed-key,通过JS异步获取。秒杀暴露就是将符合条件的秒杀 暴露给用户,以便互联网用户能参与商品的秒杀。这个操作可以是商户手动完成,生产场景下的更合理的方式是系统定时任务去完成。秒杀暴露主要是生成一个 具备实效性的 exposed-key。
静态资源CDN缓存:图片、CSS、JavaScript等静态资源通过CDN分发,减少主服务器的负担,加快加载速度。 动态内容CDN支持:对于部分动态内容,使用CDN进行缓存,可以减少源站压力,提高响应速度。
5.3 反向代理
安全增强:反向代理隐藏了真实的Web服务器,增加了一层安全防护。 缓存静态内容:通过缓存机制,减少对后端服务器的请求,提高响应速度。
5.4 Web组件分离
组件并行加载:利用浏览器对不同域名的并行下载优势,提升资源加载效率。 减少Cookie传输:静态资源使用独立域名,减少Cookie在HTTP请求中的传输,降低请求大小。
5.5 前端服务化
按业务拆分服务:根据业务逻辑将应用拆分成多个微服务,实现独立部署和扩展。 数据和服务分离:将数据存储和业务逻辑分离,提高数据处理效率和应用性能。
6. 微服务架构优化
6.1 架构设计原则
6.2 微服务架构
假如流量接入层使用的是高性能的Nginx,则我们可以预估Nginx最大的并发度为:10W+,这里是以万为单位。 假设服务层我们使用的是Tomcat,而Tomcat的最大并发度可以预估为800左右,这里是以百为单位。 假设持久层的缓存使用的是Redis,数据库使用的是MySQL,MySQL的最大并发度可以预估为1000左右,以千为单位。Redis的最大并发度可以预估为5W左右,以万为单位。
服务注册:服务提供方将自己调用地址注册到服务注册中心,让服务调用方能够方便地找到自己。 服务发现:服务调用方从服务注册中心找到自己需要调用的服务的地址。 负载均衡:服务提供方一般以多实例的形式提供服务,负载均衡功能能够让服务调用方连接到合适的服务节点。并且,节点选择的工作对服务调用方来说是透明的。 服务网关:服务网关是服务调用的唯一入口,可以在这个组件是实现用户鉴权、动态路由、灰度发布、A/B 测试、负载限流等功能。 配置中心:将本地化的配置信息(properties, xml, yaml 等)注册到配置中心,实现程序包在开发、测试、生产环境的无差别性,方便程序包的迁移。 API 管理:以方便的形式编写及更新 API 文档,并以方便的形式供调用者查看和测试。 集成框架:微服务组件都以职责单一的程序包对外提供服务,集成框架以配置的形式将所有微服务组件(特别是管理端组件)集成到统一的界面框架下,让用户能够在统一的界面中使用系统。 分布式事务:对于重要的业务,需要通过分布式事务技术(TCC、高可用消息服务、最大努力通知)保证数据的一致性。 调用链:记录完成一个业务逻辑时调用到的微服务,并将这种串行或并行的调用关系展示出来。在系统出错时,可以方便地找到出错点。 支撑平台:系统微服务化后,系统变得更加碎片化,系统的部署、运维、监控等都比单体架构更加复杂,那么,就需要将大部分的工作自动化。现在,可以通过 Docker 等工具来中和这些微服务架构带来的弊端。例如持续集成、蓝绿发布、健康检查、性能健康等等。严重点,以我们两年的实践经验,可以这么说,如果没有合适的支撑平台或工具,就不要使用微服务架构。
降低系统复杂度:每个服务都比较简单,只关注于一个业务功能。 松耦合:微服务架构方式是松耦合的,每个微服务可由不同团队独立开发,互不影响。 跨语言:只要符合服务 API 契约,开发人员可以自由选择开发技术。这就意味着开发人员可以采用新技术编写或重构服务,由于服务相对较小,所以这并不会对整体应用造成太大影响。 独立部署:微服务架构可以使每个微服务独立部署。开发人员无需协调对服务升级或更改的部署。这些更改可以在测试通过后立即部署。所以微服务架构也使得 CI/CD 成为可能。 Docker 容器:和 Docker 容器结合的更好。 DDD 领域驱动设计:和 DDD 的概念契合,结合开发会更好。
微服务强调了服务大小,但实际上这并没有一个统一的标准:业务逻辑应该按照什么规则划分为微服务,这本身就是一个经验工程。有些开发者主张 10-100 行代码就应该建立一个微服务。虽然建立小型服务是微服务架构崇尚的,但要记住,微服务是达到目的的手段,而不是目标。微服务的目标是充分分解应用程序,以促进敏捷开发和持续集成部署。 微服务的分布式特点带来的复杂性:开发人员需要基于 RPC 或者消息实现微服务之间的调用和通信,而这就使得服务之间的发现、服务调用链的跟踪和质量问题变得的相当棘手。 分区的数据库体系和分布式事务:更新多个业务实体的业务交易相当普遍,不同服务可能拥有不同的数据库。CAP 原理的约束,使得我们不得不放弃传统的强一致性,而转而追求最终一致性,这个对开发人员来说是一个挑战。 测试挑战:传统的单体WEB应用只需测试单一的 REST API 即可,而对微服务进行测试,需要启动它依赖的所有其他服务。这种复杂性不可低估。 跨多个服务的更改:比如在传统单体应用中,若有 A、B、C 三个服务需要更改,A 依赖 B,B 依赖 C。我们只需更改相应的模块,然后一次性部署即可。但是在微服务架构中,我们需要仔细规划和协调每个服务的变更部署。我们需要先更新 C,然后更新 B,最后更新 A。 部署复杂:微服务由不同的大量服务构成。每种服务可能拥有自己的配置、应用实例数量以及基础服务地址。这里就需要不同的配置、部署、扩展和监控组件。此外,我们还需要服务发现机制,以便服务可以发现与其通信的其他服务的地址。因此,成功部署微服务应用需要开发人员有更好地部署策略和高度自动化的水平。 总的来说(问题和挑战):API Gateway、服务间调用、服务发现、服务容错、服务部署、数据调用。
6.3 服务网格与无入侵的微服务治理
从最原始的主机之间直接使用网线相连 网络层的出现 集成到应用程序内部的控制流 分解到应用程序外部的控制流 应用程序的中集成服务发现和断路器 出现了专门用于服务发现和断路器的软件包/库,如 Twitter 的 Finagle 和 Facebook 的 Proxygen,这时候还是集成在应用程序内部 出现了专门用于服务发现和断路器的开源软件,如 Netflix OSS、Airbnb 的 synapse 和 nerve 最后作为微服务的中间层 Service Mesh 出现
应用程序间通讯的中间层 轻量级网络代理 应用程序无感知 解耦应用程序的重试/超时、监控、追踪和服务发现
Linkerd(https://github.com/linkerd/linkerd):第一代 Service Mesh,2016 年 1 月 15 日首发布,业界第一个 Service Mesh 项目,由 Buoyant 创业小公司开发(前 Twitter 工程师),2017 年 7 月 11 日,宣布和 Istio 集成,成为 Istio 的数据面板。 Envoy(https://github.com/envoyproxy/envoy):第一代 Service Mesh,2016 年 9 月 13 日首发布,由 Matt Klein 个人开发(Lyft 工程师),之后默默发展,版本较稳定。 Istio(https://github.com/istio/istio):第二代 Service Mesh,2017 年 5 月 24 日首发布,由 Google、IBM 和 Lyft 联合开发,只支持 Kubernetes 平台,2017 年 11 月 30 日发布 0.3 版本,开始支持非 Kubernetes 平台,之后稳定的开发和发布。 Conduit(https://github.com/runconduit/conduit):第二代 Service Mesh,2017 年 12 月 5 日首发布,由 Buoyant 公司开发(借鉴 Istio 整体架构,部分进行了优化),对抗 Istio 压力山大,也期待 Buoyant 公司的毅力。 nginMesh(https://github.com/nginmesh/nginmesh):2017 年 9 月首发布,由 Nginx 开发,定位是作为 Istio 的服务代理,也就是替代 Envoy,思路跟 Linkerd 之前和 Istio 集成很相似,极度低调,GitHub 上的 star 也只有不到 100。 Kong(https://github.com/Kong/kong):比 nginMesh 更加低调,默默发展中。
微服务是弱入侵的服务治理框架:业务程序 需要 依赖 服务治理框架的 注解、配置文件、api 接口,完成RPC调用、限流、熔断和监控 等工作。 服务网格是 无入侵的 服务治理框架:业务程序 专注 业务逻辑,业务程序对 服务直接的 RPC调用、限流、熔断和监控 ,彻底无感知。。
6.4 容器化与编排
6.5 大型中台化架构
Tips: 在云服务厂商的支持下,集群架构已经能够支撑较大的用户流量了。云服务器、云数据库等云端基础服务的支撑能力,也比前些年要好了很多,升级扩容也方便了许多,已经足够满足一般规模下的系统性能需求了。所以,不要觉得业务量一上来,就立马要改系统架构,因为这反而可能带来不必要的麻烦。有时,直接通过升级云服务器/云数据库等的配置,就可以解决问题了。(通常来说,常规业务场景下,通过一些优化改造,顶住1万以内的QPS是没有太大问题的)。
7. 硬件升级
使用高性能硬件:升级CPU、内存和存储设备,提高应用的运行速度和响应能力。 利用固态硬盘(SSD):相比传统硬盘,SSD提供更快的数据读写速度,提升前端应用的加载性能。
7.1 存储设备升级
传统机械硬盘(HDD)升级到固态硬盘(SSD),SSD的读写速度远超HDD,可以大幅度减少数据访问时间。 使用NVMe接口的SSD,相比SATA接口的SSD,NVMe SSD提供更高的传输速率和更低的延迟。
7.2 内存扩展
对于服务器和工作站,增加RAM是常见的性能提升手段,特别是在处理大量数据或运行内存密集型应用时。
7.3 CPU升级
选择具有更多核心或更高主频的CPU,可以提升并行处理能力和单线程任务的处理速度。
7.4 网络设备升级
升级网络接口卡(NIC)到10Gbps或更高速率,可以提高数据传输速度,减少网络延迟。
7.5 显卡升级
7.6 其他硬件组件
高质量的电源供应器可以提供稳定的电力,避免电力问题影响系统稳定性。 有效的散热系统可以防止硬件过热,保持系统在最佳状态运行。
8. 数据库优化
8.1 索引优化
选择性索引:为查询条件中的列创建索引,特别是那些具有高选择性的列,可以快速定位到特定的数据行。 复合索引:在多个列上创建索引,可以提高查询效率,尤其是当查询条件中包含这些列时。 索引维护:定期对索引进行维护,如重建索引,以减少索引碎片,保持索引的高效性。
8.2 查询优化
减少子查询:避免在查询中使用子查询,改用连接查询(JOIN)来提高性能。 避免SELECT:指定需要的列名,而不是使用SELECT *,减少数据的检索量。 使用合适的JOIN类型:根据实际情况选择合适的JOIN操作,如INNER JOIN、LEFT JOIN等。
8.3 缓存优化
使用内存缓存:如Redis或Memcached,将频繁查询的结果缓存起来,减少对数据库的直接访问。 本地缓存:在应用层面实现数据缓存,减少对远程数据库的请求。
8.4 硬件优化
升级CPU:使用多核处理器可以提高并行处理能力。 增加内存:更多的内存可以提供更大的缓存空间,减少磁盘I/O操作。 使用SSD:固态硬盘相比传统硬盘有更快的读写速度,可以大幅提升数据库性能。
8.5 数据库配置优化
调整缓冲区大小:根据系统内存和数据库使用情况,合理设置缓冲区大小。 并发连接数:根据服务器性能和应用需求,调整数据库的最大连接数。
8.6 分库分表
垂直分割:将表中的列分成不同的部分,存储在不同的表或数据库中。 水平分割:按照某种规则,将表中的数据行分布到多个表或数据库中。
按范围分表:根据某一字段的范围进行拆分,如:按日期、ID范围...等。 按哈希分表:根据某一字段的哈希值进行拆分,保证数据均匀分布。
8.7 读写分离
主从复制:使用主数据库处理写操作,从数据库处理读操作。 负载均衡:通过负载均衡技术,合理分配读操作到各个从数据库。
主库(Master):负责处理所有的写操作(比如:插入、更新、删除......)、和写操作相关的事务; 从库(Slave):负责处理读操作(查询),通过主从复制机制从主库同步数据; 复制机制:主库将数据更改记录到二进制日志(binlog),从库读取并执行这些日志中的操作,以保持与主库的数据一致性。
8.8 索引重建、适当反范式化、批量执行
sql复制代码-- 重建指定表上的所有索引
ALTER TABLE table_name ENGINE=InnoDB;
-- 重建指定索引
ALTER TABLE table_name DROP INDEX index_name, ADD INDEX index_name (column_name);
-- 用户表
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,
order_total DECIMAL(10, 2),
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
-- 反范式化后的订单表
CREATE TABLE orders (
order_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
user_name VARCHAR(100),
order_total DECIMAL(10, 2)
);
-- 批量插入示例
INSERT INTO orders (user_id, user_name, order_total) VALUES
(1, 'Alice', 99.99),
(2, 'Bob', 49.99),
(3, 'Charlie', 19.99);
8.9 定期维护
数据清理:定期清理无用数据,释放存储空间。 索引重建:定期重建索引,避免索引碎片化。
8.10 监控与分析
性能监控:使用工具监控数据库的运行状态,如CPU使用率、内存使用率、磁盘I/O等。 慢查询日志:分析慢查询日志,找出性能瓶颈并进行优化。
9. 过载保护优化
限流(Rate Limiting):对进入系统的请求数量进行限制,以防止系统过载。 熔断(Circuit Breaker):当系统检测到一定数量的连续错误或异常时,自动断开服务的某些部分,以防止问题扩散。 快速失败(Fail Fast):在检测到严重问题时,系统快速失败并通知用户,而不是尝试继续执行可能导致更多问题的复杂操作。 降级服务(Service Degradation):在系统负载过高时,有选择地降低某些非关键服务的优先级或质量,以保证关键服务的正常运行。 资源隔离:将关键资源与非关键资源隔离,确保关键操作即使在高负载下也能获得所需资源。 动态扩缩容:根据系统负载动态调整资源分配,如自动增加服务器数量或资源分配。
10. 度量与监控系统
10.1 度量指标的确立
10.2 监控工具的选择
prometheus学习圣经Part1:使用prometheus+Grafana实现指标监控 prometheus学习圣经Part2:使用prometheus+Alertmanager实现指标预警
10.3 数据采集与分析
10.4 实时监控与告警
10.5 可视化展示
10.6 性能基线的建立
10.7 历史数据的存储与对比
10.8 度量结果的应用
10.9 监控系统的可靠性与健壮性
10.10 性能优化方案的综合评估
总结:架构学问,也是艺术
说在最后:有问题找老架构取经
被裁之后, 空窗一年/空窗二年, 如何 起死回生 ?
空窗2年案例:42岁被裁2年,天快塌了,急救1个月,拿到开发经理offer,起死回生
空窗半年案例:35岁被裁6个月, 职业绝望,转架构急救上岸,DDD和3高项目太重要了
被裁之后,100W 年薪 到手, 如何 人生逆袭?
年薪100W,底层逻辑是什么? 如何实现年薪百万? 如何远离 中年危机?
年薪100W案例2:40岁小伙被裁6个月,跟着尼恩猛卷3月硬核技术,100W年薪逆袭 ,上岸秘诀:首席架构/总架构
其他 历史逆袭案例,包含AI、大数据、golang、Java 等
实现职业转型,极速上岸
关注职业救助站公众号,获取每天职业干货
助您实现职业转型、职业升级、极速上岸
---------------------------------
实现架构转型,再无中年危机
关注技术自由圈公众号,获取每天技术千货
一起成为牛逼的未来超级架构师
几十篇架构笔记、5000页面试宝典、20个技术圣经
请加尼恩个人微信 免费拿走
暗号,请在 公众号后台 发送消息:领电子书
如有收获,请点击底部的"在看"和"赞",谢谢