TiDB 스케줄링

스케줄링을 하는 이유

앞에서는 TiKV 클러스터가 TiDB 데이터베이스의 분산 KV 스토리지 엔진인 것을 소개하고 있다. 데이터는 리전에 복제된 후에 관리된다. 각 리전에는 서로 다른 TiKV 노드에 분산된 여러 복제본이 있다. 이러한 복제본 중 리더는 읽기/쓰기를 담당하고, 팔로어는 리더에서 보낸 Raft 로그를 동기화한다. 그럼 다음 질문에 대해 생각해 보자.

  • 동일한 리전의 여러 복제본이 서로 다른 노드에 분산되어 있는지 확인하려면 어떻게 해야 할까? 그리고, 하나의 컴퓨터에서 여러 TiKV 인스턴스를 시작하려면 어떻게 해야 하나?
  • TiKV 클러스터가 재해 복구(Disaster Recovery)에 대비하여 여러 위치에 배포된 경우, 단일 데이터 센터에 장애가 발생하여도, Raft 그룹의 여러 복제본이 손실되지 않도록 하려면 어떻게 해야 할까?
  • TiKV 클러스터의 다른 노드의 데이터를 새로 추가된 노드로 이동하려면 어떻게 해야 할까?
  • 노드가 고장나면 어떻게 하나? 클러스터 전체에서 무엇을 해야 하나? 노드에 일시적인 장애가 발생한 경우(예: 서비스 다시 시작), 어떻게 해결해야 한까? 장시간 장애(예: 디스크 장애 또는 데이터 손실)의 경우는 어떻게 해야 할까?
  • 각 Raft 그룹에 N개의 복제본이 있어야 한다. 1개의 Raft 그룹에서 복제본이 부족(예: 노드가 실패하고 복제본이 손실된 경우)하거나, 너무 많은 경우(예: 장애가 발생한 노드가 다시 실행되어 자동으로 클러스터에 추가된 경우)가 있다. 어떻게 복제 수를 설정할 수 있는가? 읽기/쓰기는 리더가 수행되는데, 모든 리더가 여러 노드에 모인 경우에 클러스터는 어떻게 되나?
  • 모든 리전에 액세스할 필요는 없으며, 핫스팟이 여러 리전에 존재하는 것으로 보인다. 이 경우는 어떻게 해야 할까?
  • 클러스터는 로드 밸런싱 과정에서 데이터를 마이그레이션해야 한다. 이러한 데이터 이동은 네트워크 대역폭, 디스크 IO, CPU를 많이 소비하는데, 온라인 서비스에 영향을 미치지는 않는가?

위의 문제 중 하나를 하나를 해결하는 것은 간단하지만, 조합하게 되면 어려워 진다. 예를 들어, 복제본을 추가할지 여부는 숫자가 부족한지 여부를 확인하는 것과, 1개의 Raft 그룹의 내부 상황을 생각하면 좋은 문제도 있다. 그러나 실제로는 이 복제본을 어디에 추가할지 포괄적인 관점이 필요하다. 전체 시스템은 역동적으로 변화하고 있다. 지역 분할, 노드 조인, 노드 고장, 핫스팟 액세스 변경 등이 항상 발생한다. 스케줄링 시스템은 또한 최상의 상태를 유지하기 위해 계속 조정되어야 한다. 전반적인 정보를 파악하고 스케줄링하고 구성할 수 있는 컴포넌트가 없다면, 이러한 요구를 충족시키는 것은 어려울 것이다. 따라서 전체 시스템의 상황을 제어하고 조정하는 중앙 노드가 필요하다. 거기서 등장한 것이 Placement Driver(PD) 모듈이다.

스케줄링 요구 사항

앞서 언급한 질문을 분류하고 정리해 보겠다. 크게 나누어 두 종류가 있다.

분산형이고 가용성이 높은 스토리지 시스템은 다음 요구 사항을 충족해야 한다.

  • 적절한 수의 복제본 생성
  • 복제본을 다른 컴퓨터에 분산
  • 다른 노드의 복제본을 노드 추가 후에 이동 가능
  • 노드가 오프라인 일 때, 노드의 데이터 이동

탁월한 분산 시스템에는 다음과 같은 최적화가 필요하다.

  • 클러스터에서 리더의 균형 잡힌 배치
  • 각 노드의 스토리지 용량의 균형 잡힌 배치
  • 핫스팟 액세스의 균형 잡힌 배포
  • 온라인 서비스에 영향을 미치지 않는 밸런싱 속도 제어
  • 수동으로 노드 온라인/오프라인을 전환하거나 장애가 발생한 노드를 자동으로 오프라인으로 전환하는 등 노드 상태 관리

첫번째 요구 사항을 충족하는 경우는 시스템은 여러 복제본의 재해 복구, 동적 확장성, 노드 장애 내성 및 자동 재해 복구를 지원한다. 그리고, 두번째 요구 사항을 충족하면 시스템 부하 균형이 좋고 관리가 쉬워진다.

이러한 요구 사항을 충족하려면 먼저 각 노드의 상태, 각 Raft 그룹의 정보, 비즈니스 액세스 및 운영 통계와 같은 정보를 충분히 수집해야 한다. 그런 다음 PD가 이러한 정보와 스케줄링 정책을 기반으로 위의 요청을 충족하는 스케줄링 계획을 수립하도록 정책을 설정해야 한다.

스케줄링의 기본 작업(operation)

스케줄링의 기본 작업은 매우 간단하다. 즉, 스케줄링 정책을 따라 할 수 있다는 것이다. 이것이 스케줄러 전체의 본 바탕이다.

위의 스케줄러 요구 사항은 복잡해 보이지만 세 가지 작업으로 크게 나눌 수 있다.

  • 복제본 추가
  • 복제본 삭제
  • Raft 그룹의 다른 복제본 간의 리더 역할 이동

Raft 프로토콜은 우연히 이러한 요구 사항을 충족하고, AddReplica, RemoveReplica, TransferLeader의 각 명령은 이 세 가지 기본 작업을 지원한다.

정보 수집

스케줄링은 클러스터 전체의 정보 수집에 따라 다른다. 간단히 말해서 각 TiKV 노드와 각 지역의 상태를 알아야 한다. TiKV 클러스터는 두 가지 유형의 정보를 PD에 보고한다.

각 TiKV 노드는 노드 전체에 대한 정보를 PD에 주기적으로 보고한다.

TiKV 스토어와 PD 사이에는 하트비트(Heartbeat)가 있다. PD는 하트비트로 각 데이터스토어가 활성 상태인지, 새로 추가된 데이터스토어가 있는지 확인한다. 반면에 하트비트에는 해당 데이터스토어의 상태 정보가 포함된다. 주로 다음과 같다.

  • 총 디스크 용량
  • 여유 디스크 용량
  • 지역 수
  • 데이터 쓰기 속도
  • 보내고 받은 스냅샷 수(복제본은 스냅샷으로 데이터를 동기화한다)
  • 오버로드하지 있지 않은가?
  • 라벨 정보(라벨은 상하 관계가 있는 일련의 태그이다)

각 Raft 그룹의 리더를 PD에 정기적으로 보고

각 Raft 그룹의 리더와 PD는 하트비트로 연결되어 있으며, 이 리전의 상태를 다음과 같이 보고한다.

  • 리더의 지위
  • 팔로워 위치
  • 오프라인 복제본 수
  • 데이터 읽기/쓰기 속도

이 두 종류의 하트비트를 통해 PD는 전체 클러스터의 정보를 수집하고 판단한다. 또한 PD는 관리 인터페이스를 통해 추가 정보를 얻어 보다 정확한 판단을 내린다. 예를 들어, 데이터스토어의 하트비트가 중단되면 PD는 그것이 일시적인 것인지 영구적인 것인지를 알 수 없다. PD는 일정 시간(기본적으로 30분)만 기다릴 수 있다. 정해진 시간을 기다려도 하트비트가 없다면, PD는 해당 데이터스토어가 오프라인이 되었다고 판단하고 해당 데이터스토어의 모든 리전을 이동해야 한다. 그러나, 운영 스태프가 수동으로 시스템을 오프라인으로 설정한 경우에는 그 스태프가 관리 인터페이스를 통해 PD에 데이터 스토어를 사용할 수 없음을 알려야 한다. 이 경우 PD는 데이터스토어의 모든 리전을 즉시 이동한다.

스케줄링 정책

정보를 수집한 후 구체적인 스케줄링 계획을 그리려면 PD에 몇 가지 정책이 필요하다.

1. 리전의 복제본 수가 정확하다.

PD는 리전 리더의 하트비트를 통해서 어느 리전의 복제본 수가 요구 사항을 충족하지 못한다는 것을 발견하면 복제본 추가/제거 작업을 통해 복제본 수를 수정한다. 이는 다음과 같은 경우에 발생한다.

  • 노드가 고장나서 모든 데이터를 잃고, 일부 지역에서 복제본이 존재하지 않는다.
  • 실패한 노드가 다시 작동하고 자동으로 클러스터에 참여한다. 이 경우 중복 복제본이 존재하므로 삭제해야 한다.
  • 관리자가 복제 정책 및 최대 복제본 수 설정을 변경한다.

2. 1개의 Raft 그룹의 여러 복제본이 같은 위치에 존재해서는 안된다.

동일한 위치이고, 동일한 노드가 아니라는 점에 유의해야 한다. 일반적으로 PD가 보장할 수 있는 것은 노드가 고장날 때 많은 복제본이 손실되는 문제를 피하기 위해 여러 복제본이 동일한 노드에 존재하지 않는다는 것이다. 실제 도입 시에는 다음과 같은 요건이 나올 수 있다.

  • 동일한 물리적 장비에 여러 노드가 배치된다.
  • TiKV 노드가 여러 서버에 분산되어 있다. 서버가 꺼져도 시스템을 사용할 수 있다고 가정한다.
  • TiKV 노드가 여러 IDC에 분산되어 있다. 데이터 센터가 꺼져도 시스템은 그대로 사용할 수 있다.

기본적으로 공통 위치 속성을 가지며, 최소 내장 유닛을 구성하는 노드가 필요하다. 이 장치 중 여러 지역 복제본이 공존하지 않는 것이 바람직하다. 이 때 노드에 레이블을 설정하고 PD의 로케이션 레이블을 설정하여 어떤 레이블을 위치 식별자로 지정할지 지정한다. 복제본을 배포할 때 여러 복제본을 저장하는 노드는 동일한 위치 식별자를 갖지 않는다.

3. 복제본이 각 데이터 저장소에 균등하게 분산

각 복제본의 데이터 저장 용량은 고정되어 있으므로 각 노드의 복제본 수의 균형을 유지하면 전체 부하가 더욱 균형을 이룬다.

4. 리더 수가 각 데이터 스토어에 균등하게 분산

Raft 프로토콜은 리더를 통해 읽기/쓰기를 수행하기 때문에 계산 부하는 주로 리더에서 걸린다. 따라서 PD는 리더를 다른 데이터스토어에 분산시켜 관리한다.

5. 핫스팟 수가 각 데이터 저장소에 균등하게 분포

정보를 보낼 때 각 데이터스토어와 리전 리더는 키 읽기/쓰기 속도와 같은 해당 시점의 액세스 부하에 대한 정보를 전달한다. PD는 핫스팟을 확인하고 여러 노드에 분산한다.

6. 각 데이터스토어의 스토리지 공간 점유율이 거의 동일

각 데이터스토어는 시작 시에 용량 매개변수를 지정하지만, 이는 데이터스토어의 스토리지 공간 한계를 나타낸다. PD는 스케줄링 시 노드의 나머지 공간을 고려한다.

7. 온라인 서비스에 영향을 미치지 않도록 스케줄링 속도 제어

스케줄링 동작은 CPU, 메모리, 디스크 I/O, 네트워크 대역을 소비하기 때문에 온라인 서비스에 영향을 주지 않도록 해야 한다. PD는 진행 중인 작업 수를 제어하며 기본 속도는 보수적이다. 스케줄링을 가속화하려는 경우(서비스 업그레이드 중지, 새 노드 추가, 가능한 한 빨리 스케줄링하려는 경우)는 pd-ctl으로 사용하여 수동으로 가속화할 수 있다.

8. 오프라인 노드를 수동으로 지원

pd-ctl으로 수동으로 노드를 오프라인으로 설정하면 PD는 특정 속도 제어 범위 내에서 노드의 데이터를 떼어 놓는다. 그런 다음 노드를 오프라인으로 만든다.

스케줄링 구현

그럼, 스케줄링의 흐름을 살펴보겠다.

PD는 데이터스토어와 리더의 하트비트를 통해 항상 정보를 수집하여 클러스터의 상세한 데이터를 검색한다. PD는 이 정보와 스케줄링 정책을 기반으로 동작 순서를 작성하고 리전 리더에서 보낸 하트비트를 수신하면 이 리전에 수행할 작업이 있는지 확인한다. PD는 하트비트 응답 메시지를 통해 향후 수행할 작업을 리전 리더에게 반환하고 다음 하트비트에서 실행 결과를 모니터링한다. 이러한 작업은 지역 리더에 대한 제안일 뿐이며 실행이 보장되지는 않는다. 실행할지 여부 및 언제 실행할지 여부는 리전 리더가 현재 상태에 따라 결정한다.

마무리

여기에서는 스케줄링을 위한 분산 스토리지 시스템을 구축하기 위해 무엇을 고려해야 하는지, 그리고 보다 유연하게 정책을 확장할 수 있도록 정책과 구현을 분리하는 방법에 대해서 소개하였다.

세 가지 블로그(스토리지, 컴퓨팅, 스케줄링)가 TiDB의 기본 개념과 구현 원리를 이해하는 데 도움이 되기를 바란다.




최종 수정 : 2022-08-05