标签归档:php

php7性能测试扩展php-xhprof-extension初探

最近发现测试环境接口响应巨慢,为了验证是哪里出了问题,遂引入性能测试。由于使用的php7,目前可用的性能测试扩展似乎只有php-xhprof-extension可选。

下载安装:https://tideways.com/profiler/downloads

以下为centos安装方法

echo "[tideways]
name = Tideways
baseurl = https://s3-eu-west-1.amazonaws.com/qafoo-profiler/rpm" > /etc/yum.repos.d/tideways.repo
rpm --import https://s3-eu-west-1.amazonaws.com/qafoo-profiler/packages/EEB5E8F4.gpg
yum makecache --disablerepo=* --enablerepo=tideways
yum install tideways-php tideways-cli tideways-daemon安装

安装好后,重启php-fpm

service php-fpm restart

如报异常:

Module 'tideways' already loaded in Unknown on line 0

可能是tideways重复加载了。

[root@test]# php -i | grep .ini$
 Loaded Configuration File => /etc/php.ini
 /etc/php.d/tideways.ini
 user_ini.filename => .user.ini => .user.ini
 vi /etc/php.d/tideways.ini

注释掉:extension=tideways.so

这时检查下扩展是否已经引用

php -m | grep tide
tideways

模块就做好了。

下面开始使用,官网文档使用是这样的:

<?php

tideways_xhprof_enable();

my_application();

$data = tideways_xhprof_disable();

file_put_contents("/tmp/profile.xhprof", serialize($data));

其实就是两个函数的使用,但是当你使用时会报错,什么错误呢

PHP Fatal error:  Uncaught Error: Call to undefined function tideways_xhprof_disable()

再次确认下tideways扩展有没有装好,可以用phpinfo()看一下。发现已经引入了模块。

这就很奇怪了。

再一番Google后,找到了这个问答的评论部分 https://stackoverflow.com/questions/38103784/how-to-use-tideways-on-own-server

Thank you for this. The projects own documentation contains incorrect commands (i.e. tideways_xhprof_enable() and tideways_xhprof_disable()) which meant all I could ever get was fatal errors. Remove the _xhprof token and it all works 🙂

啥意思呢?

就是把函数tideways_xhprof_enable();中的_xhprof去掉就可以了。

然后本人试了下,改成这样

<?php

tideways_enable();

echo "test";

$data = tideways_disable();

file_put_contents("/tmp/profile.xhprof", serialize($data));

这时就可以了,原来方法名都已经改了😳

运行完后可以读取文件,然后反序列化就可以拿到分析结果了。

类似这样:

<?php

array(
    "main()" => array(
        "wt" => 1000,
        "ct" => 1,
        "cpu" => 400,
    ),
    "main()==>foo" => array(
        "wt" => 500,
        "ct" => 2,
        "cpu" => 200,
    ),
    "foo==>bar" => array(
        "wt" => 200,
        "ct" => 10,
        "cpu" => 100,
    ),
)

关于对数据的处理和展示,后续有空的时候更新。

php微信网页授权demo

最近在做微信网页授权相关功能,以下整理简单的授权demo,在开始做之前认真看下微信的开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 讲解的十分详细。

没有公共账号的话可以到这里申请一个测试账号: https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

以下代码auth()方法为入口,路由上直接绑定这个方法即可,如果是Laravel建议使用:https://www.easywechat.com/docs/master/zh-CN/official-account/oauth

<?php

namespace App\Http\Controllers\WeChat;

class WeChatController
{
    private $app_id = 'wx107********'; // 替换为自己的app_id
    private $app_secret = '7d29151e****'; // 替换为自己的app_secret


    public function auth()
    {
        $redirect_uri = "https://mango/wechat/auth"; // 请替换成自己的url
        if (!isset($_GET['code'])) {
            $authorizationUrl = $this->get_authorize_url($redirect_uri, "test");
			header('Location: ' . $authorizationUrl);
            exit;
            
        } else {
            $accessToken = $this->get_access_token($this->app_id, $this->app_secret, $_GET['code']);
            var_dump($accessToken);
            if (!empty($accessToken)) {
                $userInfo = $this->get_user_info($accessToken['access_token'], $accessToken['openid']);
                var_dump($userInfo);
            }

        }

    }


    /**

    获取微信授权链接

    @param string $redirect_uri 跳转地址

    @param mixed $state 参数
     */

    public function get_authorize_url($redirect_uri = '', $state = '')
    {

        $redirect_uri = urlencode($redirect_uri);
        return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->app_id}&redirect_uri={$redirect_uri}&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect";
    }


    /**

    获取授权token

    @param string $code 通过get_authorize_url获取到的code
     */

    public function get_access_token($app_id = '', $app_secret = '', $code = '')
    {

        $token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->app_id}&secret={$this->app_secret}&code={$code}&grant_type=authorization_code";
        $token_data = $this->http($token_url, "GET");

        if($token_data[0] == 200)
        {
            return json_decode($token_data[1], TRUE);
        }

        return FALSE;
    }

    /**

    获取授权后的微信用户信息

    @param string $access_token

    @param string $open_id
     */

    public function get_user_info($access_token = '', $open_id = '')
    {

        if($access_token && $open_id)
        {
            $info_url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$open_id}&lang=zh_CN";
            $info_data = $this->http($info_url, 'GET');

            if($info_data[0] == 200)
            {
                return json_decode($info_data[1], TRUE);
            }
        }

        return FALSE;
    }

    public function http($url, $method, $postfields = null, $headers = array(), $debug = false)
    {

        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($ci, CURLOPT_TIMEOUT, 30);
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);

        switch ($method) {
            case 'POST':
                curl_setopt($ci, CURLOPT_POST, true);
                if (!empty($postfields)) {
                    curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
                    $this->postdata = $postfields;
                }
                break;
        }
        curl_setopt($ci, CURLOPT_URL, $url);
        curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ci, CURLINFO_HEADER_OUT, true);

        $response = curl_exec($ci);
        $http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);

        if ($debug) {
            echo "=====post data======\r\n";
            var_dump($postfields);

            echo '=====info=====' . "\r\n";
            print_r(curl_getinfo($ci));

            echo '=====$response=====' . "\r\n";
            print_r($response);
        }
        curl_close($ci);
        return array($http_code, $response);
    }
}

开启OPcache加速你的PHP应用

什么是OPcache?

Zend OPcache 通过 opcode 缓存和优化提供更快的php执行过程。它将预编译的脚本文件存储在共享内存中供以后使用,从而避免了从磁盘读取代码并进行编译的时间消耗。同时,它还应用了一些代码优化模式,使得代码执行更快。

为什么要用?

如下图php的执行的生命周期,第一部分是没有opcode缓存的情况。第二部分则是缓存了opcode的情况。

从图中我们可以清楚的看到,PHP开始执行请求->读文件->词法分析->语法分析->生成opcode->再由Zend引擎执行opcode返回执行结果。

聪明如你肯定发现在php文件没有更改的情况下,每次都要经过词法分析、语法分析、生成opcode有点浪费。那在代码没有更改的时候能不能把要执行代码的opcode缓存起来用于下次使用呢?这样不就提高了速度么。

OPcache就是来管理opcode缓存的,如上图下半部分。

是共享内存么?

PHP官方文档:
PHP processes with opcode cache enabled use shared memory for opcode caching. Yet, PHP processes will be able to “share” that shared memory, only if they were all created (forked) from the same, original PHP process, that allocated that shared memory.

据笔者的实验,开启OPcache后php-fpm的主进程内存占用会增加,即是把生成的opcode放在主进程里了。

补充一条查看php进程内存使用命令:

  1. 查看php-fpm的进程个数
    ps -fe |grep “php-fpm”|grep “pool”|wc -l
  2. 查看单个进程内存占用大小
    ps -ylC php-fpm –sort:rss
    RSS 为内存大小,单位K

性能有多大提升?

笔者在Ubuntu php7.0下开启OPcache的情况下速度可以提升13%左右,目前用在测试环境中,还在观察。

如何配置?

官方文档讲的很清楚,这里不作赘述。
http://php.net/manual/zh/opcache.configuration.php#ini.opcache.max-wasted-percentage

如何发布?

  • 手动重置:
    如果validate_timestamps 选项设置很久的话,就需要手工重置opcode。PHP提供了两个方法:
    opcode_reset() 重置整个字节码缓存内容
    opcache_invalidate 废除指定文件opcode缓存
  • 自动更新:
    validate_timestamps 设置5秒的话,在代码更新好后等个5秒就好了。
  • 重启php-fpm,不太建议这么做。

相关工具

OPcache Status
https://github.com/rlerdorf/opcache-status
CacheTool – Manage cache in the CLI
https://github.com/gordalina/cachetool