该部分笔记源于慕课视频听讲后所记录的笔记,有一些优化在以前的项目中曾经使用过,大部分并没有真正做过。毕竟很少有一开始写代码就考虑优化,都是项目运行一段时间后逐渐改良。一些项目还来不及优化就离职,一些上线后并不怎么使用,也就谈不上优化了。而且之前使用过XHProf来分析过,大部分耗时的任务基本都是在框架加载上和数据库查询上。一般来说,PHP的性能优化都是数据库优化上。
一年前在望京SOHO作业盒子面试,他说你写的兑换码,那你是怎么处理并发的?我们项目很小,没考虑并发。那你这不考虑并发,两个请求如果同时发出,那不是给公司造成损失了吗?是呀,如果真的存在并发请求,是极可能给数据库记录造成混乱的。毕竟是第三份工作,待的都是小公司,很少会考虑这些,面试也没什么说的,就结结巴巴的敷衍过去了。后来我想了下,那如果要考虑并发,该怎么写,也一直没弄明白。后来的一段时间在世纪佳缘面试,我也问了同样的问题。他说PHP都是按进程来的,我们也没有考虑并发,都是一个进程过来就处理一个进程。我才知道,其实问这些,多半没什么意义,一个项目真的到了考虑并发的时候,肯定会有办法的。后来看了一些消息队列的东西,发觉并发编程其实挺不容易,要考虑很多东西。
1. 性能问题
- 语法使用不恰当
- 使用它做了不擅长做的事情
- 连接的服务提供不给力
- 语言自身的短板
- 不知道的问题
2. PHP的性能问题,占整体项目性能一般不会到50%
性能优化项目,不要局限于仅优化PHP
3. 解决方向
- 语言级的性能优化
- 周边问题性能的优化
- 语言自身的分析、优化(底层C的优化)
容易 —-> 困难
4. ab(Apache Benchmark)压力测试工具
./ab -n2000 -c100 http://127.0.0.1
-n 请求数
-c 并发数
目标测试地址
5. 语言级别
- 少写代码,多用php自身能力
- 自写的代码冗余较多,可读性不佳,并且性能低
- 编译解析为底层语言,每一次请求都会处理一遍,开销较大
- 多使用内置变量、常量、函数
6. 代码运行流程
- .php->源代码文件
- Scanner->逐行扫描
- Exprs->转码
- Parser->解析
- Opcodes->生成code码(大多数缓存机制的缓存位置)
- Exec->执行
- Output->输出
7. 内置函数性能优劣
- 内置函数之间依然存在快慢的差别,多去了解内置函数的时间复杂度
- 尽可能少用魔法函数,性能不佳
为了给PHP程序员省事,语言为此做了很多
尽可能规避使用魔法函数
(#time php test.php)time能直接看到一个程序的运行开销,只对但文本,意义不大
避免使用产生额外开销的错误抑制符号@,在该行代码开始前、结束后,增加Opcode,忽略报错
8. vld扩展
dumps all the opcode
显示opcode码
9. 有内存回收机制,但也请小心使用内存
利用unset()即是释放不使用的内存,unset()会出现注销不掉的情况
10. 尽量少使用正则表达式
回溯开销大,没有金刚钻别揽瓷器活;利用字符串处理函数,使用相同的逻辑
11. 避免在循环内做运算
循环内的计算式将会被重复计算
12. 减少计算密集型业务
- 大批量数据处理,日志分析
- 语言特性不适合做大数据量运算
- 适合衔接WebServer与后端服务,UI呈现
13. 周边问题分析
- Linux运行环境
- 服务器上的硬盘(硬件)
- 数据库(软件)
- 内存(redis部分,memcached缓存直接借助内存)
- 网络连接(带宽,介质)
14. 常见的开销场景
- 读写内存->直接与底层交互,开销最小
- 读写数据库->使用内存作为缓存,热点数据等异步写入文件
- 读写磁盘
- 读写网络数据->所有网络请求都是通过本地socket完成的,网络延迟
15. 网络请求
- 对方接口的不确定因素
- 网络稳定性
16. 设置超时时间
- 连接超时 200ms
- 读超时 800ms
- 写超时 500ms
17. 将串行请求并行化
- 使用curlmulti*()扩展,超时返回依赖最长超时时间
- 使用swoole扩展
18. 接口输出
- 压缩,Gzip
- 利于数据输出,Client端更快获取接口数据
- 额外的CPU开销
- 返回几十K时,效果不好
19. 缓存复用
- 多次请求,内容不变的情况
- 优先查找缓存数据
20. 重叠时间窗口
- 并行
- 任务之间没有依赖时可使用
21. 旁路方案
中间使用并行
22. XHProf
分析代码运行开销。
23. Opcode Cache: PHP扩展APC
- 通过PHP扩展代替原PHP代码中的高频逻辑
- Runtime优化: HHVM
慕课视频: 课程来源