All Articles

innodb_ruby로 InnoDB의 페이지 관리 방법 직접 확인해보기

원문: Exploring InnoDB page management with innodb_ruby

이 포스트는 innodb_ruby 0.8.8 버전 (2014/02/03)을 기준으로 작성되었습니다.

InnoDB 핵심을 이해하기 위한 여행 에서 innodb_ruby 프로젝트의 라이브러리와 커맨드 라인 툴을 소개했습니다. 그리고 innodb_ruby 빠르게 훑어보기 에서 innodb_ruby의 커맨드 라인 도구에 대한 간단한 데모를 살펴보았습니다.

그리고 지난 포스트인 InnoDB Space 파일의 페이지 관리 방법에선 InnoDB의 extent, 파일 segment 및 free space 관리 구조에 대해 알아보았습니다. 이제 innodb_space를 사용하여 실제 테이블에서 이 구조들을 확인해보겠습니다.

A minimal, empty table

InnoDB 페이지 관리 구조체의 “최소” 상태를 보여주기 위해, 빈 테이블 (스키마는 중요하지 않음)을 만들었습니다. space-page-type-regions 모드는 동일한 페이지 타입을 갖는 연속된 영역을 요약해 보여줍니다:

$ innodb_space -f test/e.ibd space-page-type-regions
start       end         count       type                
0           0           1           FSP_HDR             
1           1           1           IBUF_BITMAP         
2           2           1           INODE               
3           3           1           INDEX               
4           5           2           FREE (ALLOCATED)  

테이블은 IBD space 파일의 표준 페이지인 FSP_HDR, IBUF_BITMAP, INODE 및 (빈) index의 root에 대한 INDEX 페이지를 가집니다. 미사용 중인 두 개의 FREE (ALLOCATED) 페이지도 있습니다.

space-lists 모드는 space의 extent descriptor 및 inode 리스트를 확인하는 데 사용할 수 있습니다:

$ innodb_space -f test/e.ibd space-lists
name                length      f_page      f_offset    l_page      l_offset    
free                0           0           0           0           0           
free_frag           1           0           158         0           158         
full_frag           0           0           0           0           0           
full_inodes         0           0           0           0           0           
free_inodes         1           2           38          2   

free_frag extent descriptor 리스트에만 항목이 있으며, 거기엔 하나의 extent만 존재합니다. free_inodes 리스트에는 위에서 확인한 것처럼 하나의 INODE 페이지가 있습니다.

free_frag 리스트의 내용은 space-list-iterate 모드로 확인할 수 있으며, 하나의 extent 리스트 안의 모든 extent를 통틀어 페이지 사용률을 그래피컬하게 출력합니다. (”#” 은 페이지가 사용 중이라는 걸, ”.”은 페이지가 미사용 중이라는 걸 의미합니다):

$ innodb_space -f test/e.ibd -L free_frag space-list-iterate
start_page  page_used_bitmap                                                
0           ####............................................................

Space 내 모든 index에 대한 파일 segment는 space-indexes 모드로 확인할 수 있습니다:

$ innodb_space -f test/e.ibd space-indexes
id          root        fseg        used        allocated   fill_factor 
16          3           internal    1           1           100.00%     
16          3           leaf        0           0           0.00%       

internal 파일 segment만 allocated 페이지를 가지며, 현재 하나의 페이지만 할당된 상태입니다. index-fseg-internal-lists 모드는 internal 파일 segment의 extent 리스트를 요약해 보여줍니다:

$ innodb_space -f test/e.ibd -p 3 index-fseg-internal-lists
name                length      f_page      f_offset    l_page      l_offset    
free                0           0           0           0           0           
not_full            0           0           0           0           0           
full                0           0           0           0 

이 빈 테이블에 full extents가 할당되지 않았으므로 세 개의 리스트가 모두 비어 있습니다. 사용된 페이지 하나는 어디로 갔을까요? 그 페이지는 “fragment” 페이지이며 index-fseg-internal-frag-pages 모드로 확인할 수 있습니다:

$ innodb_space -f test/e.ibd -p 3 index-fseg-internal-frag-pages
page        index   level   data    free    records 
3           16      0       0       16252   0      

여기까지가 빈 bookkeeping 구조와 하나의 INDEX 페이지를 갖는 최소한의 상태입니다. 이제 실제 데이터가 포함된 테이블을 살펴보겠습니다.

백만 개의 행을 갖는 테이블

innodb_ruby 빠르게 훑어보기 에서 백만 개의 행이 있는 테이블을 만들었습니다. 여기서도 같은 테이블을 사용하겠습니다.

총 2,165 개의 페이지가 있으며, 일반적인 테이블은 주로 INDEX 타입의 페이지를 갖습니다:

$ innodb_space -f test/t.ibd space-page-type-regions
start       end         count       type                
3           37          35          INDEX               
38          63          26          FREE (ALLOCATED)    
64          2188        2125        INDEX               
2189        2239        51          FREE (ALLOCATED)    
2240        2240        1           INDEX               
2241        2303        63          FREE (ALLOCATED)    
2304        2304        1           INDEX               
2305        2367        63          FREE (ALLOCATED)    
2368        2368        1           INDEX               
2369        2431        63          FREE (ALLOCATED)    
2432        2432        1           INDEX               
2433        2495        63          FREE (ALLOCATED)    
2496        2496        1           INDEX               
2497        2687        191         FREE (ALLOCATED)  

INDEX 페이지 블록 사이에 있는 FREE (ALLOCATED) 페이지들은 서로 약간 다릅니다. InnoDB는 빈 페이지를 순차적으로 사용하는 것을 보장하지 않으며, 대량 데이터 로드에 대한 많은 최적화 기법들로 인해 페이지가 순서대로 사용되지 않습니다. (페이지 splitting 및 최적화 기법에 대한 자세한 내용은 추후 다른 포스트에서 확인하실 수 있습니다.)

Space의 리스트를 보면, free_frag 상태인 일반적인 extent 뿐만 아니라 free 상태인 extent도 몇 개 있습니다:

$ innodb_space -f test/t.ibd space-lists
name                length      f_page      f_offset    l_page      l_offset    
free                2           0           1758        0           1798        
free_frag           1           0           158         0           158         
full_frag           0           0           0           0           0           
full_inodes         0           0           0           0           0           
free_inodes         1           2           38          2  

free extent descriptor 리스트의 페이지는 예상대로 모두 비어있습니다:

$ innodb_space -f test/t.ibd -L free space-list-iterate
2560        ................................................................
2624        ................................................................

free_frag extent descriptor 리스트에는 다음과 같이 여러 “fragment” 페이지들도 사용됩니다:

$ innodb_space -f test/t.ibd -L free_frag space-list-iterate
start_page  page_used_bitmap                                                
0           ######################################..........................

예상대로, index 파일 segment는 사용된 페이지의 대부분이 leaf 파일 segment에 할당되었음을 보여줍니다 (B+tree에서 2,137개의 leaf 페이지를 관리하기 위한 leaf가 아닌 internal 페이지가 3개뿐 임):

$ innodb_space -f test/t.ibd space-indexes
id          root        fseg        used        allocated   fill_factor 
15          3           internal    3           3           100.00%     
15          3           leaf        2162        2528        85.52%      

Leaf index 파일 segment에는 실제 사용하는 것보다 많은 페이지가 할당되어 85.52%의 fill factor를 보여주는 것도 확인할 수 있습니다. InnoDB의 “segment fill factor”는 MySQL에서 87.5%로 고정되어 있지만, Facebook에서 MySQL Bug 64673을 제출한 덕분에 Twitter MySQL에서 설정할 수 있습니다.

internal index 파일 segment에는 3개의 페이지만 있으므로, 파일 segment 리스트가 모두 비어 있습니다:

$ innodb_space -f test/t.ibd -p 3 index-fseg-internal-lists
name                length      f_page      f_offset    l_page      l_offset    
free                0           0           0           0           0           
not_full            0           0           0           0           0           
full                0           0           0           0           0           

사용된 세 개의 페이지는 fragment 페이지로 할당됩니다:

$ innodb_space -f test/t.ibd -p 3 index-fseg-internal-frag-pages
page        index   level   data    free    records 
3           15      2       26      16226   2       
36          15      1       14521   1401    1117    
37          15      1       13585   2341    1045    

Leaf index 파일 segment 리스트는 32개의 full extent 및 6개의 not full extent를 갖습니다:

$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-lists
name                length      f_page      f_offset    l_page      l_offset    
free                0           0           0           0           0           
not_full            6           0           1518        0           1718        
full                33          0           198         0           1478        

또한 leaf index 파일 segment는 가능한 모든 32개의 fragment 페이지를 할당했습니다:

$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-frag-pages
page        index   level   data    free    records 
4           15      0       9812    6286    446     
5           15      0       15158   860     689     
6           15      0       10912   5170    496     
7           15      0       10670   5412    485     
8           15      0       12980   3066    590     
9           15      0       11264   4808    512     
10          15      0       4488    11690   204     
11          15      0       9680    6418    440     
12          15      0       9306    6800    423     
13          15      0       9658    6434    439     
14          15      0       10032   6062    456     
15          15      0       9988    6108    454     
16          15      0       9570    6530    435     
17          15      0       9130    6978    415     
18          15      0       8844    7266    402     
19          15      0       11770   4300    535     
20          15      0       9020    7092    410     
21          15      0       8646    7462    393     
22          15      0       9746    6354    443     
23          15      0       11066   5014    503     
24          15      0       8910    7204    405     
25          15      0       11748   4322    534     
26          15      0       10978   5094    499     
27          15      0       11132   4940    506     
28          15      0       9350    6750    425     
29          15      0       13508   2526    614     
30          15      0       14938   1082    679     
31          15      0       14520   1506    660     
32          15      0       9086    7016    413     
33          15      0       9724    6368    442     
34          15      0       10978   5102    499     
35          15      0       9504    6592    432     

예상했던 대로, full extent는 full 상태입니다:

$ innodb_space -f test/t.ibd -p 3 -L full index-fseg-leaf-list-iterate
start_page  page_used_bitmap                                                
64          ################################################################
128         ################################################################
192         ################################################################
256         ################################################################
320         ################################################################
384         ################################################################
448         ################################################################
512         ################################################################
576         ################################################################
640         ################################################################
704         ################################################################
768         ################################################################
832         ################################################################
896         ################################################################
960         ################################################################
1024        ################################################################
1088        ################################################################
1152        ################################################################
1216        ################################################################
1280        ################################################################
1344        ################################################################
1408        ################################################################
1472        ################################################################
1536        ################################################################
1600        ################################################################
1664        ################################################################
1728        ################################################################
1792        ################################################################
1856        ################################################################
1920        ################################################################
1984        ################################################################
2048        ################################################################
2112        #####################################################

not_full extent는 예상대로 부분적으로 채워진 상태입니다:

$ innodb_space -f test/t.ibd -p 3 -L not_full index-fseg-leaf-list-iterate
start_page  page_used_bitmap                                                
2176        #############...................................................
2240        #...............................................................
2304        #...............................................................
2368        #...............................................................
2432        #...............................................................
2496        #...............................................................

InnoDB의 페이지 split optimization의 결과를 여기에서 확인할 수 있습니다: 데이터를 디스크에 순차적으로 배치하기 위해 첫 번째 페이지를 여러 번 (페이지 번호 “hinting”?) 꺼냈습니다. 이에 대한 심층적인 내용은 추후에 다룰 예정입니다.