扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
可以先使用 uptime 命令查看 CPU 平均负载
我们提供的服务有:成都做网站、网站建设、微信公众号开发、网站优化、网站认证、鸡冠ssl等。为数千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的鸡冠网站制作公司
那个 2 users 表示用户连接数,指的是总连接数。
那个 load average 就是系统平均负载,1 分钟、5 分钟、15 分钟系统负载的平均值。
指的是一段时间内 CPU 正在处理以及等待 CPU 处理的进程数之和的统计信息,也就是 CPU 使用队列的长度的统计信息。这个数字越小越好。
然后再用 vmstat 命令看下 CPU 是否饱和
这里面的 r 就是等待 CPU 的进程数,可以用来判定 CPU 是否饱和,当 r 值高于 CPU 数时,就意味着饱和了。
最右边那个 us,sy,id,wa,st 表示所有 CPU 的使用百分比。它们分别是 user time,system time,idle,wait I/O 和 steal time 的缩写。将 us 和 sy 的百分比加和,可以确定 CPU 是否处于忙碌状态。
如果是多核的机器还可以使用 mpstat 命令查看是否均衡
与 CPU 相关的命令还有 pidstat
这个命令展示了 CPU 消耗在了哪些进程上面,消耗过大的进程需要格外关注下。
基本上你使用上述几个命令 就可以初步了解 CPU 出现了何种问题
有了猜测的方向之后 你就可以进一步深入去排查了
生产环境中,MySQL 不经意间吃掉全部的内容,然后开始吃掉 SWAP,性能一降再降,怎么办?
可以从下面三点查看原因:
MySQL 使用内存,有两个途径。
永久占用的内容
比如全局缓冲区(Global Buffer)类别,是在服务器启动期间从操作系统获得的,不会释放到任何一个别的进程。
动态请求的内存
线程缓冲区由MySQL使用,它是在处理新查询时从操作系统请求的内存。在执行查询之后,该内存被释放回操作系统。
这意味着 MySQL 的内存使用,是 全局缓冲区 加上 线程缓冲区 以及 允许的最大连接数 。
对于专用数据库服务器,该值需要保持在服务器内存的90%以下。在共享服务器的情况下,它应该保持在服务器内存的50%以下。
检查一下 MySQL 设置,有助于确定内存使用情况,从而为 MySQL 分配合适的值。
一个近似的公式:
当网站受到攻击时,有可能在短时间内建立异常高的连接数量。MySQL 中的 PROCESSLIST 可用于检测顶级用户并阻止对滥用连接的访问。
找出查询需要很长时间才能执行的语句,因为这些查询需要进一步优化服务器才能更好地执行,可以通过服务器查询日志进行识别。由于查询速度慢,导致磁盘读取较多,导致内存和CPU使用率较高,影响服务器性能。
最后,到了加内存条的时候了。虽然在优化数据库设置之后,服务器会不断地路由到使用交换内存,但也必须增加内存。俗话说:“巧妇难为无米之炊”,就是这个意思。
上面说的这些方向,大家可以在实际操作中验证体会,希望大家在数据库优化的路上,麻溜顺畅,砥砺前行。
通过以前对mysql的操作经验,先将mysql的配置问题排除了,查看msyql是否运行正常,通过查看mysql data目录里面的*.err文件(将扩展名改为.txt)记事本查看即可。如果过大不建议用记事本了,容易死掉,可以用editplus等工具。
简单的分为下面几个步骤来解决这个问题:
1、mysql运行正常,也有可能是同步设置问题导致
2、如果mysql运行正常,那就是php的一些sql语句导致问题发现,用root用户进入mysql管理
mysql -u root -p
输入密码
mysql:show processlist 语句,查找负荷最重的 SQL 语句,优化该SQL,比如适当建立某字段的索引。
通过这个命令我看到原来是有人恶意刷搜索,因为dedecms搜索后面调用搜索最高的词,导致很多人用工具刷这个,而且是定时有间隔的,所以将这个php程序改名跳转都方法解决了。
当然如果你的确实是sql语句用了大量的group by等语句,union联合查询等肯定会将mysql的占用率提高。所以就需要优化sql语句,网站尽量生成静态的,一般4W ip的静态网站,mysql占用率几乎为0的。所以这对于程序员的经验是个考虑。尽量提高mysql性能 (MySQL 性能优化的最佳20多条经验分享)
下面是豆芽收集的文章,大家都可以参考下
MYSQL CPU 占用 100% 的现象描述
早上帮朋友一台服务器解决了 Mysql cpu 占用 100% 的问题。稍整理了一下,将经验记录在这篇文章里
朋友主机(Windows 2003 + IIS + PHP + MYSQL )近来 MySQL 服务进程 (mysqld-nt.exe) CPU 占用率总为 100% 高居不下。此主机有10个左右的 database, 分别给十个网站调用。据朋友测试,导致 mysqld-nt.exe cpu 占用奇高的是网站A,一旦在 IIS 中将此网站停止服务,CPU 占用就降下来了。一启用,则马上上升。
MYSQL CPU 占用 100% 的解决过程
今天早上仔细检查了一下。目前此网站的七日平均日 IP 为2000,PageView 为 3万左右。网站A 用的 database 目前有39个表,记录数 60.1万条,占空间 45MB。按这个数据,MySQL 不可能占用这么高的资源。
于是在服务器上运行命令,将 mysql 当前的环境变量输出到文件 output.txt:
d:\web\mysql mysqld.exe --help output.txt
发现 tmp_table_size 的值是默认的 32M,于是修改 My.ini, 将 tmp_table_size 赋值到 200M:
d:\web\mysql notepad c:\windows\my.ini
[mysqld]
tmp_table_size=200M
然后重启 MySQL 服务。CPU 占用有轻微下降,以前的CPU 占用波形图是 100% 一根直线,现在则在 97%~100%之间起伏。这表明调整 tmp_table_size 参数对 MYSQL 性能提升有改善作用。但问题还没有完全解决。
于是进入 mysql 的 shell 命令行,调用 show processlist, 查看当前 mysql 使用频繁的 sql 语句:
mysql show processlist;
反复调用此命令,发现网站 A 的两个 SQL 语句经常在 process list 中出现,其语法如下:
SELECT t1.pid, t2.userid, t3.count, t1.date
FROM _mydata AS t1
LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid
LEFT JOIN _mydata_body AS t2 ON t1.pid=t3.pid
ORDER BY t1.pid
LIMIT 0,15
调用 show columns 检查这三个表的结构 :
mysql show columns from _myuser;
mysql show columns from _mydata;
mysql show columns from _mydata_body;
终于发现了问题所在:_mydata 表,只根据 pid 建立了一个 primary key,但并没有为 userid 建立索引。而在这个 SQL 语句的第一个 LEFT JOIN ON 子句中:
LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid
_mydata 的 userid 被参与了条件比较运算。于是我为给 _mydata 表根据字段 userid 建立了一个索引:
mysql ALTER TABLE `_mydata` ADD INDEX ( `userid` )
建立此索引之后,CPU 马上降到了 80% 左右。看到找到了问题所在,于是检查另一个反复出现在 show processlist 中的 sql 语句:
SELECT COUNT(*)
FROM _mydata AS t1, _mydata_key AS t2
WHERE t1.pid=t2.pid and t2.keywords = '孔雀'
经检查 _mydata_key 表的结构,发现它只为 pid 建了了 primary key, 没有为 keywords 建立 index。_mydata_key 目前有 33 万条记录,在没有索引的情况下对33万条记录进行文本检索匹配,不耗费大量的 cpu 时间才怪。看来就是针对这个表的检索出问题了。于是同样为 _mydata_key 表根据字段 keywords 加上索引:
mysql ALTER TABLE `_mydata_key` ADD INDEX ( `keywords` )
建立此索引之后,CPU立刻降了下来,在 50%~70%之间震荡。
再次调用 show prosslist,网站A 的sql 调用就很少出现在结果列表中了。但发现此主机运行了几个 Discuz 的论坛程序, Discuz 论坛的好几个表也存在着这个问题。于是顺手一并解决,cpu占用再次降下来了。(2007.07.09 附注:关于 discuz 论坛的具体优化过程,我后来另写了一篇文章,详见:千万级记录的 Discuz! 论坛导致 MySQL CPU 100% 的 优化笔记 )
解决 MYSQL CPU 占用 100% 的经验总结
增加 tmp_table_size 值。mysql 的配置文件中,tmp_table_size 的默认大小是 32M。如果一张临时表超出该大小,MySQL产生一个 The table tbl_name is full 形式的错误,如果你做很多高级 GROUP BY 查询,增加 tmp_table_size 值。
对 WHERE, JOIN, MAX(), MIN(), ORDER BY 等子句中的条件判断中用到的字段,应该根据其建立索引 INDEX。索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL不得不首先以第一条记录开始并然后读完整个表直到它找出相关的行。表越大,花费时间越多。如果表对于查询的列有一个索引,MySQL能快速到达一个位置去搜寻到数据文件的中间,没有必要考虑所有数据。如果一个表有1000行,这比顺序读取至少快100倍。所有的MySQL索引(PRIMARY、UNIQUE和INDEX)在B树中存储。
根据 mysql 的开发文档:
索引 index 用于:
快速找出匹配一个WHERE子句的行
当执行联结(JOIN)时,从其他表检索行。
对特定的索引列找出MAX()或MIN()值
如果排序或分组在一个可用键的最左面前缀上进行(例如,ORDER BY key_part_1,key_part_2),排序或分组一个表。如果所有键值部分跟随DESC,键以倒序被读取。
在一些情况中,一个查询能被优化来检索值,不用咨询数据文件。如果对某些表的所有使用的列是数字型的并且构成某些键的最左面前缀,为了更快,值可以从索引树被检索出来。
假定你发出下列SELECT语句:
mysql SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
如果一个多列索引存在于col1和col2上,适当的行可以直接被取出。如果分开的单行列索引存在于col1和col2上,优化器试图通过决定哪个索引将找到更少的行并来找出更具限制性的索引并且使用该索引取行。
CPU占用过高诊断思路
mpstat -P ALL 1,查看cpu使用情况,主要消耗在sys即os系统调用上
perf top,cpu主要消耗在_spin_lock
生成perf report查看详细情况
CPU主要消耗在mutex争用上,说明有锁热点。
采用pt-pmp跟踪mysqld执行情况,热点主要集中在mem_heap_alloc和mem_heap_free上。
Pstack提供更详细的API调用栈
Innodb在读取数据记录时的API路径为
row_search_for_mysql --》row_vers_build_for_consistent_read --》mem_heap_create_block_func --》mem_area_alloc --》malloc --》 _L_unlock_10151 --》__lll_unlock_wait_private
row_vers_build_for_consistent_read会陷入一个死循环,跳出条件是该条记录不需要快照读或者已经从undo中找出对应的快照版本,每次循环都会调用mem_heap_alloc/free。
而该表的记录更改很频繁,导致其undo history list比较长,搜索快照版本的代价更大,就会频繁的申请和释放堆内存。
Linux原生的内存库函数为ptmalloc,malloc/free调用过多时很容易产生锁热点。
当多条 SQL 并发执行时,会最终触发os层面的spinlock,导致上述情形。
解决方案
将mysqld的内存库函数替换成tcmalloc,相比ptmalloc,tcmalloc可以更好的支持高并发调用。
修改my.cnf,添加如下参数并重启
[mysqld_safe]malloc-lib=tcmalloc
上周五早上7点执行的操作,到现在超过72小时,期间该实例没有再出现cpu长期飙高的情形。
以下是修改前后cpu使用率对比
对于包括 mysql 在内的大多数数据库系统而言
性能问题的排查主要有以下方向:
1. 需求的不合理造成的性能问题
比方说,不需要实时更新的内容,被要求做成实时更新
2. 架构的不合理造成的性能问题
比方说,不适合数据库保存的数据,被存放在数据库中
或者,频繁访问但是很少变更的数据,没有做缓存
3. 查询语句的不合理造成的性能问题
比方说,重复执行相同的 SQL 会造成资源浪费
或者,大量复杂的 join 语句会导致查询效率低下
4. 数据库设计的不合理造成的性能问题
比方说,盲目追求三范式、四范式,有时候并没有必要
5. 硬件配置的不合理造成的性能问题
比方说,数据库服务器的 io 性能、CPU 、网络状况,都会影响性能
以上这些都是性能问题定位和调优的方向
数据库优化一方面是找出系统的瓶颈,提高MySQL数据库的整体性能,而另一方面需要合理的结构设计和参数调整,以提高用户的相应速度,同时还要尽可能的节约系统资源,以便让系统提供更大的负荷.
1. 优化一览图
2. 优化
笔者将优化分为了两大类,软优化和硬优化,软优化一般是操作数据库即可,而硬优化则是操作服务器硬件及参数设置.
2.1 软优化
2.1.1 查询语句优化
1.首先我们可以用EXPLAIN或DESCRIBE(简写:DESC)命令分析一条查询语句的执行信息.
2.例:
显示:
其中会显示索引和查询数据读取数据条数等信息.
2.1.2 优化子查询
在MySQL中,尽量使用JOIN来代替子查询.因为子查询需要嵌套查询,嵌套查询时会建立一张临时表,临时表的建立和删除都会有较大的系统开销,而连接查询不会创建临时表,因此效率比嵌套子查询高.
2.1.3 使用索引
索引是提高数据库查询速度最重要的方法之一,关于索引可以参高笔者MySQL数据库索引一文,介绍比较详细,此处记录使用索引的三大注意事项:
2.1.4 分解表
对于字段较多的表,如果某些字段使用频率较低,此时应当,将其分离出来从而形成新的表,
2.1.5 中间表
对于将大量连接查询的表可以创建中间表,从而减少在查询时造成的连接耗时.
2.1.6 增加冗余字段
类似于创建中间表,增加冗余也是为了减少连接查询.
2.1.7 分析表,,检查表,优化表
分析表主要是分析表中关键字的分布,检查表主要是检查表中是否存在错误,优化表主要是消除删除或更新造成的表空间浪费.
1. 分析表: 使用 ANALYZE 关键字,如ANALYZE TABLE user;
2. 检查表: 使用 CHECK关键字,如CHECK TABLE user [option]
option 只对MyISAM有效,共五个参数值:
3. 优化表:使用OPTIMIZE关键字,如OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;
LOCAL|NO_WRITE_TO_BINLOG都是表示不写入日志.,优化表只对VARCHAR,BLOB和TEXT有效,通过OPTIMIZE TABLE语句可以消除文件碎片,在执行过程中会加上只读锁.
2.2 硬优化
2.2.1 硬件三件套
1.配置多核心和频率高的cpu,多核心可以执行多个线程.
2.配置大内存,提高内存,即可提高缓存区容量,因此能减少磁盘I/O时间,从而提高响应速度.
3.配置高速磁盘或合理分布磁盘:高速磁盘提高I/O,分布磁盘能提高并行操作的能力.
2.2.2 优化数据库参数
优化数据库参数可以提高资源利用率,从而提高MySQL服务器性能.MySQL服务的配置参数都在my.cnf或my.ini,下面列出性能影响较大的几个参数.
2.2.3 分库分表
因为数据库压力过大,首先一个问题就是高峰期系统性能可能会降低,因为数据库负载过高对性能会有影响。另外一个,压力过大把你的数据库给搞挂了怎么办?所以此时你必须得对系统做分库分表 + 读写分离,也就是把一个库拆分为多个库,部署在多个数据库服务上,这时作为主库承载写入请求。然后每个主库都挂载至少一个从库,由从库来承载读请求。
2.2.4 缓存集群
如果用户量越来越大,此时你可以不停的加机器,比如说系统层面不停加机器,就可以承载更高的并发请求。然后数据库层面如果写入并发越来越高,就扩容加数据库服务器,通过分库分表是可以支持扩容机器的,如果数据库层面的读并发越来越高,就扩容加更多的从库。但是这里有一个很大的问题:数据库其实本身不是用来承载高并发请求的,所以通常来说,数据库单机每秒承载的并发就在几千的数量级,而且数据库使用的机器都是比较高配置,比较昂贵的机器,成本很高。如果你就是简单的不停的加机器,其实是不对的。所以在高并发架构里通常都有缓存这个环节,缓存系统的设计就是为了承载高并发而生。所以单机承载的并发量都在每秒几万,甚至每秒数十万,对高并发的承载能力比数据库系统要高出一到两个数量级。所以你完全可以根据系统的业务特性,对那种写少读多的请求,引入缓存集群。具体来说,就是在写数据库的时候同时写一份数据到缓存集群里,然后用缓存集群来承载大部分的读请求。这样的话,通过缓存集群,就可以用更少的机器资源承载更高的并发。
一个完整而复杂的高并发系统架构中,一定会包含:各种复杂的自研基础架构系统。各种精妙的架构设计.因此一篇小文顶多具有抛砖引玉的效果,但是数据库优化的思想差不多就这些了.
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流