一个诊断案例( )
成都创新互联是一家专注网站建设、网络营销策划、小程序开发、电子商务建设、网络推广、移动互联开发、研究、服务为一体的技术型公司。公司成立十多年以来,已经为近千家食品包装袋各业的企业公司提供互联网服务。现在,服务的近千家客户与我们一路同行,见证我们的成长;未来,我们一起分享成功的喜悦。
我们看到了两种可能性 要么是数据库导致了I/O(如果能找到源头的话 那么可能就找到了问题的原因) 要么不是数据库导致了所有的I/O 而是其他什么导致的 而系统因为缺少I/O 资源影响了数据库性能 我们也很小心地尽力避免引入另外一个隐式的假设 磁盘很忙并不一定意味着MySQL 会有问题 要记住 这个服务器主要的压力是内存读取 所以也很可能出现磁盘长时间无法响应但没有造成严重问题的现象
如果你一直跟随我们的推理逻辑 就可以发现还需要回头检查一下另外一个假设 我们已经知道磁盘设备很忙 因为其等待时间很高 对于固态硬盘来说 其I/O 平均等待时间一般不会超过 / 秒 实际上 从iostat 的输出结果也可以发现磁盘本身的响应还是很快的 但请求在块设备队列中等待很长的时间才能进入到磁盘设备 但要记住 这只是iostat 的输出结果 也可能是错误的信息
究竟是什么导致了性能低下?
当一个资源变得效率低下时 应该了解一下为什么会这样 有如下可能的原因
资源被过度使用 余量已经不足以正常工作
资源没有被正确配置
资源已经损坏或者失灵
回到上面的例子中 iostat 的输出显示可能是磁盘的工作负载太大 也可能是配置不正确(在磁盘响应很快的情况下 为什么I/O 请求需要排队这么长时间才能进入到磁盘?) 然而 比较系统的需求和现有容量对于确定问题在哪里是很重要的一部分 大量的基准测试证明这个客户使用的这种SSD 是无法支撑几百MB/s 的写操作的 所以 尽管iostat 的结果表明磁盘的响应是正常的 也不一定是完全正确的 在这个案例中 我们没有办法证明磁盘的响应比iostat 的结果中所说的要慢 但这种情况还是有可能的 所以这不能改变我们的看法 可能是磁盘被滥用注 或者是错误的配置 或者两者兼而有之 是性能低下的罪魁祸首
在检查过所有诊断数据之后 接下来的任务就很明显了 测量出什么导致了I/O 消耗 不幸的是 客户当前使用的GNU/Linux 版本对此的支持不力 通过一些工作我们可以做一些相对准确的猜测 但首先还是需要探索一下其他的可能性 我们可以测量有多少I/O来自MySQL 但客户使用的MySQL 版本较低以致缺乏一些诊断功能 所以也无法提供确切有利的支持
作为替代 基于我们已经知道MySQL 如何使用磁盘 我们来观察MySQL 的I/O 情况 通常来说 MySQL 只会写数据 日志 排序文件和临时表到磁盘 从前面的状态计数器和其他信息来看 首先可以排除数据和日志的写入问题 那么 只能假设MySQL 突然写入大量数据到临时表或者排序文件 如何来观察这种情况呢?有两个简单的方法 一是观察磁盘的可用空间 二是通过lsof 命令观察服务器打开的文件句柄 这两个方法我们都采用了 结果也足以满足我们的需求 下面是问题期间每秒运行df–h 的结果
下面则是lsof 的数据 因为某些原因我们每五秒才收集一次 我们简单地将mysqld 在/tmp 中打开的文件大小做了加总 并且把总大小和采样时的时间戳一起输出到结果文件中
$ awk
/mysqld *tmp/ {
total += $ ;
}
/^Sun Mar / total {
printf %s % f MB\n $ total/ / ;
total = ;
} lsof txt
: : MB
: : MB
: : MB
: : MB
: : MB
从这个数据可以看出 在问题之初MySQL 大约写了 GB 的数据到临时表 这和之前在SHOW PROCESSLIST 中有大量的 Copying to tmp table 相吻合 这个证据表明可能是某些效率低下的查询风暴耗尽了磁盘资源 根据我们的工作直觉 出现这种情况比较普遍的一个原因是缓存失效 当memcached 中所有缓存的条目同时失效 而又有很多应用需要同时访问的时候 就会出现这种情况 我们给开发人员出示了部分采样到的查询 并讨论这些查询的作用 实际情况是 缓存同时失效就是罪魁祸首(这验证了我们的直觉) 一方面开发人员在应用层面解决缓存失效的问题 另一方面我们也修改了查询 避免使用磁盘临时表 这两个方法的任何一个都可以解决问题 当然最好是两个都实施
返回目录 高性能MySQL
编辑推荐
ASP NET开发培训视频教程
数据仓库与数据挖掘培训视频教程
lishixinzhi/Article/program/MySQL/201311/29695
测量PHP 应用程序
如果不使用New Relic 也有其他的选择 尤其是对PHP 有好几款工具都可以帮助进行性能剖析 其中一款叫做xhprof(//pecl php net/package/xhprof) 这是Facebook开发给内部使用的 在 年开源了 xhprof 有很多高级特性 并且易于安装和使用 它很轻量级 可扩展性也很好 可以在生产环境大量部署并全天候使用 它还能针对函数调用进行剖析 并根据耗费的时间进行排序 相比xhprof 还有一些更底层的工具 比如xdebug Valgrind 和cachegrind 可以从多个角度对代码进行检测注 有些工具会产生大量输出 并且开销很大 并不适合在生产环境运行 但在开发环境却可以发挥很大的作用
下面要讨论的另外一个PHP 性能剖析工具是我们自己写的 基于本书第二版的代码和原则扩展而来 名叫IfP(instrumentation for php) 代码托管在Goole Code 上(//code google /p/instrumentation for php/) Ifp 并不像xhprof 一样对PHP 做深入的测量 而是更关注数据库调用 所以当无法在数据库层面进行测量的时候 Ifp 可以很好地帮助应用剖析数据库的利用率 Ifp 是一个提供了计数器和计时器的单例类 很容易部署到生产环境中 因为不需要访问PHP 配置的权限(对很多开发人员来说 都没有访问PHP配置的权限 所以这一点很重要)
Ifp 不会自动剖析所有的PHP 函数 而只是针对重要的函数 例如 对于某些需要剖析的地方要用到自定义的计数器 就需要手工启动和停止 但Ifp 可以自动对整个页面的执行进行计时 这样对自动测量数据库和memcached 的调用就比较简单 对于这种情况就无须手工启动或者停止 这也意味着 Ifp 可以剖析三种情况 应用程序的请求(如page view) 数据库的查询和缓存的查询 Ifp 还可以将计数器和计时器输出到Apache 通过Apache 可以将结果写入到日志中 这是一种方便且轻量的记录结果的方式 Ifp 不会保存其他数据 所以也不需要有系统管理员的权限
使用Ifp 只需要简单地在页面的开始处调用start_request() 理想情况下 在程序的一开始就应当调用
require_once( Instrumentation php )
Instrumentation::get_instance() start_request()
这段代码注册了一个shutdown函数 所以在执行结束的地方不需要再做更多的处理
IFP会自动对SQL添加注释 便于从数据库的查询日志中更灵活地分析应用的情况 通过SHOW PROCESSLIST也可以更清楚地知道性能低的查询出自何处 大多数情况下 定位性能低下查询的来源都不容易 尤其是那些通过字符串拼接出来的查询语句 都没有办法在源代码中去搜索 那么IFP的这个功能就可以帮助解决这个问题 它可以很快定位到查询是从何处而来的 即时应用和数据库中间加了代理或者负载均衡层 也可以确认是哪个应用的用户 是哪个页面请求 是源代码中的哪个函数 代码行号 甚至是所创建的计数器的键值对 下面是一个例子
File: index php Line: Function: fullCachePage request_id: ABC session_id: XYZ
SELECT * FROM …
如何测量MySQL 的调用取决于连接MySQL 的接口 如果使用的是面向对象的mysqli接口 则只需要修改一行代码 将构造函数从mysqli 改为可以自动测量的mysqli_x 即可 mysqli_x 构造函数是由Ifp 提供的子类 可以在后台测量并改写查询 如果使用的不是面向对象的接口 或者是其他的数据库访问层 则需要修改更多的代码 如果数据库调用不是分散在代码各处还好 否则建议使用集成开发环境(IDE)如Eclipse 这样修改起来要容易些 但不管从哪个方面来看 将访问数据库的代码集中到一起都可以说是最佳实践
Ifp 的结果很容易分析 Percona Toolkit 中的pt query digest 能够很方便地从查询注释中抽取出键值对 所以只需要简单的将查询记录到MySQL 的日志文件中 再对日志文件进行处理即可 Apache 的mod_log_config 模块可以利用Ifp 输出的环境变量来定制日志输出 其中的宏%D 还可以以微秒级记录请求时间
也可以通过LOAD DATA INFILE 将Apache 的日志载入到MySQL 数据库中 然后通过SQL 进行查询 在Ifp 的网站上有一个PDF 的幻灯片 详细给出了使用示例 包括查询和命令行参数都有
或许你会说不想或者没时间在代码中加入测量的功能 其实这事比想象的要容易得多 而且花在优化上的时间将会由于性能的优化而加倍地回报给你 对应用的测量是不可替代的 当然最好是直接使用New Relic xhprof Ifp 或者其他已有的优化工具 而不必重新去发明 轮子
MySQL 企业监控器的查询分析功能
MySQL 的企业监控器(Enterprise Monitor)也是值得考虑的工具之一 这是Oracle 提供的MySQL 商业服务支持中的一部分 它可以捕获发送给服务器的查询 要么是通过应用程序连接MySQL 的库文件实现 要么是在代理层实现(我们并不太建议使用代理层) 该工具有设计良好的用户界面 可以直观地显示查询的剖析结果 并且可以根据时间段进行缩放 例如可以选择某个异常的性能尖峰时间来查看状态图 也可以查看EXPLAIN 出来的执行计划 这在故障诊断时非常有用
返回目录 高性能MySQL
编辑推荐
ASP NET开发培训视频教程
数据仓库与数据挖掘培训视频教程
lishixinzhi/Article/program/MySQL/201311/29717
测试何种指标
在开始执行甚至是在设计基准测试之前 需要先明确测试的目标 测试目标决定了选择什么样的测试工具和技术 以获得精确而有意义的测试结果 可以将测试目标细化为一系列的问题 比如 这种CPU 是否比另外一种要快? 或 新索引是否比当前索引性能更好?
有时候需要用不同的方法测试不同的指标 比如 针对延迟(latency)和吞吐量(throughput)就需要采用不同的测试方法
请考虑以下指标 看看如何满足测试的需求
吞吐量
吞吐量指的是单位时间内的事务处理数 这一直是经典的数据库应用测试指标 一些标准的基准测试被广泛地引用 如TPC C(参考// tpc ) 而且很多数据库厂商都努力争取在这些测试中取得好成绩 这类基准测试主要针对在线事务处理(OLTP)的吞吐量 非常适用于多用户的交互式应用 常用的测试单位是每秒事务数(TPS) 有些也采用每分钟事务数(TPM)
响应时间或者延迟
这个指标用于测试任务所需的整体时间 根据具体的应用 测试的时间单位可能是微秒 毫秒 秒或者分钟 根据不同的时间单位可以计算出平均响应时间 最小响应时间 最大响应时间和所占百分比 最大响应时间通常意义不大 因为测试时间越长 最大响应时间也可能越大 而且其结果通常不可重复 每次测试都可能得到不同的最大响应时间 因此 通常可以使用百分比响应时间(percentile responsetime)来替代最大响应时间 例如 如果 % 的响应时间都是 毫秒 则表示任务在 % 的时间段内都可以在 毫秒之内完成
使用图表有助于理解测试结果 可以将测试结果绘制成折线图(比如平均值折线或者 % 百分比折线)或者散点图 直观地表现数据结果集的分布情况 通过这些图可以发现长时间测试的趋势 本章后面将更详细地讨论这一点
并发性
并发性是一个非常重要又经常被误解和误用的指标 例如 它经常被表示成多少用户在同一时间浏览一个Web 站点 经常使用的指标是有多少个会话注 然而 HTTP协议是无状态的 大多数用户只是简单地读取浏览器上显示的信息 这并不等同于Web 服务器的并发性 而且 Web 服务器的并发性也不等同于数据库的并发性 而仅仅只表示会话存储机制可以处理多少数据的能力 Web 服务器的并发性更准确的度量指标 应该是在任意时间有多少同时发生的并发请求
在应用的不同环节都可以测量相应的并发性 Web 服务器的高并发 一般也会导致数据库的高并发 但服务器采用的语言和工具集对此都会有影响 注意不要将创建数据库连接和并发性搞混淆 一个设计良好的应用 同时可以打开成百上千个MySQL 数据库服务器连接 但可能同时只有少数连接在执行查询 所以说 一个Web 站点 同时有 个用户 访问 却可能只有 ~ 个并发请求到MySQL 数据库
换句话说 并发性基准测试需要关注的是正在工作中的并发操作 或者是同时工作中的线程数或者连接数 当并发性增加时 需要测量吞吐量是否下降 响应时间是否变长 如果是这样 应用可能就无法处理峰值压力
并发性的测量完全不同于响应时间和吞吐量 它不像是一个结果 而更像是设置基准测试的一种属性 并发性测试通常不是为了测试应用能达到的并发度 而是为了测试应用在不同并发下的性能 当然 数据库的并发性还是需要测量的 可以通过sy *** ench 指定 或者 个线程的测试 然后在测试期间记录MySQL 数据库的Threads_running 状态值 在第 章将讨论这个指标对容量规划的影响
可扩展性
在系统的业务压力可能发生变化的情况下 测试可扩展性就非常必要了 第 章将更进一步讨论可扩展性的话题 简单地说 可扩展性指的是 给系统增加一倍的工作 在理想情况下就能获得两倍的结果(即吞吐量增加一倍) 或者说 给系统增加一倍的资源(比如两倍的CPU 数) 就可以获得两倍的吞吐量 当然 同时性能(响应时间)也必须在可以接受的范围内 大多数系统是无法做到如此理想的线性扩展的 随着压力的变化 吞吐量和性能都可能越来越差
可扩展性指标对于容量规范非常有用 它可以提供其他测试无法提供的信息 来帮助发现应用的瓶颈 比如 如果系统是基于单个用户的响应时间测试(这是一个很糟糕的测试策略)设计的 虽然测试的结果很好 但当并发度增加时 系统的性能有可能变得非常糟糕 而一个基于不断增加用户连接的情况下的响应时间测试则可以发现这个问题
一些任务 比如从细粒度数据创建汇总表的批量工作 需要的是周期性的快速响应时间 当然也可以测试这些任务纯粹的响应时间 但要注意考虑这些任务之间的相互影响 批量工作可能导致相互之间有影响的查询性能变差 反之亦然
归根结底 应该测试那些对用户来说最重要的指标 因此应该尽可能地去收集一些需求 比如 什么样的响应时间是可以接受的 期待多少的并发性 等等 然后基于这些需求来设计基准测试 避免目光短浅地只关注部分指标 而忽略其他指标
返回目录 高性能MySQL
编辑推荐
ASP NET开发培训视频教程
数据仓库与数据挖掘培训视频教程
lishixinzhi/Article/program/MySQL/201311/29741