Lnmp技术手册
Php篇
一 配置
1) Php.ini
display_errors=(boolen) 错误信息是否显示到屏幕 生产环境必须关闭
output_buffering = On 设一个输出处理器自动地打开输出缓冲
register_globals=off 开启全局变量(安全问题 做关闭操作)
max_execution_time 每个脚本运行的最长时间
memory_limit 脚本运行最大消耗的内存
magic_quotes_gpc 字符串的转义 一般防止出错 不建议开启 建议程序自己处理
如果有上传文件的需要考虑:
一般考虑时间超长和默认资源限制
upload_max_filesize 10M //所上传的文件的最大大小
post_max_size 10M //设定 POST 数据所允许的最大大小 若果超过内存限制 memory_limit 也会影响上传 通常memory_limit 应该比 post_max_size 要大
max_input_time 300 //脚本等待输入数据的时间
max_execution_time 300 //设置PHP 脚本的最大执行时间(进程的CPU时间) {php-cgi(php-fpm) 中,该参数不会起效需要配置 php-fpm.conf中request_terminate_timeout 替代此函数}
另外也要考虑webserver 的资源限制
2) php-fpm
pm = static|dynamic(如果是大内存服务器的话 建议开启静态 每个干净的php进程一般6M左右)
pm.max_children 子进程的数量 根据应用场景 如果次数太小 会出现502
pm.max_requests 设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的
request_terminate_timeout 设置单个请求的超时中止时间. 该选项可能会对php.ini设置中的'max_execution_time'因为某些特殊原因没有中止运行的脚本有用
pm.max_requests和request_terminate_timeout的设置 对于一些异常进程非常重要 咱们多个系统出现过此类问题
二Php调试
1) 内置api基本调试
Echo、 print _r 、var_dump(var_export)、debug_zval_dump 。
2) 错误控制和日志记录
display_errors error_reporting log_errors log_errors等
详见:http://cn2.php.net/manual/zh/errorfunc.configuration.php#ini.display-errors
3) 错误抛出和处理
Try catch截取异常 throw抛出异常
错误抛出和处理主要是说我们在程序中,能够自己触发错误,或者是自己截获处理错误,类似于面向对 象编程里的异常处理 throw 抛出异常,catch 截获异常一个思路。
trigger_error 、set_error_handler、set_exception_handler 这三个api 主要就是处理错误抛出和处理内置函数。
使用 trgger_error 可以触发一个错误,触发级别跟上文的 error_reporting 的设定级别一致,主要是能够触 发的是 E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE 三种级别的错误,如果不做处理,那么 在程序执行就会报错,错误提示跟上文描述差不多,会出现 Fatal Error 、Warning 、Notice三种错误显示。
trigger_error 是一个抛出错误的函数,可以抛出任何用户级别错误,在非面向对象时代的编里,可以作 为一个提示错误的一种方式。
详见:http://www.php.net/manual/zh/language.exceptions.php
4) 第三方工具
Xdebug、、firebug、firephp、 xhprof 、apd(Advanced PHP debugge)等
1)Xdebug
重点说一下Xdebug
实例:
团购抓取增加了很多功能 抓取速度骤然变慢 要确定是什么拉慢了系统
安装xdebug
[root@localhost zhangminsong]# wget http://xdebug.org/files/xdebug-2.2.1.tgz
[root@localhost zhangminsong]# tar xvf xdebug-2.2.1.tgz
[root@localhost zhangminsong]# cd xdebug-2.2.1
[root@localhost xdebug-2.2.1]# /usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20090626
Zend Module Api No: 20090626
Zend Extension Api No: 220090626
[root@localhost xdebug-2.2.1]# ./configure --with-php-config=/usr/local/php/bin/php-config
[root@localhost xdebug-2.2.1]# make
[root@localhost xdebug-2.2.1]# make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/
修改 php.ini 增加
[Xdebug]
zend_extension="/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"
xdebug.auto_trace = on
xdebug.auto_profile = on
xdebug.collect_params = on
xdebug.collect_return = on
xdebug.profiler_enable = on
xdebug.trace_output_dir="/tmp/xdebug"
xdebug.profiler_output_dir="/tmp/xdebug"
xdebug.profiler_output_name="script"
Mkdir /tmp/xdebug
重启php 查看phpinfo
跑一下抓取脚本 会在/tmp/xdebug中产生如下文件
[root@localhost xdebug-2.2.1]# ll /tmp/xdebug/
总用量 904
-rw-r--r-- 1 www www 234232 2月 1 23:46 script
-rw-r--r-- 1 www www 686293 2月 1 23:46 trace.619174344.xt
Sz /tmp/xdebug/script 到本地分析这个文件 分析这个文件需要下载一个工具
WinCacheGrind(http://sourceforge.net/projects/wincachegrind/ )
一目了然
跑到这个函数 浪费了这么时间(1600个商品)居然调用了17w次的redis 平均一次0.2
Ms,问题找到了 然后修改了代码逻辑 ok 速度变快了.
2)APD(Advanced PHP Debugger)
高级 PHP 调试器。是用来给 PHP 代码提供规划与纠错的能力, 以及提供了显示整个堆栈追踪的能力。支持交互式纠错,但默认是将数据写入跟踪文件。它还提供了 基于事件的日志,因此不同级别的信息(包括函数调用,参数传递,计时等)可以对个别的脚本打开或关闭。
详情:http://cn2.php.net/manual/zh/intro.apd.php
3)Xhprof
它是个轻量级的性能监测工具,安装部署简单,占用系统资源更少, Xhprof 不是通过配置来启用监测,是否启用你直接在代码里启用,你需要监测哪个文件就在该文件启 用监测,这样不会像Xdebug 一样每个执行的文件都会记录下性能情况,Xhprof 自带Web 断的结果查看页面,不需要像Xdebug 另外安装 。
详情:http://cn2.php.net/manual/zh/intro.xhprof.php
5)php单元测试
Phpuint
PHPUnit 是一个轻量级的PHP 测试框架。它是在PHP5 下面对JUnit3 系列版本的完整移植,是xUnit 测试框架家族的一员(它们都基于模式先锋Kent Beck 的设计) 。
单元测试是几个现代敏捷开发方法的基础,使得PHPUnit 成为许多大型PHP 项目的关键工具。这个工 具也可以被 Xdebug 扩展用来生成代码覆盖率报告 ,并且可以与phing 集成来自动测试,最后它还可以和 Selenium 整合来完成大型的自动化集成测试。
详见:http://pear.phpunit.de/
三Php加速优化工具(主要是优化php opcode)
APC、 xcache 、eaccelerator、Zend Optimize等
建议做个必须条件安装到线上
四 php扩展安装
1)安装php扩展
进行PHP的扩展开发有两种方式 ,第一种是从PHP源码进行,第二种是从PHP提供的独立的工具进行 第一种少了灵活性 所以我们一般选择第二种方式。
PHP的核心(core)有两部分组成最底层的Zend引擎和他上面的phpcode,所以扩展类型又有两种:
extension意为基于php(core)的扩展
zend_extension意为基于zend引擎的扩展
我们常用第二种方式进行扩展即外部加载
php的扩展包 大部分在/php源码/ext 下 如果没有可以单独下载
步骤
/usr/local/php/bin/phpize
./configure --help
./configure --with-php-config=/usr/local/php/bin/php-config
make
make test #就算这里提示出错,不要理它!
make install
注:phpize 是属于 php-devel 中的东西,主要是设定 php 外挂模块的一些设定(一般存在于php-devel 中)
make install会生成xxx.so 然后在php.ini中手动加载进去。
2)编写php扩展
1 获取php源码包解压
wget http://
tar
2 进入php源码包ext 目录
cd php-5.2.14/ext
3 生成扩展框架
./ext_skel --extname=zhang
实例:
--------------
[root@domain09 ext]# ./ext_skel --extname=zhang
Creating directory zhang
Creating basic files: config.m4 config.w32 .cvsignore zhang.c php_zhang.h CREDITS EXPERIMENTAL tests/001.phpt zhang.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/zhang/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-zhang
5. $ make
6. $ ./php -f ext/zhang/zhang.php
7. $ vi ext/zhang/zhang.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/zhang/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.
------------------------------------------------------------------
这个命令会在php-5.2.14/ext目录里面生成 zhang目录 并在该目录生成一些文件 其中用到的 是3个文件 一个是config.m4 一个是php_zhang.h 一个是 zhang.c
实例:
------------------------------------------------------
[root@domain09 zhang]# ll
total 64
-rw-r--r-- 1 root root 1975 Jan 20 09:59 config.m4
-rw-r--r-- 1 root root 282 Jan 20 09:59 config.w32
-rw-r--r-- 1 root root 4 Jan 20 09:59 CREDITS
-rw-r--r-- 1 root root 0 Jan 20 09:59 EXPERIMENTAL
-rw-r--r-- 1 root root 2666 Jan 20 09:59 php_zhang.h
drwxr-xr-x 2 root root 4096 Jan 20 09:59 tests
-rw-r--r-- 1 root root 5133 Jan 20 09:59 zhang.c
-rw-r--r-- 1 root root 496 Jan 20 09:59 zhang.php
------------------------------------------------------------
编辑 这三个文件
vi config.m4
把下面这两句前面的的dnl去掉,保存
dnl PHP_ARG_ENABLE(zhang, whether to enable zhang support,
dnl [ --enable-zhang Enable zhang support])
vi php_zhang.h
找到PHP_FUNCTION(confirm_zhang_compiled); /* For testing, remove later. */
,新增一行:
PHP_FUNCTION(zhang_test);
保存
vi zhang.c
代码后面加上你的c代码
比如
PHP_FUNCTION(zhang){
RETURN_STRING("hello world! zhangminsong",1);
}
然后开始编译
[root@domain09 zhang]# phpize
[root@domain09 zhang]# ./configure --with-php-config=/usr/local/ku6/php/bin/php-config
[root@domain09 zhang]# make
然后 zhang/modules/下会生成一个zhang.so
cp 到php的extensions目录 然后 vi php.ini 加上
extension = zhang.so
重启php
<?php
phpinfo();
echo zhang();
?>
五php程序安全
1 是命令注入攻击 主要通过system eval passthru等这些函数 执行外部提交过来的命令
2 客户端脚本注入攻击(注意过滤提交数据)
3 跨站脚本攻击(注意过滤提交数据)
4 sql 注入攻击(注意过滤特殊字符)
5 跨站伪造请求攻击 (检查页面来源)
6 session 劫持攻击(注意session id 的安全 如封装 更改名称等)
7 session固定攻击(不要get post获取 重新生成新的seesion id 检查来源等)
8 HTTP响应拆分攻击(使用最新版的php 就行了 或者检查http头或者sessionid)
9 文件上传攻击(限制上传条件)
10 目录穿越攻击(检查目录字符)
11 远程文件引入攻击(检查目录字符)
12 变量指定攻击 (注意检查变量)
基本就这些了 括号里面我粗略的注释了防范的方法 总的来说就要不要信任站外提交一切数据 必须按照规则检查过滤
附录 php一些常见错误
1 语法构造错误
This is a syntax error
2 头出输出错误
Warning: Cannot add header information - headers already sent by
Warning: Cannot send session cache limiter - headers already sent in somefile.php on line
3 mySql 资源错误
Warning: Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in…
SQL查询语句错误(但错误没有被抛出)
4 Sessions 不能被创建或者被修改维护
Sessions are not being created or maintained
5文件流错误
Warning: failed to open stream…
6文件没有权限被读取
Warning: fopen(…): failed to open stream: Permission denied in…
7 空白页面
8 乱码
9 最大执行时间错误
Max Execution Time Error
10 打开基目录错误
warning: Unknown(): open_basedir restriction in effect.
Mysql 篇
1)mysql安全
1 mysql目录文件的权限设置
MySQL所在的主机的安全性是最首要的问题,如果主机不安全,被攻击者控制,那么MySQL的安全性也无从谈起。其次就是数据目录和数据文件的安全性,也就是权限设置问题
mysql的运行建立mysql用户和mysql用户组:
/usr/sbin/groupadd mysql
/usr/sbin/useradd -g mysql mysql
chmod +w /usr/local/ku6/mysql/
chown -R mysql:mysql /usr/local/ku6/mysql/
chown -R mysql:mysql mysql/
以mysql用户帐号的身份建立数据表:
/usr/local/ku6/mysql/bin/mysql_install_db --
basedir=/usr/local/ku6/mysql --datadir=/mysql/3306/data --user=mysql
2 修改root用户口令,删除空口令
mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> delete from user where user='';
Query OK, 0 rows affected (0.00 sec)
mysql> update user set password=password('testpasswd') where
user='root';
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
3 mysql的访问问题
避免外部连接
启动时Skip-networking
my.cnf bind-address=内网ip
限定连接IP
mysql> grant ALL PRIVILEGES on *.* to ktvtest@'%' to
ktv_user@'x.x.x.x/x.x.x.x' identified by 'passwd';
4 危险的函数
LOAD DATA INFILE(只能读全局可读文件)
SELECT …INTO OUTFILE(不能覆盖文件)
举例:
mysql>create table a (cmd text);
mysql>insert into a values ("<?php" );
mysql>insert into a values ("phpinfo()" );
mysql>insert into a values ("<php?>" );
mysql>select * from a into outfile “/usr/local/ku6/ktv/shell.php";
5 mysql 启动安全问题
绝对不要作为使用root用户运行MySQL服务器。应该用普通非特权用户运行mysql
my.cnf user=mysql
6 命令历史记录保护
# rm .bash_history .mysql_history
# ln –s /dev/null .bash_history
# ln –s /dev/null .mysql_history
7 构建choot 环境
MySQL运行在一个独立的环境下,将其和主系统隔离
2)mysql监控与调优
1 检查系统的状态
主要察看 CPU问题 内存问题 磁盘IO问题 网络问题
命令 top 、vmstat 、sar、iostat等
1) 用vmstat察看关于内核进程,虚拟内存,磁盘,cpu的的活动状态
[root@ks01 ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 208 811596 326016 2485004 0 0 0 1 0 0 0 0 100 0 0
其中:
kthr--内核进程的状态
--r 运行队列中的进程数,在一个稳定的工作量下,应该少于5
--b 等待队列中的进程数(等待I/O),通常情况下是接近0的.
memory--虚拟和真实内存的使用信息
--avm 活动虚拟页面,在进程运行中分配到工作段的页面空间数.
--fre 空闲列表的数量.一般不少于120,当fre少于120时,系统开始自动的kill进程去释放
free list
page--页面活动的信息
--re 页面i/o的列表
--pi 从页面输入的页(一般不大于5)
--po 输出到页面的页
--fr 空闲的页面数(可替换的页面数)
--sr 通过页面置换算法搜索到的页面数
--cy 页面置换算法的时钟频率
faults--在取样间隔中的陷阱及中断数
--in 设备中断
--sy 系统调用中断
--cs 内核进程前后交换中断
cpu--cpu的使用率
--us 用户进程的时间
--sy 系统进程的时间
--id cpu空闲的时间
--wa 等待i/o的时间
一般us+sy 在单用户系统中不大于90,在多用
2 )sar来检查操作系统是否存在IO问题
sar可以显示CPU、运行队列、磁盘I/O、分页(交换区)、内存、CPU中断、网络等性能数据
[root@ks01 ~]# sar
Linux 2.6.18-194.el5 (ks01.oss.com) 05/03/2011
12:00:01 AM CPU %user %nice %system %iowait %steal %idle
12:10:01 AM all 0.00 0.00 0.00 0.03 0.00 99.96
12:20:01 AM all 0.00 0.00 0.00 0.01 0.00 99.98
...
其中:
-CPU
CPU编号
--%user
在用户模式中运行进程所花的时间的百分比
--%nice
运行正常进程所花的时间的百分比
--%system
在内核模式(系统)中运行进程所花的时间的百分比
--%iowait
没有进程在该CPU上执行时,处理器等待I/O完成的时间的百分比 --这个值过高,表示硬盘存在I/O瓶颈
--%idle
CPU空闲时间百分比 ---如果这个值很高 但是系统响应慢 这时候应该加大内存 如果这个值持续太低 说明系统缺少cpu资源
附:sar 命令行的常用格式:
sar -u 是sar的缺省输出 (CPU 使用情况)
sar [options] [-A] [-o file] t [n]
在命令行中,n 和t 两个参数组合起来定义采样间隔和次数,t为采样间隔,是必须有
的参数,n为采样次数,是可选的,默认值是1,-o file表示将命令结果以二进制格式
存放在文件中,file 在此处不是关键字,是文件名。options 为命令行选项,sar命令
的选项很多,下面只列出常用选项:
-A:所有报告的总和。
-u:CPU利用率
-v:进程、I节点、文件和锁表状态。
-d:硬盘使用报告。
-r:没有使用的内存页面和硬盘块。
-g:串口I/O的情况。
-b:缓冲区使用情况。
-a:文件读写情况。
-c:系统调用情况。
-R:进程的活动情况。
-y:终端设备活动情况。
-w:系统交换活动。
比如
[root@ks01 ~]# sar -u 2 5 每2秒采集一下信息 收集5次
Linux 2.6.18-194.el5 (ks01.oss.com) 05/03/2011
03:33:47 PM CPU %user %nice %system %iowait %steal %idle
03:33:49 PM all 0.00 0.00 0.00 0.00 0.00 100.00
03:33:51 PM all 0.00 0.00 0.00 0.00 0.00 100.00
03:33:53 PM all 0.00 0.00 0.00 0.03 0.00 99.97
03:33:55 PM all 0.00 0.00 0.00 0.00 0.00 100.00
03:33:57 PM all 0.00 0.00 0.00 0.00 0.00 100.00
Average: all 0.00 0.00 0.00 0.01 0.00 99.99
2 检查mysql状态
几个命令:
show status 显示系统状态
show variables 显示系统变量
show processlist 显示进程状态
show profiles; 收集执行查询资源信息 默认是关闭的 开启 set profiling=1;
------------------------------------
常用的衍生命令:
连接失败情况
show status like'%aborted%'
Aborted_clients 客户端非法中断连接次数 如果随时间而增大 看看mysql的链接是否正常 或者检查一下网络 或者检查一下max_allowed_packet 超过此设置的查询会被中断( show variables like'%max%')
Aborted_connects 连接mysql失败次数 如果指过高 那就该检查一下网络 错误链接失败会在此记录
mysql> show status like'%aborted%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| Aborted_clients | 46 |
| Aborted_connects | 1 |
+------------------+-------+
2 rows in set (0.00 sec)
慢查询:
show variables like '%slow%'
show status like '%slow%';
默认是关闭的 开启 set global log_slow_queries=ON ;
Slow_launch_threads 值较大 说明有些东西正在延迟链接的新线程
mysql> show variables like '%slow%' ;
+---------------------+--------------------------------------+
| Variable_name | Value |
+---------------------+--------------------------------------+
| log_slow_queries | ON |
| slow_launch_time | 1 |
| slow_query_log | ON |
| slow_query_log_file | /data0/mysql/3306/data/ks01-slow.log |
+---------------------+--------------------------------------+
4 rows in set (0.00 sec)
mysql> show status like '%slow%';
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| Slow_launch_threads | 0 |
| Slow_queries | 0 |
+---------------------+-------+
2 rows in set (0.00 sec)
连接数
show variables like 'max_connections' 最大连接数
show status like 'max_used_connections'响应的连接数
max_used_connections / max_connections * 100% (理想值 ≈ 85%)
如果max_used_connections跟max_connections相同 那么就是max_connections设置过低或者超过服务器负载上限了
mysql> show variables like 'max_connections' ;
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 5000 |
+-----------------+-------+
1 row in set (0.00 sec)
缓存簇
show status like 'key_blocks_u%';使用和未使用缓存簇(blocks)数
show variables like '%Key_cache%';
show variables like '%Key_buffer_size%';
如果Key_blocks_used * key_cache_block_size 远小于key_buffer_size 那么就意味着内存呗浪费了 应该调大key_buffer_size值
mysql> show status like 'key_blocks_u%';
+-------------------+--------+
| Variable_name | Value |
+-------------------+--------+
| Key_blocks_unused | 213839 |
| Key_blocks_used | 503 |
+-------------------+--------+
2 rows in set (0.00 sec)
mysql> show variables like '%Key_cache%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| key_cache_age_threshold | 300 |
| key_cache_block_size | 1024 |
| key_cache_division_limit | 100 |
+--------------------------+-------+
3 rows in set (0.00 sec)
mysql> show variables like '%Key_buffer_size%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| key_buffer_size | 268435456 |
+-----------------+-----------+
1 row in set (0.00 sec)
线程使用情况
show status like 'Thread%';如果发现Threads_created值过大的话,可以适当增加配置文件中thread_cache_size值
Threads_cached用来缓存线程
mysql> show status like 'Thread%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_cached | 4 |
| Threads_connected | 1 |
| Threads_created | 5 |
| Threads_running | 1 |
+-------------------+-------+
4 rows in set (0.00 sec)
打开的文件数
show status like '%open_file%';
show variables like '%open_file%';
如果Open_files和open_files_limit接近 就应该增加open_files_limit的大小
不过mysql打开的文件描述符限制都是OS的文件描述符限制,和配置文件中open_files_limit的设置没有关系
mysql> show status like '%open_file%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_files | 178 |
+---------------+-------+
1 row in set (0.00 sec)
mysql> show variables like '%open_file%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| innodb_open_files | 300 |
| open_files_limit | 25000 |
+-------------------+-------+
2 rows in set (0.00 sec)
全联接
show status like '%select_full__%';
全链接是无索引链接 最好避免
如果Select_full_range_join过高 说明系统运行了很多范围查询联接表
mysql> show status like '%select_full__%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| Select_full_join | 0 |
| Select_full_range_join | 0 |
+------------------------+-------+
2 rows in set (0.00 sec)
打开表情况
show tatus like 'open%tables%';
如果open_tables接近table_cache的时候,并且Opened_tables这个值在逐步增加,说明table_cache不够用 表缓存没有完全用上 那就要考虑增加table_cache的大小了。还有就是Table_locks_waited比较高的时候,也需要增加table_cache
mysql> show status like 'open%tables%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_tables | 95 |
| Opened_tables | 0 |
+---------------+-------+
2 rows in set (0.00 sec)
查询缓存
show status like 'qcache%';
show variables like 'query_cache%';察看query_cache的配置
query_cache_limit:超过此大小的查询将不缓存
query_cache_min_res_unit:缓存块的最小大小
query_cache_size:查询缓存大小
query_cache_type:缓存类型,决定缓存什么样的查询,示例中表示不缓存 select sql_no_cache 查询
query_cache_wlock_invalidate:当有其他客户端正在对MyISAM表进行写操作时,如果查询在query cache中,是否返回cache结果还是等写操作完成再读表获取结果
mysql> show status like 'qcache%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 3 |
| Qcache_free_memory | 536800368 |
| Qcache_hits | 224134 |
| Qcache_inserts | 382 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 404 |
| Qcache_queries_in_cache | 40 |
| Qcache_total_blocks | 95 |
+-------------------------+-----------+
8 rows in set (0.00 sec)
mysql> show variables like 'query_cache%';
+------------------------------+-----------+
| Variable_name | Value |
+------------------------------+-----------+
| query_cache_limit | 2097152 |
| query_cache_min_res_unit | 2048 |
| query_cache_size | 536870912 |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
+------------------------------+-----------+
5 rows in set (0.00 sec)
排序情况
show status like 'sort%';
Sort_merge_passes过大 就要增加Sort_buffer_size 但是盲目的增加 Sort_buffer_size 并不一定能提高速度
mysql> show status like 'sort%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Sort_merge_passes | 0 |
| Sort_range | 0 |
| Sort_rows | 0 |
| Sort_scan | 0 |
+-------------------+-------+
4 rows in set (0.00 sec)
高速缓存
show variables like 'key_buffer_size';MyISAM 存储引擎键高速缓存 对MyISAM表性能影响很大大
show status like 'key_read%';磁盘读取索引的请求次数
索引未命中缓存的概率=Key_reads / Key_read_requests * 100%
不能以Key_read_requests / Key_reads原则来设置key_buffer_size
Key_reads 将这个值和系统的i/o做对比
mysql> show variables like 'key_buffer_size';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| key_buffer_size | 268435456 |
+-----------------+-----------+
1 row in set (0.00 sec)
mysql> show status like 'key_read%';
+-------------------+--------+
| Variable_name | Value |
+-------------------+--------+
| Key_read_requests | 115144 |
| Key_reads | 1311 |
+-------------------+--------+
2 rows in set (0.00 sec)
mysql>
表锁情况
show status like 'table_locks%';
Table_locks_waited显示了多少表呗锁住并导致了mysql的锁等待 可以开启慢查询看一下
mysql> show status like 'table_locks%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Table_locks_immediate | 20370 |
| Table_locks_waited | 0 |
+-----------------------+-------+
2 rows in set (0.00 sec)
表扫描情况
show status like 'handler_read%';
show status like 'com_select';
如果Handler_read_rnd_next /Handler_read_rnd 的值过大 那么就应该优化索引、查询
mysql> show status like 'handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 0 |
| Handler_read_key | 0 |
| Handler_read_next | 0 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 20 |
+-----------------------+-------+
6 rows in set (0.00 sec)
mysql> show status like 'com_select';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select | 0 |
+---------------+-------+
1 row in set (0.00 sec)
临时表情况
show status like 'created_tmp%';
show variables like 'tmp_table%';
show variables like 'max_heap%';
如果Created_tmp_disk_tables值较高 则有可能是因为:tmp_table_size或者max_heap_table_size太小
或者是选择blob、text属性的时候创建了临时表
Created_tmp_tables 过高的话 那么就有话查询吧
mysql> show status like 'created_tmp%';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0 |
| Created_tmp_files | 5 |
| Created_tmp_tables | 0 |
+-------------------------+-------+
3 rows in set (0.00 sec)
mysql> show variables like 'tmp_table%';
+----------------+-----------+
| Variable_name | Value |
+----------------+-----------+
| tmp_table_size | 257949696 |
+----------------+-----------+
1 row in set (0.00 sec)
mysql> show variables like 'max_heap%';
+---------------------+-----------+
| Variable_name | Value |
+---------------------+-----------+
| max_heap_table_size | 257949696 |
+---------------------+-----------+
1 row in set (0.00 sec)
二进制日志缓存
show status like'%binlog%';
show variables like'%binlog%';
如果Binlog_cache_disk_use 和 Binlog_cache_use 比例很大 那么就应该增加binlog_cache_size的值
mysql> show status like'%binlog%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| Binlog_cache_disk_use | 0 |
| Binlog_cache_use | 69166 |
| Com_binlog | 0 |
| Com_show_binlog_events | 0 |
| Com_show_binlogs | 0 |
+------------------------+-------+
5 rows in set (0.00 sec)
mysql> show variables like'%binlog%';
+-----------------------------------------+------------+
| Variable_name | Value |
+-----------------------------------------+------------+
| binlog_cache_size | 4194304 |
| binlog_direct_non_transactional_updates | OFF |
| binlog_format | MIXED |
| innodb_locks_unsafe_for_binlog | OFF |
| max_binlog_cache_size | 8388608 |
| max_binlog_size | 1073741824 |
| sync_binlog | 0 |
+-----------------------------------------+------------+
7 rows in set (0.00 sec)
附录 mysql 故障
1 应用获取不到连接池
2 数据库响应慢
3 SQL慢
4 服务器load高
5 SWAP
6 表不见了
7 MySQL crash
Nginx篇
1)配置
worker_processes 8
nginx要开启的进程数 一般等于cpu的总核数 其实一般情况下开4个或8个就可 以了 多了没有太多用
每个nginx进程消耗的内存10兆的模样
worker_cpu_affinity
仅适用于linux,使用该选项可以绑定worker进程和CPU(2.4内核的机器用不
了)
假如是8 cpu 分配如下:
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000
00100000 01000000 10000000
nginx可以使用多个worker进程,原因如下:
to use SMP
to decrease latency when workers blockend on disk I/O
to limit number of connections per process when select()/poll() is
used
The worker_processes and worker_connections from the event sections
allows you to calculate maxclients value: k
max_clients = worker_processes * worker_connections
worker_rlimit_nofile 102400;
每个nginx进程打开文件描述符最大数目 配置要和系统的单进程打开文件数一
致,linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应
应该填写65535
nginx调度时分配请求到进程并不是那么的均衡,假如超过会返回502错误。我
这里写的大一点
use epoll
Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模
型,而Apache则使用的是传统的select模型。
处理大量的连接的读写,Apache所采用的select网络I/O模型非常低效。
在高并发服务器中,轮询I/O是最耗时间的操作 目前Linux下能够承受高并发
访问的Squid、Memcached都采用的是epoll网络I/O模型。
worker_connections 65535;
每个工作进程允许最大的同时连接数 (Maxclient = work_processes * worker_connections)
keepalive_timeout 75
keepalive超时时间
这里需要注意官方的一句话:
The parameters can differ from each other. Line Keep-Alive:
timeout=time understands Mozilla and Konqueror. MSIE itself shuts
keep-alive connection approximately after 60 seconds.
client_header_buffer_size 16k
large_client_header_buffers 4 32k
客户请求头缓冲大小
nginx默认会用client_header_buffer_size这个buffer来读取header值,如果
header过大,它会使用large_client_header_buffers来读取
如果设置过小HTTP头/Cookie过大 会报400 错误 nginx 400 bad request
求行如果超过buffer,就会报HTTP 414错误(URI Too Long)
nginx接受最长的HTTP头部大小必须比其中一个buffer大,否则就会报400的
HTTP错误(Bad Request)。
open_file_cache max 102400
使用字段:http, server, location 这个指令指定缓存是否启用,如果启用,将记录文件以下信息: ·打开的文件描述符,大小信息和修改时间. ·存在的目录信息. ·在搜索文件过程中的错误信息 -- 没有这个文件,无法正确读取,参考open_file_cache_errors 指令选项:
·max - 指定缓存的最大数目,如果缓存溢出,最长使用过的文件(LRU)将被移除
例: open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;
open_file_cache_errors
语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.
open_file_cache_min_uses
语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1 使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如 果使用更大的值,文件描述符在cache中总是打开状态.
open_file_cache_valid
语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了何时需要检查open_file_cache中缓存项目的有效信息.
开启gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css
application/xml;
gzip_vary on;
缓存静态文件:
location ~* ^.+\.(swf|gif|png|jpg|js|css)$ {
root /usr/local/ku6/ktv/show.ku6.com/;
expires 1m;
}
附录:一些错误排查
502 504错误
php-cgi进程数不够用、php执行时间长(链接mysql等后端服务慢、异常等)、或者是php-cgi 进程死掉
,都会出现502错误
一般来说Nginx 502 Bad Gateway和php-fpm.conf的设置有关,而Nginx 504 Gateway Time-out则是与nginx.conf(fastcgi_*)的设置有关
1、查看当前的PHP FastCGI进程数是否够用:
netstat -anpo | grep "php-cgi" | wc -l
如果实际使用的“FastCGI进程数”接近预设的“FastCGI进程数”,那么
,说明“FastCGI进程数”不够用,需要增大。
2、部分PHP程序的执行时间超过了Nginx的等待时间,可以适当增加
nginx.conf配置文件中FastCGI的timeout时间,例如:
http
{
......
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
......
}
413 Request Entity Too Large
增大client_max_body_size
client_max_body_size:指令指定允许客户端连接的最大请求实体大小,它出现在请求头部的Content-Length字段. 如果请求大于指定的值,客户端将收到一个"Request Entity Too Large" (413)错误. 记住,浏览器并不知道怎样显示这个错误.
php.ini中增大
post_max_size 和upload_max_filesize
附录 nginx一些错误
误信息 |
错误说明 |
"upstream prematurely(过早的) closed connection" |
请求uri的时候出现的异常,是由于upstream还未返回应答给用户时用户断掉 连接造成的,对系统没有影响,可以忽略 |
"recv() failed (104: Connection reset by peer)" |
(1)服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉; (2)客户关掉了浏览器,而服务器还在给客户端发送数据; (3)浏览器端按了Stop |
"(111: Connection refused) while connecting to upstream" |
用户在连接时,若遇到后端upstream挂掉或者不通,会收到该错误 |
"(111: Connection refused) while reading response header from upstream" |
用户在连接成功后读取数据时,若遇到后端upstream挂掉或者不通, 会收到该错误 |
"(111: Connection refused) while sending request to upstream" |
Nginx和upstream连接成功后发送数据时,若遇到后端upstream挂掉或者不通, 会收到该错误 |
"(110: Connection timed out) while connecting to upstream" |
nginx连接后面的upstream时超时 |
"(110: Connection timed out) while reading upstream" |
nginx读取来自upstream的响应时超时
|
"(110: Connection timed out) while reading response header from upstream" |
nginx读取来自upstream的响应头时超时 |
"(110: Connection timed out) while reading upstream" |
nginx读取来自upstream的响应时超时 |
"(104: Connection reset by peer) while connecting to upstream" |
upstream发送了RST,将连接重置 |
"upstream sent invalid header while reading response header from upstream" |
upstream发送的响应头无效 |
"upstream sent no valid HTTP/1.0 header while reading response header from upstream" |
upstream发送的响应头无效 |
"client intended to send too large body" |
用于设置允许接受的客户端请求内容的最大值,默认值是1M, client发送的body超过了设置值 |
"reopening logs" |
用户发送kill -USR1命令 |
"gracefully shutting down", |
用户发送kill -WINCH命令 |
"no servers are inside upstream" |
upstream下未配置server |
"no live upstreams while connecting to upstream" |
upstream下的server全都挂了 |
"SSL_do_handshake() failed" |
SSL握手失败 |
"SSL_write() failed (SSL:) while sending to client" |
|
"(13: Permission denied) while reading upstream" |
|
"(98: Address already in use) while connecting to upstream" |
|
"(99: Cannot assign requested address) while connecting to upstream" |
|
"ngx_slab_alloc() failed: no memory in SSL session shared cache" |
ssl_session_cache大小不够等原因造成 |
"could not add new SSL session to the session cache while SSL handshaking" |
ssl_session_cache大小不够等原因造成 |
"send() failed (111: Connection refused)" |
|
优化Linux内核参数
vi /etc/sysctl.conf
这个希望运维给的权威一些
# Add
net.ipv4.tcp_max_syn_backlog = 65536
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
#net.ipv4.tcp_tw_len = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
#net.ipv4.tcp_fin_timeout = 30
#net.ipv4.tcp_keepalive_time = 120
net.ipv4.ip_local_port_range = 1024 65535
前端篇
1 组件切分到多个域(垂直切割):
比如动静分开 图片服务域 (公司图片hash)js服务域 css服务域 静态html服务域等
作用:分散流量 浏览器的并发 (域名要注意cookies的作用域 不然http头会带上cookies)
2 减少HTTP请求:
合并js、css
CSS Sprites
Image Map
Data URI编码图片
3 浏览器缓存 :
这个我要重点说一下
浏览器会在用户的系统创建一个目录 用来存放缓存的内容 并会给他们一些标识 用来区分是否过期
不同的浏览器采用不同的方式来缓存内容 比如火狐可以用 about:cache?device=disk或者about:cache?device=memory 来看到底放那里了
注意的几个参数:
1) Last-Modified 与If-Modified-Since 告诉里浏览器最后修改的时间和这个时间之后是否更新
我这里是用nginx来自动生成的
location ~* ^.+\.(swf|gif|png|jpg|js|css)$ {
root /usr/local/ku6/ktv/xiu.ku6.com/;
expires 时间;
}
2) etag 打死我都不会用的 用不好 太耗费流量了
附上http头信息:
响应头信息:
Date Mon, 02 May 2011 14:55:07 GMT
Content-Type text/html; charset=utf-8
Last-Modified Mon, 25 Apr 2011 07:39:09 GMT
Vary Accept-Encoding
Content-Encoding gzip
X-Cache HIT from cache.fastweb.com.cn
请求头信息:
Host xiu.ku6.com
User-Agent Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 QQDownload/1.7
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language zh-cn,zh;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
If-Modified-Since Mon, 25 Apr 2011 07:39:09 GMT
Cache-Control max-age=0
4 图片优化:
控制图片大小
使用png8代替256色的jpg
Jpeg使用渐变渲染模式 提高载入速度
使用CSS代替图片
拼合css sprites图片
避免img标签缩图 防止内存泄漏
另:
压缩inline——css、js 减少加载时间(服务器nginx也开启了gizp 这个后面另说)
减少嵌套层级 要符合标准
避免使用iframe标签 Iframe标签相当于新开一个浏览器窗口
html 去掉注释及空白符
删除非必要的html属性 防止浏览器回流页面
内联脚本、外链脚本优化 防止阻塞
压力测试工具
Ab、Webbench、loadrunner
Webbench -c 【】 -t 【】 “url”
常见一些线上问题
1 系统重启 nginx php等服务没有随机启动 解决:/etc/rc.d/rc.local
2 502等问题 比如php进程100 mysql连接数50 解决:增大mysql连接数
3 504 413 错误 解决:详见nginx篇
4 权限问题 比如www用户目录跟root用户执行与写的问题
5 nginx 110: Connection timed out 防火墙ip_conntrack哈希表满拒绝连接问题 解决:关闭防火墙 或者修改参数
6 sql 过大 mysql报错 解决:max_allowed_packet 增大
7 MySQL server has gone away 解决:wait_timeout interactive_timeout 增大值
8 端口无法访问 解决:检查防火墙设置
9 sql 执行效率问题 解决 :explain sql和慢查询日志
10 CLOSE_WAIT和TIME_WAIT过多 解决:修改系统参数
11 mysql引擎的选择 (根据应用)
12 php版本升级 与程序兼容的问题 解决:php版本日志找出差异
13 告警与容灾处理机制
14 程序安全(sql注入、test.php与test.php_bak svn文件)
15 数据库count 过慢 检查引擎是否为myisam
16 乱码问题 解决:字符集的设定