프로젝트에서 mongodb 를 사용하던 중, Data Insert 시에 DB 가 down 되는 상황이 발생해서, 로그를 확인해보니 다음과 같았다.
{"s":"F", "c":"CONTROL", "id":6384300, "ctx":"ftdc","msg":"Writing fatal message","attr":{"message":"terminate() called. An exception is active; attempting to gather more information\n"}}
{"s":"F", "c":"CONTROL", "id":6384300, "ctx":"ftdc","msg":"Writing fatal message","attr":{"message":"DBException::toString(): FileStreamFailed: Failed to write to interim file buffer for full-time diagnostic data capture: /var/lib/mongodb/diagnostic.data/metrics.interim.temp\nActual exception type: mongo::error_details::ExceptionForImpl<(mongo::ErrorCodes::Error)39, mongo::AssertionException>"}}
/var/lib/mongodb/diagnostic.data 쪽은 mongodb 에서 data 를 저장하는 쪽인데, 해당 부분에서 AssertionException 이 발생한 것이다. 용량이 의심되어서 df -h 명령어로 용량 현황을 살펴보니, /var 경로의 용량이 100% 로 가득차서 발생하는 문제임을 발견했다. 현재 VM 에 600GB 스토리지를 함께 발급받았었기 때문에, 이를 사용하기 위해 현재 상황을 살펴보았다.
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 99G 0 part
├─rootvg-root_lv 253:2 0 45G 0 lvm /
├─rootvg-tmp_lv 253:3 0 12G 0 lvm /tmp
├─rootvg-var_lv 253:4 0 25G 0 lvm /var
└─rootvg-swap_lv 253:5 0 16G 0 lvm [SWAP]
sdb 8:16 0 600G 0 disk
└─sdb1 8:17 0 600G 0 part
├─vg001-appdata_lv 253:0 0 600G 0 lvm /appdata
sr0 11:0 1 1024M 0 rom
처음보면 뭔 상황인지 잘 모르겠으나, 확실한건 600G 짜리 디스크가 존재하고, 이는 전혀 사용중이지 않음을 알 수 있다 (df 명령어들로 통해 확인 가능). 이쯤에서 PV, VG, LV 에 대해 이해해보고 가면 좋다.
* PV, VG, LV 에 대하여
PV : Physical Volume
> 물리적 디스크 그 자체 혹은 물리적인 파티션을 말한다
> /dev/sda1, /dev/sdb1 이런 공간들은 실제 디스크 내부의 파티션이다.
> PV 위에서 논리적 볼륨을 구성한다
VG : Volume Group
> PV 들을 묶는다. 여러개의 PV 들을 논리적으로 묶어놓은 Pool (여러 PV 들을 합쳐서 하나의 큰 Storage Pool 만듬)
> 가령, VG001 은 sda1 과 sdb1을 합쳐서 만든 볼륨 그룹
> rootvg 같은건 Volume Group 이다.
> lsblk 명령어에 실질적으로 등장하진 않는다. LV들의 소속을 보여줄 뿐이다.
LVM : Logical Volume Management
> 디스크 관리 방식 중 하나, 물리 디스크를 논리적으로 나누고, 그들을 묶기도 하여 효율적으로 공간을 관리하고 확장하기 위한 수단
<예시>
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 99G 0 part
├─rootvg-root_lv 253:1 0 45G 0 lvm /
├─rootvg-tmp_lv 253:2 0 12G 0 lvm /tmp
├─rootvg-var_lv 253:3 0 25G 0 lvm /var
└─rootvg-swap_lv 253:4 0 16G 0 lvm [SWAP]
> 다 폴더 별로 관리되는 것 같음, 그래서 이 폴더는 이 공간에! 이런 느낌
> 위 그림을 보면, sda 내부에 sda1,2,3 는 PV 로, 파티션 물리 볼륨이다 (sda 가 실제 디스크)
> sda3 라는 공간은, 4가지 LV 가 분리되어서 담당한다 (이 때 남는 공간은 그냥 sda3 에게 할당되어 있는 듯)
> sda3 라는 공간은, 또한 rootvg 의 일부이다. rootvg 가 사용하는 PV 들 중 하나인 것
> rootvg 내부에 생성된 LV 들은 rootvg-{}-lv 들로, PV 에 배치된다
> 그니까 PV 에게 담당 LV 를 지정하는 구조가 아니라, PV 들이 모여 VG 이 되고, VG 안에서 LV 들을 만듬 (위 그림이랑 같이 이해)
> PV 는 자동으로 담당되는 LV 들이 생김!
* 문제 상황
/var 의 용량이 부족하므로, 600G 의 디스크 파티션 내에서 새로운 LV 를 생성해 /var 에 추가해주는 방식을 생각해 보았다. PV 가 다르더라도, /var 라는 공간에 같이 할당될 수 있을 것이라 생각했다 (참고로 결론은 불가능하다).
맨 위에 lsblk 상황을 보면 새 디스크에는 이미 sdb1 이라는 PV, vg001 이라는 VG 이 만들어졌고, 600G 모두 vg001-lv 라는 생성되어 있는 LV에 할당되어 있다. 따라서 이 LV 를 줄인 다음에 새 LV 를 만든 후 /var 에 마운트를 해주면 될 것 같다 (600GB 의 LV 에서 100GB 를 떼어내려 함)
1. 데이터 백업 (혹시 모르니 데이터를 백업했다, 완료시 간단히 삭제하면 되므로)
> 디스크 관련 작업이나 DB 관련 작업을 한다면 무조건 백업 해두는게 좋다. "에이 설마.." 싶긴 했는데 이번에도 역시 필요했다 ㅋㅋㅋㅋ 정말 꼭 필수이다.
> 기존 사용하던 계정의 홈 디렉토리가 /appdata 였는데, 이거는 또 디스크 LV (/vg001-appdata_lv) 에 마운트 된 채로 발급되었다. /vg001-appdata_lv 는 우리가 100GB 를 떼어내고 싶은 LV 이므로, unmount 를 해야 한다. 따라서 현재 /appdata 에 있는 데이터 백업을 진행한다
> cp 를 하면 특수 파일 복사에 한계가 있다고 해서, rsync 명령어를 사용했다
> $ sudo rsync -avh --progress /appdata/ /{백업데이터_경로}/
>> -a 는 권한, 심볼릭 링크, 타임스태프 등을 모두 복사, -vh 는 출력모드 설정, -progress 는 진행 상태 표시
2. unmount 및 기존 LVM 볼륨 축소 진행
> 디스크에 마운트 되어 있던 /appdata 를 언마운트한다. (참고로 이 때 /appdata 내부에서 실행된 프로세스들은 모두 종료되어야 한다. 작은 작업이 아닌 것)
> $ sudo umount /appdata
>> /appdata 라는 공간에 마운트된 File System 이 있다면 모두 해제하는 명령어
>> 참고로 unmount 를 진행하면 기존 /appdata 는 당연히 빈공간이 된다. 기존 데이터들은 appdata_lv 에 있기 때문이다.
> 중요한 건 파일 시스템을 먼저 축소하고, LV 의 크기를 축소해야 한다 (내가 여기에서 좀 꼬인듯 하다. 아래 나온다) - 파일시스템을 반드시 먼저 줄여야 한다고 함
> $ sudo resize2fs /dev/vg001/appdata_lv 500G (100기가를 줄임)
>> /appdata_lv 에서 생성한 File System 의 크기를 500GB 로 줄인다 (File System 과 Volume 시스템과는 다른 것인듯)
> $ sudo lvreduce -L -100G /dev/vg001/appdata_v (LV 자체를 줄임)
>> /appdata_lv 의 LV 자체의 크기를 500GB로 줄인다
3. 새 LVM 생성
> $ sudo lvcreate -L 100G -n new_lv vg001
>> vg001 VG 내에 새로운 new_lv LV 를 생성하고, 이 LV 에 100G 를 할당한다
> 이 때, 용량이 100G 불가능하다는 오류가 뜰 수 있는데, 이럴 때는 extent 단위로 환산하면 된다 (99 기가 남았는데 100기가로 할당 이런 문제라서 그런 걸 수도 있음)
> ex:: $ sudo lvcreate -l 25599 -n new_lv vg001 (나도 이런 식으로 하긴 함)
> 여기까지 됐다면 아래와 같은 상황이 된 것
sdb 8:16 0 600G 0 disk
└─sdb1 8:17 0 600G 0 part
├─vg001-appdata_lv 253:0 0 500G 0 lvm /appdata
├─vg001-new_lv 253:0 0 100G 0 lvm
4. 생성한 LVM 을 /var 에 할당
> $ sudo mount /dev/vg001/new_lv /var
>> /var 경로에 새로 만든 new_lv LV 를 추가적으로 mount 해준다.
> 진행하고 확인해보니, 추가된 것이 아니라 기존 LV 를 (rootvg-var_lv) 를 빼고 새 LV mount 하는 현상이 확인되었다 (이중 mount 는 안되는 것 ㅠㅠ)
> 따라서 그냥 용량을 가장 많이 차지하는 /var/lib 에 새 LV 를 마운트해줬다
>> 심볼릭 링크로 공간들이 존재하기 때문에, /var 라는 공간은 rootvg 에 마운트되어 있지만, 그 안에 /var/lib 라는 공간만은 더 넓은 vg001 에 마운트 되어 있는 형태가 가능한 것
> 그리고 기존에 있던 /var/lib 는 백업해 두었고 , 새로운 공간의 /var/lib 에 다시 넣어줬다 (이 때도 rsync 사용)
* 이후 벌어진 일들 (can't read superblock on /dev/~)
이제 다시 처음에 LV 축소를 위해 unmount 해줬던 /appdata-lv 를 다시 mount 해줘야 기존 profile 설정 및 해당 계정의 데이터들이 복원되는데, 문제가 발생했다.
$ sudo mount /dev/vg001/appdata_lv /appdata
mount: /appdata: can't read superblock on /dev/mapper/vg001-appdata_lv.
$ sudo xfs_repair /dev/mapper/vg001-appdata_lv # 구글링 혹은 GPT 가 위 에러 발생시 repair 해보라고 함
xfs_repair: error - read only 0 of 512 bytes
위와 같은 오류들이 지속 발생한다. 매우 해결하는데 오래 걸렸고, 웬만한건 다 시도해본 것 같다 (-t xfs 등). 결론은 실제로 vg001-appdata_lv 가 손상되었다는 것으로 결론을 내릴 수밖에 없었다. 지금 리뷰하며 생각해보면, resize 만 하고 lvreduce 를 안했던 것 같다!! 그래서 xfs 시스템이 손상됐던 것 같다.
어쨌든 아무리해도 안되었으므로, (천만다행으로 appdata 를 백업해놨었음..) 그냥 기존 appdata_lv 를 삭제하고 새로 만들어줬다.
이 때, appdata_lv 를 굳이 xfs 로 만들 필요 없는 것 같아서 (알아보니 DB쪽에 적합하다고 함) ext4 형태의 파일 시스템으로 다시 생성하고 100G 를 할당하여, /appdata 에 다시 mount 하니 정상적으로 mount 되었다. 완성된 lsblk 의 모습은 아래와 같았다.
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 99G 0 part
├─rootvg-root_lv 253:2 0 45G 0 lvm /
├─rootvg-tmp_lv 253:3 0 12G 0 lvm /tmp
├─rootvg-var_lv 253:4 0 25G 0 lvm /var
└─rootvg-swap_lv 253:5 0 16G 0 lvm [SWAP]
sdb 8:16 0 600G 0 disk
└─sdb1 8:17 0 600G 0 part
├─vg001-appdata_lv 253:0 0 100G 0 lvm /appdata ## 새로 만든 appdata_lv
└─vg001-var_lv 253:1 0 100G 0 lvm /var/lib ## 새로 만든 var_lv
sr0 11:0 1 1024M 0 rom
sdb1 에 PV 내에 남은 400G 가 존재하고, 필요할 때 sdb 디스크 파티션을 새로 하거나, 혹은 LV 들 증설을 하면 될 것 같다. appdata 백업해둔 내용들은 역시 rsync 를 통해서 복원해주니 정상적으로 복원되었다.
* 마운트 내용을 fstab 에 추가 및 주요 시스템 restart
/etc/fstab 은 서버가 기동될 때 (세션 시작이 아닌, 종료 후 시작) 파일 시스템들을 확인하여 대상 경로들과 파일 시스템들을 mount 하기 위해 사용되는 파일로, 없으면 파일 시스템이 아무 마운팅도 하지 않은 상태로 초기화된다. 따라서 fstab 에 다음과 같이 추가 후 저장해 두었다
/dev/mapper/vg001-appdata_lv /appdata ext4 defaults 0 0
/dev/mapper/vg001-var_lv /var/lib ext4 defaults 0 0
## 0 0 은 백업 옵션들인데, 안한다고 설정한 것 (자세히는 추후 알아보자)
서버 재부팅 후에도 정상적으로 mount 되었으며, /var 를 중심으로 실행되는 docker, nginx, mysql, mongod 를 다시 켜줘보니, 모든 Data 들이 그대로이며 정상적으로 동작하는 것이 확인되었다 (추가 마운트 후 복원해준 /var/lib 데이터들이 다 정상적으로 동작한다는 뜻). appdata 역시 정상적으로 연계되었으므로 성공적으로 디스크 증설 성공하였다
$ df -h
/dev/mapper/rootvg-var_lv 25G 8.9G 15G 39% /var (약 60% 감소)
/dev/mapper/rootvg-tmp_lv 12G 41M 12G 1% /tmp
/dev/mapper/vg001-var_lv 98G 15G 79G 16% /var/lib
/dev/mapper/vg001-appdata_lv 98G 12G 82G 13% /appdata
참고로 위 내용은 이전 후 현재 마운팅 포인트들의 용량들을 보여준 것이다. /var 는 기존의 /var/lib 를 사용하지 않으므로 100% 에서 39% 사용으로 감소하였고, /var/lib 라는 새로운 마운팅 포인트가 생겼으며, /appdata 와 함께 당장은 넉넉한 100GB 의 용량이 할당되었음을 알 수 있다.
* 다하고 남은 궁금증
> Volume 들과 파일 시스템? 이거의 연관 관계를 잘 모르겠음. ext4, ext3, xfs 이런 파일 시스템들..
> 적진 않았지만, docker 따위가 var 및 var/lib 내부에 많은 데이터를 사용하고 있기 때문에, 기존 /var/lib 를 청소 (모두 삭제) 하는데에는 실패하였다 .완전히 깔끔하게 하려면 docker 를 재설치하는 것이 깔끔해보였다.

끝!
'웹 운영 > 운영 구축' 카테고리의 다른 글
RaspberryPi + Cloudflare 서비스로 LAN 내에서 서버 구축하기 (1) | 2024.09.30 |
---|---|
[Jenkins] 강의 (0) | 2023.02.20 |