MySQL技術內幕:InnoDB存儲引擎讀書筆記(下)

 

第六章、鎖

  鎖是區別文件系統和數據庫系統的一個關鍵特性。

  6.1、什麼是鎖?

  鎖是用來管理對共享文件的併發訪問。innodb會在行級別上對數據庫上鎖。不過innodb存儲引擎會在數據庫內部其他多個地方使用鎖,從而允許對不同資源提供併發訪問。例如操作緩衝池中的LRU列表,刪除,添加,移動LRU列表中的元素,爲了保證一致性,必須有鎖的介入。

  6.2、innodb存儲引擎中的鎖

  6.2.1、鎖的類型

  S lock 共享鎖 允許事務讀一行數據

  X lock 排它鎖 允許事務刪除或者更新一條數據

  IS lock 意向共享鎖 事務想要獲得一個表中某幾行的共享鎖

  IX lock 意向拍他所 事務想要獲得一個表中某幾行的排它鎖

  可以使用 show engine innodb status\G查看 TRANSACTIONS中關於鎖的信息。也可以使用 show full processlist查看相關信息。在innodb插件版本以後,可以通過查看INFORMATION—SCHEMA中的INNODB_TRX,INNODB_LOCKS,INNODB_LOCK_WAITS三張表來分析存在的鎖問題。

  具體參見 P207

  6.2.2、一致性的非鎖定讀操作

  一致性非鎖定讀(consistent nonlocking read)是指innodb通過多版本控制(multi versioning)的方式來讀取當前執行時間數據庫中行的數據。

  多版本控制是通過快照實現的,快照數據其實就是當前數據之前的歷史版本,可能有多個版本。這種技術稱爲行多版本技術,由此帶來的併發控制叫做多半本併發控制(multi version concurrency control,MVCC).

  在Read Committed和Repeatable Read(innodb默認的事務隔離級別)下,innodb存儲引擎使用非鎖定的一致性讀。但是對於快照數據的定義卻不同。

  在Read Commited級別,對於快照數據,非一致性讀總是讀取被鎖定行的最新一份快照。

  在Repeatable級別下,對於快照數據,非一致性讀總是讀取事務開始時的行數據版本。

  6.2.3、SELECT…FOR UPDATE & SELECT…LOCK IN SHARE MODE

  SELECT…FOR UPDATE 可以獲得一個X鎖。

  SELECT…LOCK IN SHARE MODE 可以獲得一個S鎖。

  6.2.4、子增長和鎖

  對於含有子增長計數器的表進行插入時,會執行”SELECT MAX(auto_inc_col) FROM t FOR UPDATE;”插入操作會更具這個自增長的計數器值加1賦予自增長列。這個實現方式叫做AUTO-INC Locking。這是一種特殊的鎖,爲了提高併發,它不會在事務執行完才釋放,只是在語句執行後立即釋放。

  從mysql-5.1.22版本開始,innodb引擎提供了一種輕量級互斥量的自增長實現機制,這種機制大大提高了子增長值插入的性能。並且mysql-5.1.22開始,innodb引擎提供了一個參數

  innodb_autoinc_lock_mode,默認的值爲1

  在討論新的增長方式之前我們需要對自增長實現方式分類:

  INSERT-LIKE:指所有的插入語句,比如 INSERT、REPLACE、INSERT…SELECT、REPLACE…SELECT,LOAD DATA等

  Simple insert:指在插入前就能確定插入行數的語句,包括INSERT、REPLACE,不包含INSERT…ON DUPLICATE KEY UPDATE這類語句。

  Bulk inserts:指在插入前不能確定得到插入行的語句。如INSERT…SELECT,REPLACE…SELECT,LOAD DATA.

  Mixed-mode inserts:指其中一部分是子增長的,有一部分是確定的。

  現在有SIMPLE INSERT、BULK INSERTS、MIXED-MODE INSERTS三種類型的INSERT語句,有AUTO-inc locking(最早的)和輕量級互斥量的自增長兩種auto—increment鎖。

  innodb_autoinc_lock_mode=0 5.1.22之前的方式,也就是所有類型的insert都用AUTO-inc locking。

  innodb_autoinc_lock_mode=1 這個參數是5.1.22之後出現的也是之後的默認值,對於SIMPLE INSERT,使用輕量級互斥量的鎖,對於BULK INSERT,使用AUTO-inc locking,

  innodb_autoinc_lock_mode=2 指不管什麼情況都使用輕量級互斥的鎖,效率最高,但是複製只能使用row-base replication,因爲statement-base replication會出現問題。

  另外就是innodb和myisam的一個區別,innodb下,自增長必須是索引,而且必須是索引的第一個列,不然會報錯,myisam不會出現這個問題。

  6.2.5、外鍵和鎖

  innodb中,對於一個外鍵列,如果沒有顯示的對這個列加索引,innodb就自動的對其加一個索引。

  6.3、鎖的算法

  innodb引擎有三種鎖的算法設計:

  Record lock:單個記錄上的鎖

  Gap lock:間隙鎖,鎖定一個範圍,但不包含記錄本身

  Next-key lock:Gap lock+Next-key lock鎖定一個範圍,並鎖定記錄本身。

  6.4、鎖問題

  本來鎖問題會導致的是更新丟失、幻讀、髒讀、不可重複讀,但是innodb作者卻只寫出了三種問題,可能是幻讀通過innodb Next-key Lock解決了,作者就沒有提及。

  這幾個鎖問題對應事務隔離的4個安全級別:

  READ UNCOMMITTED(事務隔離最低的級別,有事務隔離就能解決更新丟失,但是存在髒讀的問題),

  READ COMMITED(ORACLE和SQL SERVER默認的隔離級別,解決了髒讀,但是一個事務多次讀取的內容不同,出現了不可重複讀的問題),

  READ REPEATABLE(可重複讀,innodb引擎的默認事務隔離級別,解決了不可重複讀的問題,但是產生了幻讀,innodb通過Next-key lock解決了幻讀).

  SERIALIZABLE(可串行話,通過強制事務排序解決幻讀問題,會降低性能)總的看來innodb默認的 READ REPEATABLE是非常棒的。

  6.5、阻塞

  innodb中需要其他事務的鎖釋放它鎖佔用的資源,這個時候就會發生鎖等待,這就是阻塞。

  innodb引擎有兩個相關參數

  innodb_lock_wait_timeout 用來設定等待的時間,默認是50秒,這是一個動態參數,可以隨時調整

  innodb_rollback_on_timeout 用來設定是否在等待超時時對進行中的事務進行回滾操作,默認是OFF,代表不回滾,這是一個靜態參數。

  6.6、死鎖

  死鎖會慘生阻塞,所以可以通過6.5的參數,讓超時的阻塞回滾。還有就是開發的時候,每個事務對錶,字段,行的操作,都是順序的,這樣可以很大程度上避免死鎖。

  6.7、鎖升級

  innodb不存在鎖升級問題,鎖升級一般在SQL SERVER中使用。

  第七章、事務

  transaction是數據庫區別於文件系統的重要特性之一,innodb引擎完全符合事務的ACID特性。

  Automicity 原子性

  Consistency一致性

  Isolation 隔離性

  durability 持久行

  7.1、事務概述

  詳細介紹了ACID屬性。

  7.2、事務的實現

  隔離性通過鎖來實現,原子性、一致性、持久性通過數據庫的redo和undo來完成。

  7.2.1、redo

  innodb通過redo日誌文件和innodb log buffer來實現redo。

  當事務開始時,innodb會記錄該事務的一個LSN(Log Sequence Number,日誌序列號)

  當執行事務時,會往innodb log buffer寫入事務日誌

  當事務提交時,必須將innodb存儲引擎的日誌緩存寫入磁盤(默認的實現,通過innodb_flush_log_at_trx_commit=1)

  這意味這磁盤上的頁和內存緩衝池中的頁是不同步的,可以通過 show ENGINE INNODB STATUS\G來觀察當前磁盤和日誌的”差距”,在LOG字段。Log sequence number表示當前的LSN,Log flushed up to表示刷新到重做日誌文件的LSN,Last checkpoint at表示刷新到磁盤的LSN。

  7.2.2、undo

  undo和redo相反,redo是重做,undo是撤銷。使用rollback語句請求回滾就可以利用undo信息將數據回滾到修改之前的樣子。

  redo存放在redo日誌裏面,undo存放在數據庫內部的一個特殊段(undo segment),undo段位於共享表空間裏。

  undo是邏輯操作,它實際上是做與之前相反的工作,之前是insert,它就delete對於每個update,undo都會執行一個相反的update。

  7.3、事務控制語句

  AUTOCOMMIT = 0 關閉自動提交,等於1 開啓自動提交

  START TRANSACTION | BEGIN 顯示的開啓一個事務

  COMMIT 提交你的事務

  ROLLBACK 回滾

  SAVEPOINT identifier SAVEPOINT允許你的事務中創建一個保存點,一個事務中可以有多個保存點

  RELEASE SAVEPOINT identifier 刪除一個事務的保存點

  ROLLBACK TO [savepoint]identifier 回滾到之前創建的保存點

  SET TRANSACTION 這個語句用來設置事務的隔離級別,innodb的隔離級別在6.4已經說過了。

  completion_type = 0 時COMMIT和COMMIT WORK功能完全相同

  completion_type = 1 時COMMIT WORK等於COMMIT AND CHAIN,表示提交後馬上開啓一個相同隔離級別的事務

  complation_type = 2 時COMMIT WORK等於COMMIT AND RELEASE,當事務提交後會自動斷開與服務器的鏈接

  7.4、隱式提交的SQL語句

  完成這些語句就會自動提交:

  DDL

  CREATE USER,DROP USER,GRANT、RENAME USER,REVOKE,SET PASSWORD

  ANALYZE TABLE、CACHE INDEX、CHECK TABLE、LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE

  注意:TRUNCATE TABLE屬於DDL語句,不能rollback。

  7.5、對於事務的統計

  QPS = Question Per Second = 每秒請求數

  TPS = Transaction Per Second = 每秒事務處理能力

  計算TPS的方法是com_commit + com_rollback/TIME = TPS

  7.6、事務隔離級別

  參考6.4

  7.7、分佈式事務

  innodb引擎支持XA分佈式事務。

  分佈式事務指營運需多個獨立的事務資源(transactional resources)參與一個全局的事務中。事務資源通常是關係型數據庫系統。全局事務要求在其中所有參與的事務要麼都提交、要麼都回滾,對於原有的ACID有了提高。

  注意:在使用分佈式事務時,innodb存儲引擎的事務隔離級別必須設置成SERIALIABLE。

  7.8、不好的習慣

  7.8.1、在循環中提交事務

  7.8.2、不要開啓自動提交事務 set auto_commit = 0

  7.8.3、使用自動回滾,存儲過程中使用 declare exit handler for sqlexception rollback;

  第八章、備份與恢復

  對於dba來說,備份應該佔工作比重的50%以上。

  8.1、備份於恢復概述

  hot backup

  cold backup

  warm backup

  邏輯備份

  裸文件備份

  完全備份

  增量備份

  日誌備份

  8.2、冷備

  關閉數據庫,拷貝frm文件、共享表空間、單獨表空間、重做日誌文件,還有推薦備份my.cnf

  冷備份的優點:

  備份簡單,只是拷貝相關文件

  備份文件易於在不同操作系統、不同mysql版本上進行恢復

  恢復簡單

  恢復速度快

  缺點:

  冷備份比邏輯備份佔用更多的空間

  要停止數據庫

  8.3、邏輯備份

  mysqldump 最常用的邏輯備份工具,用法這裏就不說明了,主要提示幾個重要的參數。

  –single-transaction 在備份開始前使用start transaction以此保證備份的一致性,需要保證沒有其他DDL語句,針對innodb有效。

  –lock-tables -l 在備份中依次鎖住每個建構下所有的表,保證備份的一致性,一般用於myisam備份

  –lock-all-tables -x 在備份過程中,對所有架構中的所有表上鎖

  –master-data=value 當值爲1時,轉儲文件中有change master語句,如果值爲2,change master語句是被註釋的,此參數會忽略–lock-tables.如果沒有使用–singletransaction則會自動使用–lock-all-tables

  –events -E 備份事件調度器

  –routines -R 備份存儲過程和函數

  –triggers 備份觸發器

  –tab=path 產生TAB分割的數據文件。對於每張表mysqldump會創建一個包含create table的table_name.SQL和一個包含數據的tbl_name.txt,可以使用參數改變默認的分割符和換行符。

  8.3.2、select …. into outfile

  使用select … into outfile ‘/tmp/file’; 和 load data infile ‘/tmp/file’ into table tablename;

  8.4、二進制日誌備份與恢復

  8.5、熱備

  8.5.1、ibbackup工作原理如下:

  1、記錄備份開始時,innodb存儲引擎重做日誌文件檢查點的LSN。

  2、拷貝共享表空間文件以及獨立表空間文件。

  3、記錄拷貝完表空間文件後,innodb存儲引擎重做日誌文件檢查點的LSN。

  4、拷貝在備份時產生的重做日誌

  在線備份

  備份性能好

  支持壓縮備份

  跨平臺支持

  8.5.2、xtrabackup

  暫時留空

  8.6、快照備份

  使用文件系統快照或者LVM快照備份數據庫。暫時留空

  8.7、複製

  8.7.1、複製的工作原理

  a、主服務器把數據更新記錄寫道binlog

  b、從服務器把主服務器的二進制日誌拷貝到自己的中繼日誌中

  c、從服務器重做做中繼日誌中的時間,把更新應用到自己服務器上。

  從服務器有兩個線程,一個io線程,負責讀取主服務器的二進制日誌,並將起保存爲中繼日誌,另外一個sql線程,負責執行中繼日誌。

  8.7.2、快照+複製的備份架構

  主要功能:

  數據分佈 mysql的複製並不需要很多帶寬,可以跨機實現數據拷貝

  讀取的負載平衡 通過讀寫分離實現

  數據庫備份 複製對備份有幫助,但是複製不能代替備份

  高可用性和故障轉移

  從服務器做快照可以避免複製對誤操作的處理能力,主需要根據從服務器的快照,然後根據二進制日誌執行point-in-time的恢復即可。

  第九章、性能調優

  性能調悠主要涉及一下內容:

  選擇合適的CPU

  內存的重要性

  硬盤對數據性能的影響

  合理的設置raid

  操作系統的選擇也很重要

  不同文件系統對數據庫的影響

  選擇合適的基準測試工具

  9.1、選擇合適的CPU

  OLTP的特點

  用戶操作併發大

  事務處理的時間一般比較短

  查詢的語句較爲簡單、一般走索引

  複雜的查詢較少

  OLTP對CPU的需求不是很大,但是OLTP屬於IO密集型的操作。

  OLAP對CPU的需求比較大,需存儲空間要求比較大,對操作時間不太敏感。

  對於多核的CPU機器,可以修改innodb_read_io_threads和innodb_write_io_threads來增加IO線程,來充分利用多核的性能。

  9.2、內存的重要性

  學會判斷內存是否已經達到瓶頸了?

  通常innodb存儲引擎的緩衝池的命中率不應該小於99%。

  show global status like ‘innodb%read%’;

  Innodb_buffer_pool_reads 表示物理磁盤讀取頁的次數

  Innodb_buffer_pool_read_ahead 預讀的次數

  Innodb_buffer_pool_ahead_evicted 預讀的頁,但是沒有被讀取就從緩衝池中被替換的數量,一般用來判斷預讀的效率

  Innodb_buffer_pool_read_requests 從緩衝池中讀取頁的次數

  Innodb_data_read 總共讀入的字節數

  Innodb_data_reads 發起讀取請求的次數,每次讀取可能需要讀取多個頁

  計算緩衝池命中率 = Innodb_buffer_pool_read_requests / (Innodb_buffer_pool_read_requests+Innodb_buffer_pool_read_ahead+Innodb_buffer_pool_reads)

  平均每次讀取的字節數 = Innodb_data_read / Innodb_data_reads

  9.3、硬盤對數據庫性能的影響

  9.3.1、傳統機械硬盤

  機械硬盤兩個重要的指標:尋道時間、轉速。

  機械硬盤順序訪問的速度遠遠大於隨機訪問。

  可以通過raid提高數據庫的性能,也可以將數據分佈式的放到多個硬盤上。

  9.3.2、固態硬盤

  固態硬盤是有多個閃存組成的。

  固態硬盤優點:

  具有很高的隨機讀取能力、低延遲性、低功耗、防震等有點。

  固態硬盤缺點:

  閃存中的數據不可更新,只能通過山區的覆蓋重寫,而覆蓋從寫之前需要執行耗時的erase操作。earse操作通常以擦除塊爲單位,通常一個塊是128KB。

  所以使用固態硬盤應該很好的利用他的隨機讀取性能,避免過多的寫入。

  如果使用了固態硬盤,可以通過優化innodb_io_capacity參數,來充分利用固態硬盤的高IOPS特性。

  9.4、合理的利用raid

  9.4.1、raid類型

  raid的作用:

  增強數據集成度

  增強容錯功能

  增加處理量或容量

  根據不同磁盤的組合方式,常見的raid組合可以分爲raid0、raid1、raid5、raid10和raid01.

  raid0 具有所有raid級別中最高的讀寫性能,最高的存儲空間利用率,最低的安全性,需要至少兩快硬盤。

  raid1 具有所有raid級別中最高的安全性,最低的存儲空間利用率,較高的讀性能和稍微減弱的寫性能,需要至少兩塊硬盤。

  raid5 是raid0和raid1的這種方案,具有和raid0相近的數據讀取能力,寫性能降低很利用,用於寫入奇偶校驗信息了,需要至少三塊硬盤。

  raid10 先將所有硬盤視爲raid 0的最低級別,也就是把所有硬盤分成兩部分,做成raid0.然後把這兩部分中的硬盤做成raid1.提供較高的保護性和不錯的性能。至少4塊硬盤。

  raid01 先將所有硬盤視爲raid 1的最低級別,也就是把所有硬盤分成兩部分,做成raid1,然後把這兩部分中的硬盤做成raid0,提供了最高的性能,安全性較低。至少4塊硬盤

  raid50 …..

  推薦使用raid10.

  9.4.2、RAID write Backup功能

  RAID write Backup功能就是將raid控制器要寫入硬盤的數據寫入自己的緩存中,並把他們安排到後期一起寫入硬盤。這樣做的目的肯定是提高磁盤性能。緩存比磁盤的IOPS高多非常多。

  缺點是斷電可能會丟失數據,所以提供了BBU(Battery backup unit,電池備份單元)。由於電池維護較爲麻煩,所以又新出了BFWC技術。具體參見我的

  9.4.3、RAID配置工具

  一般可以在BIOS配置界面調節,頁可以使用系統工具調節。P308介紹了LSI公司的MegaCLI工具的使用。

  9.5、操作系統的選擇

  推薦linux和freebsd。

  9.6、不同文件系統對數據庫的影響

  推薦ZFS或者使用lvml邏輯卷管理。

  9.7、選擇合適的基準測試工具

  9.7.1、sysbench

  參見我blog的sysbench的文章。

  9.7.2、mysql-tpcc

 

發佈了125 篇原創文章 · 獲贊 0 · 訪問量 6278
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章