一文了解OOM及解決方案,你還看不明白?

InnoDB總體結構

首先我們來看官網的一張圖(圖片來源于MySQL官網):

image

從上圖中可以看出其主要分為兩部分結構,一部分為內存中的結構(上圖左邊),一部分為磁盤中的結構(上圖右邊)

內存結構

InnoDB內存中的結構主要分為:Buffer Pool,Change Buffer和Log Buffer三部分。

Buffer Pool

Buffer Pool是InnoDB緩存表和索引的一塊主內存區域,Buffer Pool允許直接從內存中處理經常使用的數據,從而加快處理速度,帶來一定的性能提升。 但是緩存總有放滿的時候,當緩存滿了新來的數據怎么處理呢?Bufer Pool中采用的是LRU(least recently used,最近最少使用)算法,LRU列表中最前面存的是高頻使用頁,尾部放的是最少使用的頁。當有新數據過來而緩存滿了就會覆蓋尾部數據。

假如我們有一條查詢語句非常大,返回的結果集直接就超過了Buffer Pool的大小,而這種語句使用場景又是極少的,可能查詢這一次之后很久不會查詢,而這一次就將緩存占滿了,將一些熱點數據全部覆蓋了。為了避免這種情況發生,InnoDB對傳統的LRU算法又做了改進,將LRU列表分拆分為2個,如下圖(圖片來源于MySQL官網):

image

該算法在new子列表中保留大量頁面(5/8),old子列表包含較少使用的頁面(3/8);old子列表中數據可能會被覆蓋,該算法具體操作如下:

  • 3/8的Buffer Pool空間用于old子列表

  • 列表的中點是new子列表的尾部與old子列表的頭部之間的邊界

  • 當InnoDB將一個頁面讀入緩沖池時,它首先將它插入到中間點(old子列表的頭)。讀取的頁面是由用戶發起的操作(比如SQL查詢)或InnoDB自動執行的預讀操作

  • 訪問old子列表中的頁面使其“young”,并將其移動到new子列表的頭部。如果讀取的頁是由用戶發起的操作,那么就會立即進行第一次訪問,并使頁面處于young狀態;如果讀取的頁是由預讀發起的操作,那么第一次訪問不會立即發生,而且可能直到覆蓋都不會發生。

  • 操作數據時,Buffer Pool中未被訪問的頁會逐漸移到尾部,最終會被覆蓋。

默認情況下,查詢讀取的頁面會立即移動到新的子列表中,這意味著它們在緩沖池中停留的時間更長。

Change Buffer

Change Buffer是一種特殊的緩存結構,用來緩存不在Buffer Pool中的輔助索引頁, 支持insert, update,delete(DML)操作的緩存(注意,這個在MySQL5.5之前叫做Insert Buffer,僅支持insert操作的緩存)。當這些數據頁被其他查詢加載到Buffer Pool后,則會將數據進行merge到索引數據葉中。

image

InnoDB在進行DML操作非聚集非唯一索引時,會先判斷要操作的數據頁是不是在Buffer Pool中,如果不在就會先放到Change Buffer進行操作,然后再以一定的頻率將數據和輔助索引數據頁進行merge。這時候通常都能將多個操作合并到一次操作,減少了IO操作,尤其是輔助索引的操作大部分都是IO操作,可以大大提高DML性能。

如果Change Buffer中存儲了大量的數據,那么可能merge操作會需要消耗大量時間。

為什么Change Buffer只能針對非聚集非唯一索引

因為如果是主鍵索引或者唯一索引,需要判斷數據是否唯一,這時候就需要去索引頁中加載數據判斷而不能僅僅只操作緩存。

Change Buffer什么時候會merge

總體來說,Change Buffer的merge操作發生在以下三種情況:

  • 輔助索引頁被讀取到Buffer Pool時。 當執行一條select語句時,會去檢查當前數據頁是否在Change Buffer中,如果在,就會把數據merge到索引頁

  • 該輔助索引頁沒有可用空間時。 InnoDB內部會檢測輔助索引頁是否還有可用空間(至少有1/32頁),如果檢測到當前操作之后,當前索引頁剩余空間不足1/32時,會進行一次強制merge操作

  • 后臺線程Master Thread定時merge。 Master Thread是一個非常核心的后臺線程,主要負責將緩沖池中的數據異步刷新到磁盤,保證數據的一致性。

Adaptive Hash Index

Adaptive Hash Index,自適應哈希索引。InnoDB引擎會監控對索引頁的查詢,如果發現建立哈希索引可以帶來性能上的提升,就會建立哈希索引,這種稱之為自適應哈希索引,InnoDB引擎不支持手動創建哈希索引。

Log Buffer

日志緩沖區是存儲要寫入磁盤日志文件的一塊數據內存區域,大小由變量innodb_log_buffer_size 控制,默認大小為16MB(5.6版本是8MB):

SHOW VARIABLES LIKE 'innodb_log_buffer_size';-- global級別,無session級別

上文講述update語句更新流程一文中,我們只提到了Buffer Pool用來代替緩存區,通過本文對內存結構的分析,實際上Buffer Pool中嚴格來說還有Change Buffer,Log Buffer和Adaptive Hash Index三個部分,DML操作會緩存在Change Buffer區域,而寫redo log之前會先寫入Log Buffer,所以Log Buffer又可以稱之為redo Log Buffer。

Log Buffer什么時候寫入redo log

一個大的Log Buffer空間大允許運行大型事務,而無需在事務提交之前將redo log數據寫入磁盤。Log Buffer中的數據會定期刷新到磁盤,那么Log Buffer的數據又是如何寫入磁盤的呢?Log Buffer數據flush到磁盤有三種方式,通過變量innodb_flush_log_at_trx_commit 控制,默認為1。 |value|描述|

image

  • 當設置為0時,由于數據還在內存,所以崩潰后數據基本會被丟失

  • 當設置為2時,由于數據已經實時寫到redo log了,如果磁盤文件沒有被損壞,還是可以恢復的

另外,Mast Thread默認1s進行一次刷盤操作,這個可以通過變量innodb_flush_log_at_timeout控制,默認1s。

SHOW VARIABLES LIKE 'innodb_flush_log_at_timeout';-- global級別,無session級別

磁盤結構

InnoDB引擎的磁盤結構,從大的方面來說可以分為Tablespace和redo log兩部分

Tablespace

Tablespace可以分為4大類,分別是:System Tablespace,File-Per-Table Tablespaces,General Tablespaces,Undo Tablespaces

System Tablespace

系統表空間中包括了 InnoDB data dictionary,doublewrite buffer, change buffer, undo logs 4個部分,默認情況下InnoDB存儲引擎有一個共享表空間ibdata1,如果我們創建表沒有指定表空間,則表和索引數據也會存儲在這個文件當中,可以通過一個變量控制(后面會介紹)。

ibdata1文件默認大小為12MB,可以通過變量innodb_data_file_path來控制,改變其大小的最好方式就是設置為自動擴展。

innodb_data_file_path=ibdata1:12M:autoextend

上面表示默認表空間ibdata1大小為12MB,支持自動擴展大小。

當我們的文件達到一定的大小之后,比如達到了998MB,我們就可以另外開啟一個表空間文件:

innodb_data_home_dir=
innodb_data_file_path=/ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend

關于上面的設置有3點需要注意:

  • innodb_data_home_dir如果不設置的話,那么就默認所有的表空間文件都在datadir目錄下,而我們上面指定了2個不同路徑,所以需要把innodb_data_home_dir設為空

  • autoextend這個屬性,只能放在最后一個文件

  • 指定新的表空間文件名的時候,不能和現有表空間文件名一致,否則啟動MySQL時會報錯

當然,表空間可以增大,自然也可以減少,但是一般我們都不會去設置減少,而且減少表空間也相對麻煩,在這里就不展開敘述了。

InnoDB Data Dictionary

InnoDB數據字典由內部系統表組成,其中包含用于跟蹤對象(如表、索引和表列)的元數據。元數據在物理上位于InnoDB系統表空間中。由于歷史原因,數據字典元數據在某種程度上與存儲在InnoDB表元數據文件(.frm文件)中的信息重疊。

Doublewrite Buffer

Doublewrite Buffer,雙寫緩沖區,這個是InnoDB為了實現double write而設置的一塊緩沖區,double write和上面的change buffer一個確保了可靠性,一個確保了性能的提升,是InnoDB中非常重要的兩大特性。

我們先來看下面一張圖:

image

InnoDB默認頁的大小是16KB,而操作系統是4KB,如果存儲引擎正在寫入頁的數據到磁盤時發生了宕機,可能出現頁只寫了一部分的情況,比如只寫了 4K,這種情況叫做部分寫失效(partial page write),可能會導致數據丟失。

可能有人會說,可以通過redo log來恢復,但是注意,redo log恢復數據有一個前提,那就是頁沒有損壞,如果頁本身已經被損壞了,那么是沒辦法恢復的,所以為了確保萬無一失,我們需要先保存一個頁的副本,如果出現了上面的極端情況,可以用頁的副本結合redo log來恢復數據,這就是double write技術。

double write也是由兩部分組成,一部分是內存中的double write buffer,大小為2MB,另一部分是物理磁盤上的共享表空間中的連續128個頁,大小也是2MB,寫入流程如下圖(圖片來源于《MySQL技術內幕 InnoDB存儲引擎》):

image

double write機制會使得數據寫入兩次磁盤,但是其并不需要兩倍的I/O開銷或兩倍的I/O操作。通過對操作系統的單個fsync()調用,數據以一個大的順序塊的形式寫入到雙寫入緩沖區。

在大多數情況下默認啟用了doublewrite緩沖區。要禁用doublewrite緩沖區,可通過將變量innodb_doublewrite設置為0即可。

面試資料整理匯總

成功從小公司跳槽進螞蟻定級P7,只因刷了七遍這些面試真題

成功從小公司跳槽進螞蟻定級P7,只因刷了七遍這些面試真題

這些面試題是我朋友進阿里前狂刷七遍以上的面試資料,由于面試文檔很多,內容更多,沒有辦法一一為大家展示出來,所以只好為大家節選出來了一部分供大家參考,需要全部文檔的,關注小編后,點擊這里即可免費領取。

面試的本質不是考試,而是告訴面試官你會做什么,所以,這些面試資料中提到的技術也是要學會的,不然稍微改動一下你就涼涼了

多,沒有辦法一一為大家展示出來,所以只好為大家節選出來了一部分供大家參考,需要全部文檔的,關注小編后,點擊這里即可免費領取。

面試的本質不是考試,而是告訴面試官你會做什么,所以,這些面試資料中提到的技術也是要學會的,不然稍微改動一下你就涼涼了

在這里祝大家能夠拿到心儀的offer!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385622.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385622.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385622.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

信號 09 | 函數pause

函數pause 調用該函數可以造成進程主動掛起,等待信號喚醒,調用該系統調用的進程處于阻塞狀態(主動放棄CPU)直到有信號遞達將其喚醒。 將進程置為可中斷睡眠狀態。然后 它調用schedule(),使linux進程調度器找到另一個進程來運行。pause使調用…

一文搞懂JVM架構和運行時數據區,全網最新

1.Java基礎面試知識點 Java中和equals和hashCode的區別int、char、long各占多少字節數int與integer的區別探探對Java多態的理解String、StringBuffer、StringBuilder區別什么是內部類?內部類的作用抽象類和接口區別抽象類的意義抽象類與接口的應用場景抽象類是否可…

一條正確的Java職業生涯規劃,幫你突破瓶頸

面試題模塊介紹: 一、Java 基礎 JDK 和 JRE 有什么區別? 和 equals 的區別是什么?兩個對象的 hashCode()相同,則 equals()也一定為 true,對嗎?final 在 java 中有什么作用?java 中的 Math.roun…

【線程】線程基本函數

一、pthread_self函數 功能:獲取線程ID。 pthread_t pthread_self(void); 線程ID:pthread_t類型,本質:在Linux為無符號整數(%lu),其他系統可能是結構體實現線程ID是進程內部識別標志。(兩個進程間&#…

一條正確的Java職業生涯規劃,順利通過阿里Java崗面試

珍藏版(1)——Mybatis入門 1.什么是MyBatis 2.為什么我們要用Mybatis? 3.Mybatis快速入門 3.1 導入開發包 3.2準備測試工作 3.3 創建mybatis配置文件 3.4 編寫工具類測試是否獲取到連接 3.5 創建實體與映射關系文件 3.6 編寫DAO 4.Mybatis工作…

線程控制 12 | 線程屬性

本節作為指引性介紹,linux下線程的屬性是可以根據實際項目需要,進行設置,之前我們討論的線程都是采用線程的默認屬性,默認屬性已經可以解決絕大部分開發遇到的問題。如我們對程序的性能提出更高的要求那么需要設置線程屬性&#x…

一次違反常規的Java大廠面試經歷,系列教學

第一部分 Java相關以及答案 答案 第二部分算法跟編程 第三部分html&JavaScript&ajax部分 答案 第四部分Javaweb部分 答案 第五部分數據庫部分 答案 第六部分XML部分 答案 第七部分.流行的框架與新技術 答案 第八、九部分.軟件工程與設計模式以及j2ee部分 最后 筆者…

函數perror、strerror

perror函數 函數原型&#xff1a; #include<stdio.h> void perror(const char *msg); 測試代碼&#xff1a; #include<unistd.h> #include<errno.h> #include<stdio.h>int main() {int ret;ret close(10);if(ret -1) {perror("close error…

一次違反常規的Java大廠面試經歷,重難點整理

目錄 Kafka的基本介紹Kafka的設計原理分析Kafka數據傳輸的事務特點Kafka消息存儲格式副本&#xff08;replication&#xff09;策略Kafka消息分組&#xff0c;消息消費原理Kafak順序寫入與數據讀取消費者&#xff08;讀取數據&#xff09; Kafka的基本介紹 Kafka是最初由Lin…

一步搞定你疑惑的數據結構與算法系列,原理+實戰講解

螞蟻金服一面&#xff1a; 下午杭州的電話&#xff0c;問有沒有空&#xff0c;果斷有空&#xff0c;雖然感覺略顯緊張&#xff0c;有點懵逼。 面試的題目&#xff1a; HashMap和Hashtable的區別實現一個保證迭代順序的HashMap說一說排序算法&#xff0c;穩定性&#xff0c;復…

互斥量(互斥鎖)

一、互斥量mutex Linux提供一把互斥鎖mutex(也稱之為互斥量)每個線程在對資源操作前都嘗試先加鎖&#xff0c;成功加鎖才能操作&#xff0c;操作結束后解鎖。資源還是共享的&#xff0c;線程間也還是競爭的&#xff0c;但通過鎖將資源的訪問變為互斥操作&#xff0c;而后與時間…

一眼就能看懂的Java自學手冊,終局之戰

珍藏版&#xff08;1&#xff09;——Mybatis入門 1.什么是MyBatis 2.為什么我們要用Mybatis? 3.Mybatis快速入門 3.1 導入開發包 3.2準備測試工作 3.3 創建mybatis配置文件 3.4 編寫工具類測試是否獲取到連接 3.5 創建實體與映射關系文件 3.6 編寫DAO 4.Mybatis工作…

Centos 6.x

1. centos升級gcc教程&#xff1a;鏈接 2. 虛擬機中的Centos聯通網絡&#xff1a;鏈接 3. 虛擬機安裝Centos7系統教程&#xff1a;鏈接

Java虛擬機學習集錦是我攢來的,帶你碾壓面試官!

1. 一致性&#xff08;Consistency&#xff09; 一致性&#xff08;Consistency&#xff09;是指多副本&#xff08;Replications&#xff09;問題中的數據一致性。可以分為強一致性、順序一致性與弱一致性。 1.1 強一致性&#xff08;Strict Consistency&#xff09; 也稱為…

Java虛擬機學習集錦是我攢來的,看這篇文章準沒錯!

一面 介紹一下自己 問項目經歷, 聊"數據同步" 接著聊上了 K8S 的項目 有沒有什么鉆研得比較深得技術&#xff1f;&#xff08;大佬&#xff1a;kubernetes, golang, prometheus, java&#xff09; kubernetes 的架構是怎么樣的? 這個問題很大&#xff0c;拆成 …

文件描述符、函數open和openat

文件描述符 pcb&#xff1a;結構體一個進程有一個文件描述符&#xff1a;1024文件描述符&#xff1a;尋找磁盤文件函數open和openat 函數原型&#xff1a; include<sys/stst.h> #include<fcntl.h>int open(const char *pathname, int flags); int open(const ch…

Java這些高端技術只有你還不知道,移動架構師成長路線

并發編程共享模型篇 并發編程概覽進程與線程Java線程共享模型之管程共享模型之內存共享模型之無鎖共享模型之不可變共享模型之工具 共享模型之管程 原理之 Monitor(鎖) 原理之偽共享 模式篇—正確姿勢 同步模式之保護性智停同步模式之Blking同步模式之順序控制異步模式之生產…

函數read、write、lseek

函數原型&#xff1a; #include<unistd.h> ssize_t read(int fd, void *buf, size_t count);返回值&#xff1a;讀到的字節數&#xff0c;若已到文件尾&#xff0c;返回0&#xff1b;若出錯&#xff0c;返回-1 參數&#xff1a; fd&#xff1a;函數open的返回值buf&a…

Java這些高端技術只有你還不知道,薪資翻倍

正文 我的第一份工作是在一家外企&#xff0c;當時抱著“逃離”上海的想法去了二線城市的分公司&#xff0c;但是管理文化氛圍跟總部幾乎都是一樣的&#xff0c;這份工作經歷對我后面的工作不論是做事風格、習慣上還是思考問題的方式方法上都有很大的影響。后面陸續進入國企&a…

函數dup和dup2

函數原型&#xff1a; #include<unistd.h> int dup(int oldfd);返回值&#xff1a;若成功&#xff0c;返回新的文件描述符&#xff1b;若出錯&#xff0c;返回-1 參數&#xff1a; oldfd&#xff1a;要復制的文件描述符dup調用成功&#xff1a;有兩個文件描述符指向同…