OpenStack 업무 회고 #1

YL. Gho·2022년 8월 30일

회고

목록 보기
1/2
post-thumbnail

지난 업무을 회고하면서 커리어에 의미있는 경험들을 글로 정리하고자 하였다.
그 중 OpenStack 기반의 퍼블릭 클라우드를 구축하고 운영했던 업무에 대해 먼저 적어본다.

그때가 2016년, 지금은 거의 관심을 받지 못하지만 당시에는 OpenStack 프로젝트가 꽤 주목받던 때였다.
당시 일하던 회사에서는 퍼블릭 클라우드 사업을 하고 있었고 여러 OpenStack 파생 프로젝트 중, Mirantis OpenStack 7.0 를 기반으로 해서 새로운 클라우드 플랫폼을 만들고 있었다.

Mirantis OpenStack(이하 MOS) 의 구조는 크게는 Kubernetes 의 구조와 거의 동일하다.

mos_archController Nodes = Control Plane
Compute Nodes = Data Plane
Ceph Nodes = 스토리지 백엔드

Controller Nodes 를 좀 더 살펴보면,

  • 각 컴포넌트의 API 및 Scheduler 는 리소스 생성 요청을 처리하고
  • RabbitMQ 는 각 컴포넌트 간 요청을 전달하는 큐를 제공하고
  • MySQL 은 etcd 와 같은 역할로 플랫폼 상태를 지속적으로 보관하고
  • MongoDB 는 이벤트 및 메트릭 데이터를 보관하고
  • PaceMaker/Corosync 는 다수의 Controller Nodes 를 클러스터링하여 HA 를 구성하고
  • HAProxy 는 API 엔드포인트 용 VIP 를 제공한다.

Compute Nodes 는 간단한데,

  • nova-compute 는 kubelet 과 같은 역할로 VM 을 관리하고
  • 그림엔 없지만 OpenVSwitch, L3-Agent 와 같은 프로세스들이 L2/L3 레벨의 가상 네트워크(DVR)를 구성한다.

큰 그림에서 MOS 는 위와 같은 구조로 여기서 나는 블록 스토리지 파트를 담당했다.

블록 스토리지는 OpenStack 의 여러 컴포넌트 중 cinder 가 책임지는 부분이다.
cinder 로 볼륨 생성 요청이 전달되면 cinder 는 자신에게 연결된 스토리지 백엔드에서 실제 I/O를 처리할 볼륨을 생성하고 해당 볼륨 정보를 기반으로 cinder 볼륨을 생성한다.

볼륨 기능을 구현하기 위해서는 먼저 스토리지 백엔드를 선정해야 했다.
위 그림에서는 Ceph 를 백엔드로 사용하지만 회사에서는 상용 스토리지를 사용하는 방향으로 진행했고 여러 벤더 중 당시 가장 OpenStack 과 호환성이 좋고 가성비가 좋았던 NetApp 의 FAS 시리즈 스토리지를 벡엔드로 선정하였다.
그리고 하이엔드 볼륨 용으로 SolidFire 스토리지가 백엔드로 (NetApp FAS 스토리지보다 먼저) 선정되었다.

벡엔드 선정 후 한 일은 PoC 이다. PoC 에서 중점적으로 본 부분은,

  • 성능 측정(IOPS, Throughput)
  • HA 안정성
  • OpenStack 호환성

이렇게 세가지인데 특히 성능 측정에 많은 시간을 들였고 성능 측정 툴인 fio 를 매우 다채롭게(?) 사용하였다.

성능 측정의 의도는 최대 IOPS 와 Throughput 이 얼마나 나오는가 를 확인하는 것이다.
이를 위해 다양한 케이스를 만들어 I/O 스트레스를 발생시키는 작업을 반복하는데, 테스트 초기에 Read I/O 측정에서 문제가 있었다.
우리는 디스크를 분산하여 많이 사용하면 할 수록 당연히 읽기 성능도 높이 나올거라 예상했는데 몇 개의 디스크를 사용하는지와는 상관없이 성능이 매번 잘나왔다.
원인 파악을 위해 I/O 발생 내부를 분석해보니, I/O 가 처리 될 때 OS 차원에서 메모리에 캐싱(cache)하며 I/O 가 진행되는 걸 인지 못하고 그냥 스트레스만 무작정 생성했기 때문에 이런 잘못된 결과가 나타난 것이었다.
fio 를 통해 생성된 I/O 가 스토리지 디스크까지 가지 못하고 OS 레벨 메모리 캐시에서 처리되었고 그렇기 때문에 디스크 갯수와 상관없이 성능이 잘 나왔던 것이다.
이를 해결하기 위해선 fio 옵션에 direct=1 를 넣어주었고 이후 테스트부턴 바로 스토리지로 I/O 를 보낼 수 있었다.

하지만 하나 더 문제가 있었으니, 이는 넷엡 스토리지 레벨에서의 캐싱이었다.
I/O 가 스토리지로 갔지만 넷앱 스토리지도 캐싱을 수행하여 디스크까지 안가고 스토리지 메모리에서 처리가 끝나는 것이었다.
이를 바꿀 옵션은 당연히 fio 에 없고 스토리지에서도 제공하지 않았다.
결국 최종적으로 사용한 방법은 매번 fio 테스트 마다 읽기 I/O 생성에 사용되는 더미 파일을 새로 만들며 진행하는 것이었다. 사용된적이 없는 새 파일이라면 캐싱되어 있을게 없으니까.

이외에도 fio 의 다양한 옵션들을 사용하였는데 대표적으로 아래와 같다

  • numjobs=int: 병렬로 다수의 I/O 발생시켜 스트레스 더 효과적으로 발생시킨다. group_reporting 옵션과 함께 사용하면 좋다.
  • rw=[read|write|randread|randwrite|rw|randrw]: I/O 패턴을 선택한다. 주로 randrw 사용했다.
  • rwmixread=int rwmixwrite=int: Read/Write 비율 설정한다. 실제 운영 R/W 비율을 적용하여 PoC 의 신뢰성을 높일 수 있다.
  • runtime=int: 여기서 정해진 시간 만큼만 I/O 를 발생시킨다. time_based=int 과 함께 사용하면 좋다.

PoC 가 완료된 이 후부터 본격적으로 cinder 와 연동 작업을 시작했다.
이때 부터 cinder 기능이 안정적으로 작동하는지 특히 드라이버의 적합성을 중점적으로 확인하였는데, kilo 버전의 넷엡 드라이버는 여러가지로 이슈가 많이 나타났다.
특히 가장 큰 이슈 중 하나는 cinder 볼륨을 삭제하면 해당하는 매핑된 LUN 만 삭제해야 하는데 상관없는 다른 LUN 도 함께 지워지는 문제였다. 해당 버그는 드라이버 코드 이슈로 매핑된 볼륨을 정확히 구분하는 메써드가 제대로 구현안되서 나타나는 문제였고 직접 드라이버를 수정하여 해결할 수 있었다.
liberty 부터는 드라이버가 전체적으로 다 바뀌어 해당 이슈가 아마도 더 이상 발생하지 않을듯 하다.

대략 위와 같은 작업을 수행하며 cinder 서비스 구현을 완성했고 다른 팀원들의 작업도 함께 더해 퍼블릭 클라우드 서비스를 1차 완성할 수 있었다.
하지만 서비스라는 것은 구축 완료부터 시작이니 이제부터 본격적인 서비스 운영 업무에 들어갔고 이때부터 구축때와는 비교할 수 없는 더 큰 이슈들이 펑펑 터졌다.

다음 글에서는 서비스 운영하며 느낀 점들에 대해서 이어서 적어보려 한다.

profile
YLdot Padomaic

0개의 댓글