【性能调优】高性能实践

缓存思想

性能优化,缓存为王,所以开始先介绍一下缓存。缓存在我们的架构设计中无处不在,常规请求是浏览器发起请求,请求服务端服务,服务端服务再查询数据库中的数据,每次读取数据都至少需要两次网络 I/O,性能会差一些,我们可以在整个流程中增加缓存来提升性能。

异步化处理

  • 例如 Redis 的 bgsave,bgrewriteof 就是分别用来异步保存 RDB 跟 AOF 文件的命令,bgsave 执行后会立刻返回成功,主线程 fork 出一个线程用来将内存中数据生成快照保存到磁盘,而主线程继续执行客户端命令;
  • Redis 删除 key 的方式有 del 跟 unlink 两种,对于 del 命令是同步删除,直接释放内存,当遇到大 key 时,删除操作会让 Redis 出现卡顿的问题,而 unlink 是异步删除的方式,执行后对于 key 只做不可达的标识,对于内存的回收由异步线程回收,不阻塞主线程。
  • MySQL 的主从同步支持异步复制、同步复制跟半同步复制。异步复制是指主库执行完提交的事务后立刻将结果返回给客户端,并不关心从库是否已经同步了数据;同步复制是指主库执行完提交的事务,所有的从库都执行了该事务才将结果返回给客户端;半同步复制指主库执行完后,至少一个从库接收并执行了事务才返回给客户端。有多种主要是因为异步复制客户端写入性能高,但是存在丢数据的风险,在数据一致性要求不高的场景下可以采用,同步方式写入性能差,适合在数据一致性要求高的场景使用。
  • 此外对于 Kafka 的生产者跟消费者都可以采用异步的方式进行发送跟消费消息,但是采用异步的方式有可能会导致出现丢消息的问题。对于异步发送消息可以采用带有回调函数的方式,当发送失败后通过回调函数进行感知,后续进行消息补偿。
  • 非核心功能,异步处理是将发送消息这个动作发送消息到消息队列中,不同的场景消费消息队列中的消息进行各自逻辑的处理,这种设计保证了写入性能,也解耦不同场景业务逻辑,提高系统可维护性。

并行化处理

  • 线程的并发处理(线程池),将多个串行的 I/O 操作改为并行处理,缩短接口的响应时长
  • 对于 I/O 存在相互依赖的情况,可以进行多阶段分批并行化处理(CompletableFuture)
  • Redis6.0版本引入了多线程模型,多个IO线程处理网络请求
  • Redis 的切片集群
  • Kafka多分区,多个消费者并行处理

批量化处理

  • Kafka批量发送消息处理
  • Redis持久化,执行命令写入AOF 缓冲区,再写入到磁盘中,AOF通常配置为 everysec 批量写入到磁盘
  • 批量查:
    • 数据库一次批量查询数据,节省网络 I/O;(注意批量的条数也会做限制,防止单批数据量过大)
  • 批量写:
    • 调下游服务接口,下游就不支持过多的批量数据,此时可以将多条数据分批并发请求。

分片化

  • Redis 集群是将数据自动分片到多个节点上,每个节点负责数据的一部分,每个节点都可以对外提供服务,突破单机 Redis 存储限制跟读写上限,提高整个服务的高并发能力。除了官方推出的集群模式,代理模式 codis 等也是将数据分片到不同节点,codis 将多个完全独立的 Redis 节点组成集群,通过 codis 转发请求到某一节点,来提高服务存储能力和读写性能。
  • 同样的 Kafka 中每个 topic 也支持多个 partition,partition 分布到多个 broker 上,减轻单台机器的读写压力,通过增加 partition 数量可以增加消费者并行消费消息,提高 Kafka 的水平扩展能力和吞吐量。

顺序写

  • MySQL 的 InnoDB 存储引擎在创建主键时通常会建议使用自增主键,而不是使用 uuid。最主要的原因是 InnoDB 底层采用 B+树用来存储数据,每个叶子结点是一个数据页,存储多条数据记录,页面内的数据通过链表有序存储,数据页间通过双向链表存储。由于 uuid 是无序的,有可能会插入到已经空间不足的数据页中间,导致数据页分裂成两个新的数据页以便插入新数据,影响整体写入性能。
  • 此外 MySQL 中的写入过程并不是每次将修改的数据直接写入到磁盘中,而是修改内存中 buffer pool 内存储的数据页,将数据页的变更记录到 undolog 和 binlog 日志中,保证数据变更不丢失,每次记录 log 都是追加写到日志文件尾部,顺序写入到磁盘。对数据进行变更时通过顺序写 log,避免随机写磁盘数据页,提升写入性能,这种将随机写转变为顺序写的思想在很多中间件中都有所体现。
  • kakfa 中的每个分区是一个有序不可变的消息队列,新的消息会不断的添加的 partition 的尾部,每个 partition 由多个 segment 组成,一个 segment 对应一个物理日志文件,kafka 对 segment 日志文件的写入也是顺序写。顺序写入的好处是避免了磁盘的不断寻道和旋转次数,极大的提高了写入性能。

池化

  • MySQL等数据库也都提供连接池,可以预先创建一定数量的连接用于处理数据库请求。当请求到来时,可以从连接池中选择空闲连接来处理请求,请求结束后将连接归还到连接池中,避免连接创建和销毁带来的开销,提升数据库性能。
  • 创建线程池用来处理请求,在请求到来时同样的从链接池中选择空闲的线程来处理请求,处理结束后归还到线程池中,避免线程创建带来的消耗,在 Web 框架等需要高并发的场景下非常常见。
  • 线程池
  • 连接池
相关推荐
jump_jump2 天前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
小小工匠3 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
大鱼>3 天前
地平线BPU部署实战:YOLOv8在J5/X3上的算法适配与性能优化
算法·yolo·性能优化
醉颜凉3 天前
Elasticsearch高性能优化:Bulk API大规模数据导入性能调优全攻略
elasticsearch·性能优化·jenkins
隔窗听雨眠3 天前
C语言函数递归从入门到精通(下):性能优化与工程实践
c语言·算法·性能优化
昇腾CANN3 天前
【cann-samples系列】GroupedMatmul MX量化矩阵乘的深度性能优化实践
线性代数·性能优化·矩阵·昇腾·cann
霸道流氓气质3 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
步步为营DotNet3 天前
Blazor 与 Microsoft.Extensions.AI 在客户端性能优化中的协同应用
人工智能·microsoft·性能优化
不能只会打代码4 天前
边缘视频分析平台的架构设计与性能优化——从750ms到190ms的调优之路
java·spring boot·redis·性能优化·边缘计算·物联网竞赛
山东点狮信息科技有限公司4 天前
企业级 MES 制造执行系统架构设计与实践
spring cloud·性能优化·系统架构·策略模式·点狮