一次性能调优过程总结

  最近对我司地图引擎进行性能调优整改,本次调优主要解决 CPU性能内存 两方面问题,本文主要介绍此次优化过程和方法进行总结。

  调优思路整体如下:

  1. 首先确认调优目标,具体指标参数看项目要求;
  2. 其次查找性能瓶颈,找出哪里占用CPU过高,哪里内存占用过多;
  3. 最后寻找解决方案,实施调优手段。

  整个过程其实和看病挺像的,先给程序把把脉,看看病在哪里,然后对症下药。

一、确认调优目标

  根据当前程序占用资源情况,预估可优化空间,然后设立调优目标,比如 :

  指标1:CPU峰值不能超过30%;

  指标2:内存不超过400M;

  指标3:...

  其实性能和内存很多时候不可兼得,更多的场景是拿空间换时间,或者拿时间换空间,但是只要优化方法得当,比之前方案更优或新技术加持下,是可以做到的。

二、查找性能瓶颈

  这个过程需要借助一些工具进行诊断,本次我使用的是 valgrind 可点击下载,下载后执行下面命令安装

  tar -jxvf valgrind-3.19.0.tar.bz2
  cd valgrind-3.19.0
  ./configure
  make
  make install

  工具的使用这里就不做过多介绍了,网上搜索下有很多相关介绍,使用也比较简单。也有同事推荐使用 performance 跑个火焰图(flame graph),运行时对 Linux 内核版本要求 4.15.0-142,后面就没有整了,perf 工具结果看起来应该更直观,推荐大家使用这个。

  通过 valgrind 提供的不同功能的命令,挂载程序跑几遍之后,基本可以锁定哪个函数耗时过多、内存占用情况、有没有内存泄漏等等。在我们地图引擎中,占用CPU和内存最多的其实是地图加载模块,整个地图大约有几个GB,地图加载 IO 读写占用了大部分CPU,以及地图缓存占用了大部分的内存。

  其实对模块比较熟悉的话,也能看出来资源消耗在哪里,但是具体耗在那个函数还是得通过专业工具把把脉。

三、寻找解决方案

  通过瓶颈分析,优化主要从地图加载模块下手。众所周知,NDS格式地图存储介质为SQLlite数据库,调优主要从两方面入手:

  1. SQLite数据库本地读写优化;
  2. 数据加载模块本身逻辑优化。

  下面主要讲解第一部分--SQLite数据库读写优化,第二部分由于业务原因仅做简单介绍,对于解决实际问题来说,还是很有经验借鉴的。

  分析业务对地图的读写逻辑,大部分时间都是读数据库,写的时候主要是地图升级的时候,结合读写情况,对数据库专门设置了读写两种模式。

  先了解下SQLite提供的一些性能优化配置项:

  • synchronous 设置磁盘的同步模式,有下面三种:

    0 或 OFF :不进行同步,写入数据后传递给操作系统完成,系统缓存满或者一定时间之后同步;
    1 或 NORMAL :sqlite2的默认模式,在关键磁盘的每个序列后同步,有小概率在断电等场景导致数据库损坏,对数据丢失不太敏感时可设置为此模式;
    2 或 FULL :sqlite3的默认模式,在每个关键磁盘操作后同步,频繁刷盘,性能较差,但是安全性高,系统崩溃或者断电不会损坏数据库文件,每写入一条记录大概需耗费100ms。

   设置时执行一条 sql 语句即可:PRAGMA synchronous = OFF;

  • journal_mode 设置日志文件的存储方式,journal为数据库事务的回滚操作提供支持,数据库 begin trans 写入时,首先写入 journal 文件中,commit 操作时,根据 journal_mode 来处理日志文件,有点类似redis的AOF方式, journal_mode 有下面几种模式:

    OFF :不保留任务日志;
    TRUNCATE :日志文件被阶段为零字节长度;
    PERSIST :日志文件保留在原地,但头部被重写,标明日志不再有效;
    MEMORY :日志记录在内存中,而不是磁盘;
    DELETE :默认模式,事务结束时,日志文件删除。读写操作时 DELETE 模式要处理各种锁,写操作是独享的,写阻塞读;读完成时才能写,读阻塞写;
    WAL :修改不直接写入数据库文件中,而是直接一个WAL的文件中,若事务失败,WAL记录被忽略,若事务成功,随后在某个checkpoint时间点写回数据库,若要继续提升性能,可修改checkpoint,具体如果写入很频繁,可定期执行 pragma wal_checkpoint(full) 来提交写入内容 

   设置时执行一条 sql 语句即可:PRAGMA journal_mode = WAL;

  • temp_store 内存模式

    0 或 DEFAULT :使用编译时的C预处理宏 TEMP_STORE来定义储存临时表和临时索引的位置;
    1 或 FILE :则存放于文件中,temp_store_directory pragma 可用于指定存放该文件的目录;
    2 或 MEMORY :临时表和索引则存放于内存中。

   设置时执行一条 sql 语句即可:PRAGMA temp_store = MEMORY;

   还有一些其它配置项,如:vacuum、optimize等,对于我们程序优化没啥帮助,这里就不过多介绍了。

  另外在内存方面,SQLite也提供的一些优化的配置项:

  • page_size 分页大小,决定着数据库最小储存单元 page 的大小。当查询记录大小大于 page_size 时,此时需要多次寻址才能完成本次操作,如果 page_size 大于查询记录大小,一次寻址即可。

   page_size 默认 4096,可配置值为512、1024、2048、4096、8192、16384、32768、65536

  • cache_size 缓存中的页面数

   默认大小为 2000 页,最小为 10 页,PRAGMA cache_size = xxx ,可动态设置缓存大小,仅当前数据库链接有效。

  • mmap_size

  mmap对I/O性能的提升大大增强,尤其是对于读操作。SQLite在OS层封装了mmap的接口,可以无缝地切换mmap和普通的I/O接口。只需配置PRAGMA mmap_size=XXX 即可开启mmap。

  通过 PRAGMA page_size/cache_size 能够查询当前页大小和缓存页数,理论上 page_size 和 cache_size 越大越好,实际需要结合硬件缓存以及数据库记录。当缓存足够大的时候,一次查询能够直接命中数据库最后一条记录,在向上调整就没有效果了;当缓存和内存资源紧张,特别是嵌入设备,根据实际场景调整,page_size 设置尽量接近需要频繁查询的记录大小。然后调整 cache_size,这样也可以一定程度控制数据库大小。

  SQLite 作为一款轻量级的嵌入式关系数据库,没有大型数据库的一些高端操作,调优也只是相对默认配置的修改,本次读写模式主要修改这些配置项,读模式时将配置联合起来利于读,写模式时将配置联合起来利于写,同时一定程度上兼顾数据一致性和安全性。本次调优配置如下:

  读:PRAGMA synchronous = OFF、journal_mode = OFF

  写:PRAGMA synchronous = NORMAL 、journal_mode = WAL

  共同:temp_store = MEMORY、mmap_size = 500000000

  上面参数建议在连接时设置下共同的配置,读写切换时再设置下对应模式的配置, page_size 和 cache_size 则需要结合硬件平台来配置。

  另外再简单介绍下业务处理逻辑方面的优化项:

  1. 升级时涉及数据下载和本地升级两步,其中有大量I/O操作,而且耗时都是分钟级别,全量升级时甚至达到小时级别,主要看数据量大小,优化思想是对耗性能集中的操作做切片处理,延时计算,每个线程周期执行其中一个切片。切片时涉及到NDS API 和 解压等源码级切片,难度还是挺大的,但是在我的一步步细化下都化繁为简,将升级时CPU飙升压下来,缺点是升级时间会有一些延长,所有切片颗粒度还要结合业务来处理;
  2. 升级批量替换表时,显示开启事务,替换结束后提交事务,所有操作只执行一次事务,大大提高IO效率;
  3. 数据缓存时调整缓存策略,使用LRU算法,只保留活跃的缓存,对于不活跃的缓存过时淘汰;
  4. 业务逻辑梳理,代码的一些细节,局部缓存调整等优化,比较杂,就不进一步展开了。

四、总结

  本次调优最终测试数据外网不便带出,这里简单总结下,按照最初制定的优化目标 CPU峰值、均值已达标,内存也有一些优化,但是离目标还差些许距离,后面考虑使用内存池进一步优化,效果可以的话到时再单独写一篇内存池原理和使用的随笔来进一步介绍。同时,我也会一步一个脚印,持续优化,尽我所能将程序结合硬件资源发挥到极致。

  本篇如果对您有帮助的话,欢迎点赞加评论,一起讨论交流,谢谢大家。

 

参考网址:

https://developer.aliyun.com/article/1206830

 

本文作者:博客园博主 KeepHopes,对大数据、人工智能领域颇感兴趣,请多多赐教!
原文链接:https://www.cnblogs.com/yuwanxian/p/17715454.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处,谢谢!
posted @ 2023-09-20 10:22  ywx-super  阅读(62)  评论(0编辑  收藏  举报