如何进行系统性能优化

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

前言

不战而屈人之兵,善之善者也

性能优化的第一原则是,通过测试,日志,profiling 分析出哪有问题,然后有的放失。

性能优化时持久战,在深入理解业务后,结合系统响应,系统吞吐,系统并发量指标再对系统进行优化

一般来说,一个系统有性能问题: 有可能是一下几方面: CPU, 内存, IO(磁盘IO,网络IO).

性能优化的目标是追求合适的性价比。

性能优化前,需要深入的理解业务,代码是为了业务服务,服务于最终用户。

性能优化,可以在需求阶段,设计阶段,实现阶段。

高手总是花80%时间用来思考, 20%时间实现。

需求阶段,如果可以达到一样的目的,但是用更优方式解决, 这样稍微调整需求的基础上,能大大解决程序性能问题。

设计阶段: 架构设计,技术选型,接口设计等,这些设计如果做了不好,后续也很难优化。

实现阶段: 一个函数的,一段代码的好坏,也会影响后续的优化,静态的优化,编译时的优化,运行时的优化等。

说完了道,谈谈术。

阿里巴巴 Java 开发手册(华山版).pdf

性能优化方法

代码优化

看看代码是否有如下问题:

  • for 循环是否过多
  • 是否做了很多无谓的条件判断
  • 做了重复逻辑

go 中有 pprof 工具

一般代码层面可以结合火焰图观察

python 有一些 profile 结合性能分析

import profile
def a():
    sum = 0
    for i in range(1, 10001):
        sum += i
    return sum

def b():
    sum = 0
    for i in range(1, 100):
        sum += a()
    return sum
if __name__ == "__main__":
   profile.run("b()")
复制代码

数据库优化

SQL 优化

  • 可以通过 explain工具来进行调优

连接池优化

  • 查询优化
  • 连接池优化, 为了英语实现数据库连接的高效获取, 对数据库连接的限流,一般来说,一个应用节点,通常会当前使用连接池方案。 连接池优化,一般需要结合连接池原理连接池监控参数当前业务量,决定最终的调优参数。。

分库分表

  • 读写分离
  • 多从库负载均衡
  • 集群
  • 水平和垂直分库分表

缓存优化

没有什么性能问题不是缓存解决不了的。如果有,就再加一顿,不, 是加一级缓存 !!!

缓存的本质是加速访问,访问的数据,要么是其他数据的副本,要么是之前计算结果(避免重复计算)

缓存是以空间换时间。

缓存,我们会想到,本地缓存(HashMap/ConcurrentHashMap, Ehcache, Guava Cache)

也会想到一些中间件 Redis/Tair/Memcahe

但缓存也不是万能的,需要考虑如下问题

  • 缓存的一致性问题,特别是分布式系统中强一致性的场景
  • 缓存穿透,缓存击穿等问题
  • 什么时候更新缓存,缓存的更新时效问题
  • 缓存丢失怎么办?

并发

一个线程或者说一个协程goroutine干不完,可以启多个协程干。并发提高了系统的吞吐,又减少用户的平局等待时间。

多个协程或者多个线程处理用户请求,可以充分利用多核 CPU 。 还有 IO的时候,也用多线程,NIO,其实也是一种并发。

批量

有网络IO,磁盘 IO 时候,需要合并操作,批量操作,往往可以提升吞吐,提高性能。

每次读取数据的时候,批量读,防止频繁建立 IO 连接。因为当涉及到网络请求是,网络传输的消耗往往大于处理时间。

比如 mysql 中的批量插入, redis 中的 pipelinemongodbbulk operation

异步

异步也是一种优化方式,针对接口,可以做一些请求附属,非主要流程的事情。

  • 可以缩短接口响应时间, 加快用户请求,用户体验提升
  • 避免线程长时间运行等待阻塞,占用系统 CPU, 内存等机器性能。

异步的方式一般如下:

  • 新起一个线程去做一些事情,比如启动一些线程去查并行调用其他接口,等其他接口返回后,主接口组装结果返回即可
  • 也可以使用 MQ , 天生的异步处理方式,不关系处理结果,将数据发送 MQ ,交给其他系统来处理即可, 把当前的响应直接返返回,要注意的是,主接口可以不关心 MQ 处理结果,直接返回。
欢迎关注工作号:程序员财富自由之路

猜你喜欢

转载自juejin.im/post/7032515443969490974