一、PHP7性能演示
1.1 性能展现
单个脚本:生成一个有50w元素的数组,逐个查找key是否存在

执行 PHP test7.php
real 0.415s
user 0.217s
sys  0.144s
执行/usr/local/php7.0.10/bin/php testphp7.php
real 0.149s
user 0.076s
sys  0.086s

在单个执行脚本紧依靠php7语言引擎解释性能提升3倍有余

1.2 新版本优化的点

大量的细节优化,检查PHP中的内置函数,思考有无提升的空间
Zval(PHP中储存变量的结构体)  zval从24位缩减至16位
内部类型zend_string( PHP中储存字符串的结构体)进行了优化
PHP数组的变化(HashTable和Zend Array)HashTable从72位减少至56位
函数调用机制的改变(Function Calling Convention)
通过宏定义和内联函数(inline),让编译器提前完成部分工作
对相应扩展的升级

更详细的新特性,请参考:http://www.php7.site/book/php7/about-30.html

二、PHP版本升级函数的变更

  1. 在升级中遇到函数变更带来的问题:记录如下

1.3.1 子类重写父类中的方法,需保证参数个数相同

PHP5.3以后有此要求,否则会报一个 E_STRICT 警告
方法名不区分大小写(一直如此),父类与子类中只有大小写不同的方法名也是重写,需要保证参数个数相同

1.3.2.调用时弃用引用传参

php5.4时被移除。
现要求:定义时使用引用参数,引用时直接使用参数传递

1.3.3 .json_encode和json_decode

① json_encode()使用:encode前需转为UTF-8格式
② json_decode使用: 
仅能对UTF-8格式的数据进行解码
如果被解码的数据中包含非小写的字面量,例如:'{"a":true,"b":"true","c":TRUE,"d":"TRUE"}', 无法被解析、解析时会产生警告(PHP5.6+)
原先decode出错时,会把源字符串直接返回,现在会返回null

1.3.4 .call_user_func()和call_user_func_array()方法

要求:传入call_user_func()的参数不能为引用传递
如: 
function increment(&$a)
{
      $a ++;
}
$a = 1;
call_user_func('increment', $a);  //错误用法  返回$a值不变call_user_func('increment', &$a);  //错误用法  会报fatal error


PHP5.3之前,是否引用传参都可按引用传参方式使用,且不会报notice
call_user_func_array('increment', array(&$a));  //之前可以统一这样使用

PHP5.3+ 中,必须在需要引用传参的时候,传递引用参数
call_user_func_array('increment', array(&$a));  //需要引用传参时
call_user_func_array('increment', array($a));    //不需要引用传参时,必须正常传参

1.3.5 mysql 扩展及系列函数被废弃

mysql扩展自 PHP 5.5.0 起已废弃,并在自 PHP 7.0.0 开始被移除。
mysql系列函数,例如:
mysql_connect
mysql_db_name
mysql_db_query
......
mysql_close
都已废弃
替换方案:使用pdo_mysql扩展、mysqli扩展

1.3.6 .preg_replace() 函数中用到的 /e 修饰符现在被弃用。

方法作用:执行一个正则表达式搜索并且使用一个回调进行替换
现在使用 preg_replace_callback() 函数来替代

1.3.7 Mcrypt函数需要有效长度的密钥和初始向量

mcrypt_encrypt(),mcrypt_decrypt(), mcrypt_cbc(),mcrypt_cfb(),mcrypt_ecb(),mcrypt_generic() 以及 mcrypt_ofb() 函数不再接受无效长度的密钥和初始向量, 对于需要初始向量的分组加密模式,如果不提供初始向量,函数调用将会失败。
之前版本中,对于长度不足的密钥和初始向量会在其后补齐 '\0' 使其达到有效长度。
现在不接受$key和$iv参数为无效或者缺省的状态

三、升级步骤以及遇到的坑
3.1 梳理问答项目中依赖的PHP扩展和SDK,确定支持的稳定版本,搭建环境

PHP扩展:
    memcached和libmemcached类库的问题
    mongodb扩展的API不友好的问题
    redis当时最新版本(3.1.1)hgetall的使用存在bug的问题
    zookeeper 当时没有官方稳定版,只有0.3.1 alpha版
 SDK:
    idgenclient  仍使用memcache API
    quclient 仍使用类名作为构造函数的函数名

根据PHP手册上的changelog,找出变更的函数和使用,grep代码,批量修改
从PHP 5.6.x 移植到 PHP 7.0.x
从PHP 5.5.x 移植到 PHP 5.6.x
从 PHP 5.4.x 迁移到 PHP 5.5.x
从 PHP 5.3.X 迁移到 PHP 5.4.X
从 PHP 5.2.x 移植到 PHP 5.3.x

3.2 使用开源的PHP代码兼容检测工具

php7cc 
    A command line tool designed to make migration from PHP 5.3-5.6 to PHP 7 easier.
使用composer 安装   https://github.com/sstalle/php7cc  
使用方法: php7cc –extensions=php,inc,tpl  dirname/filename
从代码层面找出不兼容的函数和使用(提示分级别,比较详细,给出所有可能出问题的提示)

3.3 diff线上和升级环境的请求结果

从线上的访问日志批量提取请求,同时访问两个环境的代码,diff结果
使用郭牛提供的webdiff工具
页面中存在着非功能性的差异(server_time、不同环境的图片地址不同、异步接口随机展现数据不同)
使用sed、awk提取请求和对比结果

3.4 逐步上线步骤和方法

小流量发布线上机器
遇到memcache与memcached扩展的不兼容问题。解决方法:加前缀来区分
各种由于memcache扩展变更导致的主从不同步问题。。。
批量发布线上机器
上线步骤:下线部分机器、部署PHP7环境、删旧代码、发新代码
机器升级步骤:每次升级两台 → 升级一半 → 升级剩余机器(保留对照机)
升级worker机、导入机、用户行为机
逐个过一遍每个consumer任务、crontab任务
手工执行脚本文件排错
线下流程大范围报错,debug过程继续修改代码

3.5 升级过程对项目扩展带来的要求

PHP5            PHP7
apc             ZendOpCache
gearman         √
memcahce        memcached
mongo           mongodb
mysql           ×
PDO             √
pdo_mysql       √
redis           √
zookeeper       √尚未发布稳定版本
xhprof          ×

3.6 使用memcached扩展时的问题

memcached客户端功能更丰富、更强大,且找不到支持PHP7的memcache扩展
升级时的过渡状态,两个客户端需要共存。为解决共存问题,通过加前缀区分
          Memcache扩展      Memcached扩展
第三方依赖     不需要            需要libmemcached库  
哈希分布策略和     代码忽略..
哈希函数配置      
设置是否压缩
使用长连接

3.7 使用redis扩展的问题

支持PHP7的redis版本为3.0.0+
选择了redis3.1.1, 使用 hgetall()方法,总是报“内存越界”错误
修改配置、gbd调试,都不行。版本降为3.0.0, 解决问题

四、升级结果以及带来的性能体验

问答全站 18个模块
涉及机器: 
前端机     35台
后端机 19台
worker机  6台
数据导入机 7台
用户行为机 2台
Beta机    6台

性能提升 (涉及到了I/O操作,访问文件,网络或数据库连接)

页面      QPS   持续时间   响应时间(PHP5)  PHP7   提升比较   CPUIDLE(PHP5) PHP7  比较
详情页:   
         50    3600      197              177    10%升     83%             88%   6%
         100   3600      239              212    11%       45%             69%   53%
         100   14400                      142
  
列表页:   
         20    3600      119              88     26%升     86%             91%   6%
         40    3600      109              89     18%       86%             91%   6%
         50    14400                      90                               96%

主 页:   
         20    3600      81               70     14%升     86%             97%   13%
         40    3600      86               76     12%       88%             95%   8%
         50    14400                                                       95%

踩到的坑总结:
模块过多,同一功能的基类在各个模块都有出现,修改代码量增加n倍
机器类别多,对应每种机器的环境不一致(qbus扩展问题没法统一安装),不同机器的升级步骤不同(删掉的代码目录不同,发布的代码模块不同)
废弃的代码多,很多代码没从代码库中去掉或者做标识,废弃代码中存在问题多,加大了升级工作量