The Btrfs File System
1. 개요
Btrfs는 많은 우수한 스토리지 기술들을 지원하는 차세대 Copy-on-write file system 이다.
Btrfs는 2007년 Oracle에서 Chris Mason의 주도 하에 개발이 시작된 프로젝트로서 처음부터 리눅스 용으로 설계되었으며, 쓰기 가능/읽기 전용 스냅샷, 서브볼륨, 동적 아이노드 할당, 압축, 체크섬, 다중 장치를 사용한 파일시스템 수준의 RAID와 같은 다양한 기능을 제공하는 파일 시스템으로서 리눅스 파일 시스템의 미래로 알려져있다.
현재 Btrfs는 RedHat, SUSE, Oracle, Facebook, Fujitsu 등의 업체 들의 지원에 힘을 입어 빠른 속도로 추가 기능 개발과 개선이 이루어지고 있다. 2009년 3월을 기점으로 리눅스 커널 2.6.29에 비안정화 버전으로 탑재되었으며, 2013년 7월 리눅스 커널 3.10에 안정화 버전으로 탑재되었다.
2014년 이래로 Chris Mason과 다른 많은 Btrfs 개발자들이 Facebook을 위해 일하고 있으며 Facebook은 현재 Btrfs를 사용하고 있는 몇 안되는 기업 중 하나이다. 또한 SUSE는 Btrfs를 SUSE Linux Enterprise Server 12(SUSE 2015)의 기본 파일 시스템으로 설정하였다.
2. 특징
2.1 서브볼륨
기존의 파일시스템들은 하나의 블록 장치가 하나의 파일시스템으로 초기화되어 단일 볼륨으로 동작한다. Btrfs는 여기에 서브볼륨이라는 개념을 도입하였다. 각 서브볼륨은 독립된 POSIX 파일 이름공간으로서 취급되어 파일시스템 공간에 그 메타 정보가 저장된다. 결과적으로 하나의 파일시스템 내에 부착이 가능한 독립된 이름공간을 갖는 볼륨이 여러 개가 존재하게 되는 것이다.
2.2 스냅샷
스냅샷은 특정 시점에서 파일시스템의 상태를 보존해두었다가 원하는 시점에 다시 복원할 수 있게 하도록 고안된 개념으로서 안정성을 중요시하는 환경 에서 사용되는 기능 중 하나이다. 이런 스냅샷은 LVM과 같은 볼륨 관리자 혹은 WAFL과 같은 일부 파일시스템에서만 자체적으로 제공이 되던 기술로서 기존 파일시스템의 개념으로는 그 구현이 상당히 어려운 기술이다. 파일시스템 스냅샷은 주로 COW 기술을 근간으로 하여 구현되는데, Btrfs는 자체적으로 COW를 사용하기에 상대적으로 스냅샷을 위한 추가 구현에 대한 예외가적다. 또한 서브볼륨을 이용하여 각 스냅샷을 서브볼륨과 동일하게 취급함으로써 사용자의 접근 편의성 또한 높였다.
2.3 RAID
일반적으로 서비스 안정성을 요구하는 인프라에서는 미러링/스트라이핑/패리티 분산을 제공하는 RAID(Redundant Array for Independent Disks) 기술을 저장 장치에 적용함으로써 그 안정성이나 효율성을 높이는데, 데이터의 중요도가 높을수록 이는 필수불가결한 요소로 다루어진다. 허나 RAID 전용 하드웨어가 그 비용이 높고 최소 , 2개 이상의 물리적 디스크가 필요하다는 제약으로 인해 그 활용성이 높음에도 불구하고 일반 사용자들이 접하기에는 어려움이있었다. 그렇기에 리눅스 커널 메인테이너 중 한 명인 Brown Neil은 리눅스 커널에 다중 장치(Multiple Device, MD) 기술을 구현함으로써 소프트웨어적으로 RAID를 사용할 수 있도록 하였고, 상대적으로 그 수준이 높아진 사용자들의 데이터 처리 기술에 대한 요구치에 부응할 수 있었다. 하지만 이 소프트웨어 RAID는 기존 파일시스템이 사용하는 공간과는 별도로 스냅샷을 위한 COW공간을 마련하기 때문에 그 효율성과 안정성 및 편의성 관점에서 불만이 야기되어 왔다. Btrfs는 파일시스템 내부에서 블록 장치들을 추상화하는 가상 장치라는 개념을 도입함으로써 파일시스템 그 자체가 가상 장치들에 대한 RAID기술을 적용할 수 있도록 구현하였다. 따라서 사용자들은 단순히 파일시스템을 사용하는 것만으로도 RAID를 적용하여 저장 장치의 고가용성과 내결함성을 얻을 수 있게 되었다.
2.4 체크섬
오늘날 파일시스템의 데이터에 대한 정합성을 보장하는 것은 의도치 않은 혹은 의도된 위/변조에 대한 대응책으로서 반드시 필요한 것으로 여겨지는데, Btrfs는 내부적으로 모든 메타데이터와 데이터에 대해 CRC-32C 방식의 체크섬을 유지하기 때문에 데이터의 위/변조에 대한 정합성을 보장한다.
2.5 섀도잉과 클로닝
Btrfs의 구조를 설명하기에 앞서서, 본 연구의 이해를 위해 반드시 필요한 핵심 알고리즘에 대한 Ohad Rodeh의 연구를 간략히 설명하고자 한다.
이 연구는 B-트리를 기반으로 하여 섀도잉(Shadowing)과 클로닝(Cloning)을 적용한 파일시스템 알고리즘에 대한 것이다. 이 연구에서의 기본 전제는 파일시스템을 고정된 크기의 페이지들에 대한 트리이며, 페이지를 덮어쓰기 하지 않는다는 2가지이다. 또한 모든 파일시스템 연산은 다음과 같은 세 단계를 거쳐 실제 저장 장치에 반영된다.
첫째로 연산에 대한 짧은 논리적 로그 엔트리를 별도로 기록한다.
둘째로 메모리 상의 페이지들에 대해서 해당 연산을 수행하며, 마지막으로 현재까지의 변경 내역에 대한 체크포인트를 주기적으로 저장 장치에 반영하는 순서를 거치는데 이를 섀도잉이라 하며 WAFL, ZFS와 같은 파일시스템에서 사용되는 알고리즘이다.
이런 일련의 연산은 트랜잭션으로서 취급되며, 충돌이 발생할 경우 직전의 체크포인트로 되돌리고 기록했던 로그 엔트리를 다시 수행함으로써 복구가 이루어진다 이 연구에서는 페이지가 . 일단 섀도잉되면 다음 체크포인트까지는 다시 섀도잉될 필요가 없다는 점을 이용하여, 더티 페이지(메모리 상에서만 변경된 페이지)들을 일괄적으로 묶어서 순차적으로 저장 장치에 씀으로써 알고리즘의 최적화를 제안했다. 따라서 여기에서 제안된 섀도잉은 파일시스템 연산의 안정성과 복제를 가능케 함으로써 스냅샷과 충돌 복구, 일괄 쓰기, RAID등에서 매우 유용하게 사용될 수 있음을 알 수 있다.
클로닝은 트리를 복제하는 알고리즘으로서, 이 연구에서는 기존의 WAFL과같은 파일시스템에서 데이터 블록마다 존재하는 비트맵을 이용하여 해당 블록을 각 클론에 사상시키는 방식 대신에 각 블록에 대한 참조 계수(reference count)를 유지함으로써 여러 트리 간에 같은 블록을 공유할 수 있도록 하였다. 뿐만 아니라 동시성을 해치지 않기 위해서 기존의 B-트리 구조에서 모든 잎노드 간의 연결을 제거하여 같은 트리 내의 접근에 대한 경합을 최소한으로 줄였다. 이러한 접근법을 통해 기존의 연구에서 갖던 데이터 블록에 대한 비트맵 크기만큼의 클론 개수를 가진다는 제약 사항을 벗어날 수 있었으며, 클로닝을 위한 모든 여유 공간에 대한 부가적인 작업이 단순히 루트 노드의 자식 노드들에 대한 참조 계수만을 증가 혹은 감소시키는 것으로 대체됨으로써 알고리즘의 복잡도와 부하가 감소하였다는 결론을 시사하였다.
결과적으로 Btrfs는 위 관련 연구에서 제안한 B-트리 상의 섀도잉과 클로닝를 바탕으로 하여 기존보다 더 효율적이고 안정적인 파일시스템 연산을 실제로 구현하였다.
4.1 동적 inode 할당
동적 아이 노드 할당은 파일 시스템을 만들 때 몇 개의 inode 만 설정된다는 것을 의미합니다. 실제 작업 부하에 따라 추가 inode가 생성되어 임시로 할당됩니다.
Btrfs inode는 struct btrfs_inode_item에 저장됩니다. Btrfs inode는 파일 및 디렉토리에 대한 전통적인 통계 데이터를 저장합니다.
Btrfs inode 구조는 상대적으로 작으며 임베디드 파일 데이터 나 확장 된 속성 데이터를 포함하지 않습니다 [2].
4.2 Btrfs 스냅 샷 및 하위 볼륨
Btrfs 서브 볼륨은 파일과 디렉토리를 저장하는 (이름이 지정된) btree를 반영합니다 [3].
서브 볼륨에 블록 할당량을 지정할 수 있으며이 할당량에 도달하면 새로운 쓰기 조작이 허용되지 않습니다.
서브 볼륨 내부의 모든 블록 및 파일 범위는 참조 카운트됩니다 (스냅 샷 작업을 허용하기 위해).
현재 Btrfs 파일 시스템 당 최대 264 개의 서브 볼륨을 생성 할 수 있습니다.
Btrfs에서 스냅 샷은 서브 볼륨과 동일하지만 루트 블록은 처음에 다른 서브 볼륨과 공유됩니다 [1].
스냅 샷을 만들 때 루트 블록의 참조 횟수가 증가하고 스냅 샷 또는 소스 서브 볼륨에서 수행 된 변경 사항이 해당 루트에 대해 비공개 적이라는 것을 copy-on-write Btrfs 트랜잭션 메커니즘이 확인하도록합니다.
스냅 샷은 쓰기가 가능하며 (스냅 샷에 대한 활성 업데이트가 가능함), 스냅 샷을 여러 번 반복 할 수 있습니다.
읽기 전용 스냅 샷이 필요한 경우 생성 시간 [2]에 블록 할당량이 1로 설정됩니다.
다시 말하면 Btrfs 스냅 샷은 기본적으로 백업 또는 기존 데이터 세트의 빠른 응급 복사본으로 활용할 수 있습니다.
Btrfs는 스냅 샷 기능과 관련하여 방대한 융통성을 제공합니다.
Btrfs Copy-On-Write
Btrfs의 메타 데이터뿐만 아니라 데이터는 쓰기시 기록 (copy-on-write) 기록 [3]으로 보호됩니다.
디스크에 공간을 할당 한 트랜잭션이 커밋되면 파일 또는 btree의 해당 논리 주소에 대한 새로운 쓰기 작업이 새로 할당 된 블록으로 이동하고 btree 및 수퍼 블록의 블록 포인터가 업데이트되어 새 위치를 반영합니다. 또한 Btrfs는 카피 - 온 (copy-on) 기록 메커니즘을 스냅 샷 우화와 함께 사용합니다.
3. 기본 구조
Btrfs는 파일시스템의 모든 정보를 트리로 관리하며, 그림. 3.1은 이렇게 Btrfs에서 유지하는 모든 트리들을 나타낸다. 모든 트리 정보는 청크 트리(Chunk tree) 내에 저장되기 때문에 파일시스템의 부트스트랩 과정에서 이 트리가 반드시 필요하다. 청크 트리 자신에 대한 정보 또한 여기에 포함되기 때문에 일반적으로 “닭이 먼저냐 달걀이 먼저냐”라고 부르는 순환 논리의 오류가 발생한다. Btrfs에서는 이 청크 트리의 정보를 슈퍼블록에 복사하여 유지함으로써 이런 문제를 해결했다. 모든 트리에 대한 파일시스템 연산은 저널링(Journaling)을 하며 필요한 경우 각 트리에 대한 기록(Log)를 트리로 유지하는데, 이런 기록에 대한 정보를 유지하는 트리가 로그 트리(Log tree)이다. Btrfs에서는 하나의 서브볼륨 Btrfs /스냅샷이 하나의 파일시스템 트리와 대응되어 그 정보를 유지하기에 한 Btrfs 파일시스템 내에 여러 파일시스템 트리가 존재할 수 있다. 루트 트리(Root tree)는 이러한 각 파일시스템 트리를 포함하는 모든 트리들의 루트에 대한 참조를 트리로 구성하여 기록할 뿐만 아니라 파일 시스템 트리의 루트 디렉터리에 대한 참조 정보도 유지한다.
3.1 슈퍼블록
파일시스템은 그 구성의 핵심이 되는 정보들을 저장하는 특정한 영역인 슈퍼블록(Superblock)을 필요로 한다. 다른 파일시스템들과 마찬가지로 Btrfs 또한 64 KiB, 64 MiB, 256 GiB, 1 PiB의 각 오프셋에 4096 바이트 크기를 가지는 슈퍼블록과 그 복제본을 유지한다.
3.2 트리와 노드
는 파일시스템 초기화 Btrfs 시점에서 블록 장치를 메타데이터/데이터의 두그룹으로 나누고, 이 그룹을 다시 익스텐트라는 디스크 공간 단위로 나누어 할당을 하게 된다. 메타데이터 그룹에는 다양한 파일시스템 정보들을 포함하며, 각각이 트리 원소들로 사상되는 트리 블록들이 저장되며, 데이터 그룹에는사용자 영역으로 보여지는 실제 데이터들에 대한 정보가 저장된다.
3.3 루트 트리
파일시스템 전역적으로 단 하나만 유지되는 청크 트리, 익스텐트 트리와 같은 단일 트리들도 있지만 파일시스템 트리처럼 동일한 유형의 트리가 여러 개가 존재할 수도 있다. 따라서 모든 트리들의 루트에 대한 정보를 유지할 필요가 있는데, 이러한 트리 루트들의 정보를 저장하는 트리를 루트 트리(Root tree)라고 한다. 루트 트리는 다른 모든 트리 루트들을 가리키는 루트 참조 아이템(Root reference item), 루트 아이템(Root item)과 같은 아이템들을 잎 노드의 아이템으로 저장한다.
저장되는 모든 트리 루트들은 그 키의 객체 식별자를 가지게 되며, 각 트리의 객체 식별자에 대한 정보는 표 3.2(2)에서 보여진다. 파일시스템 트리는 256이상의 객체 식별자를 갖는데, 이는 서브볼륨들에 대해 할당되는 객체 식별자이다. 따라서 최상위 파일시스템을 가리키는 5가 아닌 256 이상의 객체 식별자들을 통해서 서브볼륨이나 스냅샷에 대한 추적이 가능함을 알 수 있다.
3.4 청크 트리
Btrfs는 블록 장치를 256 MiB 혹은 1 GiB의 청크(chunk)라는 단위로 분할하여 취급한다. 이 청크들은 논리적 주소 공간을 통해 실제 블록 장치의 주소로 사상되는데, RAID와 같은 기능을 사용할 때 여러 블록 장치들에 걸쳐서 데이터를 다루기 위해 사용된다. 청크 트리(Chunk tree)는 이러한 논리적 주소 공간를 물리적 주소 공간으로 사상하기 위한 청크 아이템(Chunk item)과 각 장치들에 대한 정보를 위한 나타내기 위한 장치 아이템(Device item)을 잎 노드의 아이템으로 저장한다.
3.5 장치 트리
장치 트리 는 (Device tree) 블록 장치의 바이트 범위가 어떤 청크에 사상되는지를 나타내기 위한 장치 익스텐트 아이템(Device extent item)을 포함한다.
3.6 익스텐트 트리
Btrfs에서는 공간의 할당 단위로서 4 KiB의 익스텐트(Extent)를 사용한다. 익스텐트는 블록 그룹 익스텐트(Block group extent), 데이터 익스텐트(Data extent), 메타데이터 익스텐트(Metadata extent)와 더불어 트리 블록이나 익스텐트 데이터로의 참조 정보를 저장할 수 있는데, 이와 같은 각기 다른 유형을 갖는 익스텐트들을 유지하기 위해 존재하는 트리가 익스텐트 트리이다.
블록 그룹은 파일시스템의 가상 주소 공간을 구성하는 기본 할당 단위로서 블록 장치의 개수에 따라 여러 개의 청크들로 구성될 수 있다. 익스텐트는 파일시스템 할당자에 의해 블록 그룹을 쪼개어 할당한 공간으로서 크게 데이터 익스텐트와 메타데이터 익스텐트로 나뉘어진다. 데이터 익스텐트는 파일시스템이 관리하는 데이터를 포함하며, 메타데이터 익스텐트는 트리 블록과 같은 파일시스템 메타데이터를 포함한다.
3.7 파일시스템 트리
파일시스템 트리(Filesystem tree)는 리눅스 커널의 VFS를 통해 접근되는 파일/디렉터리 객체들의 정보를 저장하는 트리다. 여기에는 아이노드 참조 아이템(Inode reference item), 아이노드 아이템(Inode item), 디렉터리 아이템(Directory item), 디렉터리 색인 아이템(Directory index item), 파일 익스텐트 아이템(File extent item)과 같은 아이템들이 저장된다.
아이노드 아이템은 리눅스 파일시스템의 파일/디렉터리 객체가 갖는 고유식별자인 아이노드 정보를 유지하는 아이템이다. 파일시스템 트리 내에서 아이노드 아이템은 (objectid=아이노드 번호, type=INODE_ITEM, offset=0)의 삼중자로 참조한다. 이 아이템의 내부에는 코드 3.7과 같은 정보들을 포함하게 된다. 운영 체제에서 기본적으로 요구되는 항목들인 크기, 사용자/그룹 권한, 파일 종류와 접근/속성 변경/내용 변경/생성 각각에 대한 시간을 기록한다.
Btrfs는 디렉터리의 메타 정보 뿐만 아니라 디렉터리 탐색 속도의 향상을 위해 추가된 색인용 아이템을 포함한 2가지의 디렉터리 아이템을 제공한다. 파일시스템 트리 내에서 디렉터리 아이템은 (objectid=아이노드 번호,type=DIR_ITEM, offset=해시된 디렉터리 이름)의 삼중자로 참조한다.
디렉터리 색인 아이템은 디렉터리 참조 속도의 향상을 위해서 사용되는 아이템으로서 그 구조가 디렉터리 아이템과 동일하다. 하지만 디렉터리 아이템이 DIR_ITEM, 해시된 디렉터리 이름을 키의 type과 offset으로 사용하여 참조함과는 다르게 DIR_INDEX, 아이노드 번호를 키의 type과 offset으로 참조한다. 그 결과 디렉터리 아이템을 통한 트리 순회는 이름을 기준으로 정렬된 순서를가지며, 디렉터리 색인 아이템을 통한 트리 순회는 아이노드 번호를 기준으로 정렬된 순서를 가진다.
Btrfs는 일반적으로 파일의 데이터를 코드. 3.9에서 보여지는 파일 익스텐트 아이템을 통해 저장한다. 이 아이템은 압축 및 암호화 기능에 대한 플래그와 더불어 익스텐트 트리 내의 익스텐트 아이템을 참조할 수 있는 정보를 유지한다.
파일 익스텐트 아이템은 특정 파일 내부에서의 오프셋과 길이를 offset,num_bytes에 기록하며 그에 , 사상되는 익스텐트에 대한 오프셋과 길이를 각각disk_bytenr, disk_num_bytes에 기록한다. 따라서 이를 통해서 익스텐트 트리내의 익스텐트 아이템을 참조할 수 있을 뿐만 아니라 익스텐트 트리의 설명에서 언급한 바와 같이 익스텐트 아이템이 가리키는 익스텐트에 대해서도 접근이 가능하게 된다. 이 아이템은 파일 연산의 효율성을 위해 그 크기가 한 노드보다 작은 파일에 대해서는 익스텐트 트리가 아닌 노드 자체에 그 데이터를 저장한다.
4. 비교
4.1 ZFS와 Btrfs의 비교
4.2 성능 비교 테스트
웹서버의 일반적인 성능 비교의 경우에는 ZFS, Btrfs , ext4, XFS 의 성능에는 별다른 차이를 볼 수 없었다.
하지만 write, re-write, read 같은 일반 파일 사용 작업을 하는 파일서버의 경우
single, raid5, raid10 모두 Btrfs가 다른 파일시스템에 비해 최고 성능을 내는 것을 확인 할 수 있다.
모두 Btrfs가 높은 성능을 내지는 않았다.
Btrfs의 성능이 다른 파일 시스템에 비해 다소 부족한 경우는 작은 파일 크기에 대한 read 및 strided read가 있으며, 이것은 일반적으로 관계형 데이터베이스 서버를 예로 들수 있다. OLTP sing disk 테스트에서 Btrfs는 최악의 성능을 보여준다
단일 디스크와 작은 파일 크기를 읽는 성능이 뛰어나지는 않지만 다중 디스크 설정에서는 다른 파일 시스템에 비해 Btrfs의 성능이 뛰어나다.
종합적으로 봤을 때 Btrfs는 다른 파일시스템보다 높은 성능을 보여준다는 것을 보여준다.
Random read: 존재하는 파일의 블록을 무작위로 읽는 명령이다. 캐시 크기, 또는 디스크의 수, 블록 탐지 속도 등에 의해 성능이 달라진다. 특히, 하드디스크는 스핀들 모터 때문에 매우 느린 속도를 보이는 반면, SSD는 순차 방식과 큰 차이를 보이지 않는다. 경우에 따라 더 빠른 속도를 보일 수 있다.
Random write: 파일에서 무작위로 데이터 블록을 선택하여 데이터를 갱신하는 명령이다. 캐시 크기, 또는 디스크의 수, 블록 탐지 속도 등에 의해 성능이 달라진다. 특히, 하드디스크는 스핀들 모터 때문에 매우 느린 속도를 보이는 반면, SSD는 순차 방식과 큰 차이를 보이지 않는다.경우에 따라 더 빠른 속도를 보일 수 있다
Stride read: 일정 크기를 건너뛰면서 읽는 명령이다. 대부분의 운영체제에서 이 명령을 위한 기법을 제공하지 않지만, 경우에 따라 병목현상이 발생할 수 있는 명령으로 성능 평가가 필요하다.
5. 실습
5.1 btrfs setup
btrfs 관련 기능은 kernel에 포함되어 있음
btrfs 관련 하여 개선된 성능과 안정성을 원하면 kernel 을 update
5.2 btrfs filesystem 만들기
• # mkfs.btrfs option device_path
• blkid 명령어로 uuid 확인
• fstab 에 추가
• btrfs fi show
• btrfs fi df /path_to_mount
5.3 테스트
테스트 시나리오
• btrfs 파일시스템 생성 - raid0
• btrfs 에서 파일 쓰기 - 1Gb x 1, 10mb X 100
• btrfs 에서 생성된 파일 md5sum 확인
• btrfs 파일 시스템 raid 모드 변경 - raid0 -> raid10
• btrfs 에서 생성했던 파일 md5sum 값 확인
• btrfs 스냅샷 - snap1
• btrfs 구성하고 있는 물리 디스크 강제 fault
• btrfs 안에 내용 확인
• btrfs 에 파일 추가 쓰기 - 1Gb x1, 10Mb x 100
• btrfs 스냅샷 - snap2
• btrfs 에 추가한 파일 삭제
• btrfs snap 1로 snapshot 복구 후 내용물 확인
• btrfs snap 2로 snapshit 복구 후 내용물 확인
• 강제 fault 시킨 하드에 대한 원상 복구
• btrfs 상태 확인
댓글