MySQL 參數故事 innodb_additional_mem_pool_size

字號+ 編輯: 国内TP粉 修訂: 面向ICU 來源: 淘宝MySQL月报 2023-09-11 我要說兩句(0)

innodb_additional_mem_pool_size配置項詳解。

參數簡介

innodb_additional_mem_pool_size 是 InnoDB 用來保存數據字典信息和其他内部數據結構的内存池的大小,單位是 byte,參數默認值爲8M。數據庫中的表數量越多,參數值應該越大,如果 InnoDB 用完了内存池中的内存,就會從操作系統中分配内存,同時在 error log 中打入報警信息。

innodb_use_sys_malloc 配置爲 ON 時,innodb_additional_mem_pool_size 失效(直接從操作系統分配内存)。

innodb_additional_mem_pool_size 和 innodb_use_sys_malloc 在 MySQL 5.7.4 中移除。

參數合理值預估

./storage/innobase/handler/ha_innodb.cc:

srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;

./storage/innobase/srv/srv0srv.cc:        mem_init(srv_mem_pool_size);

storage/innobase/mem/mem0dbg.cc: mem_comm_pool = mem_pool_create(size);

從源碼中可以看出,innodb_additional_mem_pool_size 的參數值用於指定内存池 mem_comm_pool 的大小;

storage/innobase/mem/mem0mem.cc:

block = static_cast<mem_block_t*>(
   mem_area_alloc(&len, mem_comm_pool));

函數 mem_area_alloc 從 mem_comm_pool 内存池中分配内存;

storage/innobase/mem/mem0pool.cc:

/* If we are using os allocator just make a simple call
to malloc */
if (UNIV_LIKELY(srv_use_sys_malloc)) {
    return(malloc(*psize));
}

......

area = UT_LIST_GET_FIRST(pool->free_list[n]);
if (area == NULL) {
    ret = mem_pool_fill_free_list(n, pool);
    if (ret == FALSE) {
        /* Out of memory in memory pool: we try to allocate
        from the operating system with the regular malloc: */
        mem_n_threads_inside--;
        mutex_exit(&(pool->mutex));
        return(ut_malloc(size));
    }
    area = UT_LIST_GET_FIRST(pool->free_list[n]);
}

如果 innodb_use_sys_malloc (上述代碼中的srv_use_sys_malloc) 設置爲 ON,或者内存池中沒有足夠的内存可供分配,則直接從操作系統中分配内存。

mem_area_alloc 調用棧如下(use database 觸發斷點)

#0  mem_area_alloc
#1  0x000000000118048d in mem_heap_create_block_func
#2  0x000000000149a390 in mem_heap_create_func
#3  0x00000000014aa6d5 in dict_load_table
#4  0x0000000001481082 in dict_table_open_on_name
#5  0x000000000109d769 in ha_innobase::open
#6  0x00000000006d5245 in handler::ha_open
#7  0x0000000000b830ae in open_table_from_share
#8  0x000000000091deee in open_table
#9  0x0000000000922eea in open_and_process_table
#10 0x000000000092492f in open_tables
#11 0x0000000000926c21 in open_normal_and_derived_tables
#12 0x0000000000a83834 in mysqld_list_fields
#13 0x00000000009f28e1 in dispatch_command
#14 0x00000000009eeb51 in do_command
#15 0x0000000000982cb6 in do_handle_one_connection
#16 0x000000000098238b in handle_one_connection
#17 0x0000000001877f91 in pfs_spawn_thread
#18 0x0000003d8c007851 in start_thread ()
#19 0x0000003d8bce767d in clone ()

函數 dict_load_table 中會爲每張表分配32k的空間 ( mem_heap_create(32000) 實際分配32744字節空間 ),數據字典中每張表所佔空間的上限是32k,具體佔用空間根據列數和索引數量分配,分配完成後回收32k中未使用的空間

storage/innobase/dict/dict0load.cc: heap = mem_heap_create(32000);

show engine innodb status BUFFER POOL AND MEMORY Dictionary cache

實際使用的數據字典緩存,不會超過每張表32k,實測過程中,每張表不包括索引佔4K,每個索引佔2k,列數對空間佔用影響不大。

測試用表如下,未建索引時,1000張表佔用空間4M,增加列佔用空間增長不明顯,每增加一個索引,佔用空間增加2M,可以估測每張表佔用空間4k(不含索引),每個索引佔用空間2k。

Create Table: CREATE TABLE `1000` (
  `id` int(11) DEFAULT NULL,
  `a` varchar(255) DEFAULT NULL,
 `b` varchar(255) DEFAULT NULL,
  `c` varchar(255) DEFAULT NULL,
  `d` varchar(255) DEFAULT NULL,
  KEY `a` (`a`),
  KEY `b` (`b`),
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

引入和移除該參數的原因

早期操作系統的内存分配器性能和可伸縮性較差,並且當時沒有適合多核心CPU的内存分配器。所以,InnoDB 實現了一套自己的内存分配系統,做爲内存系統的參數之一,引入了innodb_additional_mem_pool_size。

隨著多核心CPU的廣泛應用和操作系統的成熟,操作系統能夠提供性能更高、可伸縮性更好的内存分配器,包括 Hoard、libumem、mtmalloc、ptmalloc、tbbmalloc 和 TCMalloc 等。InnoDB 實現的内存分配器相比操作系統的内存分配器並沒有明顯優勢,所以在之後的版本,會移除 innodb_additional_mem_pool_size 和 innodb_use_sys_malloc 兩個參數,統一使用操作系統的内存分配器。

閲完此文,您的感想如何?
  • 有用

    0

  • 沒用

    0

  • 開心

    0

  • 憤怒

    0

  • 可憐

    0

1.如文章侵犯了您的版權,請發郵件通知本站,該文章將在24小時内刪除;
2.本站標注原創的文章,轉發時煩請注明來源;
3.交流群: 2702237 13835667

相關課文
  • [InnoDB] Failed to set NUMA memory policy of buffer pool page frames

  • 讓Mysql查詢後直接返回json字符串的方法

  • postgresql的pg_dump備份簡單方法

  • 使用sql語句在MySQL庫中去掉字段左邊、右邊指定字符串

我要說說
網上賓友點評