关于接口性能优化的思路
前几天看了一篇文章使用不同的接口方案将性能性能提高,原文在此:用了这18种方案,接口性能从11.3s降为170ms!笔者将自己的做法结合文章来做个总结,基于LabVIEW、Python、SQL来思考。
1、批量思想:批量操作数据库
笔者遇到一个软件设计不合理的问题,在监控服务器上面得程序将读取到所有的数据每隔一定周期一起写入数据库,瞬间数据量过于庞大。数据写入数据库时,磁盘IO脉冲式增加,特别是减少数据读取周期为6秒时,磁盘IO一直保持在100%,造成监控服务器十分卡顿。
具体案例在此Mysql数据库磁盘IO达到100%的解决方法。最后厂家设置了偏差值,就是如果数据在偏差内就不需要写入数据库,这样大大减少一次性写入的数据量。但是笔者以为将程序功能分模块才是最终的解决办法,将压力分担,就是削峰填谷的做法。
最近又想起LabVIEW的两个案例,此案例中有一个将数据批量写入的案例,而不是将数据一次次写入文件中。所以批量就是按照功能模块分区集中写入,但是要预防一次性大量数据写入的脉冲式压力。
2、异步思想:耗时操作,考虑放到异步执行
关于异步处理,队列、MQ、生产者消费者是笔者接触最多的例子。实现将各个功能模块解耦合,有点类似于现在的微服务的功能。数据采集、数据处理、数据文件分开来进行,中间通过队列来实现交互,完成异步处理。生产者消费者具体的案例在此最近又想起LabVIEW的两个案例。
关于MQ,UDP监听获取大量的数据,为了和后端的数据处理功能解耦合,实现异步处理。具体案例在此Python完成RabbitMQ实践。
3、空间换时间思想:恰当使用缓存。
缓存其实就是一种空间换时间的思想,就是你把要查的数据,提前放好到缓存里面,需要时,直接查缓存,而避免去查数据库或者计算的过程。Redis作为Mysql数据库缓存的简单配置,将Redis配置成Mysql数据库缓存,实现读写分离,热点数据直接读取Redis内存数据库,提供快速响应服务。
4、预取思想:提前初始化到缓存
此方法在加载配置等初始化操作时,使用方便,避免在进入程序后再来从文件或数据库中读取配置。冷数据在前期用户打开软件时进行加载,变成内存中的热数据后,相比于进入界面后再加载,更加友好。
5、池化思想:预分配与循环使用
每次需要用到线程,都去创建,就会有增加一定的耗时,而线程池可以重复利用线程,避免不必要的耗时。Python实现数据库连接池化, 在并发多个sql语句时,要创建多个数据库连接,数据库连接时稀有资源,MySQL的默认max connections是151。数据库池化技术用在避免每执行一个sql语句就创建一个数据库连接,同时限制某个业务的连接数量。
LabVIEW利用数据库连接池来完成DB操作,基于虚拟仪器,将打开3个数据库连接入队列,然后入队列依次执行数组中的SQL语句,执行完毕后再将数据库连接入队列。
6、事件回调思想:拒绝阻塞等待
不用阻塞等待系统B的接口,而是先去做别的操作。等系统B的接口处理完,通过事件回调通知,我们接口收到通知再进行对应的业务操作即可。
在LabVIEW中,“运行VI”调用节点的“Wait Until Done”属性设置为False,表示被调用VI被执行、显示界面后,调用VI还可以继续去干别的事情。
7、调用由串行改为并行
Python多线程实践,python的全局解释器锁(GIL)会限制并发,在任意时刻只有一个线程在处理python代码。程序是cpu密集型的额,多线程无法提升程序的执行效率,如果程序是IO密集型的,多线程可以提高整个程序的下效率。python的多线程使用标准库的threading的Thread类。
8、锁粒度避免过粗
mysql存储引擎MyISAM和InnoDB的有不同之处,其中锁粒度不同,MyISAM是表锁,InnoDB是行锁。在插入业务较多的情况下,应该使用InnoDB,这也是数据库默认的模式。在插入数据较少,读取数据频繁的情况下,MyISAM的效率更高。
9、切换存储方式:文件中转暂存数据
落地数据库实在是慢的话,就可以考虑先用文件的方式暂存。先保存文件,再异步下载文件,慢慢保存到数据库。其实也是一种削峰填谷的思路。
10、索引和SQL优化
explain执行计划查看SQL语句的执行情况。