vlambda博客
学习文章列表

如何进行软件性能调优 by onedayday

学习的一天天
专注大数据技术知识分享。数据仓库、数据中台、数据湖、Flink、Spark、Hive、OLAP、ClickHouse、Hudi、Doris...... 让我们一起study onedayday!
5篇原创内容
Official Account

- 调优原则、目的、手段


  - 平衡


    - 性能置换


      - 空间换时间

        - 全量


      - 内存换CPU

        - 缓存


      - CPU换空间、网络IO


        - 压缩


        - 序列化&反序列化


- 调优的本质


  - 根据木桶理论,最短的木板决定了木桶的容量,因此,对于一只有短板的木桶,其他木板调节得再高也无济于事,最短的木板才是木桶容量的瓶颈。


- 关于软件性能优化,有个著名的论断。


  - \1. 你不能优化一个没有经过性能测试的软件。


    - 软件的主要性能指标包括:


      - 响应时间:完成一次任务(请求)花费的时间。


      - 并发数:同时处理的任务数(请求数)。


      - 吞吐量:单位时间完成的任务数(请求数、事务数、查询数……)。


      - 性能计数器:System Load,线程数,进程数,CPU、内存、磁盘、网络使用率等。


    - 如果没有性能指标,我们也就不清楚软件性能的瓶颈,优化前和优化后也是无从对比。这样的优化工作只能是主观臆断:别人这样做说性能好,我们也这样优化。


  - \2. 你不能优化一个你不了解其架构设计的软件。

    - 而如果不了解软件的架构设计,你可能根本无从判断性能瓶颈产生的根源,也不知道该从哪里优化。


- 性能优化的一般过程是:


  - \1. 做性能测试,分析性能状况和瓶颈点。


  - \2. 针对软件架构设计进行分析,寻找导致性能问题的原因。

    - 架构优化的关键是识别瓶颈,这类优化有很多套路:

      - 比如通过负载均衡做分布式改造,比如用多线程协程做并行化改造,比如用消息队列做异步化和解耦,比如用事件通知替代轮询,比如为数据访问增加缓存,比如用批处理+预取提升吞吐,比如IO与逻辑分离、读写分离等等。


  - \3. 修改相关代码和架构,进行性能优化。


  - \4. 做性能测试,对比是否提升性能,并寻找下一个性能瓶颈。


- 性能调优的本质我们可以归纳为 4 点。


  - 1.性能调优不是一锤子买卖,补齐一个短板,其他板子可能会成为新的短板。因此,它是一个动态、持续不断的过程。


  - 2.性能调优的手段和方法是否高效,取决于它针对的是木桶的长板还是瓶颈。针对瓶颈,事半功倍;针对长板,事倍功半。


  - 3.性能调优的方法和技巧,没有一定之规,也不是一成不变,随着木桶短板的此消彼长需要相应的动态切换。


  - 4.性能调优的过程收敛于一种所有木板齐平、没有瓶颈的状态。


- 运行时诊断


  - 对于任务的执行情况,Spark UI 提供了丰富的可视化面板,来展示 DAG、Stages 划分、执行计划、Executor 负载均衡情况、GC 时间、内存缓存消耗等等详尽的运行时状态数据;


  - 对于硬件资源消耗,开发者可以利用 Ganglia 或者系统级监控工具,如 top、vmstat、iostat、iftop 等等来实时监测硬件的资源利用率;


  - 特别地,针对 GC 开销,开发者可以将 GC log 导入到 JVM 可视化工具,从而一览任务执行过程中 GC 的频率和幅度。


- 角度


  - 从硬件资源消耗的角度切入

    - 从硬件的角度出发,计算负载划分为计算密集型、内存密集型和 IO 密集型。


  - 并不是所有负载都能明确划分出资源密集类型。比如说,Shuffle、数据关联这些数据分析领域中的典型场景,它们对 CPU、内存、磁盘与网络的要求都很高,任何一个环节不给力都有可能形成瓶颈。因此,就性能瓶颈定位来说,


  - 除了从硬件资源的视角出发,我们还需要关注典型场景。


- 系统化的性能调优方法论归纳为 4 条:


  - 通过不同的途径如专家经验或运行时诊断来定位性能瓶颈;


  - 从不同场景(典型场景)、不同视角(硬件资源)出发,综合运用不同层面(应用代码、Spark 配置项)的调优手段和方法;


  - 随着性能瓶颈的此消彼长,动态灵活地在不同层面之间切换调优方法;


  - 让性能调优的过程收敛于不同硬件资源在运行时达到一种平衡、无瓶颈的状态。


- 从基本的开发原则、配置项、Shuffle 以及硬件资源这四个方面,去学习一些通用的调优方法和技巧,它们会适用于所有的计算场景。


  - 先从应用开发的角度入手,去探讨开发阶段应该遵循的基础原则。如果能在开发阶段就打好基础、防患于未然,业务应用的执行性能往往会有个不错的起点。开发阶段就像学生时代的考卷,虽然有很难的拔高题,但只要我们稳扎稳打,答好送分的基础题,成绩往往不会太差。


  - 这些“基础题”对应的就是工作中一些“常规操作”,比如 Filter + Coalesce 和用 mapPartitions 代替 map,以及用 ReduceByKey 代替 GroupByKey 等等。我相信,你在日常的开发工作中肯定已经积累了不少。但是据我观察,很多同学在拿到这些技巧之后,都会不假思索地“照葫芦画瓢”。不少同学反馈:“试了之后怎么没效果啊?算了,反正能试的都试了,我也实在没有别的调优思路了,就这样吧”。


- “常规操作”可以归纳为三类:


  - 坐享其成

    - 设置相关的配置项,或是调用相应的 API 充分享用框架自身带来的性能优势。


  - 能省则省、能拖则拖


    - 省的是数据处理量,因为节省数据量就等于节省计算负载,更低的计算负载自然意味着更快的处理速度;拖的是 Shuffle 操作,因为对于常规数据处理来说,计算步骤越靠后,需要处理的数据量越少,Shuffle 操作执行得越晚,需要落盘和分发的数据量就越少,更低的磁盘与网络开销自然意味着更高的执行效率。


    - 尽量把能节省数据扫描量和数据处理量的操作往前推;


      - 谓词下推


      - 过滤和列剪枝这些可以节省数据访问量的操作尽可能地往前推


    - 尽力消灭掉 Shuffle,省去数据落盘与分发的开销;


    - 如果不能干掉 Shuffle,尽可能地把涉及 Shuffle 的操作拖到最后去执行。

      - 对数据进行展开、抽取、过滤之后,再对记录去重。


  - 跳出单机思维

    - 在日常的开发工作中,我们要谨防单机思维模式,摆脱单机思维模式有利于培养我们以性能为导向的开发习惯。


--END--

▼ 关注「学习的一天天」,获取更多技术干货 

学习的一天天
专注大数据技术知识分享。数据仓库、数据中台、数据湖、Flink、Spark、Hive、OLAP、ClickHouse、Hudi、Doris...... 让我们一起study onedayday!
5篇原创内容
Official Account