zoco

php级别性能优化分享

2017-05-17


前言

指导思想:能自动化的,要自动化;不能自动化的,要半自动化。

性能分析最理想的方式是强智能,也就是让机器独立处理所有事情,自动发现问题并解决问题。但是需要用到人工智能,深度学习等等。要学的东西还很多,暂时还做不了那么牛逼的事,既然现在强智能还不够强,那么我们暂时先用弱智能+人工确认的方式,来实现「半智能化」:用机器帮咱们做预选,人工来做最终选择,虽然依然包含了人工干预,但却可以把生产效率提升几十倍。

性能分析

  1. 方法、工具、思路
  2. 查找瓶颈
  3. 重点优化(耗时多、请求多、超过150ms的接口)
  4. 查看单个请求调用链(次数,时间)
  5. 各个性能参数变化率
  6. 机器流量,负载,内存,qps,php.ini+php-fpm.conf

性能分析-工具

xhprof源码分析: https://zoco.fun/program/Xhprof源码分析

性能分析-方法

  1. 耗时
  2. 次数
  3. 聚合分析
  4. 增量分析
  5. 实时分析
  6. 数据报表
  7. 性能报表

耗时

原则:耗时是可控的

  1. 找到耗时最多的调用:发现递归,循环,不合理的用法,异常的服务。
  2. 数据源调用耗时异常,去推动他们优化。
  3. curl替代file_get_contents并且增加超时时间。
  4. 微服务的超时时间在合理的范围内尽量小一些。

次数

原则:越少越好

  1. 找到调用次数异常的调用:寻找批量方案或者预加载方案。
  2. 对多个无上下关联的数据源并行化或者异步化。

聚合分析

  1. 能看到当前接口所有运行过的函数。
  2. 平均值处理,也避免了程序运行中的不规律事件。
  3. 统计值比孤立值更具说服力。
  4. 为增量统计做准备。

增量分析

检测每个接口多余出的方法以及此类方法的耗时从而得出业务变化对性能的影响。(对新上的代码)

实时分析

因为数据量相对较少,所以每小时跑一次数据,暂时针对各个数据源整体耗时和该接口所有微服务进行聚合。

如果有全量的日志,那么这个做起来就很有意义了。

数据报表

项目性能分析总览,调用次数,总耗时,平均耗时,趋势。

  1. 单日性能统计,天级别(次数、平均耗时、最大耗时、平均内存、最大内存)
  2. 所有uri性能总览,uri级别(uri、次数、平均耗时、最大耗时、平均内存、最大内存、微服务(Max)、Redis(Max)、Mongo(Max))
  3. 单个uri性能分析(时间、耗时、内存、微服务、Redis、Mongo、Host)
  4. 单个uri性能整合分析(耗时分布饼图、整体耗时、耗时分布面积图、耗时折线图、各功能耗时、实时数据)
  5. xhprof html
  6. xhprof graph

性能报表

这里是根据已有的数据进行二次分析

  1. 邮件汇总接口图表(每日邮件数据汇总)
  2. 超出150ms的接口(重点分析)
  3. 所有接口分析(接口内的方法聚合)
  4. 微服务分析(每个接口调用了哪些微服务)
  5. 微服务排行榜(所有微服务调用的耗时和次数)

性能分析-优化方案

  1. 预加载
  2. 批量
  3. 短路
  4. 降维
  5. 并行和异步化
  6. 抽象
  7. 缓存

预加载

事先将请求到的数据放到内存中,同一次请求同一份数据不要取两次,用的时候随时取(bridge)。

批量

尽量减少同一个微服务的调用,在写业务代码的时候尽量让微服务提供方提供批量的接口。

短路

将经常判断的条件放在if中条件的前面(尤其是判断条件是从数据源中取数据)

案例:

优化前:
     if($sex == ‘F’ && $region == ‘美国’ && $age >90) {}
优化后:
     if($age > 90 && $region == ‘美国’ && $sex == ’F’) {}
代码实例:
	 if (($charlet = $this->outputChatlet()) && ($this->ctx->old->loginUser->isLocal())) {}

降维

案例:API output时候需要对输出结果进行过滤

优化前:
	array_walk_recursive递归进行正则处理
优化后:
	将数组通过json_encode降维成字符串,一次正则即可

并行和异步化

在完全串行运行的系统里,一次请求总响应时间满足如下公式:

一次请求总耗时=解析请求耗时 + ∑(获取数据耗时+处理数据耗时) + 组装返回结果耗时

多次请求耗时=∑(一次请求总耗时)

解决方法:

将微服务调用并行化,将互相不依赖的微服务使用专门的服务打包调用。

并行化后请求时间总耗时公式:

多次请求总耗时=解析请求耗时 + Max(单次请求耗时) + 组装返回结果耗时

抽象

尽量构建公共方法,优化的时候会有蝴蝶效应的惊喜,风险是有,但收益更大,要大胆试错。

缓存

科学的设置缓存

  1. 查询量
  2. 缓存item数量
  3. 命中率
  4. 查询耗时
  5. 占用内存

性能分析-自动化(开发中)

根据聚合分析和增量分析

  1. 找出接口的瓶颈
  2. 新上的业务(或者下掉的业务)对性能的影响
  3. 每天报表中性能波动的原因

实例:如何进行一次简单的性能分析

https://zoco.fun/program/如何进行一次简单的性能分析