10-MySQlL DBA筆記-基礎知識

第四部分 運維篇
首先來了解一下數據庫的定義,數據庫是高效的、可靠的、易用的、安全的多用戶存儲引擎,咱們能夠經過它訪問大量的持久化數據。
咱們管理和維護數據庫,本質上也是要確保如上的特性,儘量地保證數據庫的高效、可靠、易用、安全、高併發和高吞吐。
好比,對於安全,咱們要儘可能避免因各類軟件、硬件、操做錯誤而致使的數據丟失或損毀。
對於高併發,也要求咱們在訪問控制、併發控制上作適當的設置和調優。
數據庫系統也應該是易用的,應儘量地作到對應用程序透明,研發人員不用去關心具體的物理存儲對於應用程序的影響。
數據存儲在磁盤上的方式和佈局應與程序認爲的邏輯結構無關。
數據庫系統應該是高效的,好比可以處理高併發的請求,可以處理複雜的查詢,或者可以計算大量的數據。
MySQL處理複雜查詢的能力目前還不太好,對大數據的分析處理也不是強項,但對於互聯網的OLTP應用,若是設置、調優得當,獲得較高的吞吐率其實並非一件難事。
此外,數據庫也應該是可靠的、高可用的,數據庫運維很重要的一個指標就是服務的可用性,若是不能提供持續穩定的服務,那麼其餘指標再好也沒有用。
運維篇將首先介紹數據庫運維的一些基礎知識,接着再介紹各類維護任務所須要的知識和技能,如監控、複製、升級、遷移、備份和恢復。
而後經過一些案例給讀者講述一些維護技巧及如何處理問題。
數據庫運維歷來都不只僅是一個技術問題,本篇最後將講述規模化運維管理的一些原則、經驗總結和認知。mysql

第10章 基礎知識
筆者在此假設本書的讀者是熟悉Unix或Linux操做系統的,至少會進行通常的操做,這本書不會講述操做系統的學習和腳本語言的撰寫,
若是你是一個初學者,那麼建議先閱讀一些入門圖書,好比《Unix&Linux大學教程》、《鳥哥的Linux私房菜》、《Linux命令行與Shell腳本編程大全》等。
讀者還須要搭建本身的學習和測試環境,配備了基礎的學習環境並懂得構建本身的測試環境後,才能夠經過實踐不斷拓寬、深化本身的知識體系。
若是你如今仍然沒有一個適宜的學習環境,那麼建議你儘快搭建一套LAMP或LNMP環境。
基礎環境的部署和使用將有助於你快速熟悉操做系統和數據庫。
本章將主要講述和MySQL相關的一些基礎知識。包括與MySQL相關的數據庫文件及參數設置,最後也會簡要介紹下MySQL的災難恢復過程。 sql

10.1 文件和I/O管理
10.1.1 MySQL日誌文件
如表10-1所示,MySQL有幾個不一樣的日誌文件,能夠幫助你瞭解mysqld(MySQL Server的主程序)內部發生的事情。
表10-1 MySQL的日誌文件及功能
默認狀況下,全部日誌均建立於mysqld數據目錄中。
經過刷新日誌,能夠強制mysqld關閉和從新打開日誌文件(或者在某些狀況下切換到一個新的日誌中)。
當你執行一個flush logs語句或執行mysqladmin flush-logs或mysqladmin refresh時,會使得日誌刷新。
下面將分別敘述各類日誌文件。 shell

1.錯誤日誌
錯誤日誌文件包含了mysqld啓動或中止時,以及服務器在運行過程當中發生任何嚴重錯誤時的相關信息。
能夠用--log-error[=file_name]選項來指定mysqld保存錯誤日誌文件的位置。
若是沒有給定file_name值,mysqld將使用錯誤日誌名host_name.err,並在數據目錄中寫入日誌文件。
須要留意的是,對於MySQL 5.1,當咱們使用flush logs命令刷新日誌時,錯誤日誌會被清空,並生成一個備份的錯誤日誌,
這種狀況下,每每只能看到最近的錯誤日誌,這可能會導致咱們不能及時發現問題。
咱們可使用工具實時監控錯誤日誌,好比swatch,或者本身編寫腳本檢查錯誤日誌。
也能夠發送MySQL錯誤日誌到系統日誌服務Syslog,這樣,咱們就能夠利用一些日誌分析工具集中分析和處理錯誤信息。 數據庫

2.通用日誌
若是想要知道mysqld內部發生了什麼,你應該用--log[=file_name]或-l[file_name]選項啓動它。
若是沒有給定file_name的值,那麼默認名就是host_name.log。
全部鏈接和語句都將被記錄到日誌文件中。
若是懷疑在客戶端發生了錯誤而且想要確切地知道該客戶端發送給mysqld的語句,那麼該日誌可能會很是有用。
生產環境中,下線一個業務的時候,也能夠打開這個日誌,檢查是否仍然有流量過來訪問。
mysqld按照它接收的順序將語句記錄到查詢日誌。這個順序可能與執行的順序不一樣。
以下命令可查詢通用日誌的路徑。
mysql> show variables like ‘%gene%’ ;
可使用命令SET GLOBAL general_log ON打開通用日誌記錄。
因爲通用日誌記錄了全部的查詢,因此必定要記得關閉它,不然,在一個生產繁忙的系統中,通用日誌在幾小時以內可能就會塞滿磁盤。 編程

3.二進制日誌
二進制日誌包含了全部更新了數據或已經潛在更新了數據的語句。
語句以「事件」(event)的形式保存,它描述了數據的更改信息。
二進制日誌還包含了每一個更新數據庫的語句的執行時間信息,但它不包含沒有修改任何數據的語句。
若是想要記錄全部的語句(例如,爲了識別有問題的查詢),那麼咱們應該使用通用日誌。
二進制日誌的主要目的是恢復數據,由於二進制日誌包含備份後進行的全部更新。
二進制日誌還用於在主複製服務器上記錄全部將要發送給從服務器的語句。
若是未給出二進制日誌的文件名,那麼默認名爲主機名-bin。
若是給出了文件名,但沒有包含路徑,那麼文件將被寫入數據目錄。
建議最好指定一個文件名,語句以下。 log-bin =/path/to/logmysql-bin
mysqld將在每一個二進制日誌名的後面添加一個數字擴展名。每次要啓動服務器或刷新日誌時,該數字將會增長。
若是當前的日誌大小達到了max_binlog_size參數設置的值,那麼mysqld會自動建立新的二進制日誌。
mysqld還將建立一個二進制日誌索引文件,其中包含了全部使用二進制日誌文件的文件名。
默認狀況下該索引文件與二進制日誌文件的文件名相同,擴展名 爲「.index」。
當mysqld正在運行時,不可手動編輯該文件,這樣作可能會使mysqld發生異常。
咱們可使用mysql鏈接數據庫,運行SHOW BINARY LOGS命令查看當前有哪些二進制文件,
還能夠用RESET MASTER語句刪除全部的二進制日誌文件,或者用PURGE BINARY LOGS命令只刪除部分二進制文件。
以下的例子將刪除歷史二進制日誌,一直到mysql-bin.000005這個文件爲止。
mysql> purge binary logs to ‘ mysql-bin.000005’ ;
具備SUPER權限的客戶端能夠經過SET sql_log_bin=0語句禁止將本身的語句記入二進制記錄中。
這在某些狀況下頗有用,好比進行數據庫的主主切換時,再或者進行數據庫的版本升級時。
咱們能夠用mysqlbinlog工具檢查二進制日誌文件。若是想要從新處理日誌上的語句,那麼這個工具將會頗有用。
例如,能夠用二進制日誌更新MySQL數據庫,方法以下。 shell> mysqlbinlog log-file | mysql -h host -P port
默認狀況下,並非每次寫入時都會將二進制日誌與硬盤同步。
所以若是操做系統或機器(不只僅是MySQL服務器)發生崩潰,那麼二進制日誌中最後的語句有可能就會丟失。
要想防止這種狀況的發生,能夠設置sync_binlog全局變量爲N(1是最安全的值,但也是最慢的),使二進制日誌在每N次二進制日誌寫入後就與硬盤同步一次。
下面來簡單介紹下二進制日誌的格式。
MySQL有兩種記錄命令的形式,一種是語句級(binlog_format=statement),一種是行級(binlog_format=row)。
建議將記錄命令的形式設置爲混合模式 (binlog_format=mixed),
這在大部分狀況下是適用的,它在通常狀況下將使用語句記錄日誌,但在一些特殊狀況下,就會臨時更改成行級記錄的形式,以便獲得更健壯的複製特性。
(1)語句級(statement-based)
基於語句級的日誌記錄裏包含了原始執行的SQL語句(這會讓DBA的維護更方便),還有其餘信息,如執行語句的線程ID,語句執行時的時間戳,執行所耗時長等。
(2)行級(row-based)
若是是行級格式的日誌,那麼它所記錄的事件信息包含了行的更改信息而不是原始的SQL語句,這樣可能會讓DBA以爲不方便。
經過mysqlbinlog默認看到的都是一些通過base-64編碼的信息,mysqlbinlog加參數-verbose(或-v),將會生成帶註釋的語句,
若是連續兩次使用這個參數(如-v–v),則會生成字段的類型、長度、是否爲NULL等屬性信息。
通常而言,行級日誌更健壯,而語句級的日誌若是應用了MySQL的一些額外特性,好比存儲過程、觸發器,則可能會致使複製異常。
因此,若是使用的是語句級的複製,那麼請務必保持數據庫應用的簡單性,只用到基本的核心特性便可。
如下將簡單介紹下mysqlbinlog解析出來的二進制日誌,主要有以下幾項。
#at 141:事件的起始點。
#1003099:28:36 server id 123 end_log_pos 245:語句執行的時間,對於複製,這個時間會傳輸到從庫。
server id是產生這個事件的MySQL實例的server id參數值。 end_log_pos指下一個事件的開始點,其實也就是這個事件的終點+1。
Query thread_id=3350 exec_time=11 error_code=0:thread_id指執行這個SQL的線程id。
exec_time在主從庫中有不一樣的含義,在主庫中,等於執行這個事件所花費的時間;
在從庫中,等於這個事件結束執行的時間點減去在主庫上開始執行的時間點,這個差別能夠表徵主從之間的滯後程度。
error_code爲錯誤狀態,等於0時表示狀態正常。 緩存

4.慢查詢日誌
當參數slow_query_log=1時,mysqld將記錄一個執行時間超過long_query_time秒的全部SQL語句的日誌文件。
若是沒有給出慢查詢文件名,則默認爲主機名,後綴爲「-slow.log」。
若是給出了文件名,但不是絕對路徑名時,文件將會寫入數據目錄。
執行完語句而且釋放完全部鎖後便可記入慢查詢日誌。記錄順序與執行順序能夠不相同。
慢查詢日誌能夠用來找到執行時間很長的查詢,能夠用於優化。
可是,檢查又長又慢的查詢日誌會很困難。
要想讓檢查變得容易些,可使用mysqldump slow命令或pt-query-digest得到日誌中顯示的查詢摘要來處理慢查詢日誌。
慢查詢日誌的詳細介紹和相關命令的使用請參考4.3節。 安全

5.日誌文件維護
MySQL服務器能夠建立各類不一樣的日誌文件,從而能夠很容易地查看所進行的操做。
可是,必需要按期清理這些文件,以確保日誌文件不會佔用太多的硬盤空間。
至於錯誤日誌文件,通常狀況下不會變得很大;慢查詢日誌在慢查詢不少的狀況下可能會變得很大,這時可能須要手動處理或編寫腳本進行處理;
對於二進制日誌文件,能夠設置合適的過時策略,如expire-logs-days=10,該語句的意思是設置過時日期爲10天。
expire_logs_days設置會在運行flush logs命令後觸發刪除過時的日誌,
注意,不要用操做系統下的rm命令刪除日誌,這可能會致使你執行日誌清理的命令失敗,你可能須要手動編輯文件hostname-bin.index來反映實際的文件列表。
雖然MySQL 5.1能夠設置日誌過時策略,但仍然存在一個可能,對於生產繁忙的系統,二進制日誌可能會塞滿磁盤,
MySQL 5.6能夠設置保留的二進制日誌文件大小, 以避免磁盤空間過滿,這在必定程度上改善了日誌的保留策略。 服務器

10.1.2 InnoDB數據文件和日誌文件
1.概述
先來簡單看下數據庫數據目錄下的一些文件。
假設數據目錄爲/usr/lib/mysql/data,此目錄下可能有以下這些文件。
(1)db.opt 數據庫的結構定義和設置。
(2)*.frm 數據表的結構定義。
(3)*.MYD MyISAM表數據。
(4)*.MYI MyISAM索引數據。
(5)ibdata* InnoDB表空間數據文件。
若是將innodb_file_per_table設置爲1,那麼InnoDB數據表能夠各自存儲爲一個文件,稱爲獨立表空間。
若是innodb_file_per_table等於0,那麼InnoDB數據表則能夠統 一存放在一個共享表空間裏。
默認innodb_file_per_table等於0,即InnoDB將使用共享表空間的方式,全部的數據都會存儲在相似ibdata*這樣的文件內。
(6)ib_logfile* InnoDB日誌數據。
(7)*.idb InnoDB數據和索引(當將innodb_file_per_table設置爲1,即爲獨立表空間的方式)。
(8)*.trg 觸發器。
如下將主要討論InnoDB表空間數據文件和它的日誌文件。
若是你指定了無InnoDB配置選項,那麼MySQL將在MySQL數據目錄下建立一個名爲ibdata1的10MB大小的自動擴展數據文件,以及兩個名爲ib_logfile0和ib_logfile1的5MB大小的日誌文件。
對於通常的生產負荷來講,這種配置過小了,可能會致使性能問題,因此須要手動設置大小。
筆者建議日誌文件應大於256MB,數據文件初始能夠分配1GB到5GB,並設置爲自動擴展,這樣的配置在通常狀況下已經夠用了,相關的配置項設置以下。
innodb_data_file_path = ibdata1:1000M:autoextend
innodb_log_file_size = 256M
innodb_data_file_path的值應該爲一個或多個數據文件規格的列表。若是要命名一個以上的數據文件,請用分號「;」分隔它們。
其語法格式爲: innodb_data_file_path=datafile_spec1[;datafile_spec2]...
例如: innodb_data_file_path=ibdata1:5000M;ibdata2:5000M:autoextend
其中,autoextend屬性和後面跟着的屬性只能被用於innodb_data_file_path行裏的最後一個數據文件。
若是對最後的數據文件指定autoextend選項,那麼當數據文件耗盡表空間中的自由空間時,InnoDB就會擴展這個數據文件,擴展的幅度默認是每次8MB。 session

2.獨立表空間的原理和設置
共享表空間的使用很簡單,維護方便,同時它也是MySQL默認的配置,因此在生產中獲得了普遍的應用,
但它也存在一些劣勢,使用共享表空間比較明顯的缺點是,不能快速回收刪除大表的空間,I/O操做可能會消耗更多的資源等待。
而獨立表空間是不少DBA推薦使用的方式,它恰好在這兩點上彌補了共享表空間的不足。
使用獨立表空間,能夠在它本身的文件中存儲每一個InnoDB表和它的索引,這種狀況下,每一個表都有它本身的表空間。
能夠向my.cnf的[mysqld]節中添加下面的語句來容許使用獨立表空間,重啓MySQL實例(MySQL Server)便可生效。
[mysqld]
innodb_file_per_table
重啓實例以後,InnoDB將會把每一個新建立的表存儲到數據庫目錄下的文件tbl_name.ibd中。
這相似於MyISAM存儲引擎所作的,但MyISAM是把表分紅數據文件tbl_name.MYD和索引文件tbl_name.MYI。
對於InnoDB,數據和索引則會被一塊兒存放到.ibd文件中。不過tbl_name.frm文件照舊會被建立。
若是從my.cnf文件裏刪除了innodb_file_per_table行,並重啓了實例,那麼InnoDB將會在共享的表空間文件裏再次建立表。
也就是說,innodb_file_per_table只會影響表的建立。
若是用這個選項啓動實例,那麼新表將會被.ibd文件建立,可是你仍然可以訪問共享表空間中的表。
若是刪掉了這個選項,那麼新表將在共享表空間內被建立,可是你仍然能夠訪問用獨立表空間建立的任何表。
即便使用了獨立表空間,也仍然有一部分共享數據須要存放在共享表空間內,因此idata*文件仍然存在。
你不能像對待MyISAM同樣,在數據目錄之間隨意地移動.ibd文件。這是由於表定義是被存放在InnoDB共享表空間內的,並且InnoDB必須保持事務ID和事務日誌順序號的一致性。
若是某個數據文件變得很大,好比上百GB,這時你可能想要另外增長一個數據文件;或者磁盤已滿,這時你想要把其餘數據添加到另外一個硬盤上,那麼這時能夠手動添加一個數據文件。 多線程

3.InnoDB增長數據文件
手動增長一個數據文件時須要重啓MySQL實例,咱們能夠計算出最後一個文件的大小(針對按MB計算的大小取整,即字節數除以1024^2,再四捨五入),
而後修改配置文件,把innodb_data_file_path參數指定的最後一個文件大小設置爲該值,並在其後繼續追加新的數據文件。
解決方案具體以下:
當你要添加一個新文件名到innodb_data_file_path參數指定的文件名列表時,請確信它並不存在。
當你重啓實例時,InnoDB會建立並初始化這個文件。
若是最後一個數據文件是用關鍵字autoextend定義的,那麼在編輯my.cnf文件時必須考慮最後一個數據文件已經增加到多大了。
你須要獲取這個數據文件的大小, 四捨五入,使其最接近1024*1024 bytes的乘積(即1MB),
而後在innodb_data_file_path中明確指定大體的尺寸。
而後添加另外一個數據文件。
記住,只有 innodb_data_file_path裏的最後一個數據文件才能夠被指定爲自動擴展。
以下是一個修改數據文件大小的示例。
首先關閉實例,查看最後一個數據文件的大小。以下是Linux操做系統ll命令的輸出。
-rw-rw--- 1 mysql mysql 10829692928 Mar 10 10:27 ibdata4
而後計算最後一個數據文件的大小。 10829692928/1024/1024=10328 MB(四捨五入)
那麼對原配置文件: innodb_data_file_path = ibdata1:4000M;ibdata2:4000M;ibdata3:4000M;ibdata4:4000M:autoextend
作以下修改,增長一個數據文件ibdata5,初始值爲8000MB,可自動擴展。
innodb_data_file_path = ibdata1:4000M;ibdata2:4000M;ibdata3:4000M;ibdata4:10328M;ibdata5:8000M:autoextend
最後,從新啓動實例,MySQL Server會自動建立ibdata5。

4.改變InnoDB事務日誌大小
不要試圖經過直接更改配置文件來設置InnoDB事務日誌的大小,這會致使不能啓動數據庫。
若是想要改變InnoDB事務日誌文件的數量和大小,那麼必需要中止MySQL實例,並肯定它被無錯誤地關閉了。
隨後複製舊日誌文件到一個安全的地方做爲備份,萬一出錯還能夠恢復,
而後從日誌文件目錄刪除全部的舊日誌文件,
以後編輯my.cnf改變日誌文件配置,並再次啓動MySQL實例。
mysqld在啓動之時會發現沒有日誌文件,而後告訴你它正在建立一個新的日誌文件。
更改InnoDB事務日誌大小的具體步驟以下:
1)乾淨關閉MySQL。
2)使用mv命令移走舊的InnoDB事務日誌。
3)修改配置文件,更改innodb_log_file_size。
4)啓動MySQL。
注意,在舊版本的MySQL中,全部事務日誌大小的總和不能超過4GB。MySQL 5.6將總大小的限制擴展到了512GB。

5.InnoDB的undo區域
undo區域也稱爲undo空間、undo表空間,是InnoDB設計的一個特殊存儲區域,它保存了被活動事務更改的數據的副本(前像),
若是另外一個事務須要查看原來的數據(例如,知足一致性讀),那麼能夠從undo區域中得到未被更改的數據。
默認狀況下,undo區域也是在InnoDB共享表空間內。
MySQL的更高版本(MySQL 5.6及以上)也提供了該選項,能夠把undo空間放到獨立的表空間裏,這樣就能夠把undo表空間放到其餘更快的磁盤設備上,進行專門的優化。
若是undo暴漲可能會把共享表空間撐大。
出現這種狀況,多是由於寫負載很大,好比執行了大量的刪除和修改操做,但在生產環境中,更可能出現的一種狀況是存在長時間未提交的事務。
若是一個事務長時間未提交,而咱們默認使用的是repeatable read事務隔離級別,那麼InnoDB不會去清理舊的行版本(old rowversions),由於未提交的事務仍然須要看到它。
當這個事務一直保持打開而不提交,就可能會致使大量舊的版本數據沒法刪除,從而致使undo暴漲。
將事務的隔離級別更改成read committed能夠解決此問題。但根本的處理措施仍是檢查代碼,找到未提交的事務。
經過命令SHOW INNODB STATUS的輸出,能夠看到當前有多少沒有被清理的記錄。
對比下面的Purge done for trx和Trx id counter,若是差別很大,則多是由於大量事務所致使,也多是操做大量數據的個別事務所致使的。
------------ TRANSACTIONS ------------
Trx id counter 0 80157601
Purge done for trx’
s n:o <0 80154573 undo n:o <0 0
對於寫操做很頻繁的應用,InnoDB清理線程的速度可能會跟不上,從而致使undo表空間愈來愈大,能夠經過設置innodb_max_purge_lag參數,來避免InnoDB表空間的過度增大。
InnoDB事務系統維持了一個事務列表,該列表記錄被UPDATE或DELETE操做標誌爲刪除的索引記錄。
這個列表的長度爲purge_lag。當purge_lag超過 innodb_max_purge_lag之時,每一個INSERT、UPDATE和DELETE操做都將被延遲必定的時間,好比咱們能夠將其設置爲100萬。
即容許有100萬條未清理的記錄,在達到 100萬的閾值後,就會觸發延遲其餘的查詢操做。
簡而言之,undo裏保存了數據的前像,它能夠知足一致性查詢,同時,在災難恢復過程當中,它也扮演了重要的角色,它的主要功能是在災難恢復過程當中回滾那些沒有提交的變動。
災難恢復的具體過程請參考10.2節。

10.1.3 臨時文件
MySQL使用環境變量TMPDIR的值做爲保存臨時文件的目錄路徑名。
若是未設置TMPDIR,那麼MySQL將使用系統的默認值,一般爲/tmp、/var/tmp或/usr/tmp。
若是包含臨時文件目錄的文件系統太小,則能夠對mysqld使用「--tmpdir」選項,在具備足夠空間的文件系統內指定1個目錄,或者修改配置文件內的參數tmpdir。
在MySQL 5.1中,「--tmpdir」選項可被設置爲多個路徑的列表,以循環的方式使用。
在Unix平臺上,路徑可用冒號字符「:」隔開,在Windows、NetWare和OS/2平臺 上,路徑可用分號字符「;」隔開。
注意,爲了有效地分佈負載,這些路徑應位於不一樣的物理磁盤上,而不是位於相同磁盤的不一樣分區中。
若是MySQL服務器正做爲複製從服務器使用,那麼不該將「--tmpdir」設置爲指向基於內存的文件系統的目錄,或者當服務器主機重啓時將要清空的目錄。
對於複製從服務器,須要在機器重啓時仍保留一些臨時文件,以便可以複製臨時表或執行LOAD DATA INFILE操做,若是在服務器重啓時丟失了臨時文件目錄下的文件, 那麼複製將會失敗。
MySQL會以隱含的方式建立全部的臨時文件。這樣,就能確保在停止mysqld時會刪除全部的臨時文件。
使用隱含文件的缺點在於,在臨時文件目錄所在的位置中,看不到佔用了文件系統的大臨時文件。
進行排序時(ORDER BY或GROUP BY),MySQL一般會使用1個或多個臨時文件。
對於大數據量的排序,臨時空間可能會超過/tmp空間,此時,執行查詢將會失敗,MySQL錯誤日誌裏會出現錯誤記錄「sortabort」。
解決方案是優化查詢或把臨時目錄設置到另外一個空間足夠大的分區中。
對於某些SELECT查詢,MySQL還會建立臨時SQL表,它們有sql_*形式的名稱。
ALTER TABLE會在與原始表目錄相同的目錄下建立臨時表。

10.1.4 MySQL套接字文件
服務器用來與本地客戶端進行通訊的Linux套接字文件(也稱爲socket文件),其默認位置是/tmp/mysql.sock。
此文件位於/tmp目錄下可能會致使一些問題,緣由在於,在某些版本的Linux上,任何人都能刪除/tmp目錄下的文件。
在Linux系統下,系統會自動刪除/tmp目錄下的一些文件,但並不會刪除socket文件。
但某些沒有經驗的系統管理員可能配置了定時任務去刪除/tmp目錄下的文件,極可能連socket文件也會被刪除,這將致使MySQL沒法經過socket文件的方式進行登陸。
因爲如今的服務器通常都很強勁,多實例的配置也很廣泛,建議不要將socket文件集中放在/tmp目錄下,最好是放在單獨的實例自身的目錄中。
咱們能夠在全局配置文件中指定socket文件路徑。例如,將下述行置於文件/etc/my.cnf中。
[mysqld]
socket=/path/to/socket
[client]
socket=/path/to/socket
若是你不放心socket文件,那麼能夠保留默認的root的其餘登陸方式,默認的root帳號能夠經過socket文件或127.0.0.1進行登陸。
建議保留127.0.0.1的root登陸帳號,以防socket文件被異常清除。

10.2 MySQL如何進行災難恢復
MySQL的災難恢復相似於其餘傳統數據庫的災難恢復。
MySQL靠預寫式日誌(Write-Ahead Logging,WAL)來保證持久性,也就是說,數據文件不會立刻寫入髒數據,而是會先寫日誌。
InnoDB的髒數據是存在於innodb_buffer_pool裏的,它會按必定的機制批量刷新到磁盤,這樣作能夠提升吞吐率。
咱們把上面這種日誌稱爲redo日誌,即InnoDB的事務日誌。
若是忽然斷電了,那麼InnoDB是不能保證數據已經寫入磁盤的,數據庫重啓後,MySQL須要知道當時執行的操做是成功了仍是部分紅功或失敗了。
這時,只要使用了預寫式日誌,程序就能夠檢查redo日誌,並將忽然斷電時計劃執行的操做內容跟實際上執行的操做內容進行比較。
在這個比較的基礎上,MySQL就能夠決定是撤銷已作的操做仍是繼續完成相應的操做,或者是保持原樣。
這就是災難恢復的過程。
因爲MySQL知道宕機時有哪些日誌是尚未被實際寫入到數據文件的,
因此它會找到事務日誌的某個點,把這個點以後的日誌運行一遍,這個時候就會產生一 個新的問題,
雖然把全部日誌都執行了一遍,但有一些更改並無被提交,須要回滾。
咱們配合undo日誌(在undo區域內)能夠肯定哪些變動是須要回滾的,而後回滾那些沒有提交的日誌,
簡單地說,災難恢復過程能夠分爲redo(重作)和undo(回退)兩個步驟。
由上可知,InnoDB事務日誌在很大程度上決定了數據的安全性,事務日誌的持久性決定了災難恢復後最多丟失了多少記錄?
事務日誌都是順序寫入的,所以能夠設置參數來調整commit(事務提交)時寫入事務日誌的頻率。
MySQL的事務日誌刷新可能會出現以下3種狀況。
(1)innodb_flush_log_at_trx=1
每次commit時都寫入磁盤。這樣理論上咱們只會丟失一個事務。
(2)innodb_flush_log_at_trx=2
每次commit時,寫日誌只緩衝(buffer)到操做系統緩存,但不刷新到磁盤,InnoDB會每秒刷新一第二天志,因此宕機丟失的是最近1秒的事務。生產環境中建議使用此配置。
(3)innodb_flush_log_at_trx=0 每秒把日誌緩衝區的內容寫到日誌文件,而且刷新到磁盤,但commit時什麼也不作。
數據文件的寫操做,可能會將塊寫壞,MySQL設計了一個數據存儲區域雙寫緩衝(double write buffer),InnoDB使用雙寫緩衝來確保數據的安全,避免損壞塊。
雙寫緩衝是InnoDB表空間的一個特殊的區域,主要用於寫入頁的備份,而且是順序寫入。
當InnoDB刷新數據(從InnoDB緩衝池到磁盤)時,首先寫入雙寫緩衝,而後寫入實際數據文件。
這樣便可確保全部寫操做的原子性和持久性。
崩潰重啓後,Innodb會檢查每一個塊(page)的校驗和,判斷塊是否損壞,若是寫入雙寫緩衝的是壞塊,
那麼顯然沒有寫入實際數據文件,就要用實際數據文件的塊來恢復雙寫緩衝,
若是寫入了雙寫緩衝,可是數據文件寫的是壞塊,那麼就用雙寫緩衝的塊來重寫數據文件。
這樣的機制雖然提供了安全保障,但也增長了I/O。
對於讀操做,InnoDB經過頁校驗碼來保證數據的存取,每頁在內存中都先算好一個校驗值,放在文件頭部,寫入的時候先寫校驗值,讀的時候也會校驗一下校驗值。
經過如上描述的預寫式日誌機制和雙寫緩衝區域,MySQL提供了極佳的災難恢復性。
MySQL的穩定版本不多會由於主機斷電等硬件故障而致使數據損壞。

10.3 變量設置、配置文件和主要參數
10.3.1 概述
不少人都喜歡研究各類參數配置文件,而後給本身的生產環境加上不少參數。
筆者的建議是,能夠去研究它,測試它,可是在生產環境中,你應該在肯定某個選項能解決特定的性能問題時,纔去設置它,不然你應該儘可能保持簡單。
配置文件添加了過多的參數可能會致使混淆,維護性可能會變差,後來接手的DBA每每會問,爲何要這麼設置。
實際的數據庫產品中,不少參數只有在特定的上下文中才有意義,時過境遷,一些參數可能反而會成爲性能問題的根源所在。
因此建議讓生產環境的配置文件儘量地保持簡單,在肯定須要時,纔去設置相應的參數。
另外,數據庫配置文件所起的做用有限。系統的性能更多地取決於物理部署和架構,取決於數據庫設計、索引和SQL質量等。
設置好正確的基本參數以後,最好就不用再去關注它,應該花費更多的時間在庫表設計、索引和查詢優化上。
官方的安裝包內有附帶的示例配置文件,但不建議使用。
裏面的一些設置不太符合生產實踐,可能會有誤導,並且這些配置也過期了,不適合如今的硬件和負載,也不適合互聯網公司流量比較大的業務。
本章稍後會給出一份比較簡單的配置文件,你們能夠去對比下,而後檢驗下你的生產環境設置得是否合理。
注意,適合生產環境的纔是最佳的,而任何建議的參考配置文件,每每是不可能覆蓋到各類應用類型的,僅僅是爲你的決策提供一個參照物。
因此,仍然建議以本身的生產配置爲準。

10.3.2 如何設置參數、變量
配置文件內的參數須要儘可能保持同樣的書寫風格,要麼都是用下劃線(如slow_query_log_file)要麼都使用中線(slow-query-log-file)。
配置文件內的參數有些是影響全局的,有些是會話(session)級別的,即咱們也能夠在獨立的鏈接內進行設置。
sort_buffer_size可用於設置全局和會話級,以下:
SET sort_buffer_size = <value>; #設置會話級。
SET GLOBAL sort_buffer_size = <value>; #設置全局。
set sort_buffer_size =default; #恢復默認值。
生產中儘可能不要使用32位系統,32位系統的機器有內存尋址的限制,不能突破二點幾GB的限制。
若是必定要使用,那麼配置參數的時候,注意不要設置得太高,內存參數若是設置得過高,可能會致使32位的MySQL實例崩潰。
咱們能夠在SET命令中使用表達式,即,SET sort_buffer_size=10*1024*1024,但配置文件不容許使用表達式。
有時咱們須要臨時設置會話變量,執行操做,而後恢復原來的設置,通行的辦法以下所示。
SET @saved_<unique_variable_name> := @@session.sort_buffer_size;
SET @@session.sort_buffer_size := <value>;
-- Execute the query...
SET @@session.sort_buffer_size := @saved_<unique_variable_name>;
有時咱們須要臨時調整一些參數或變量,來驗證本身的一些想法,但在此過程當中須要注意如下兩點。
1)調整參數須要有一個基準,調整參數後,咱們須要衡量調整的結果。最好是有一套監控系統來收集實例的運行狀態,這樣能夠方便咱們進行對比。
2)應儘可能小步調整參數,一次不要調整太多參數,調整太多參數會比較危險,也會使咱們沒法明確究竟是哪些參數調整後有效果。
隨着對生產環境的日漸熟悉,咱們總能找到一套適合本身生產環境的配置。

10.3.3 配置文件的讀取順序
在Unix中,MySQL程序從表10-2所示的文件中讀取啓動選項。
表10-2 讀取啓動項的文件
其中,MYSQL_HOME是一個環境變量,包含與服務器相關的my.cnf文件駐留的目錄路徑。
若是未設置MYSQL_HOME,而且DATADIR中有一個my.cnf文件,而BASEDIR中沒有my.cnf文件,那麼mysqld_safe將會把MYSQL_HOME設置爲DATADIR。
若是未設置MYSQL_HOME,而且在DATADIR中沒有my.cnf,則mysqld_safe將MYSQL_HOME設置爲BASEDIR。
也就是說,數據目錄內的配置文件和安裝目錄下的配置文件均可能生效。
典型狀況下二進制的安裝目錄爲/usr/local/mysql/data,源代碼的安裝目錄爲/usr/local/var。
請注意這是配置時指定的數據目錄的位置,而不是mysqld啓動時用--datadir 指定的。
運行時使用--datadir對尋找選項文件的服務器沒有效果,由於服務器在處理命令行參量以前就尋找這些選項了。
MySQL按照上述順序尋找選項文件,若是存在多個選項文件,那麼文件中指定的後讀取的選項要優先於文件中指定的先讀取的選項。
因此理論上在datadir或basedir內放置一個my.cnf便可。
在Unix平臺上,MySQL忽略了人人可寫的配置文件。這是特地設置的,它實際上是一個安全措施。
MySQL默認加載配置文件的前後順序也能夠經過應用以下命令來得知。
$ which mysqld
/usr/local/mysql/bin/mysqld
/usr/local/mysql/bin/mysqld --verbose --help | grep -A 1 ‘
Default options’
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf
經過以上命令能夠知道加載配置文件的順序。
注意:不要在生產環境中運行,由於會真的啓動mysqld程序。
雖然官方文檔中說明了配置文件的讀取順序,但是該順序不必定可靠。
建議讀者不要依賴於官方文檔所說明的順序來部署本身的多個MySQL配置文件。
對於生產環境的部署,建議僅存在並加載一個配置文件,而不要配置多個配置文件。
有些人除了配置文件,還喜歡在命令行內也設置一些參數,這樣容易致使混淆,維護性也會變差,最終將丟失你所作的變動。

10.3.4 環境變量、配置文件、命令行選項的優先級
MySQL程序首先會檢查環境變量,而後檢查選項文件,最後再來檢查命令行以肯定給出了哪些選項。
若是屢次指定一個選項,那麼最後出現的選項佔先。
這說明環境變量具備最低的優先級,命令行選項具備最高的優先級。
能夠在選項文件中指定程序選項的默認值來讓MySQL程序處理各個選項。
不須要在每次運行程序時都輸入選項,但能夠根據須要經過命令行選項來覆蓋默認值。

10.3.5 配置文件詳述
配置文件分紅了不少節,MySQL程序一般會讀取命名和本身名字同樣的節。好比以下的配置文件。
[client]
port = 3306
socket = /path/to/tmp//3306/mysql.sock
default-character-set = utf8
客戶端工具,如mysql、mysqldump會讀取client這一節的配置。
default-character-set指程序和MySQL服務器進行通訊時所使用的字符集。
這個字符集應該和輸入窗口(Windows)或控制檯窗口(Unix/Linux)裏默認使用的字符集 一致。
再來看一個配置文件:
[mysqld]
character-set-server = utf8
port = 3306
socket = /path/to/tmp//3306/mysql.sock
user = mysql
skip-external-locking
datadir =/path/to/data/3306
log-error =/path/to/log3306/mysqld.err
pid-file = /path/to/tmp//3306/mysql.pid
#init_connect=’
set autocommit=0’
#init_connect=’
set names utf8’
#read-only
mysqld服務會讀取這一節的配置。
init_connect這個參數能夠在客戶端鏈接進來的時候執行一些初始化操做,如記錄鏈接IP,但不會對Super用戶起做用。
對於my.cnf配置文件,能夠添加一些基本設置,以下是一個例子。
expire_logs_days=10;
max_connect_errors=5000;
max_connections=2048;
slow_query_log=on;
long_query_time=0.5;
skip_name_resolve
下面對其中的參數作一些簡單的介紹。
(1)max_connect_errors
將此值設置得足夠大會更好,推薦值是5000。
若是一臺嘗試鏈接數據庫的主機失敗的次數超過了此閾值,那麼這個主機會被MySQL Server阻止訪問,必須在 MySQL Server上運行FLUSH HOSTS才能解除此限制。
(2)skip_name_resolve
必須設置此項,因MySQL的DNS解析可能會致使嚴重的性能問題。
注意設置了此項以後,MySQL權限表將使用IP來統一標識主機,而不能使用主機名來標識 了。
(3)sync_binlog
默認狀況下,並非每次寫入時都會將二進制日誌與硬盤同步。
所以若是操做系統或機器(不只僅是MySQL實例)發生崩潰,那麼有可能二進制日誌中最後的語句會丟失。
要想防止出現這種狀況,可使用sync_binlog全局變量(1是最安全的值,但也是最慢的),使二進制日誌在每N次寫入後與硬盤同步一次。
待sync_binlog個記錄寫入二進制日誌後,MySQL服務器會將該二進制日誌同步到硬盤上。
請注意若是是autocommit模式,那麼每執行一個語句便會向二進制日誌寫入一次,不然每一個事務執行完才寫入一次。
sync_binlog的默認值是0,表示不與硬盤同步。
值爲1是最安全的選擇,由於崩潰時最多丟掉二進制日誌中的一個語句/事 務;可是,這也是最慢的選擇(除非硬盤有電池備份緩存,使同步工做較快)。
建議配置範圍爲8~20。

10.3.6 配置文件示例
最終的一份簡單的配置文件示例以下(MySQL 5.1)。
[mysqld]
# GENERAL
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
pid_fi = /var/lib/mysql/mysql.pid
user = mysql
port = 3306
storage_engine = InnoDB
sync_binlog = 20
# INNODB
innodb_buffer_pool_size = <value>
innodb_log_file_size = <value>
innodb_file_per_table = 1
innodb_flush_method = O_DIRECT
# MyISAM
myisam-recover=default 默認自動修復
key_buffer_size = <value>
# LOGGING
log_error = /var/lib/mysql/mysql-error.log
log_slow_queries = /var/lib/mysql/mysql-slow.log
long_query_time = <value>
# OTHER
skip_name_resolve
expire_logs_days = <value>
max_connect_errors = <value>
tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
query_cache_size = 0
max_connections = <value>
thread_cache_size = <value>
table_cache_size = <value>
open_files_limit = 65535
[client]
socket = /var/lib/mysql/mysql.sock
port = 3306

10.4 MySQL Query Cache和優化器
MySQL Query Cache內緩存了咱們提交的SQL語句的結果集及相關信息,有助於加速查詢響應。
通常不須要考慮Query Cache帶來的額外開銷,除非是寫操做很頻繁的應用。
工做原理:
當MySQL運行查詢語句時,首先會檢查是否命中緩存,若是命中那麼此時會增長Qcache_hits狀態變量的值,並返回結果集給客戶端。
若是在緩存中找不到此語句的緩存,則進入以下步驟。
1)MySQL解析器將分解查詢語句,並創建一棵「解析樹」,解析器會使用MySQL的語法解析並驗證查詢語句的語法是否正確,是否符合規範,固然各類符號也包 含在檢查範圍以內。
2)預處理器檢查「解析樹」中的表和列是否存在,列的別名是否混淆,並進行相關權限的檢查。
3)若是前面兩步都經過了檢驗,那麼再進行以下步驟。
步驟1:優化器對「解析樹」進行優化,生成執行成本最低的執行計劃。
步驟2:執行此計劃,存儲查詢結果。
步驟3:返回結果集給客戶端。

Query Cache默認是關閉的,臨時禁用Query Cache的辦法是設置query_cache_size爲0,
注意FLUSH QUERY CACHE命令並不會清空緩存。清除緩存的命令是RESET QUERY CACHE。
查看相關參數的語句爲 mysql>show variables like'%query_cache%';
查看相關狀態變量的語句爲 mysql>show global status like'%Qcache%';
至因而否能夠禁用Query Cache,對此咱們要謹慎些,若是命中率不高,好比才70%~80%,那麼關閉Query Cache通常不會有太大的問題,
但若是Query Cache有 98%~99%,那麼關閉QueryCache可能會致使比較大的衝擊,要仔細評估由於緩存失效而可能對數據庫形成的衝擊。
任何不是從緩存塊中取得數據的查詢語句都稱爲「緩存錯失(cache miss)」,形成緩存錯失的緣由有如下幾種。
1)所發送的查詢語句是不可緩存的,查詢語句不可緩存的緣由主要有兩種:
一是語句包含了不肯定的值;二是所獲得的結果集太大而沒法將它保存到緩存中。
這兩種緣由形成的結果都會增長Qcache_not_cached變量的值,能夠經過查看這個變量的值來檢查查詢語句的緩存狀況。
2)所發送的查詢語句以前沒有發送過,因此也不會有什麼緩存存在。
3)所發送的查詢語句的結果集是以前存在於緩存中的,但因爲內存不足,MySQL不得不將以前的一些緩存清除掉,以騰出空間來放置其餘新的緩存結果。
4)數據的變動也會引起緩存的失效。若是是數據的變動引發的緩存失效,那麼能夠經過查看Com_*變量的值來確認有多少查詢語句更改了數據,這些變量包括 Com_update、Com_delete等。

QueryCache有以下一些要點須要注意。
SQL語句在QueryCache中是經過散列映射表來查找的,大小寫、空格等差別都會致使不一樣的散列結果,因此開發人員應該有一致的代碼規範,以保證SQL語句風格一致。
QueryCache不會緩存子查詢。
若是QueryCache結果集中相關的對象發生了變化,那麼這個結果集就會被失效。好比某張表修改了數據,那麼Query Cache內全部涉及這張表的結果集都會失效。
須要注意的是,長時間運行的事務,會下降Query Cache的效率。
由於若是InnoDB事務內的一條語句更改了表,那麼MySQL就會讓Query Cache與這個表相關的Cache都失效掉。直到這個事務提交以後,才能夠從新緩存這個表的結果集。
Query Cache分配內存的時候,每次至少要分配query_cache_min_res_unit大小的內存塊,Query Cache並不須要等待全部的結果集在Cache內所有生成後才發送給客戶端。
由於失效等緣由,實際上生產環境結果集所須要的Query Cache並非很大,通常256MB就足夠了。
對於寫操做很頻繁的應用,能夠考慮禁用QueryCache。
留意碎片(fragmentation)的緣由是,若是每次都分配較大的內存(query_cache_min_res_unit較大),那麼更容易致使碎片化;
若是每次分配較小的內存(query_cache_min_res_unit較小),則須要更頻繁的分配,因此須要在內存的浪費和CPU的成本之間作一個取捨。
咱們能夠計算下平均查詢大小(Query Size)。公式爲:Query Size=(query_cache_size–Qcache_free_memory)/Qcache_queries_in_cache,
經過平均查詢的大小來大體肯定一個合適的query_cache_min_res_unit應該設置爲多大。
若是Qcache_lowmem_prunes比較大,而Qcache_free_blocks也比較大,那麼多是碎片比較嚴重,致使了查詢緩衝被大量剔除。
咱們不太好衡量開啓了QueryCache是否真的有幫助。
最簡單的辦法是衡量緩衝命中率,公式爲Qcache_hits/(Qcache_hits+Com_select),若是緩衝命中率比較高,那麼它就是有效的。
但即便不高(如20%~30%),也不必定意味着低效,咱們關注的是提升特定查詢的訪問速度而不是隻關注命中率這個指標。
相對查詢來講,將結果集存儲到Query Cache比結果集失效的成本更低。
若是一個系統中,大部分都是複雜的查詢,那麼用Query Cache將是一個很好的選擇。
若是Qcache_not_cached比較小,但有大量緩存未命中,那麼可能會有不少失效的操做,或者MySQL沒有預熱數據,或者重複的查詢不多。Qcache_inserts在預熱數據後,應該比Com_select小得多。
可監控一下Qcache_lowmem_prunes,肯定是否由於內存不夠而剔除告終果集。QueryCache的效率比較高的時候,Qcache_inserts應該比Com_select小得多。
若是查詢結果沒有被緩存,那麼,MySQL將解析查詢(Parse),經過優化器(Optimizer)生成執行計劃,而後運行執行計劃獲取數據。
MySQL優化器生成的執行計劃,在很大程度上決定了其性能,隨着新版本的發佈,MySQL優化器愈來愈智能,但它仍然存在不少限制,
DBA和研發人員須要熟悉所使用的MySQL版本的優化器規則,充分利用優化器,撰寫高質量的SQL。
讓優化器工做得更好,本質上就是進行查詢優化,具體可參考第6章「查詢優化」。

10.5 SHOW ENGINE INNODB STATUS解析
SHOW ENGINE INNODBSTATUS是一種經常使用的工具,但運行這個命令的輸出卻不容易閱讀。
咱們能夠經過建立一些InnoDB監控表(注意必須是InnoDB引擎的表),來啓用性能監控輸出,輸出InnoDB的各類信息,默認輸出至MySQL錯誤日誌。
以下命令將建立InnoDB標準監視器,即SHOW ENGINE INNODB STATUS輸出。
CREATE TABLE innodb_monitor (a INT) ENGINE=InnoDB;
以下命令將建立表空間監視器,以輸出共享表空間的信息。對獨立表空間來講,它不適用,若是關閉了數據文件的自動擴展,那麼經過這個監控,能夠監視數據文件是否須要擴展。
CREATE TABLE innodb_tablespace_monitor (a INT) ENGINE = InnoDB;
以下命令將開啓表監控器,會輸出系統中全部InnoDB表的一些結構和內部信息。
CREATE TABLE innodb_table_monitor (a INT) ENGINE = InnoDB;
以下命令將開啓InnoDB鎖監控器,它的輸出結果和標準監視器基本相似,但會有更多關於鎖的信息。
CREATE TABLE innodb_lock_monitor(a INT) ENGINE = InnoDB;
建立表只是發出一個命令給InnoDB引擎,同理,刪除表也是發送一箇中止監控的命令給InnoDB引擎,因此MySQL在重啓後是不會自動啓動InnoDB監控的。
如下將對InnoDB進行標準監控,也就是運行SHOW ENGINE INNODB STATUS,對其輸出作一些解析,其餘監控器(如對於表空間的監控)可參考官方文檔。
SHOW ENGINE INNODB STATUS命令的輸出信息不太方便進行腳本解析,並且輸出信息裏有不少平均值,不太好估算咱們本身指定範圍的統計結果,
SHOW GLOBAL STATUS命令也有不少InnoDB的輸出信息,使用SHOW GLOBAL STATUS會更好估算一些,也會更易於監控系統性能。
建立這些表以後,MySQL就會輸出各類內部結構和性能信息到MySQL錯誤日誌,對於InnoDB標準監視器,大概是每隔15s輸出一次。
筆者我的不多啓用各類性能監控,通常是在作診斷的時候,直接運行命令,例如:
SHOW ENGINE INNODB STATUS \G
具體的輸出解析以下。
*************************** 1. row ***************************
Status:
=====================================
100206 21:51:18 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 26 seconds
以上輸出結果爲最近26s的統計。若是是前1~2s的統計那麼結果將不太可信。咱們須要確保至少有20~30s的統計,不然結果會不太準確,還須要從新運行這個命令。
SHOW ENGINE INNODB STATUS的輸出主要包含以下幾個部分,這裏以MySQL 5.1/5.5爲例來進行講述,其餘版本與此相似。
Background Thread
Semaphores
Latest ForeignKeyError
Latest Detect Deadlock
FileI/O
Insert Bufferand Adaptive Hash Index
Log
Buffer Pool and Memory
RowOperations
Transactions
(1)信號量(Semaphores)
下面是信號量相關信息。
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 13569, signal count 11421
--Thread 1152170336 has waited at ./../include/buf0buf.ic line 630 for 0.00 seconds the semaphore:
Mutex at 0x2a957858b8 created file buf0buf.c line 517, lock var 0
waiters flag 0
wait is ending
--Thread 1147709792 has waited at ./../include/buf0buf.ic line 630 for 0.00 seconds the semaphore:
Mutex at 0x2a957858b8 created file buf0buf.c line 517, lock var 0
waiters flag 0
wait is ending
Mutex spin waits 5672442, rounds 3899888, OS waits 4719
RW-shared spins 5920, OS waits 2918; RW-excl spins 3463, OS waits 3163
解析:信號量(SEMAPHORES)節包含兩部分信息,
一部分信息是當前的操做系統等待(OS WAIT ARRAY INFO),
在高併發的環境下,咱們可能會看到這部分信息,由於InnoDB自旋等待超過了閾值,就會觸發操做系統等待,若是等待經過自旋可以解決,那麼這些信息就不會顯示了。
經過檢查這部分信息,能夠大體判斷負荷的熱點在哪裏,因爲輸出行只包含了一些文件名,所以還須要有一些源碼的知識,才能判斷出現等待的真實緣由。
另外一部分信息是事件統計(event counter),reservation count和signal count的值表徵了InnoDB須要OS WAIT的頻率。
咱們也可使用操做系統命令,如vmstat,經過檢查上下文切換(context switch)的頻率來確認OS WAIT的嚴重程度。
咱們還須要瞭解一些操做系統進程調度的知識,若是進程不能獲取鎖(mutex能夠理解爲一種輕量級的鎖),則CPU會自旋(spin),也就是CPU空轉,以等待資源,
此時並不須要進行上下文切換這種高成本的操做,也許CPU空轉一些時間片,就能夠獲取到資源,但若是自旋超過了必定的次數,仍然沒法得到資源,
那麼進程就須要切換到睡眠狀態進行等待(OS WAIT),大量的OS WAIT意味着資源競爭很厲害,將形成很高的上下文切換頻率。
若是每秒有幾萬次的OS WAIT,那麼很 可能系統中存在性能問題。
大量的spin waits和spin rounds,意味着CPU在空轉而沒有實際作事,這會消耗大量的CPU資源,因此有時咱們看到系統的CPU利用率很高,
但也許並非真正地在作事,而是CPU正在空轉等待資源。
經過調整innodb_sync_spin_loops參數,能夠在CPU資源消耗和上下文切換之間找到平衡點。
(2)死鎖
下面是一個系統的死鎖信息。
———————— LATEST DETECTED DEADLOCK————————
100206 14:46:39
*** (1) TRANSACTION:
TRANSACTION 0 353348573, ACTIVE 0 sec, process no 22381, OS thread id 823933856 inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1
MySQL thread id 3176551, query id 27696260 del40 10.12.14.181 ooes_rss update
insert into ooes_fav(id,name,uid,mtime,ctime,wapflag,url,parent_id,type) values(’ 1′ ,’ QQ’ ,’ 7080277′ ,’ 1265438796′ ,’ 1265438796′ ,」 ,」 ,」 ,’ 2′ )
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 1484846 n bits 144 index `uid` of table `ooes_rss`.`ooes_fav` trx id 0 353348573 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) TRANSACTION:
TRANSACTION 0 353348572, ACTIVE 0 sec, process no 22381, OS thread id 894077856 inserting, thread declared inside InnoDB 500
mysql tables in use 1, locked 1
7 lock struct(s), heap size 1024, 103 row lock(s), undo log entries 101 #這個事務更大
MySQL thread id 3176549, query id 27696261 del40 10.12.14.180 ooes_rss update
*** (2) HOLDS THE LOCK(S): #Note –
InnoDB only prints information about few of the locks which transaction is holding.
RECORD LOCKS space id 0 page no 1484846 n bits 72 index `uid` of table `ooes_rss`.`ooes_fav` trx id 0 353348572 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 1484846 n bits 144 index `uid` of table `ooes_rss`.`ooes_fav` trx id 0 353348572 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** WE ROLL BACK TRANSACTION (1)
解析:這段信息展現了是哪些事務致使了死鎖、死鎖過程當中它們的狀態、它們持有的鎖、要等待的鎖、回退到哪一個事務
(據官方文檔可知,MySQL會回滾成本較小的事務,好比更新更少的行)等內容。
由輸出的最後一行能夠得知,回退到了事務1。
須要留意的是,這裏只顯示了部分持有的鎖,只顯示了事務中最近的語句,而實際上佔據資源的多是事務中前面的語句。
在一些簡單狀況下,能夠經過SHOW ENGINE INNOD BSTATUS的輸出確認致使死鎖的緣由;
在複雜的狀況下, 則須要打開通用日誌,檢查具體各個事務是如何互相等待資源從而致使死鎖的。
MySQL 5.6能夠經過參數innodb_print_all_deadlocks將死鎖信息打印到錯誤日誌中。
(3)外鍵衝突
如下爲外鍵衝突信息,開發人員須要注意。
———————— LATEST FOREIGN KEY ERROR————————
060717 4:29:00 Transaction:
TRANSACTION 0 336342767, ACTIVE 0 sec, process no 3946, OS thread id 1151088992 inserting, thread declared inside InnoDB 500
mysql tables in use 1, locked 1
3 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 9697561, query id 188161264 localhost root update
insert into child values(2,2)
Foreign key constraint fails for table `test/child`: ,
CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE
Trying to add in child table, in index `par_ind` tuple:
DATA TUPLE: 2 fields;
0: len 4; hex 80000002; asc ;; 1: len 6; hex 000000000401; asc ;;
But in parent table `test/parent`, in index `PRIMARY`,
the closest match we can find is record:
PHYSICAL RECORD: n_fields 3; 1-byte offs TRUE; info bits 0
0: len 4; hex 80000001; asc ;; 1: len 6; hex 0000140c2d8f; asc – ;;
2: len 7; hex 80009c40050084; asc
(4)事務信息
------------ TRANSACTIONS ------------
Trx id counter 0 80157601
Purge done for trx’
s n:o < 0 80154573 undo n:o < 0 0
History list length 6
Total number of lock structs in row lock hash table 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 3396, OS thread id 1152440672
MySQL thread id 8080, query id 728900 localhost root
show innodb status
---TRANSACTION 0 80157600, ACTIVE 4 sec, process no 3396, OS thread id 1148250464, thread declared inside InnoDB 442
mysql tables in use 1, locked 0
MySQL thread id 8079, query id 728899 localhost root Sending data
select sql_calc_found_rows * from b limit 5
Trx read view will not see trx with id >= 0 80157601, sees < 0 80157597
---TRANSACTION 0 80157599, ACTIVE 5 sec, process no 3396, OS thread id 1150142816 fetching rows, thread declared inside InnoDB 166
mysql tables in use 1, locked 0
MySQL thread id 8078, query id 728898 localhost root Sending data
select sql_calc_found_rows * from b limit 5 Trx read view will not see trx with id >= 0 80157600, sees < 0 80157596
---TRANSACTION 0 80157598, ACTIVE 7 sec, process no 3396, OS thread id 1147980128 fetching rows, thread declared inside InnoDB 114
mysql tables in use 1, locked 0
MySQL thread id 8077, query id 728897 localhost root Sending data
select sql_calc_found_rows * from b limit 5
Trx read view will not see trx with id >= 0 80157599, sees < 0 80157595
---TRANSACTION 0 80157597, ACTIVE 7 sec, process no 3396, OS thread id 1152305504 fetching rows, thread declared inside InnoDB 400
mysql tables in use 1, locked 0
MySQL thread id 8076, query id 728896 localhost root Sending data
select sql_calc_found_rows * from b limit 5
Trx read view will not see trx with id >= 0 80157598, sees < 0 80157594
解析:事務列表可能會很長,因此對於存在大量併發事務的系統,SHOW ENGINE INNODB STATUS會截去部份內容,只顯示部分事務。
具體輸出參數及其解析以下所示。
Trx id counter…:當前事務號,每建立一個新事務,這個值就會遞增。
Purge donefor trx’s n:o…:最近一次進行線程清理的事務號,事務若是過時,則能夠被清除,清除的標準是這些事務已經提交,且不會再被其餘的事務所須要。
咱們能夠檢查當前事務號和最近一次清理線程所清理的事務號的差別,例如,0(64位)80154573(32位)與0(64位)80157601(32位),
若是差別很大,則可能有大量未被清理的事務,或者少許事務更新了大量數據。
事務應該被及時提交。長時間未提交的事務可能會阻塞清理操做,耗盡資源,不過對於Web訪問,通常都是很小的事務,這點不太可能會成爲問題。
事務更新記錄時,將在UNDO中保存記錄的前像。UNDO記錄保存在InnoDB的共享表空間內。
若是事務未提交,或者其餘用戶須要查詢UNDO記錄以得到一致性讀,此時是不能清理這部分事務的。
大量未清理的事務,可能會致使UNDO空間暴漲,在緊急狀況下,咱們能夠設置innodb_max_purge_lag參數來延緩新事務的更新,不過這個參數要慎用,由於它會下降性能,治標不治本。
下面來舉個例子說明一下這個參數。
若是你的InnoDB表空間能夠忍受100M未清理的行,也就是平均每一個事務大概影響1K的行,那麼你能夠設置這個值爲 100000(100M/1K)。
undo n:o:Purge操做正在處理的UNDO日誌記錄號。
History list length 6:在UNDO空間內未被清理的事務數量,在事務更新數據的時候該值會增長,在事務清理後該值會減小。
Total number of lock structs in row lock hash table 0:行鎖哈希表(row lock hash table)中的鎖結構(lock struct)的數量,該值不一樣於被鎖定的行,由於一般會有多個行對應一個鎖結構。
LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 00,notstarted,process no 3396,OS thread id 1152440672:
每一個事務都有兩個狀態,即not started或active。在生產系統中,同時運行的線程通常最多隻有幾個,因此大部分事務都是not started。
須要留意的是,即便鏈接的狀態是sleep,事務也多是active的,由於事務多是多語句的,
在生產環境中能夠發現,一些長時間sleep的異常線程可能會持有着資源不釋放,從而致使整個系統出現異常。
InnoDB有一個參數爲innodb_thread_concurrency,用來控制併發執行的線程數。
InnoDB試着在其內部控制操做系統線程的數量,使其少於或等於這個參數給出的限制。
若是SHOW ENGINE INNODB STATUS顯示有不少線程在等待(waiting in InnoDB queue或sleeping before joining InnoDB queue)進入隊列,那麼每每是有性能上的問題,致使系統掛死。
MySQL讓等待的線程睡眠,從避免太多線程併發競爭,若是你的計算機有多個處理器和磁盤,則能夠試着將這個值調整得更大以更好地利用計算機的資源。
一個推薦的值是採用系統上處理器和磁盤的個數之和。
注意:MySQL的配置裏還有一個thread_concurrency參數,建議設置爲CPU數的2倍大小。此變量僅僅影響Solaris系統。
在Solaris中,mysqld用該值調用 thr_setconcurrency()函數。該函數使得應用程序能夠向線程系統提供須要同時運行的、指望的線程數目。
此外,其實innodb_thread_concurrency這個參數纔會影響到全部的平臺。
mysql tables in use 1,locked 0:訪問的表數目,鎖定的表數目。通常的操做是不會鎖表的,InnoDB支持行級鎖,因此locked通常等於0,除非是進行ALTER TABLE、LOCK TABLE之類的操做。
MySQL thread id 52111305:SHOW PROCESSLIST命令輸出中的id列。
(5)I/O信息
如下是IO helper threads的狀態。
-------- FILE I/O --------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
這4個線程(Unix/Linux下老是4個)的做用分別是insert buffer merges、asynchronous log flushes、read-ahead和flushing of dirty buffers。
當前看到它們的狀態都是waiting for i/o request。
Pending normal aio reads: 0, aio writes: 0, ibuf aio reads: 0, log i/o’ s: 0, sync i/o’ s: 0
Pending flushes (fsync) log: 0; buffer pool: 0
6845394 OS file reads, 209547550 OS file writes, 1051178 OS fsyncs 7.27 reads/s, 16384 avg bytes/read, 256.68 writes/s, 1.88 fsyncs/s
若是以上Pending爲非零值,則可能存在I/O瓶頸。
對於隨機I/O,因InnoDB的I/O最小單元(pagesize)=16KB。因此爲16384 avg bytes/read,對於全表掃描(fulltablescan)、索引範圍掃描(index scan),這個avg bytes/read會大得多。
(6)INSERT BUFFER AND ADAPTIVE HASH INDEX MySQL
並無提供手段對如下結構進行調優。
———————————— INSERT BUFFER AND ADAPTIVE HASH INDEX————————————
Ibuf: size 1, free list len 0, seg size 2,
這裏ibuf即Insert buffer,雖然英文中說的是「buffer」,但實際上這是分配在InnoDB表空間中的一塊區域,
它能夠和其餘數據塊同樣,緩存在InnoDB緩衝池裏,Insert buffer能夠減小I/O,由於它能夠合併對索引葉節點的更改操做。
(7)LOG
下面將講述InnoDB的log子系統。
—LOG—
Log sequence number 44961757582
Log flushed up to 449 61751106
Last checkpoint at 448 4209429402
0 pending log writes, 0 pending chkp writes
201992232 log i/o’ s done, 250.14 log i/o’ s/second
其中的輸出參數及其解析具體以下。
Log sequence number 44961757582:表空間建立後寫入log buffer的字節數,這個值能夠用來衡量日誌的寫入速度。
經過採樣Log sequence number的輸出,能夠獲取每秒寫入的日誌量,若是咱們要設置InnoDB事務日誌的大小,那麼能保持連續寫入日誌30~60分鐘爲佳。
Log flushed up to 44961751106:最近刷新(flush)數據的位置。
由此能夠計算還有多少未刷新到日誌文件(logfile)的數據。若是這些數據大於innodb_log_buffer_size的30%,那麼就要考慮是否應增長日誌緩衝(log buffer)了。
Last checkpoint at 4484209429402:最近一次檢查點的位置。
0 pending logwrites,0 pending chkp writes:pending若是大於0,則可能有I/O瓶頸。
201992232 log i/o’s done,250.14 log i/o’s/second:這些輸出衡量了咱們的log I/O。
(8)BUFFER POOL AND MEMORY
如下是InnoDB緩衝池的信息。
---------------------- BUFFER POOL AND MEMORY ----------------------
Total memory allocated 4648979546; in additional pool allocated 16773888
Buffer pool size 262144
Free buffers 0
Database pages 258053
Modified db pages 37491
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 57973114, created 251137, written 10761167 9.79 reads/s, 0.31 creates/s, 6.00 writes/s
Buffer pool hit rate 999 / 1000
須要說明的是「Buffer pool hit rate」的參考價值不是很大。即便有很高的命中率,也可能有大量的物理磁盤讀寫。
(9)ROW OPERATIONS
如下是行操做信息。
-------------- ROW OPERATIONS --------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 10099, id 88021936, state: waiting for server activity
Number of rows inserted 143, updated 3000041, deleted 0, read 24865563
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
咱們能夠由以上信息獲知各類查詢的大概頻率,須要留意的是若是「0 queries in queue」不爲0,則是有查詢須要等待,可能意味着系統忙,你須要作進一步的診斷。

小結:本章介紹了MySQL運維所須要瞭解的各類數據庫文件及MySQL如何進行災難恢復。你必須瞭解各類文件的做用和機制,避免在操做系統下對數據庫文件誤操做。本章還介紹了數據庫的參數設置與配置文件,MySQL的配置不該該常常變更,你應該使用大多數人建議的配置,根據本身的生產環境作適當調整便可。最後介紹了查詢緩衝和MySQL優化器,咱們要熟悉這些主要的組件。此外,還講述瞭如何閱讀SHOW ENGINE INNODB STATUS\G命令的輸出。 其餘的一些基礎知識已在開發篇中進行了介紹,好比索引設計、查詢優化,讀者也應該熟悉這些內容。

相關文章
相關標籤/搜索