高性能MySQL

PHP性能优化

2018-06-09  本文已影响77人  10xjzheng

0 前言

这篇文章算是对这本书的一点笔记
《高性能PHP应用开发》
目录大概都是搬过来的,但是有些技术是2011-11(出版日期)之前的,还有有些地方跟我的技术栈有所区别,就略过了。
比如Apache(我用的是nginx),比如memcached(我用的是redis),这些就略过了。

1. 基准测试技术

1.0 PHP技术栈
image.png
1.1 定义请求/响应声明周期
image.png
1.2 Apache Benchmark (ab工具)
n: 要模拟的请求数;
c: 要模拟的并发请求数;
t: 执行模拟所需要的时间
1.3 Siege

Siege可以模拟托管文档的用户流量,与ab不同的是,Siege可以对文本文件中指定的URL列表运行负载测试。它还可以在执行其它请求之前让某个请求休眠,从而让你感觉某个用户在转移到Web应用程序的下一个文档之前正在读取该文档。

-c 200 指定并发数200
-r 5 指定测试的次数5
-f urls.txt 制定url的文件
-i internet系统,随机发送url
-b 请求无需等待 delay=0
-t 5 持续测试5分钟 [H,M,S--时分秒,默认M]
-r和-t一般不同时使用

1.4 影响基准测试数字

2.提高客户端下载和呈现性能

2.1 概述
  1. Web服务器发送的响应的细节信息;
  2. 分析JavaScript中的前端逻辑;
  3. 浏览器将读取的资源的逐项列表;
  4. 浏览器获取和接受资源所花费的时间;
  5. 对如何优化响应的建议
2.2 Firebug

好吧,我没用过,个人觉得Chrome自带的就够用了


image.png

还可以看时间花费细节:


image.png
2.3 YSlow

优化规则:
####### 2.3.1 CSS优化

2.4 YUI Compressor和Closure Compiler

这两个是JavaScript精简工具
现在不都是用gulp和webpack了吗?

2.5 图像压缩

使用Smush.it工具

3. PHP代码优化

3.1 PHP最佳实践

一些小tips

3.2 使用VLD、strace和Xdebug一探究竟
pecl install channel://pecl.php.net/vld-0.14.0 安装

测试代码

<?php
echo 'hello' , 'World!';

执行

php -dvld.active=1 test.php

结果

Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /apps/www/test/test.php
function name:  (null)
number of ops:  5
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   EXT_STMT                                                 
         1        ECHO                                                     'hello'
         2        EXT_STMT                                                 
         3        ECHO                                                     'World%21'
   3     4      > RETURN                                                   1

branch: #  0; line:     2-    3; sop:     0; eop:     4; out1:  -2
path #1: 0, 
helloWorld!
3.3 发现瓶颈
  1. Xdebug是面向PHP的调试器和概要分析工具,除了更多的调试信息外,Xdebug还可以为开发人员提供如下的信息:
  1. 举例
xdebug_start_trace('/tmp/trace', XDEBUG_TRACE_APPEND ); //开始,日志写到/tmp/trace文件
class Node {
    public $val; //值
    public $d; //距离
    public $p; //父节点
    public $linkedNodes = [];//连接的顶点
    public function __construct($val)
    {
        $this->val = $val;
    }
}


/**
 * Dijkstra
 **/
class DijkstraAlgorithm
{
    /**
     * 生成图
     * @param array $vertex
     * @return array
     */
    public function buildGraph($vertex)
    {
        $graph = [];
        $nodes = array_keys($vertex);
        foreach ($nodes as $node) {
            $graph[$node] = new Node($node);
        }
        foreach ($vertex as $key => $item) {
            foreach ($item as $value) {
                if (isset($graph[$value])) {
                    $graph[$key]->linkedNodes[] = $graph[$value];
                }
            }
        }
        return $graph;
    }

    /**
     * 初始化操作
     * @param array $graphNodes
     * @param Node $s
     */
    public function init(&$graphNodes, &$s)
    {
        foreach ($graphNodes as $graphNode) {
            $graphNode->d = 9999999;
        }
        $s->d = 0;
    }

    /**
     * 松弛操作
     * @param Node $u
     * @param Node $v
     * @param Array $w
     * @return bool
     */
    public function relax(&$u, &$v, $w)
    {
        $d = $u->d + $w[$u->val . '_' . $v->val];
        if($v->d > $d) {
            $v->d = $d;
            $v->p = $u;
            return true;
        }
        return false;
    }

    /**
     * 从队列取出最小距离的顶点
     * @param array $queue
     */
    public function extractMin(&$queue)
    {
        $result = [];
        foreach ($queue as $item) {
            $result[$item->d] = $item;
        }
        ksort($result);
        $queue = array_values($result);
        return array_shift($queue);
    }

    /**
     * Dijkstra 算法
     * 问题1:没考虑到负环路
     * @param $graphNodes
     * @param $s
     */
    public function dijkstra(&$graphNodes, $s, $w)
    {
        $this->init($graphNodes, $s);
        $gather = [];
        $queue = $graphNodes;
        while (!empty($queue)) {
            $node = $this->extractMin($queue);
            $gather[] = $node;
            foreach ($node->linkedNodes as $linkedNode) {
                if($this->relax($node, $linkedNode, $w)) {
                    if(!in_array($linkedNode, $queue)) {
                        array_push($queue, $linkedNode);
                    }
                }
            }
        }
    }
}


//顶点
$vertex = [
    'a' => ['b', 'c'],
    'b' => ['d'],
    'd' => ['e'],
    'c' => ['e'],
    'e' => [],
];
//边的权重
$w = [
    'a_b' => 1,
    'a_c' => 3,
    'b_d' => 2,
    'd_e' => 2,
    'c_e' => 4,
];

$g = new DijkstraAlgorithm();
$graphNodes = $g->buildGraph($vertex);
$g->dijkstra($graphNodes, $graphNodes['a'], $w);

$w = [
    'a_b' => 1,
    'a_c' => 3,
    'b_d' => 2,
    'd_e' => 2,
    'c_e' => 4,
];
xdebug_stop_trace();//结束行为追踪

centos的php.ini配置:

[xdebug]
zend_extension="/apps/install/php/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so"
xdebug.remote_enable = 1
xdebug.trace_format = 1
xdebug.auto_trace = 0
xdebug.trace_output_dir = /tmp/
xdebug.trace_output_name = trace.%c.%p

xdebug.collect_params = 4
xdebug.collect_includes = On
xdebug.collect_return = On
xdebug.show_mem_delta = On
xdebug.var_display_max_depth = 2

分析结果


image.png

4. Opacode缓存

4.1 回顾路线图
image.png
4.2 PHP的生命周期
image.png

在此补充一下,php7新加了语法解析树。

应用了Opcode缓存的PHP生命周期:


image.png
4.2 Opcode缓存工具

现在用opcache啦~~
有兴趣看看鸟哥这篇文章 让PHP7达到最高性能的几个Tips

5. 变量缓存

image.png

缓存可以用memcached或者redis等中间件。

6. 选择正确的Web服务器

并发当然是选择nginx

7. 优化Web服务器和内容交付

大部分是针对Apache的优化,略过。
还有负载均衡、共享会话、分布式架构的一些问题(缓存一致性、缓存版本等等)、监控应用程序Ganglia、Cacti、Nagios。

8. 数据库优化

“工作集”就是经常使用的数据集,如果这个数据集可以轻松地放到内存中,性能的提高也基本上就到了极限,特别是当拥有一个好的索引集时。

1). top监控进程
![image.png](https://img.haomeiwen.com/i3596546/d9b99687b1416f6f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2). iostat查看I/O性能
image.png

选项 说明


image.png
  1. 若 %iowait 的值过高,表示硬盘存在I/O瓶颈
  2. 若 %idle 的值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量
  3. 若 %idle 的值持续低于1,则系统的CPU处理能力相对较低,表明系统中最需要解决的资源是 CPU


    image.png
3).Mysqltuner.pl

当你看到较高的%util或%iowait值,那么应该查看驱动器的性能,或者看看打开的一些MySQL内存缓冲区以减少MySQL服务器命中磁盘所需的时间。但该系统没有显示I/O性能的任何问题,因此我们可以继续进行。
Mysqltuner.pl可以减轻配置和检查数据服务器的大量工作。


image.png image.png
-- show variables like '%max_connections%'; 查看最大连接数


set global max_connections=1000 重新设置



mysql> show status like 'Threads%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 58    |
| Threads_connected | 57    |   ###这个数值指的是打开的连接数
| Threads_created   | 3676  |
| Threads_running   | 4     |   ###这个数值指的是激活的连接数,这个数值一般远低于connected数值
+-------------------+-------+
 
Threads_connected 跟show processlist结果相同,表示当前连接数。准确的来说,Threads_running是代表当前并发数
 
这是是查询数据库当前设置的最大连接数
mysql> show variables like '%max_connections%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 1000  |
+-----------------+-------+
 
可以在/etc/my.cnf里面设置数据库的最大连接数
[mysqld]
max_connections = 1000
****命**令: show processlist;** 
**如果是root帐号,你能看到所有用户的当前连接。如果是其它普通帐号,只能看到自己占用的连接。** 
**show processlist;****只列出前100条,如果想全列出请使用****show full processlist;** 
[MySQL](http://lib.csdn.net/base/14 "MySQL知识库")> show processlist;

**命令: show status;**

**命令:show status like '%下面变量%';**

Aborted_clients 由于客户没有正确关闭连接已经死掉,已经放弃的连接数量。 
Aborted_connects 尝试已经失败的MySQL服务器的连接的次数。 
Connections 试图连接MySQL服务器的次数。 
Created_tmp_tables 当执行语句时,已经被创造了的隐含临时表的数量。 
Delayed_insert_threads 正在使用的延迟插入处理器线程的数量。 
Delayed_writes 用INSERT DELAYED写入的行数。 
Delayed_errors 用INSERT DELAYED写入的发生某些错误(可能重复键值)的行数。 
Flush_commands 执行FLUSH命令的次数。 
Handler_delete 请求从一张表中删除行的次数。 
Handler_read_first 请求读入表中第一行的次数。 
Handler_read_key 请求数字基于键读行。 
Handler_read_next 请求读入基于一个键的一行的次数。 
Handler_read_rnd 请求读入基于一个固定位置的一行的次数。 
Handler_update 请求更新表中一行的次数。 
Handler_write 请求向表中插入一行的次数。 
Key_blocks_used 用于关键字缓存的块的数量。 
Key_read_requests 请求从缓存读入一个键值的次数。 
Key_reads 从磁盘物理读入一个键值的次数。 
Key_write_requests 请求将一个关键字块写入缓存次数。 
Key_writes 将一个键值块物理写入磁盘的次数。 
Max_used_connections 同时使用的连接的最大数目。 
Not_flushed_key_blocks 在键缓存中已经改变但是还没被清空到磁盘上的键块。 
Not_flushed_delayed_rows 在INSERT DELAY队列中等待写入的行的数量。 
Open_tables 打开表的数量。 
Open_files 打开文件的数量。 
Open_streams 打开流的数量(主要用于日志记载) 
Opened_tables 已经打开的表的数量。 
Questions 发往服务器的查询的数量。 
Slow_queries 要花超过long_query_time时间的查询数量。 
Threads_connected 当前打开的连接的数量。 
Threads_running 不在睡眠的线程数量。 
Uptime 服务器工作了多少秒。

My.ini配置 虚拟内存

[](http://www.pc51.net/data/MySQL/2007-01-04/2551.html)

innodb_buffer_pool_size=576M   ->128M InnoDB引擎缓冲区

query_cache_size=100M             ->32 查询缓存
tmp_table_size=102M                  ->32M 临时表大小
key_buffer_size=16m                  ->8M

**设置max_connections**

**命令:show variables like '%max_connections%'** (这个办法在debian+mysql  Ver 12.22 Distrib 4.0.22, for pc-[Linux](http://lib.csdn.net/base/linux "Linux知识库") (i386)
里实验了)
设置办法是在my.cnf文件中,添加下面的最后红色的一行:

--------------------------------------------------------------------------------

[mysqld] 
port=3306 
#socket=MySQL 
skip-locking 
set-variable = key_buffer=16K 
set-variable = max_allowed_packet=1M 
set-variable = thread_stack=64K 
set-variable = table_cache=4 
set-variable = sort_buffer=64K 
set-variable = net_buffer_length=2K 
set-variable = max_connections=32000 
(在院里的DELL机器mysql4.0里的语法不同
max_connecionts=2000
直接这么写就好了

)

--------------------------------------------------------------------------------

修改完毕后,重启MySQL即可。当然,为了确保设置正确,应该查看一下max_connections。

注意: 
1、虽然这里写的32000。但实际MySQL服务器允许的最大连接数16384; 
2、除max_connections外,上述其他配置应该根据你们系统自身需要进行配置,不必拘泥; 
3、添加了最大允许连接数,对系统消耗增加不大。 
4、如果你的mysql用的是my.ini作配置文件,设置类似,但设置的格式要稍作变通。

用mysqld --help 可以查看到max_connections 变量。 
或者 mysql -uuser -p
**后mysql>show variables;
也会看到max_connections 。   **

下面是修改张老师 的redhat9的方法:

先是mysql -uw01f -p
mysql>show variables;
看到max_connections 为100
mysql>exit;
vi /etc/my.cnf
    [mysqld]
set-variable=max_connections=250  #加入这些内容
:wq

/etc/init.d/mysqld restart
上一篇 下一篇

猜你喜欢

热点阅读