本文概要:
0、前言;
1、监控MySQL的哪些指标;
2、一目了然的MySQL监控的UI界面;
3、Python代码获取MySQL监控状态。
0、前言
我们知道“SHOW STATUS”命令是获取MySQL实例状态的,“SHOW VARIABLES”命令是获取MySQL实例设置变量的,也是监控数据的最重要来源。
这两个命令使用如下:
“SHOW VARIABLES”命令获取状态:
mysql> SHOW GLOBAL STATUS;
mysql> SHOW [SESSION] STATUS;
查询特定状态值:
SHOW GLOBAL STATUS LIKE 'xxx'";
这里数据的主要来源是“information_schema”数据库,它是每个MySQL实例中的数据库,存储有关MySQL实例维护的所有其他数据库的信息。
“SHOW STATUS”命令设置参数:
mysql> SHOW GLOBAL VARIABLES;
mysql> SHOW [SESSION] VARIABLES;
查询特定变量值:
mysql> SHOW GLOBAL VARIABLES LIKE "XXX";
注意:
其中有些参数支持运行时修改,会立即生效;有些参数不支持,且只能通过修改配置文件,并重启服务器程序生效;
有些参数作用域是全局的,且不可改变;有些可以为每个用户提供单独的设置;
所以需要对一些重要的参数进行监控。
另外,MySQL有一个性能监控功能,MySQL Performance Schema是一种用于在较低级别监视MySQL实例执行的功能,这些监控数据保存在“performance_schema”数据库。
Performance Schema开关变量“performance_schema”:
mysql版本<= 5.6.5默认关闭; >=5.6.6默认开启。
如果关闭就没有“performance_schema”数据库了,一般也可以减少几百M内存占用。
下面列出了每个Performance Schema表,并提供了每个表的简短描述:
accounts 每个客户帐户的连接统计
cond_instances 同步对象实例
events_stages_current 当前的舞台活动
events_stages_history 每个线程最近的阶段事件
events_stages_history_long 最近的舞台活动
events_stages_summary_by_account_by_event_name 每个帐户和事件名称的舞台活动
events_stages_summary_by_host_by_event_name 每个主机名和事件名称的阶段事件
events_stages_summary_by_thread_by_event_name Stage等待每个线程和事件名称
events_stages_summary_by_user_by_event_name 每个用户名和事件名称的舞台事件
events_stages_summary_global_by_event_name 舞台等待每个事件名称
events_statements_current 当前的陈述事件
events_statements_history 每个线程最近的语句事件
events_statements_history_long 总体上最近的陈述事件
events_statements_summary_by_account_by_event_name 每个帐户和事件名称的语句事件
events_statements_summary_by_digest 每个架构和摘要值的语句事件
events_statements_summary_by_host_by_event_name 每个主机名和事件名称的语句事件
events_statements_summary_by_thread_by_event_name 每个线程和事件名称的语句事件
events_statements_summary_by_user_by_event_name 每个用户名和事件名称的语句事件
events_statements_summary_global_by_event_name 每个事件名称的语句事件
events_waits_current 目前的等待事件
events_waits_history 每个线程最近的等待事件
events_waits_history_long 最近的等待事件
events_waits_summary_by_account_by_event_name 每个帐户和事件名称等待事件
events_waits_summary_by_host_by_event_name 每个主机名和事件名称等待事件
events_waits_summary_by_instance 每个实例等待事件
events_waits_summary_by_thread_by_event_name 每个线程和事件名称等待事件
events_waits_summary_by_user_by_event_name 每个用户名和事件名称等待事件
events_waits_summary_global_by_event_name 每个事件名称等待事件
file_instances 文件实例
file_summary_by_event_name 每个事件名称的文件事件
file_summary_by_instance 每个文件实例的文件事件
host_cache 来自内部主机缓存的信息
hosts 每个客户端主机名的连接统计
mutex_instances 互斥同步对象实例
objects_summary_global_by_type 对象摘要
performance_timers 哪些活动计时器可用
rwlock_instances 锁定同步对象实例
session_account_connect_attrs 当前会话的每个连接属性
session_connect_attrs 所有会话的连接属性
setup_actors 如何初始化新前台线程的监视
setup_consumers 可以存储事件信息的消费者
setup_instruments 可以收集事件的检测对象的类
setup_objects 应监控哪些对象
setup_timers 当前事件计时器
socket_instances 活动连接实例
socket_summary_by_event_name 套接字等待和每个事件名称的I / O.
socket_summary_by_instance 套接字等待每个实例的I / O.
table_io_waits_summary_by_index_usage 表I / O等待每个索引
table_io_waits_summary_by_table 表I / O每个表等待
table_lock_waits_summary_by_table 表锁等待每个表
threads 有关服务器线程的信息
users 每个客户端用户名的连接统计
下面我们还是以“SHOW STATUS”命令获取MySQL实例状态,“SHOW VARIABLES”命令获取MySQL实例设置变量来看有哪些重要的监控指标。
1、监控MySQL的哪些指标
#系统重要指标
version
mysql版本
设置变量
runTime
mysql运行时间(秒)
Uptime
服务器已启动的秒数。
#会话相关
#、会话连接
maxConnections
max_connections
variables
最大连接数(max_connections)
mysqld实际上允许 max_connections + 1个客户端连接。保留额外的连接,以供具有SUPER特权的帐户使用 。通过将特权授予管理员而不是普通用户(该用户不需要),具有PROCESS特权的管理员也 可以连接到服务器并用于SHOW PROCESSLIST诊断问题,即使连接了最大数量的非特权客户端也是如此。
如果服务器由于max_connections达到限制而拒绝连接 ,则它将增加 Connection_errors_max_connections 状态变量。
threadsConnected
Threads_connected
当前打开的连接数
threadsRunning
Threads_running
当前活跃的连接数 : 当前正处于激活状态的线程个数
threadsCreated
创建处理连接的线程数
计算为两次监控间隔时间的增量。
Threads_created :
创建用于处理连接的线程数。
如果 Threads_created较大,则可能要增加 thread_cache_size值。
高速缓存未命中率可以计算为 Threads_created/ Connections。
threadCacheSize
最大缓存线程数
thread_cache_size
variables
服务器可以缓存多少线程以供重用。
当客户端断开连接时,如果当前线程的少于thread_cache_size线程,则将客户端的线程放入缓存中。
通过尽可能地重用从缓存中获取的线程来满足线程请求,并且仅当缓存为空时才创建新线程。如果您有很多新连接,则可以增加此变量以提高性能。
通常,如果您具有良好的线程实现,则这不会显着提高性能。但是,如果您的服务器每秒看到数百个连接,则通常应设置thread_cache_size足够高,以便大多数新连接使用缓存的线程。
通过检查Connections和Threads_created状态变量之间的差异 ,您可以了解线程缓存的效率。有关详细信息,请参见第5.1.9节“服务器状态变量”。
默认值基于以下公式,上限为100:
8 + (max_connections / 100)
threadsCached
缓存线程数量
Threads_cached :
线程缓存中的线程数。
threadCacheHitRates
线程缓存命中率,范围0~1。
可以计算为: thread_cache_hit_rate = 1 - Threads_created_increment / Connections_increment
Threads_created_increment和Connections_increment表示两次监控间隔时间的增量
connections
尝试连接MySQL次数(成功或失败)。
计算为两次监控间隔时间的增量。
Connections
与MySQL服务器的连接尝试次数(成功或失败)。
abortedClients
由于客户端在未正确关闭连接而中止的连接数
Aborted_clients
由于客户端在未正确关闭连接的情况下死亡而中止的连接数。
abortedConnects
连接到MySQL的失败尝试次数
Aborted_connects
连接到MySQL服务器的失败尝试次数。请参见第B.4.2.11节“通信错误和中止的连接”。
有关其他与连接有关的信息,请检查Connection_errors_xxx状态变量和host_cache表格。
connectionErrorsInternal
由于服务器内部错误(例如无法启动新线程或内存不足情况)而被拒绝的连接数
Connection_errors_internal
由于服务器内部错误(例如无法启动新线程或内存不足情况)而被拒绝的连接数。
connectionErrorsMaxConnections
达到最大连接限制而拒绝的连接数
Connection_errors_max_connections
由于max_connections达到服务器限制,拒绝的连接数 。
Connection_errors_xxx
这些变量提供有关客户端连接过程中发生的错误的信息。它们仅是全局的,代表跨所有主机的连接汇总的错误计数。
这些变量跟踪主机缓存未解决的错误(请参见第8.12.5.2节“ DNS查找优化和主机缓存”),例如与TCP连接不相关的错误,它们发生在连接过程的早期(甚至更早) IP地址是已知的),或者不是特定于任何特定IP地址的(例如,内存不足的情况)。
Connection_errors_accept
accept()在侦听端口上 进行呼叫期间发生的错误数 。
Connection_errors_internal
由于服务器内部错误(例如无法启动新线程或内存不足情况)而被拒绝的连接数。
Connection_errors_max_connections
由于max_connections达到服务器限制,拒绝的连接数 。
Connection_errors_peer_address
搜索连接客户端IP地址时发生的错误数。
Connection_errors_select
呼叫 侦听端口select()或poll()在侦听端口上发生的错误数 。(此操作失败不一定表示客户端连接被拒绝。)
Connection_errors_tcpwrap
libwrap库拒绝的连接数
#、会话流量
bytesReceivedPerSec
平均每秒从所有客户端接收到的字节数,单位B
Bytes_received
从所有客户端收到的字节数。
bytesSentPerSec
平均每秒发送给所有客户端的字节数,单位B
Bytes_sent
发送给所有客户端的字节数。
#、会话操作统计
commitCount
提交的操作次数
Com_commit
rollbackCount
回滚的操作次数
Com_rollback
insertCount
插入的操作次数
Com_insert + Com_insert_select
Com_insert_select统计:
INSERT SELECT FROM
如果您的数据在其他表中已经存在,可以通过INSERT SELECT FROM将数据复制到另外一张表。
updateCount
更新的操作次数
Com_update + Com_update_multi
deleteCount
删除的操作次数
Com_delete + Com_delete_multi
selectCount
查询的操作次数,不包括从缓存中返回结果的查询
Com_select
selectTotalCount
查询的操作次数,包括从缓存中返回结果的查询
selectTotalCount = Com_select + Qcache_hits
SELECT 查询总数由以下公式给出:
Com_select
+ Qcache_hits
+ queries with errors found by parser
该Com_select值由以下公式给出:
Qcache_inserts
+ Qcache_not_cached
+ queries with errors found during the column-privileges check
tps
每秒处理事务数
tps = Com_commit/s + Com_rollback/s
qps
每秒操作数
qps = selectTotalCount/s + Com_insert/s + Com_update/s + Com_delete/s
相关说明:
Com_xxx
Com_xxx语句计数器变量指示每个xxx语句已执行的次数。
每种类型的语句都有一个状态变量。例如,Com_delete和Com_update分别计数DELETE和UPDATE语句。
Com_delete_multi和Com_update_multi类似,但适用于使用多表语法的DELETE和UPDATE语句。
如果从查询缓存返回查询结果,则服务器将递增Qcache_hits状态变量,而不是Com_select。请参见第8.10.3.4节“查询缓存状态和维护”。
即使准备好的语句参数未知或执行期间发生错误,所有Com_stmt_xxx变量也会增加。
换句话说,它们的值对应于发出的请求数,而不是成功完成的请求数。
Com_stmt_xxx状态变量如下:
Com_stmt_prepare
Com_stmt_execute
Com_stmt_fetch
Com_stmt_send_long_data
Com_stmt_reset
Com_stmt_close
这些变量代表准备好的语句命令。它们的名称指的是网络层中使用的COM_xxx命令集。
换句话说,只要执行诸如mysql_stmt_prepare(),mysql_stmt_execute()之类的预备语句API调用,它们的值就会增加。
但是,对于PREPARE,EXECUTE或DEALLOCATE PREPARE,Com_stmt_prepare,Com_stmt_execute和Com_stmt_close也分别增加。
此外,对于PREPARE,EXECUTE和DEALLOCATE PREPARE语句,较旧的语句计数器变量Com_prepare_sql,Com_execute_sql和Com_dealloc_sql的值增加。
Com_stmt_fetch代表从游标获取时发出的网络往返总数。
Com_stmt_reprepare指示在元数据更改语句所引用的表或视图之后,服务器自动重新准备语句的次数。
reprepare操作会递增Com_stmt_reprepare以及Com_stmt_prepare。
#SQL性能统计相关
slowQueryCount
慢查询的次数
转增量
Slow_queries
耗时超过long_query_time秒的查询数 。无论是否启用慢查询日志,此计数器都会递增。
有关该日志的信息,请参见 第5.4.5节“慢查询日志”。
tableLocksWaited
需要等待获得表锁的请求次数
转增量
Table_locks_waited
无法立即授予对表锁的请求并需要等待的次数。
如果这很高,并且您有性能问题,则应首先优化查询,然后拆分一个或多个表或使用复制。
tableLocksWaitedPercent
需要等待获得表锁的请求比例
tableLocksWaitedPercent = Table_locks_waited / (Table_locks_waited + Table_locks_immediate)
Table_locks_immediate
可以立即授予对表锁定的请求的次数。
selectScan
对第一个表进行完全扫描的联接数量(全表扫描)
转增量
Select_scan
对第一个表进行完全扫描的联接数量
selectFullJoin
由于不使用索引而执行表扫描的联接数量
转增量
Select_full_join
由于不使用索引而执行表扫描的联接数。
如果该值不为0,则应仔细检查表的索引。
handlerReadRndPerSec
平均每秒基于固定位置读取行的请求数
Handler_read_rnd
基于固定位置读取行的请求数。
如果您要执行很多需要对结果进行排序的查询,则此值很高。
您可能有很多查询需要MySQL扫描整个表,或者您的联接未正确使用键。
handlerReadRndNextPerSec
平均每秒读取数据文件下一行的请求数
Handler_read_rnd_next
读取数据文件下一行的请求数。
如果要进行大量表扫描,则此值较高。
通常,这表明您的表未正确建立索引,或者未编写查询来利用您拥有的索引。
sortMergePasses
排序必须执行合并的次数
转增量
Sort_merge_passes
排序算法必须执行合并的次数。
如果该值很大,则应考虑增加sort_buffer_size系统变量的值。
sortScanPerSec
平均每秒通过扫描表完成的排序数量
Sort_scan
通过扫描表完成的排序次数。
sortRangePerSec
平均每秒使用范围完成的排序数量
Sort_range
使用ranges完成的排序数量。
#查询缓存
先查询判断是否支持查询缓存,没有话就没有这些指标
have_query_cache
YES如果mysqld支持查询缓存,NO则不支持。
设置变量
queryCacheSize
查询缓存空间大小,单位是字节
设置变量
query_cache_size
查询缓存空间大小。
qcacheFreeMemory
查询缓存可用空间
Qcache_free_memory
查询缓存的可用内存量。
qcacheFreePercent
查询缓存空闲率
qcacheFreePercent = qcacheFreeMemory / queryCacheSize
qcacheHitRate
查询缓存命中率
qcacheHitRate = Qcache_hits/(Qcache_hits + Com_select)
Qcache_hits
查询缓存命中数。
SELECT 查询总数由以下公式给出:
Com_select
+ Qcache_hits
+ queries with errors found by parser
该Com_select值由以下公式给出:
Qcache_inserts
+ Qcache_not_cached
+ queries with errors found during the column-privileges check
qcacheInsertsPercent
缓存查询结果的查询比例
qcacheInsertsPercent = Qcache_inserts / (Qcache_inserts + Qcache_not_cached)
Qcache_inserts :
添加到查询缓存中的查询次数。
Qcache_not_cached
无法缓存查询的数量(不可缓存或由于query_cache_type设置而无法缓存)。
qcacheLowmemPrunes
由于查询缓存空间不足而进行LRU内存回收的次数
次数过多,增加query_cache_size。
增量
Qcache_lowmem_prunes
查询缓存空间不足而进行LRU内存回收的次数。
次数过多,增加query_cache_size。
#innodb相关
#、innodb数据读写
innodbDataReadBytesPerSec
平均每秒InnoDB读取的数据量,单位为B
Innodb_data_read
自服务器启动以来读取的数据量(以字节为单位)。
innodbDataWrittenBytesPerSec
平均每秒InnoDB写入的数据量,单位为B
Innodb_data_written
到目前为止已写入的数据量(以字节为单位)。
innodbDataReadsPerSec
平均每秒InnoDB读取系统文件的次数
Innodb_data_reads
读取的数据总次数(读取OS文件)
innodbDataWritesPerSec
平均每秒InnoDB写入系统文件的次数
Innodb_data_writes
数据写入总次数。
innodbDataFsyncsPerSec
平均每秒InnoDB进行fsync操作的次数
Innodb_data_fsyncs
到目前为止,fsync()操作的数量。 fsync()调用的频率受innodb_flush_method配置选项的设置影响。
innodbDataPendingReads
InnoDB当前挂起的读取数
Innodb_data_pending_reads
当前挂起的读取数。
innodbDataPendingWrites
InnoDB当前挂起的写入数
Innodb_data_pending_writes
当前挂起的写入数。
innodbDataPendingFsyncs
InnoDB当前待处理的fsync操作数
Innodb_data_pending_fsyncs
当前待处理的fsync()操作数。 fsync()调用的频率受innodb_flush_method配置选项的设置影响。
#、innodb行操作统计
innodbRowsInsertedPerSec
平均每秒插入InnoDB表的行数
Innodb_rows_inserted
插入InnoDB表的行数。
innodbRowsDeletedPerSec
平均每秒从InnoDB表删除的行数
Innodb_rows_deleted
从InnoDB表中删除的行数。
innodbRowsUpdatedPerSec
平均每秒更新InnoDB表的行数
Innodb_rows_updated
InnoDB表中更新的行数。
innodbRowsReadPerSec
平均每秒从InnoDB表读取的行数
Innodb_rows_read
从InnoDB表读取的行数。
innodbRowLockCurrentWaits
InnoDB表上的操作当前正在等待的行锁数
Innodb_row_lock_current_waits
InnoDB表上的操作当前正在等待的行锁数。
innodbRowLockwaits
InnoDB表上的操作必须等待行锁的次数
增量
Innodb_row_lock_waits
InnoDB表上的操作必须等待行锁定的次数。
innodbRowLockTime
获取InnoDB表的行锁所花费的总时间,以毫秒为单位
增量
Innodb_row_lock_time
获取InnoDB表的行锁所花费的总时间(以毫秒为单位)。
innodbRowLockTimeAvg
获取InnoDB表的行锁的平均时间,以毫秒为单位
innodbRowLockTimeAvg增量 = innodbRowLockTime增量 / innodbRowLockwaits增量
而不是获取下面这个,下面这个是统计所有的,不能代表最近一段时间的状态
Innodb_row_lock_time_avg
获取InnoDB表的行锁的平均时间,以毫秒为单位。
#、innodb缓冲池状态
innodbBufferPoolSize
InnoDB缓存池最大空间大小,以字节为单位
innodb_buffer_pool_size
mysql配置变量参数。
缓冲池(用于InnoDB缓存表和索引数据的内存区域) 的大小(以字节为单位) 。
innodbBufferPoolBytesData
InnoDB缓存池可缓存数据的空间大小(包括脏页和干净页),以字节为单位
Innodb_buffer_pool_bytes_data
InnoDB缓冲池中包含数据的字节总数。 该数字包括脏页和干净页。
与Innodb_buffer_pool_pages_data相比,为了更准确地计算内存使用量,当压缩表导致缓冲池保存不同大小的页面时。
innodbBufferPoolBytesDirty
InnoDB缓冲池中的脏页占用空间,字节
Innodb_buffer_pool_bytes_dirty
InnoDB缓冲池中的脏页中保存的当前字节总数。
与Innodb_buffer_pool_pages_dirty相比,为了更准确地计算内存使用量,当压缩表导致缓冲池保存不同大小的页面时。
innodbBufferPoolBytesMisc
InnoDB缓冲池中由于分配给管理开销(例如行锁或自适应哈希索引)的空间大小,以字节为单位
innodbBufferPoolBytesMisc = Innodb_buffer_pool_pages_misc * Innodb_page_size
Innodb_buffer_pool_pages_misc
InnoDB缓冲池中由于分配给管理开销(例如行锁或自适应哈希索引)而繁忙的页面数。
此值也可以计算为Innodb_buffer_pool_pages_total-Innodb_buffer_pool_pages_free-Innodb_buffer_pool_pages_data。
使用压缩表时,Innodb_buffer_pool_pages_misc可能会报告超出范围的值(错误#59550)。
Innodb_page_size
InnoDB页面大小(默认为16KB)。页面中包含许多内存页统计值;页面大小使它们可以轻松转换为字节。
innodbBufferPoolDirtyPercent
Innodb缓冲池脏页空间占最大空间的比例
innodbBufferPoolDirtyPercent = innodbBufferPoolBytesDirty / innodbBufferPoolSize
innodbBufferPoolUsedPercent
Innodb缓冲池使用率
innodbBufferPoolUsedPercent = 1 - Innodb_buffer_pool_pages_free / Innodb_buffer_pool_pages_total
Innodb_buffer_pool_pages_total = Innodb_buffer_pool_pages_free + Innodb_buffer_pool_pages_data + Innodb_buffer_pool_pages_misc
Innodb_buffer_pool_pages_total
InnoDB缓冲池的总大小(以页为单位)。使用压缩表时,报告的Innodb_buffer_pool_pages_data值可能大于Innodb_buffer_pool_pages_total(错误#59550)
Innodb_buffer_pool_pages_free
InnoDB缓冲池中的可用页数。
Innodb_buffer_pool_pages_data
InnoDB缓冲池中包含数据的页面数。 该数字包括脏页和干净页。
使用压缩表时,报告的Innodb_buffer_pool_pages_data值可能大于Innodb_buffer_pool_pages_total(错误#59550)。
Innodb_buffer_pool_pages_misc
InnoDB缓冲池中由于分配给管理开销(例如行锁或自适应哈希索引)而繁忙的页面数。
此值也可以计算为Innodb_buffer_pool_pages_total-Innodb_buffer_pool_pages_free-Innodb_buffer_pool_pages_data。
使用压缩表时,Innodb_buffer_pool_pages_misc可能会报告超出范围的值(错误#59550)。
innodbBufferPoolReadsPerSec
平均每秒Innodb从物理磁盘读取页的次数(物理读次数)
Innodb_buffer_pool_reads
InnoDB无法从缓冲池满足的逻辑读取数,必须直接从磁盘读取。
innodbBufferPoolReadRequestsPerSec
平均每秒从Innodb缓冲池的读次数(逻辑读请求数)
Innodb_buffer_pool_read_requests
逻辑读取请求的数量。
innodbBufferPoolReadHitRate
Innodb缓冲池的读取命中率
计算最近时间段的:
innodb_buffer_read_hit_rate = 1 - innodbBufferPoolReadsPerSec/innodbBufferPoolReadRequestsPerSec
而整体的:
innodb_buffer_read_hit_rate = 1 - Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests
innodbBufferPoolWriteRequestsPerSec
平均每秒对Innodb缓冲池的写次数
Innodb_buffer_pool_write_requests
对InnoDB缓冲池的写入次数。
innodbBufferPoolPagesFlushedPerSec
平均每秒对Innodb缓存池中刷新页请求数
Innodb_buffer_pool_pages_flushed
从InnoDB缓冲池刷新页面的请求数。
innodbBufferPoolWaitFree
Innodb等待可用的干净页面的次数
Innodb_buffer_pool_wait_free
通常,对InnoDB缓冲池的写操作在后台进行。
当InnoDB需要读取或创建页面并且没有可用的干净页面时,InnoDB首先刷新一些脏页面并等待该操作完成。
该计数器计算这些等待的次数。如果已经正确设置了innodb_buffer_pool_size,则此值应较小。
#、key buffer/MyISAM索引缓存
keyBufferSize
MyISAM key缓存区空间大小
key_buffer_size
设置变量
MyISAM表的 索引块被缓冲并由所有线程共享。 key_buffer_size是用于索引块的缓冲区的大小。密钥缓冲区也称为密钥缓存。
keyCacheUsedSize
MyISAM key缓存已使用空间大小
keyCacheUsedSize = key_buffer_size - (Key_blocks_unused * key_cache_block_size)
keyCacheUsedPercent
MyISAM key缓存使用率
KeyCacheUsedPercent = 1 - ((Key_blocks_unused * key_cache_block_size) / key_buffer_size)
key_cache_block_size
设置变量
密钥缓存中块的大小(以字节为单位)。默认值为1024。
Key_blocks_unused
MyISAM密钥缓存中未使用的块数。您可以使用此值来确定正在使用的密钥缓存数量。
keyReadRequestsPerSec
平均每秒MyISAM key缓存读请求次数
转化为增量
Key_read_requests
从MyISAM密钥高速缓存中读取密钥块的请求数。
keyReadsPerSec
平均每秒从硬盘读取数据块到MyISAM key缓存的次数(物理读)
平均每秒从硬盘读取数据块到MyISAM key缓存的物理读取次数
转化为增量
Key_reads
从磁盘到MyISAM密钥高速缓存中的密钥块的物理读取数。
如果Key_reads很大,则您的key_buffer_size值可能太小。可以将缓存未命中率计算为Key_reads / Key_read_requests。
keyReadHitRate
MyISAM key缓存读取命中率
keyReadHitRate = 1 - Key_reads / Key_read_requests
keyWriteRequestPerSec
平均每秒将数据块写入到MyISAM key缓存的写入请求次数
转化为增量
Key_write_requests
将密钥块写入MyISAM密钥高速缓存的请求数。
keyWritesPerSec
平均每秒从MyISAM key缓存写入到磁盘的写入次数(物理写)
平均每秒从MyISAM key缓存写入到磁盘的物理写入次数
转化为增量
Key_writes
从MyISAM密钥高速缓存到磁盘的密钥块的物理写入次数。
keyWritesPercent
MyISAM key缓存物理写占比
keyWritesPercent = keyWrites / keyWriteRequest
Key_reads/Key_read_requests比率通常应小于0.01。
Key_writes/Key_write_requests如果您主要使用更新和删除操作,则该比率通常接近1;
但是如果您倾向于同时影响多个行的更新操作或使用DELAY_KEY_WRITEtable选项,则该比率可能会小得多 。
#. 临时表
createdTmpTables
创建内部临时表的数量(内存或磁盘中)
在执行语句时创建的内部临时表的数量(在内存或磁盘中)
增量
createdTmpTablesPerSec
创建内部临时表的数量(内存或磁盘中)/秒
平均每秒在执行语句时创建的内部临时表的数量(在内存或磁盘中)
Created_tmp_tables
服务器在执行语句时创建的内部临时表的数量。(在内存或磁盘中)
您可以通过比较Created_tmp_disk_tables和 Created_tmp_tables 变量的值,将创建的内部磁盘临时表的数量与创建的内部临时表的总数进行比较 。
另请参见第8.4.4节“ MySQL中的内部临时表使用”。
SHOW STATUS语句的 每次调用都使用内部临时表并增加全局 Created_tmp_tables值。
createdTmpDiskTables
创建磁盘临时表的数量
在执行语句时创建磁盘临时表的数量
增量
createdTmpDiskTablesPerSec
创建磁盘临时表的数量/秒
平均每秒在执行语句时创建磁盘临时表的数量
Created_tmp_disk_tables
服务器在执行语句时创建的内部磁盘临时表的数量。
如果内部临时表最初是作为内存表创建的,但是变得太大,MySQL会自动将其转换为磁盘表。
内存中临时表的最大大小为tmp_table_size和 max_heap_table_size值的最小值 。
如果Created_tmp_disk_tables 较大,则可能需要增加 tmp_table_size或 max_heap_table_size值,以减少内存中内部临时表将转换为磁盘表的可能性。
您可以通过比较Created_tmp_disk_tables和 Created_tmp_tables 变量的值,将创建的内部磁盘临时表的数量与创建的内部临时表的总数进行比较 。
另请参见第8.4.4节“ MySQL中的内部临时表使用”。
createdTmpDiskTablesPercent
创建磁盘临时表的比例
在执行语句时创建到磁盘的磁盘临时表的比例。
createdTmpDiskTablesPercent = Created_tmp_disk_tables/Created_tmp_tables
比值最好不要超过10%,如果Created_tmp_tables值比较大,可能是排序句子过多或者连接句子不够优化
#、打开表的缓存
openTables
当前正在打开的表数量
Open_tables
打开的表数。(当前)
openedTables
打开表的次数
转化为增量
Opened_tables
已打开的表数。(计数)
如果 Opened_tables太大或迅速增加,您的table_open_cache值可能太小。
#. 其他
openFiles:
打开的文件数量
Open_files
打开的文件数。 此计数包括服务器打开的常规文件。
它不包括其他类型的文件,例如套接字或管道。 此外,该计数不包括存储引擎使用其自身内部功能打开的文件,而不是要求服务器级别打开的文件。
Slave delay: 备库延迟
可以在slave节点上执行show slave status\G命令,Seconds_Behind_Master项的值即为slave当前的延时量,单位秒。
另外可以区分主/从库角色
2、一目了然的MySQL监控的UI界面
3、Python程序获取MySQL监控状态
# -*- coding: utf-8 -*-
import logging
import time
from xxx_utils import erlangutils
from .task import Task
from .task_config import TaskConfig
from erlang_utils.monitor_level import Level
from erlang_message.task_message import TaskMessage
import erlang_utils.mysql_template as mysql_template
logger = logging.getLogger("xxx-monitor")
class MysqlMonitorTask(Task):
def __init__(self, globalConfig: dict, instanceConfig: dict):
self.monitorPeriodTimeSec = globalConfig.get('monitorPeriodTimeSec')
self.enable = globalConfig.get(
'monitorEnable') & instanceConfig.get('enable')
self.mysqlId = instanceConfig.get('mysqlid')
self.mysqlHost = instanceConfig.get('host')
self.mysqlPort = instanceConfig.get('port')
self.mysqlUser = instanceConfig.get('user')
self.mysqlPasswd = instanceConfig.get('passwd')
self.lastMonitorTimeSec = None
self.lastMysqlUptime = None
super(MysqlMonitorTask, self).__init__()
def get_mysqlid(self):
return self.mysqlId
def do_create_config(self):
return TaskConfig('mysqlinfo', self.monitorPeriodTimeSec, enable=self.enable, level=Level.INFO, description='mysql monitoring(' + self.mysqlId + ')')
def do_run(self):
logger.debug(self.mysqlId + ' mysql monitoring task running...')
conn = None
cursor = None
try:
conn = mysql_template.get_connect(
self.mysqlHost, self.mysqlPort, self.mysqlUser, self.mysqlPasswd)
cursor = conn.cursor()
currentMonitorTimeSec = int(time.time())
mysqlVariables = mysql_template.get_mysql_variables(cursor)
mysqlStatus = mysql_template.get_mysql_status(cursor)
# print(str(mysql_variables))
# print(str(mysql_status))
# 服务器已启动的秒数
mysqlUptime = mysql_template.get_item_int(mysqlStatus, 'Uptime')
# 监控程序启动首次运行,或监控的mysql重启了
# 需要重新设置上一次状态
if self.lastMysqlUptime is None or self.lastMysqlUptime > mysqlUptime:
time.sleep(2)
self.lastMonitorTimeSec = currentMonitorTimeSec
self.lastMysqlUptime = mysqlUptime
self.lastMysqlVariables = mysqlVariables
self.lastMysqlStatus = mysqlStatus
currentMonitorTimeSec = int(time.time())
mysqlVariables = mysql_template.get_mysql_variables(cursor)
mysqlStatus = mysql_template.get_mysql_status(cursor)
mysqlUptime = mysql_template.get_item_int(
mysqlStatus, 'Uptime')
self.currentMonitorTimeSec = currentMonitorTimeSec
self.mysqlVariables = mysqlVariables
self.mysqlStatus = mysqlStatus
msg = TaskMessage()
# 系统重要指标
msg['mysqlid'] = self.mysqlId
msg['host'] = self.mysqlHost
msg['port'] = int(self.mysqlPort)
self._get_mysql_item(msg, 'version', mysqlVariables, 'version')
self._get_mysql_item_int(msg, 'runTime', mysqlStatus, 'Uptime')
# 会话连接指标
self._get_mysql_item_int(
msg, 'maxConnections', mysqlVariables, 'max_connections')
self._get_mysql_item_int(
msg, 'threadCacheSize', mysqlVariables, 'thread_cache_size')
self._get_mysql_status_item_increment(
msg, 'connections', 'Connections')
self._get_mysql_item_int(
msg, 'threadsConnected', mysqlStatus, 'Threads_connected')
self._get_mysql_item_int(
msg, 'threadsRunning', mysqlStatus, 'Threads_running')
self._get_mysql_item_int(
msg, 'threadsCached', mysqlStatus, 'Threads_cached')
self._get_mysql_status_item_increment(
msg, 'threadsCreated', 'Threads_created')
connectionsIncrement = self._return_mysql_status_item_increment(
'Connections')
threadsCreatedIncrement = self._return_mysql_status_item_increment(
'Threads_created')
if connectionsIncrement is not None and threadsCreatedIncrement is not None:
if connectionsIncrement > 0 and threadsCreatedIncrement > 0:
msg['threadCacheHitRates'] = erlangutils.math_1MinusDivision(
threadsCreatedIncrement, connectionsIncrement)
else:
msg['threadCacheHitRates'] = 1
self._get_mysql_status_item_increment(
msg, 'abortedClients', 'Aborted_clients')
self._get_mysql_status_item_increment(
msg, 'abortedConnects', 'Aborted_connects')
self._get_mysql_status_item_increment(
msg, 'connectionErrorsInternal', 'Connection_errors_internal')
self._get_mysql_status_item_increment(
msg, 'connectionErrorsMaxConnections', 'Connection_errors_max_connections')
# 会话流量指标
self._get_mysql_status_item_rates(
msg, 'bytesReceivedPerSec', 'Bytes_received')
self._get_mysql_status_item_rates(
msg, 'bytesSentPerSec', 'Bytes_sent')
# 会话操作统计指标
self._get_mysql_status_item_increment(
msg, 'commitCount', 'Com_commit')
self._get_mysql_status_item_increment(
msg, 'rollbackCount', 'Com_rollback')
insertIncrement = self._return_mysql_status_item_increment(
'Com_insert')
insertSelectIncrement = self._return_mysql_status_item_increment(
'Com_insert_select')
msg['insertCount'] = insertIncrement + insertSelectIncrement
updateIncrement = self._return_mysql_status_item_increment(
'Com_update')
updateMultiIncrement = self._return_mysql_status_item_increment(
'Com_update_multi')
msg['updateCount'] = updateIncrement + updateMultiIncrement
deleteIncrement = self._return_mysql_status_item_increment(
'Com_delete')
deleteMultiSelectIncrement = self._return_mysql_status_item_increment(
'Com_delete_multi')
msg['deleteCount'] = deleteIncrement + deleteMultiSelectIncrement
self._get_mysql_status_item_increment(
msg, 'selectCount', 'Com_select')
Qcache_hits = self._return_mysql_status_item_increment(
'Qcache_hits')
if Qcache_hits is not None:
msg['selectTotalCount'] = msg['selectCount'] + Qcache_hits
else:
msg['selectTotalCount'] = msg['selectCount']
msg['tps'] = erlangutils.math_division((msg['commitCount'] + msg['rollbackCount']),
(currentMonitorTimeSec - self.lastMonitorTimeSec))
msg['qps'] = erlangutils.math_division((msg['selectTotalCount'] + msg['insertCount'] + msg['updateCount'] + msg['deleteCount']),
(currentMonitorTimeSec - self.lastMonitorTimeSec))
# 查询缓存
# 先查询判断是否支持查询缓存,没有话就没有这些指标
haveQueryCache = mysql_template.get_item_boolean(
mysqlVariables, 'have_query_cache')
if haveQueryCache is not None and haveQueryCache is True:
self._get_mysql_item_int(
msg, 'queryCacheSize', mysqlVariables, 'query_cache_size')
self._get_mysql_item_int(
msg, 'qcacheFreeMemory', mysqlStatus, 'Qcache_free_memory')
if msg['qcacheFreeMemory'] > 0 and msg['queryCacheSize'] > 0:
msg['qcacheFreePercent'] = erlangutils.math_division(
msg['qcacheFreeMemory'], msg['queryCacheSize'])
else:
msg['qcacheFreePercent'] = 0
Qcache_hits = self._return_mysql_status_item_increment(
'Qcache_hits')
Com_select = self._return_mysql_status_item_increment(
'Com_select')
if Qcache_hits > 0 or Com_select > 0:
msg['qcacheHitRate'] = erlangutils.math_division(
Qcache_hits, (Qcache_hits + Com_select))
else:
msg['qcacheHitRate'] = 1
Qcache_inserts = self._return_mysql_status_item_increment(
'Qcache_inserts')
Qcache_not_cached = self._return_mysql_status_item_increment(
'Qcache_not_cached')
if Qcache_inserts > 0 or Qcache_not_cached > 0:
msg['qcacheInsertsPercent'] = erlangutils.math_division(
Qcache_inserts, (Qcache_inserts + Qcache_not_cached))
else:
msg['qcacheInsertsPercent'] = 1
self._get_mysql_status_item_increment(
msg, 'qcacheLowmemPrunes', 'Qcache_lowmem_prunes')
# SQL性能统计相关
self._get_mysql_status_item_increment(
msg, 'slowQueryCount', 'Slow_queries')
self._get_mysql_status_item_increment(
msg, 'selectScan', 'Select_scan')
self._get_mysql_status_item_increment(
msg, 'selectFullJoin', 'Select_full_join')
self._get_mysql_status_item_rates(
msg, 'handlerReadRndPerSec', 'Handler_read_rnd')
self._get_mysql_status_item_rates(
msg, 'handlerReadRndNextPerSec', 'Handler_read_rnd_next')
self._get_mysql_status_item_increment(
msg, 'sortMergePasses', 'Sort_merge_passes')
self._get_mysql_status_item_rates(
msg, 'sortScanPerSec', 'Sort_scan')
self._get_mysql_status_item_rates(
msg, 'sortRangePerSec', 'Sort_range')
self._get_mysql_status_item_increment(
msg, 'tableLocksWaited', 'Table_locks_waited')
Table_locks_immediate = self._return_mysql_status_item_increment(
'Table_locks_immediate')
if msg['tableLocksWaited'] > 0:
msg['tableLocksWaitedPercent'] = erlangutils.math_division(
msg['tableLocksWaited'], (msg['tableLocksWaited'] + Table_locks_immediate))
else:
msg['tableLocksWaitedPercent'] = 0
# innodb数据读写
self._get_mysql_status_item_rates(
msg, 'innodbDataReadBytesPerSec', 'Innodb_data_read')
self._get_mysql_status_item_rates(
msg, 'innodbDataWrittenBytesPerSec', 'Innodb_data_written')
self._get_mysql_status_item_rates(
msg, 'innodbDataReadsPerSec', 'Innodb_data_reads')
self._get_mysql_status_item_rates(
msg, 'innodbDataWritesPerSec', 'Innodb_data_writes')
self._get_mysql_status_item_rates(
msg, 'innodbDataFsyncsPerSec', 'Innodb_data_fsyncs')
self._get_mysql_item_int(
msg, 'innodbDataPendingReads', mysqlStatus, 'Innodb_data_pending_reads')
self._get_mysql_item_int(
msg, 'innodbDataPendingWrites', mysqlStatus, 'Innodb_data_pending_writes')
self._get_mysql_item_int(
msg, 'innodbDataPendingFsyncs', mysqlStatus, 'Innodb_data_pending_fsyncs')
# innodb行操作统计
self._get_mysql_status_item_rates(
msg, 'innodbRowsDeletedPerSec', 'Innodb_rows_deleted')
self._get_mysql_status_item_rates(
msg, 'innodbRowsInsertedPerSec', 'Innodb_rows_inserted')
self._get_mysql_status_item_rates(
msg, 'innodbRowsReadPerSec', 'Innodb_rows_read')
self._get_mysql_status_item_rates(
msg, 'innodbRowsUpdatedPerSec', 'Innodb_rows_updated')
self._get_mysql_status_item_rates(
msg, 'innodbDataFsyncsPerSec', 'Innodb_data_fsyncs')
self._get_mysql_item_int(
msg, 'innodbRowLockCurrentWaits', mysqlStatus, 'Innodb_row_lock_current_waits')
self._get_mysql_status_item_increment(
msg, 'innodbRowLockwaits', 'Innodb_row_lock_waits')
self._get_mysql_status_item_increment(
msg, 'innodbRowLockTime', 'Innodb_row_lock_time')
if msg['innodbRowLockwaits'] > 0 and msg['innodbRowLockTime'] > 0:
msg['innodbRowLockTimeAvg'] = erlangutils.math_division(msg['innodbRowLockTime'],
msg['innodbRowLockwaits'])
else:
msg['innodbRowLockTimeAvg'] = 0
# innodb缓冲池状态
self._get_mysql_item_int(
msg, 'innodbBufferPoolSize', mysqlVariables, 'innodb_buffer_pool_size')
self._get_mysql_item_int(
msg, 'innodbBufferPoolBytesData', mysqlStatus, 'Innodb_buffer_pool_bytes_data')
self._get_mysql_item_int(
msg, 'innodbBufferPoolBytesDirty', mysqlStatus, 'Innodb_buffer_pool_bytes_dirty')
innodbPageSize = mysql_template.get_item_int(
mysqlStatus, 'Innodb_page_size')
if msg['innodbBufferPoolBytesData'] is None:
Innodb_buffer_pool_pages_data = mysql_template.get_item_int(
mysqlStatus, 'Innodb_buffer_pool_pages_data')
msg['innodbBufferPoolBytesData'] = Innodb_buffer_pool_pages_data * \
innodbPageSize
if msg['innodbBufferPoolBytesDirty'] is None:
Innodb_buffer_pool_pages_dirty = mysql_template.get_item_int(
mysqlStatus, 'Innodb_buffer_pool_pages_dirty')
msg['innodbBufferPoolBytesDirty'] = Innodb_buffer_pool_pages_dirty * innodbPageSize
innodbBufferPoolPagesMisc = mysql_template.get_item_int(
mysqlStatus, 'Innodb_buffer_pool_pages_misc')
msg['innodbBufferPoolBytesMisc'] = innodbBufferPoolPagesMisc * \
innodbPageSize
innodbBufferPoolPagesTotal = mysql_template.get_item_int(
mysqlStatus, 'Innodb_buffer_pool_pages_total')
innodbBufferPoolPagesFree = mysql_template.get_item_int(
mysqlStatus, 'Innodb_buffer_pool_pages_free')
msg['innodbBufferPoolDirtyPercent'] = erlangutils.math_division(msg['innodbBufferPoolBytesDirty'],
msg['innodbBufferPoolSize'])
msg['innodbBufferPoolUsedPercent'] = erlangutils.math_1MinusDivision(
innodbBufferPoolPagesFree, innodbBufferPoolPagesTotal)
self._get_mysql_status_item_rates(
msg, 'innodbBufferPoolReadsPerSec', 'Innodb_buffer_pool_reads')
self._get_mysql_status_item_rates(
msg, 'innodbBufferPoolReadRequestsPerSec', 'Innodb_buffer_pool_read_requests')
if msg['innodbBufferPoolReadRequestsPerSec'] is not None and msg['innodbBufferPoolReadRequestsPerSec'] > 0:
msg['innodbBufferPoolReadHitRate'] = erlangutils.math_1MinusDivision(
msg['innodbBufferPoolReadsPerSec'], msg['innodbBufferPoolReadRequestsPerSec'])
else:
msg['innodbBufferPoolReadHitRate'] = 1
self._get_mysql_status_item_rates(
msg, 'innodbBufferPoolWriteRequestsPerSec', 'Innodb_buffer_pool_write_requests')
self._get_mysql_status_item_rates(
msg, 'innodbBufferPoolPagesFlushedPerSec', 'Innodb_buffer_pool_pages_flushed')
self._get_mysql_status_item_increment(
msg, 'innodbBufferPoolWaitFree', 'Innodb_buffer_pool_wait_free')
# key buffer/MyISAM索引缓存
self._get_mysql_item_int(
msg, 'keyBufferSize', mysqlVariables, 'key_buffer_size')
KeyBlocksUnused = mysql_template.get_item_int(
mysqlStatus, 'Key_blocks_unused')
keyCacheBlockSize = mysql_template.get_item_int(
mysqlVariables, 'key_cache_block_size')
msg['keyCacheUsedSize'] = msg['keyBufferSize'] - \
(KeyBlocksUnused * keyCacheBlockSize)
msg['keyCacheUsedPercent'] = erlangutils.math_1MinusDivision(
(KeyBlocksUnused * keyCacheBlockSize), msg['keyBufferSize'])
self._get_mysql_status_item_rates(
msg, 'keyReadRequestsPerSec', 'Key_read_requests')
self._get_mysql_status_item_rates(
msg, 'keyReadsPerSec', 'Key_reads')
if msg['keyReadsPerSec'] > 0 and msg['keyReadRequestsPerSec'] > 0:
msg['keyReadHitRate'] = erlangutils.math_1MinusDivision(
msg['keyReadsPerSec'], msg['keyReadRequestsPerSec'])
else:
msg['keyReadHitRate'] = 1
self._get_mysql_status_item_rates(
msg, 'keyWriteRequestPerSec', 'Key_write_requests')
self._get_mysql_status_item_rates(
msg, 'keyWritesPerSec', 'Key_writes')
if msg['keyWritesPerSec'] > 0 and msg['keyWriteRequestPerSec'] > 0:
msg['keyWritesPercent'] = erlangutils.math_division(
msg['keyWritesPerSec'], msg['keyWriteRequestPerSec'])
else:
msg['keyWritesPercent'] = 0
# 临时表
self._get_mysql_status_item_increment(
msg, 'createdTmpTables', 'Created_tmp_tables')
self._get_mysql_status_item_rates(
msg, 'createdTmpTablesPerSec', 'Created_tmp_tables')
self._get_mysql_status_item_increment(
msg, 'createdTmpDiskTables', 'Created_tmp_disk_tables')
self._get_mysql_status_item_rates(
msg, 'createdTmpDiskTablesPerSec', 'Created_tmp_disk_tables')
if msg['createdTmpDiskTables'] > 0 and msg['createdTmpTables'] > 0:
msg['createdTmpDiskTablesPercent'] = erlangutils.math_division(
msg['createdTmpDiskTables'], msg['createdTmpTables'])
else:
msg['createdTmpDiskTablesPercent'] = 0
# 打开表的缓存
self._get_mysql_item_int(
msg, 'openTables', mysqlStatus, 'Open_tables')
self._get_mysql_status_item_increment(
msg, 'openedTables', 'Opened_tables')
# 其他
self._get_mysql_item_int(
msg, 'openFiles', mysqlStatus, 'Open_files')
self.lastMonitorTimeSec = currentMonitorTimeSec
self.lastMysqlUptime = mysqlUptime
self.lastMysqlVariables = mysqlVariables
self.lastMysqlStatus = mysqlStatus
return msg
except Exception:
logger.exception(self.mysqlId + ' mysql monitoring task error!')
finally:
if cursor is not None:
cursor.close()
if conn is not None:
conn.close()
def _get_mysql_item(self, msg, keyName, mysqlInfo, itemName):
value = mysql_template.get_item(mysqlInfo, itemName)
if value is not None:
msg[keyName] = value
def _get_mysql_item_int(self, msg, keyName, mysqlInfo, itemName):
value = mysql_template.get_item_int(mysqlInfo, itemName)
if value is not None:
msg[keyName] = value
def _get_mysql_item_boolean(self, msg, keyName, mysqlInfo, itemName):
value = mysql_template.get_item_boolean(mysqlInfo, itemName)
if value is not None:
msg[keyName] = value
def _return_mysql_status_item_increment(self, itemName):
lastValue = mysql_template.get_item_int(self.lastMysqlStatus, itemName)
value = mysql_template.get_item_int(self.mysqlStatus, itemName)
if lastValue is not None and value is not None:
return value - lastValue
def _get_mysql_status_item_increment(self, msg, keyName, itemName):
lastValue = mysql_template.get_item_int(self.lastMysqlStatus, itemName)
value = mysql_template.get_item_int(self.mysqlStatus, itemName)
if lastValue is not None and value is not None:
msg[keyName] = value - lastValue
def _get_mysql_status_item_rates(self, msg, keyName, itemName):
lastValue = mysql_template.get_item_int(self.lastMysqlStatus, itemName)
value = mysql_template.get_item_int(self.mysqlStatus, itemName)
if lastValue is not None and value is not None:
msg[keyName] = round((value - lastValue) / (
self.currentMonitorTimeSec - self.lastMonitorTimeSec), 2)