Partition Alignment
Last updated
Last updated
Database나 Hadoop 어플리케이션을 띄우고, 데이터는 4TByte의 하드 디스크에 저장하며 잘 사용하고 있었습니다. 어느날, 그 Disk가 깨져서 새로 교체를 하고 파일시스템을 포맷 하였는데요, 그 뒤로 I/O가 눈에 띄게 지연되는 것을 느끼게 되었습니다.
이유가 뭘까요?
그 이유는 바로 파티션의 시작점이 정렬되지 않았기 때문입니다. OS는 설치시에 installer가 똑똑하게도 알아서 파티션의 시작 위치를 정렬하여 첫번째 파티션을 만들어주기에, 파티션 정렬이라는 개념을 고려할 필요가 없었습니다. 그러나 OS가 설치된 이후에 어떤 이유에 의해서 사용자가 직접 파티션을 만들게되는 위와 같은 상황일 때 Partition Alignment의 필요성을 모르는 사용자라면 installer가 했던 파티션 시작위치 정렬 작업을 누락하게 됩니다. 그리고 사용자는 I/O 지연을 경험하게 되겠지요. 사실은 얼마 전 까지만 해도 파티션 정렬이라는 개념을 고려하지 않아도 됐습니다. 지금은 물리 Disk의 데이터 접근 단위인 Sector의 크기를 성능 향상을 위해 키움에 따라서 문제가 되기 시작했습니다. 무슨 말인지 잘 모르셔도 괜찮습니다. 지금부터 하나 하나 설명해 보도록 하겠습니다.
Sector란 물리 디스크에 입출력을 요청하는 최소 단위 입니다. 전통적인 하드 디스크는 512Byte 크기의 Sector들로 구성 되어 있습니다. 데이터가 점점 더 많아지고, 또 그 크기가 커짐에 따라 하드 디스크 업계도 점점 더 큰 용량의 디스크를 내 놓게 되었습니다. 이 때 사용자가 큰 데이터에 접근 하고자 하는 경우 Sector의 크기가 작을수록 더 많은 수의 입출력 요청이 발생하게 되기에, 디스크 업계에서는 퍼포먼스를 올리기 위해서 Sector 자체의 크기를 늘리고자 하게 되었습니다. 그 이전부터 수 년에 걸쳐 관련한 작업이 진행되었고 2011년 1월 모든 하드 디스크 제조 업체가 Sector의 크기를 4096KByte를 표준으로 하는 것에 합의하여 제품을 출하하기 시작 했습니다.
이 과정에서 Sector의 크기를 키울 경우 기존의 전통적인 Sector 크기인 512Byte를 기준으로 설계된 여러가지 시스템, 프로그램들은 무방비로 영향을 받게 됩니다. 때문에 현재는 과도기로서 물리적으로는 Sector의 크기가 4096Byte(4KByte)인 것으로 입출력을 요청 하나, 하드디스크에 저장된 컨트롤러가 논리적 으로는 Sector의 크기가 512Byte인 것과 같이 애뮬레이션 하는 Advanced Format의 디스크가 나오게 되었습니다. 실제 물리 디스크에 입출력을 요청하는 단위를 물리 Sector라 부르고 그 크기는 4096Byte 입니다. 그리고 전통적인 Sector 크기인 512Byte로 디스크 상단에 애뮬레이션 되는 단위를 논리 Sector라 부르고 그 크기가 512Byte입니다. 논리 , 물리 Sector는 그 크기가 8배의 차이를 가지고 있는 것이지요.
Advanced Format이 사용되고 또, 데이터의 크기가 커짐에 따라 RAID의 데이터 연속 단위인 Stripe , 각 어플리케이션 들의 데이터 접근 단위들도 덩달아 커지게 되었는데요. 전통적인 방식의 하드디스크에서는 조용했던 문제가 대두되기 시작합니다.
디스크의 첫 번째 논리 Sector(CHS*(0,0,1) / LBA* 0 / 크기 : 512Byte)에는 MBR영역이 위치하고 있습니다. MBR영역에는 Boot code, Partition 정보 등이 담긴 공간으로 해당 파티션이 부팅 가능한지, 관련 주소 그리고 총 Sector의 수 등이 명시되어 있습니다. MBR 영역 뒤에는 어느정도의 공간이 파일시스템 관련 정보를 저장해두거나 비워둘 수 있는 공간이 있고 이를 Hidden Sectors라 부릅니다. (파일시스템의 종류나 파티션 테이블 종류에 따라서 Hidden Sectors의 수는 다르기도 합니다.) 그 뒤에 이어 데이터를 저장할 수 있는 첫 번째 파티션이 시작 될 수 있는데요. 아래의 그림은 63개의 논리 Sector단위의 Hidden Sector를 가진 상태입니다.
[그림 1]
[그림 1]은 디스크의 앞 부분에는 Reserved 된 Hidden Sectors(LBA 0 ~ 62 번 / 총 63개의 논리 Sectors)가 있고 그 바로 뒤인 LBA 63번 Sector부터 파티션이 시작 되는 것을 볼 수 있습니다. 이 경우 논리 Sector입장에서는 경계를 잘 지켜 데이터가 위치 한 것으로 보이지만, 물리 Sector의 경우에는 경계에 맞물려 데이터가 담긴 block이 위치하게 됩니다. 기존 Sector의 크기가 512Byte였을 당시와 비교할 때 Sector단위의 입출력 8번을 수행하는 것에 변화가 없습니다. 하지만 Sector가 4096Byte크기로 커진 Advanced Format을 사용하는 현재의 디스크들의 경우 512Byte크기의 Sector 크기로 에뮬레이션 하나 실제로는 4096Byte 크기의 Sector 단위로 입출력을 수행하기 때문에 [그림 1]에 물리 Sector의 8번과 9번 Sector에 각각 접근해야 합니다. Block의 크기는 4096Byte로 물리 Sector와 같아 어떠한 경우에는 1번의 입출력 수행으로 Block 한 개의 데이터에 접근할 수 있을 것 입니다.
만약 8번 물리 Sector의 남은 512Byte 만큼을 Indent 한다면 아래 [그림 2]와 같습니다.[그림 2]
[그림 2]의 경우 [그림 1]과 동일하게 Reserved 된 Hidden Sectors(LBA 0 ~ 62 번 / 총 63개의 논리 Sectors)를 가지고 있습니다. LBA 63번 논리 Sector가 있지만 1개 논리 Sector(512Byte)만큼 Indent를 하여 물리 Sector의 경계에 Align을 했습니다. 이 때 첫 번째 Block에 접근을 시도 한다면 9번 물리 Sector에만 입출력을 요청 하면 됩니다. 따라서 [그림 1]의 상황에 반해 그 절반인 1번의 입출력만 요청하면 되는 것 이지요. 이와 같이 불필요한 입출력을 통한 오버헤드를 줄이고 퍼포먼스를 높힐 수 있도록 파티션의 시작 지점을 물리 Sector의 경계에 맞춰 주는 것이 Partition Alignment 의 기본적인 개념입니다.
위의 그림 들은 특정파일시스템을 기준으로 하여 LBA 62번 까지가 Reserved 된 Hidden Sectors (총 63개의 논리 Sectors / 512 * 63 Byte)였는데요, 파일시스템이나 파티션 종류마다 파티션이 시작 되기 전에 필요한 Sector의 갯수가 다를 수 있기 때문에 OS Instraller는 오랜시간동안 보수적으로 결정된 크기인 1024KByte (2048 개의 논리 Sector / 256개의 물리 Sector) 만큼을 Indent하여 파티션의 시작점을 Align하고 있습니다.
RAID를 구성하면 Stripe라는 단위로 데이터가 연속하여 저장 됩니다. Stripe은 RAID 구성시에 그 크기를 결정하는 단위으로 보통의 경우 64KByte 또는 128KByte, 또는 더 큰 크기, 즉 물리 Sector(4096Byte)보다 훨씬 큰 단위로 설정을 합니다. 그 이유 역시 데이터가 커짐지고 많아짐에 따라서 입출력 요청 횟수를 줄여 퍼포먼스를 올리고자 함 입니다. 예를 들어 2개의 디스크를 RAID0, Stripe Size 64KByte로 구성을 하였을 때, 128KByte의 데이터가 쓰여진다면 1번 디스크에 Strip 크기인 64KByte만큼의 데이터가 쓰여지고, 나머지 데이터는 2번 디스크에 쓰여집니다. 4096Byte의 물리 Sector의 경계에는 잘 Align을 했더라도 파일시스템 block이 Strip의 경계에 Align이 되지 않는다면 1개의 Stripe에 쓰여질 수 있는 데이터가 2개의 Stripe에 나뉘어서 쓰여져 불필요 하게 2번의 입출력이 발생하여 I/O 지연을 경험하게 될 수 있습니다.
[그림 3]에 3,4번째 줄에 등장하는 Cluster는 Database에서 자주 사용되는 테이블의 데이터들을 Cluster라는 단위로 그룹화하는 것 입니다. 이렇게 자주 접근이 있는 데이터들을 Cluster 단위로 그룹화 하여 그 단위로 입출력을 요청 함으로서, 디스크에 적은 횟수의 입출력을 하는 효과를 보게 됩니다. 그 효과를 최대화 하기 위해서는 Cluster가 물리 디스크의 입장에서 봤을 때 물리 Sector 그리고 Raid 입장에서의 Stripe의 경계에 위치하지 않게 되어야 할 것입니다. [그림 3]의 3번째 줄은 [그림 1]과 동일 상황이라고 볼 수 있습니다. 그리고 [그림 3]의 4번째 줄은 [그림 2]와 동일 상황이라고 볼 수 있습니다. 3번째 줄의 경우 물리 Sector에 Align을 하지않아 어떤 클러스터에 접근하고자 할 때 불필요 하게 2개 물리 Sector에 접근해야하는 상황 뿐 아니라 또 어떤 클러스터에 접근 할 때에는 Stripe의 경계에도 위치하는 상황도 있어 2개의 Stripe 에 접근 해야하는 상황이기 때문에 I/O지연을 경험하게 됩니다. 4번째 줄의 경우 Cluster 크기가 비교적 작은 (4096Byte)로 물리 디스크의 앞부분에 위치한 Hidden Sectors (MBR을 포함한 Reserved Area + Indent / 64 논리 Sector)뒤에 Cluster들이 놓였을 때 Stipe의 경계에 잘 위치하여 입출력을 최소한으로 할 수 있었습니다.
[그림 4]의 경우에는 [그림 3] 과 비슷해 보이나 Cluster의 크기가 64KByte로 Stripe 크기와 동일하게 셋팅이 되었습니다. 3번째 줄은 물리 디스크의 앞부분에 위치한 Hidden Sectors (MBR을 포함한 Reserved Area / 63 논리 Sector)의 뒤에 64KB의 크기를 가진 Cluster들이 놓여 있습니다. 그리고 Stripe 경계에도 놓였는데요, Cluster의 크기가 이렇게 비교적 큰 경우에는 [그림 3]의 4번째 줄과 같이 1개의 논리 Sector크기 만큼 Indent를 주어 Align을 했더라도 Stripe 경계에 놓이게 되었을 것입니다. 이 때 [그림 4]의 4번째 줄과 같이 1개의 논리 Sector 만큼이 아닌 65개 논리 Sector만큼의 Indent를 준다면 Stripe의 경계에 Cluster가 놓이게 되지 않을 것 입니다. [그림 4]에서와 같이 4번째 줄의 첫 번째 Cluster의 데이터로 접근하기 위해 입출력을 한다면 2번째 Stripe에서 데이터 입출력을 끝낼 수 있습니다.
Alignment를 이해하고 수행 한다면, 직접 파일시스템을 포맷하고, 파티션을 만들때에도 1024KByte 만큼 파티션 시작점을 미뤄 Align을 한다면 디스크 I/O시 성능 저하를 경험하지 않을 수 있습니다.
그렇다면 어떻게 Partition Alignment를 할 수 있을지 보겠습니다.
fdisk의 경우에는util-linux-ng_2.17.1 부터 제대로 된 정렬을 지원 합니다. 그러므로 오래된 OS를 사용하고 있다면 fdisk보다는parted\를 이용할 것을 권고 합니다._
fdisk를 이용하여 파티션 정렬을 할 경우, 2.17.1 이후 버전을 사용하는 것을 권고하며, DOS 호환 모드를 비활성화 시키면, fdisk는 1MB 경계에서 정렬이 됩니다.
fdisk를 이용할 경우, 다음의 사항을 권고 합니다.
util-linux-ng 2.17.1 이후 버전을 사용
fdisk 의 경고를 잘 보십시오.
DOS 호환 모드
를 비활성화 (-c 옵션)
표시 단위는
sector
를 이용 (-u 옵션)
파티션의 끝을 지정할 경우에는, + 사이즈(M,G) 옵션 사용
a. 잘못된 정렬 예제
아래의 예제는 잘못된 정렬의 예를 보여 주며, 원인은 DOS 호환 모드 때문 입니다.
-S 32 -H 64옵션을 사용하여, 두번째 synlinder를 정렬에 사용할 수 있습니다.
Dos 호환 모드 (-c) 옵션을 비활성화 시키고, 섹터 단위를 사용하도록 옵션을 주어, LBA 주소 2048 에서 파티션을 시작할 수 있도록 할 수 있습니다.
parted 를 이용하여 파티셔닝 정렬을 할 경우에는, label을 GPT로 만들면 첫번째 실린더를 2048 sector 부터 생성해 줍니다.
이 의미는mkpart시에 시작이0이 아니라,1이어야 한다는 것입니다.
시작을 0으로 하면, 위와 같이 정렬이 되지 않는다는 메시지가 나오게 됩니다. 그러므로 아래와 같이 1로 설정을 하도록 합니다.
또는 unit을 sector로 변경을 하여 설정을 하는 것이 더 직관적 입니다.
Partition StartingOffset을 1024로 나누었을 경우, 정수의 값이 나온다면 정렬이 잘 되어 있다고 볼 수 있습니다. StartingOffset 값은 sector 값으로 보시면 되며, 첫번째 파티션의 시작 sector 값이 1024 의 배수이면 된다는 의미 입니다. 그냥 적정 값으로 2048 sector에서 시작하면 된다고 외워도 되겠습니다.
또,parted를 이용하여 확인이 가능 합니다.
CHS(Cylinder-Head-Sector) 데이터를 읽고 쓰려면 해당 섹터위치를 읽어와야 하며, Cylinder, Head, Sector를 기반으로 위치를 지정하는 방식을 CHS라 말합니다. 예를들어 어떤 파일의 시작 섹터위치가 CHS(1,2,3,)이라고 정하면, 하드디스크의 2번째 Head를 1번째 Cylinder, 3번째의 Sector에 위치시킵니다. 그렇지만 이후에 ATA 용량제한이 발생하여서 LBA 방식으로 넘어가게되었습니다.
LBA (Logical Block Addressing) 전체 섹터에 0부터 일련번호를 붙여서 지정하는 방식으로 읽고자 하는 파일의 논리적인 시작섹터주소를 찾으면 Disk Controller가 물리적 주소로 변환하여 접근가능하게 해줍니다.
[그림 3] 출처:
[그림 4] 출처: