MySQL內存計算器


MySQL如何使用內存?

首先,介紹MySQL使用內存的一些方法:

1. 會話級別的內存消耗(連接私有內存):如sort_buffer_size等,每個會話都會開辟一個sort_buffer_size來進行排序操作。

2. 全局的內存消耗(共享內存):例如:innodb_buffer_pool_size等,全局共享的內存段。

MySQL內存計算器:http://www.mysqlcalculator.com

MySQL 5.7內存使用分析

全局內存消耗(共享內存)相關參數

1)innodb_buffer_pool_size

使用過Innodb的同學都知道,這塊內存是Innodb存儲引擎最重要的內存,直接關系到MySQL的讀寫性能。與MyISAM表只緩存索引,數據寄望於OS系統緩存不同。Innodb一般都會關閉OS的緩存,所有讀到數據頁和索引都直接存在數據庫層的innodb_buffer_pool中的。

InnoDB緩沖池緩存着InnoDB表,索引,及其它輔助緩沖器中的數據。為了實現大容量讀取操作的效率,緩沖池被分成可以容納多行的頁。為了緩存管理的效率,緩沖池被實現為頁面的鏈接列表,很少使用的數據使用LRU算法的變體進行頁面替換。

緩沖池的大小對於系統性能很重要:

  • InnoDB使用malloc()方法在服務器啟動時為整個緩沖池分配內存,通常,推薦innodb_buffer_pool_size值為系統內存的50%至75%。innodb_buffer_pool_size可以在服務器運行時動態配置。
  • 在具有大量內存的系統上,你可以通過將緩沖池划分為多個緩沖池實例來提高並發性,其innodb_buffer_pool_instances系統變量用來定義緩沖池實例的數量。
  • 緩沖池太小可能會導致過多的交換,因為頁面從緩沖池中刷新后僅在短時間內可能再次需要。
  • 緩沖池太大可能會因為內存競爭而導致交換。

2)innodb_additional_mem_pool_size

主要用於存放MySQL內部的數據結構和Innodb的數據字典,所以大小主要與表的數量有關,表越多值越大。慶幸的是這個值是可變的,如果不夠用的話,MySQL會向操作系統申請的。該值默認8M,AWS所有規格都是統一的2M,由於這個值可以動態申請,所以我覺得2M應該是滿足需求的。

3)innodb_log_buffer_size

這個是redolog的緩沖區,為了提高性能,MySQL每次寫日志都將日志先寫到一個內存Buffer中,然后將Buffer按照innodb_flush_log_at_trx_commit的配置刷到disk上。目前,我們所有實例的innodb_flush_log_at_trx_commit設置為了1,即每次事務提交都會刷新Buffer到磁盤,保證已經提交的事務,redo是不會丟的。AWS該值也設的是1(為了保證不丟數據),這個值的大小主要影響到刷磁盤的次數,設置的過小,Buffer容易滿,就會增加fsync的次數,設置過大,占用內存。該值默認是8M,AWS所有規格統一128M,我覺得目前每次提交都會刷buffer,所以除非有大事務的情況,一般buffer不太可能被占滿,所以沒必要開的很大, 8M應該是滿足需求的。

4)key_buffer_size

MyISAM表的key緩存,這個只對MyISAM存儲引擎有效,所以對於我們絕大多數使用Innodb的應用,無需關心。

5)query_cache_size

MySQL對於查詢的結果會進行緩存來節省解析SQL、執行SQL的花銷,query_cache是按照SQL語句的Hash值進行緩存的,同時SQL語句涉及的表發生更新,該緩存就會失效,所以這個緩存對於特定的讀多更新少的庫比較有用,對於絕大多數更新較多的庫可能不是很適用,比較受限於應用場景,所以AWS也把這個緩存給關了。我覺得這個值默認應該關閉,根據需求調整。

會話級別的內存消耗(連接私有內存)

上面這些就是MySQL主要的共享內存空間,這些空間是在MySQL啟動時就分配的,但是並不是立即使用的。MySQL還有一部分內存是在用戶連接請求到達時動態分配的,即每個MySQL連接都單獨一個緩存,這部分緩存主要包括:

1)read_buffer_size

每個線程連續掃描時為掃描的每個表分配的緩存區的大小(字節)。如果進行多次連續掃描,可能還需要增加該值。默認值為1311072,只有當查詢需要的時候,才分配read_buffer_size指定的全部內存。

2)read_rnd_buffer_size

當以任意順序讀取行時,可以分配隨機讀取緩沖區,通過該緩沖區讀取行,以避免磁盤尋找。read_rnd_buffer_size系統變量決定緩沖器大小。

3)sort_buffer_size

每一個要做排序的請求,都會分到一個sort_buffer_size大的緩存,用於做order by和group by的排序,如果設置的緩存大小無法滿足需要,MySQL會將數據寫入磁盤來完成排序。因為磁盤操作和內存操作不在一個數量級,所以sort_buffer_size對排序的性能影響很大。由於這部分緩存是即使不用這么大,也會全部分配的,所以對系統內存分配開銷是比較大的,如果是希望擴大的話,建議在會話層設置,默認值2M,AWS也是2M。

4)thread_stack

默認256K,AWS設置為256K,MySQL為每個線程分配的堆棧大小,當線程堆棧太小時,這限制了服務器可以處理的SQL語句的復雜性。

5)join_buffer_size

每個連接的每次join都分配一個,默認值128K,AWS設置為128K。

6)binlog_cache_size

類似於innodb_log_buffer_size緩存事務日志,binlog_cache_size緩存Binlog,不同的是這個是每個線程單獨一個,主要對於大事務有較大性能提升。默認32K,AWS 32K。

7)tmp_table_size

默認16M,用戶內存臨時表的最大值,如果臨時表超過該值,MySQL就會把臨時表轉換為一個磁盤上mysiam表。如果用戶需要做一些大表的groupby的操作,可能需要較大的該值,由於是與連接相關的,同樣建議在會話層設置。

MySQL 5.7 OOM問題診斷

其實導致OOM的直接原因並不復雜,就是因為服務器內存不足,內核需要回收內存,回收內存就是kill掉服務器上使用內存最多的程序,而MySQL服務是使用內存最多,所以就OOM了。今天,來談談MySQL的OOM(out of memory)問題診斷。之前,這類問題的定位對於普通用戶來說並不怎么簡單。但是在MySQL 5.7中,OOM問題的定位變得極其容易。還沒掌握的小伙伴趕快來看下吧。通常來說,發生OOM時可在系統日志找到類似的日志提示:

MySQL 5.7的庫performance_schema新增了以下這幾張表,用於從各維度查看內存的消耗:

  • memory_summary_by_account_by_event_name
  • memory_summary_by_host_by_event_name
  • memory_summary_by_thread_by_event_name
  • memory_summary_by_user_by_event_name
  • memory_summary_global_by_event_name

簡單來說,就是可以根據用戶、主機、線程、賬號、全局的維度對內存進行監控。同時庫sys也就這些表做了進一步的格式化,可以使得用戶非常容易的觀察到每個對象的內存開銷:

細心的同學可能會發現,默認情況下performance_schema只對performance_schema進行了內存開銷的統計。根據你的MySQL安裝代碼區域可能包括performance_schema、sql、client、innodb、myisam、csv、memory、blackhole、archive、partition和其他。

但是在對OOM進行診斷時,需要對所有可能的對象進行內存監控。因此,還需要做下面的設置:

 

但是這種在線打開內存統計的方法僅對之后新增的內存對象有效:

如想要對全局生命周期中的對象進行內存統計,必須在配置文件中進行設置,然后重啟:

 

通過上面的結果,是不是可以發現可疑的內存使用了呢?

另外可以看看buffer pool page的使用情況。

對於MySQL 5.7,可以使用sys庫下的memory_global_by_current_bytes表來查詢相同的底層數據,該模式表顯示了全局服務器內當前內存使用情況,按分配類型進行細分。

此sys模式查詢通過current_alloc()代碼區域聚合當前分配的內存:

完結。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM