sonumb

TiDB - Implementation of Asynchronous Schema Change 본문

개발자 이야기/DBMS_Development

TiDB - Implementation of Asynchronous Schema Change

sonumb 2021. 11. 2. 12:16
✅ 출처: https://github.com/ngaut/builddatabase/blob/master/f1/schema-change-implement.md

중국어로 작성된 문서라 직접 번역 못함. 구글 번역기 돌림 ㅠ

 

배경

이제 일반 데이터베이스는 DDL 작업을 수행 할 때 테이블을 잠 가서이 테이블의 모든 DML 작업이 온라인 대기 상태 (일부 데이터는 읽기 작업을 지원하지만 많은 메모리를 소비하는 비용)로 들어가게합니다. 차단 된 상태에서 테이블이 클수록 영향 시간이 길어집니다. 이를 통해 DBA는 이러한 유형의 작업을 수행하기 전에 충분한 준비를 한 다음 실행에 도움이되는 기간을 선택할 수 있습니다. 이러한 이유로 건축가는 전체 시스템을 설계 할 때 테이블 구조를 신중하게 고려하여 향후 수정되지 않기를 희망합니다. 그러나 미래의 비즈니스 요구 사항은 종종 예측할 수 없으므로 DDL 작업을 완전히 피할 수는 없습니다. 이는 DDL 작업을 처리하는 원래 메커니즘이 많은 사람들에게 골치 아픈 일임을 보여줍니다. 이 기사에서는 TiDB가이 문제를 해결하는 방법을 소개합니다.

해결책

Google F1의 온라인 비동기 스키마 변경 알고리즘 구현에 따르면 간단한 최적화가 이루어졌습니다. 설계를 단순화하기 위해 전체 시스템에서 한 노드 만 동시에 스키마를 변경할 수 있습니다. 먼저이 기사에서 Google F1 스키마 알고리즘 도출 프로세스를 설명하지는 않을 것이라고 설명하겠습니다.이 알고리즘을 이해하지 못하면 원본 논문 또는 이 책 의 이전 장을 직접 읽을 수 있습니다 .

DDL의 분류 :

부트 스트랩 작업 중에 DDL을 수정해야하므로 닭고기 날 달걀과 달걀 날 닭 의존성의 문제가 발생했습니다. 따라서 DDL은 정적 DDL과 동적 DDL의 두 가지 범주로 나누어야합니다. 시스템 부트 스트랩 단계는 정적 DDL 만 사용하며 한 트랜잭션 내에서 완료되어야하며 모든 후속 작업은 동적 DDL 만 사용할 수 있습니다.

새로운 개념을 소개합니다 :

  • 메타 데이터 레코드 : 설계를 단순화하기 위해 비동기 스키마 변경 프로세스 중에 일부 메타 데이터를 기록하기 위해 시스템 데이터베이스 및 시스템 테이블이 도입되었습니다.
  • 상태 : F1의 비동기 스키마 변경 프로세스에 따라 일부 상태가 중간에 도입되며, 이러한 상태는 열, 인덱스, 테이블 및 데이터베이스에 바인딩되며 상태는 주로 없음, 삭제 만, 쓰기 전용, 쓰기 재구성 및 공개를 포함합니다. 이전 순서는 작성 조작 당시였으며 삭제 조작의 상태는 순서가 역순이었으며 쓰기 재구성이 재구성을 삭제하도록 변경되었습니다. 재구성 상태는 모두 표시되지만 서로 다른 레벨로 나뉩니다. 두 개의 상태 플래그.
  • 임대 : 시스템의 모든 노드에 최대 두 개의 서로 다른 버전의 스키마, 즉 최대 두 개의 다른 상태가 있습니다. 이로 인해 임대 기간 내의 모든 일반 노드는 스키마 정보를 자동으로로드하며, 임대 기간 동안 정상적으로로드 할 수없는 경우이 노드는 자동으로 전체 시스템을 종료합니다. 그런 다음 전체 시스템의 모든 노드가 한 상태에서 다음 상태로 업데이트되도록하려면 임대 시간의 2 배가 걸립니다.
  • 작업 : 각 개별 DDL 작업을 작업으로 볼 수 있습니다. DDL 작업이 시작되면 작업에 캡슐화되어 작업 대기열에 저장됩니다. 작업이 완료되면 작업이 작업 대기열에서 삭제되고 기록 작업 대기열에 저장되어 기록 작업을 쉽게 볼 수 있습니다.
  • Worker : 각 노드에는 작업을 처리 할 작업자가 있습니다.
  • 소유자 : 전체 시스템에서 하나의 노드 작업자 만 소유자 역할로 선출 할 수 있으며 각 노드는이 역할로 선출 될 수 있습니다. 소유자로 선출 된 후 작업자는 작업을 처리 할 권리가 있습니다. 소유자의 역할에는 용어가 있으며 소유자의 정보는 KV 계층에 저장됩니다. 작업자는 KV 계층에서 소유자 정보를 정기적으로 얻습니다. ownerID가 비어 있거나 현재 소유자가 기간을 초과하면 작업자는 KV 계층에서 소유자 정보를 업데이트하려고 시도 할 수 있습니다 (ownerID를 자신의 workerID로 설정). 근로자가 소유자가됩니다. 임대 기간 동안 전체 시스템의 한 노드 만 동시에 스키마 변경을 처리하고 있는지 확인하는 데 사용됩니다.
  • 백그라운드 작업 : 주로 이전 작업자 처리 작업 메커니즘과 마찬가지로 삭제 재구성의 최적화 처리에 주로 사용됩니다. 따라서 백그라운드 작업, 백그라운드 작업 큐, 백그라운드 작업 히스토리 큐, 백그라운드 작업자 및 백그라운드 소유자가 소개되며 해당 기능은 위에서 언급 한 역할 기능에 하나씩 대응하므로 여기에서는 자세히 설명하지 않습니다.

프로세스 변경

위의 장을 통해 비동기 스키마 변경의 기본 개념을 이해할 수 있으며,이 장에서는 이러한 기본 사항이 특정 변경 프로세스로 연결됩니다. 프로세스를 설명하는 프로세스에서 MySQL 클라이언트, MySQL 프로토콜 계층 및 KV 계층의 작업도 검토되며 TiDB SQL 계층에서 비동기 스키마 변경을 처리하는 프로세스 만 소개됩니다. 기본 프로세스는 그림 1에 나와 있습니다. 각 모듈과 특정 프로세스는 아래에 자세히 설명되어 있습니다. 

그림 1 구조 흐름도

기준 치수

  • TiDB 서버 : TiDB 의 MySQL 프로토콜 계층과 TiDB SQL 계층을 포함하며, TiDB SQL 계층의 비동기 스키마 변경과 관련된 기본 모듈을 주로 설명합니다.
  • load schema : 각 노드의 시작 부분에 생성 된 gorountine입니다 (이 모듈은 이해하기 쉽도록 위에서 언급 한 작업자와 동일합니다). 특정 노드 인 경우 각 임대 시간 후에 스키마를로드하는 데 사용됩니다 로드에 실패하면 TiDB 서버가 자동으로 전화를 끊습니다. 여기에로드하지 못하면로드 시간 종료가 포함됩니다.
  • 작업 시작 : TiDB SQL 계층이 요청을받은 후 ID를 작업에 할당하여 KV 계층에 저장하며, 작업 처리가 완료되기를 기다린 후 상위 계층으로 돌아가서 처리 결과를보고합니다.
  • worker : 각 노드는 작업을 처리하는 고 루틴을 시작하며 처리 할 작업이 있는지 정기적으로 확인합니다. 이 노드의 작업 시작 모듈에 의해 통지 된 후에는 실행할 작업이 있는지 직접 확인합니다.
  • owner : 역할로 간주 될 수 있으며 정보는 KV 계층에 저장되며 여기에는 현재이 역할을 위해 선택된 노드의 정보를 기록하는 것이 포함됩니다.
  • 작업 대기열 : KV 계층에 저장된 작업을 저장하기위한 대기열 이며 논리적으로 전체 시스템이 하나뿐입니다.
  • 작업 이력 대기열 : KV 계층에서 처리되어 저장된 작업을 저장하는 대기열이며 논리적으로 전체 시스템이 하나만 있습니다.

기본 과정

이 섹션에서는 구현 세부 사항을 무시하고 비동기 DDL 변경의 전체 프로세스에 대해 설명합니다. 시스템에 TiDB 서버 1과 TiDB 서버 2의 두 노드 만 있다고 가정합니다. TiDB 서버 1은 DDL 작업을위한 수신 노드이고 TiDB 서버 2는 소유자입니다. 아래의 그림 2는 TiDB 서버 1과 관련된 프로세스를 보여주고, 그림 3은 TiDB 서버 2와 관련된 프로세스를 보여줍니다.

그림 2 TiDB 서버 1 순서도

그림 3 TiDB 서버 2 흐름도

  1. MySQL 클라이언트는 TiDB 서버에 DDL SQL 문을 변경하라는 요청을 보냅니다.
  2. TiDB 서버는 요청을 받고 (MySQL 프로토콜 계층은 구문 분석 및 최적화 요청을 수신 한 후) 실행을 위해 TiDB SQL 계층에 도달합니다. 이 단계는 주로 TiDB SQL 계층이 요청을 수신 한 후 작업을 시작하는 모듈이 요청에 따라 특정 DDL 작업으로 패키지 한 다음이 작업을 KV 계층에 저장하고 해당 작업을 작업자에게 실행할 수있는 작업이 있음을 알립니다.
  3. TiDB 서버의 작업자는 요청을받은 후 작업 처리 알림을 수신하여 소유자 역할에 있는지 여부를 확인하고, 소유자 역할에 있으면 직접 처리되며,이 역할에 속하지 않으면 처리하지 않고 종료됩니다. 그림에서이 역할이 아닌 것으로 가정하면이 역할에 다른 TiDB 서버에 하나 있어야하는데, 소유자 역할 노드의 작업자가 정기적 인 감지 메커니즘을 통해 작업을 실행할 수 있는지 여부를 확인하면 발견됩니다. 작업을 수행하면 작업이 처리됩니다.
  4. 작업자가 작업을 처리 한 후 KV 계층의 작업 대기열에서 작업을 제거하고 작업 기록 대기열에 넣습니다.
  5. 이전에 작업을 패키지 한 작업 시작 모듈은 주기적으로 작업 히스토리 큐로 이동하여 이전에 배치 된 작업에 해당하는 ID를 가진 작업이 있는지 확인하고, 있으면 전체 DDL 조작이 종료됩니다.
  6. TiDB 서버는 MySQL 클라이언트에 응답을 반환합니다.

자세한 과정

이 섹션에서는 작업을 처리하는 작업자의 전체 프로세스를 소개하기 위해 열을 예로 표에 추가합니다. 구체적인 프로세스는 그림 4에 나와 있습니다. 이전 장과의 연속성을 고려하면 그림 4는 그림 2와 3의 확장 된 그림으로 이해 될 수 있습니다.

그림 4 열 순서도 추가

다음 소개에서 정보를 얻는 방법을 돕기 위해 작업 구조가 여기에 게시됩니다.

type Job struct {
		ID       int64      `json:"id"`
		Type     ActionType `json:"type"`
		SchemaID int64      `json:"schema_id"`
		TableID  int64      `json:"table_id"`
		State    JobState   `json:"state"`
		Error    string     `json:"err"`
		// every time we meet an error when running job, we will increase it
		ErrorCount int64         `json:"err_count"`
		Args       []interface{} `json:"-"`
		// we must use json raw message for delay parsing special args.
		RawArgs     json.RawMessage `json:"raw_args"`
		SchemaState SchemaState     `json:"schema_state"`
		// snapshot version for this job.
		SnapshotVer uint64 `json:"snapshot_ver"`
		// unix nano seconds
		// TODO: use timestamp allocated by TSO
		LastUpdateTS int64 `json:"last_update_ts"`
	}

TiDB 서버 1 프로세스

  1. 작업 시작은 작업을 완료 할 준비가되었음을 시작 작업자에게 알립니다.
  2. 작업자는 트랜잭션을 시작하고 소유자 역할인지 확인하고 소유자 역할이 아닌지 확인합니다 (이 노드 작업자가 소유자 역할이 아니라고 가정하면 이전 장과 일치 함). 트랜잭션을 제출하고 처리 루프를 종료 한 후 시작 작업자에게 리턴하고 대기합니다. 신호주기.

TiDB 서버 2 프로세스

  1. 시작 작업자의 타이머 도착 시간입니다.
  2. 트랜잭션을 시작하고이 노드가 소유자 역할인지 확인하십시오.
  3. KV 계층에서 대기열의 첫 번째 작업을 가져와 (TiDB 서버 1 이전에 작업으로 가정)이 작업의 유형을 결정한 후 적절하게 처리하십시오.
  4. 여기서 작업 유형은 열 추가이며, 플로우는 그림에서 열 정보 얻기 단계에 도달합니다.
      해당 테이블 정보 (주로 작업의 schemaID 및 tableID를 통해 획득)를 가져온 다음 추가 된 열이 존재하지 않거나 원래 테이블에 보이지 않는지 확인하십시오.
      b. 새로 추가 된 열이 원래 테이블에 없으면 새 열 정보를 테이블 정보와 연결하십시오.
      c. 이전 두 단계에서 문제가 발생하면 작업이 취소 및 반환 오류로 표시되고 그림의 반환 오류 프로세스에 도달합니다. 예를 들어, 해당 데이터베이스 또는 데이터 테이블의 상태가 존재하지 않거나 보이지 않는 경우 (즉, 상태가 공용이 아닌 경우)이 열이 이미 존재하고 표시 가능한 상태 인 것으로 확인되며 일부 오류는 여기에 나열되지 않습니다.
  5. 스키마 버전 번호를 1 씩 늘리십시오.
  6. 작업의 스키마 상태와 테이블의 열 상태를 삭제 전용으로 표시하고 테이블 정보를 KV 계층으로 업데이트하십시오.
  7. 작업 상태가 완료 (즉, 완료 또는 취소 상태)가 아니기 때문에 이전 단계에서 작업에 의해 업데이트 된 정보는 KV 계층에 직접 기록됩니다.
  8. 이전 작업을 수행하는 데 일정 시간이 걸리므로 여기에서 소유자의 마지막 업데이트 타임 스탬프가 현재 시간으로 업데이트되어 소유자 역할이 다른 서버간에 자주 전환되지 않도록하고 트랜잭션을 커밋합니다.
  9. 단계 2, 3, 4.a, 5, 6, 7, 8은 주기적으로 실행되지만 6의 상태는 삭제 전용에서 쓰기 전용으로 변경됩니다.
  10. 2, 3, 4.a, 5, 6, 7, 8 단계는 주기적으로 실행되지만 6의 상태는 쓰기 전용에서 쓰기 재구성으로 변경됩니다.
  11. 2, 3, 4.a 및 5 단계를 반복하여 현재 트랜잭션의 스냅 샷 버전을 얻은 다음 새로 추가 된 열의 데이터를 채우십시오. 버전에서 확보해야하는 테이블의 모든 핸들 (rowID와 동일)을 통해 메모리와 성능을 종합적으로 고려하기 위해이 프로세스는 일괄 처리 획득입니다. 그런 다음 각 행의 새로 추가 된 열에 대한 데이터를 채우십시오. 특정 조작은 다음과 같습니다 (다음 조작은 트랜잭션에서 완료 됨)
      .a. 이전에 얻은 핸들을 사용하여 해당 행이 존재하는지 판별하십시오 (존재하지 않는 경우) .
      b. 존재하는 경우 핸들로 구성된 키와 새로 추가 된 columnID를 통해 해당 열을 가져옵니다. 획득 한 값이 비어 있지 않으면이 라인에서 작업이 수행되지 않습니다.
      c. 값이 비어 있으면 새로 추가 된 해당 행의 정보를 통해 기본값이 얻어지고 KV 계층에 저장됩니다.
      d. 현재 작업 정보를 현재 작업 재구성 핸들 필드에 저장하고 KV 계층에 저장하십시오. 12 단계 중 절반이 실행되고 어떤 이유로 다시 쓰기 작업을 다시 실행해야하는 경우이 핸들에서 직접 작업을 시작할 수 있습니다.
  12. 테이블 정보에서 열 및 인덱스 열의 위치를 조정하고 작업의 스키마 및 테이블 정보에서 새로 추가 된 열의 상태를 공용으로 설정하고 테이블 정보를 KV 계층으로 업데이트하십시오. 마지막으로 작업 상태를 완료로 변경하십시오.
  13. 작업 상태가 이미 완료되었으므로 작업 큐에서 작업을 제거하고 작업 히스토리 큐에 넣습니다.
  14. 트랜잭션의 이전 단계 12, 13, 14 및 15와 동일한 8 단계를 수행하십시오.

TiDB 서버 1 프로세스

  1. 시작 작업의 타이밍 확인이 트리거 된 후 작업 기록 큐에 이전에 작업 큐에 배치 된 작업이 있는지 (작업 ID를 통해) 확인합니다. 있는 경우 DDL 작업이 TiDB SQL에서 완료되고 MySQL 프로토콜 계층으로 전달 된 후 마지막으로 클라이언트로 반환되어 작업이 종료됩니다.

최적화

데이터베이스 삭제, 데이터 테이블 삭제 등의 경우 상태가 줄어 듭니다. 즉, 임대 대기 시간의 두 배이며 데이터베이스 또는 데이터 테이블에서 많은 양의 데이터를 삭제하는 데 걸리는 시간입니다. 원래 삭제 조작의 상태 변경은 공용-> 쓰기 전용-> 삭제 전용-> 삭제 재구성-> 없음이었습니다. 최적화 된 프로세스는 삭제 재구성 상태를 제거하고이 상태에서 처리해야하는 메타 데이터 조작을 삭제 전용 상태로 두는 것입니다. 당시에는 특정 데이터 삭제 작업을 백그라운드에두고 상태를 none으로 직접 표시하십시오.
이는 두 가지 점에서 원래 디자인과 주로 다르며 다음은 이러한 최적화가 데이터 무결성과 일관성에 영향을 미치는지 여부를 소개합니다.

  • 특정 데이터를 삭제하는 작업은 비동기 적으로 처리됩니다. 백그라운드에서 데이터를 삭제하기 전에이 데이터 테이블의 메타 데이터 (테이블 삭제 작업이 여기에서 수행되고 동일한 가정이 나중에 언급 된 것으로 가정)가 삭제되었으며 더 이상 외부에서 테이블에 액세스 할 수 없습니다. 특정 데이터에 더 액세스 할 수 없습니다. 어떤 사람들은 모듈이 액세스하는 특정 데이터를 비동기 적으로 삭제하는 방법에 대해 의문을 가질 수 있으며, 메타 데이터를 미리 작업 정보에 저장하는 것만 큼 간단합니다. 메타 데이터가 먼저 삭제되었는지 (이 트랜잭션이 성공적으로 제출되었는지 확인한 후) 특정 데이터를 비동기 적으로 삭제하는 한 문제는 없습니다.
  • 삭제 재구성 상태가 제거되었습니다. 원래는 삭제 만하고 이전 상태는 수정되지 않았으므로 문제가되지 않습니다. 그런 다음 없음 상태, 즉 전체 시스템이 변경 정보를 수신 할 때 두 상태 만 삭제 상태에 있고 전혀 없음을 고려하십시오. 그런 다음이 상태에서 클라이언트가이 테이블에서 일부 작업을 수행하려고한다고 분석됩니다.
  • 클라이언트 액세스 테이블이 TiDB 서버의 없음 상태에 있습니다. 이것은 실제로 최적화 이전과 동일합니다. 즉,이 테이블에 액세스 할 수 없지만 여기서 설명 할 수는 없습니다.
  • 클라이언트 액세스 테이블이 삭제 전용 상태 인 TiDB 서버. 이때 클라이언트는 삭제 전용 상태를 볼 수 없으므로이 테이블을 읽고 쓰지 못합니다.

이루다

이 최적화는 기본적으로 삭제 조작 상태에있을 때 삭제 조작 (현재 데이터베이스 및 테이블 조작 만 삭제), 메타 데이터가 삭제되고 테이블에서 특정 데이터의 삭제는 제외하고 원래 코드 로직을 변경하지 않습니다. 백그라운드에서 실행되도록 연기 한 다음 DDL 작업을 종료했습니다. 백그라운드에 배치 된 작업 프로세스는 이전의 작업 처리 프로세스와 유사하며 자세한 프로세스는 다음과 같습니다.

  1. 그림 4에서 완료 작업이 참이라고 판단한 후 백그라운드에서 실행할 수 있다고 판단되면 (당분간 데이터베이스와 테이블을 삭제하는 작업 임) 백그라운드 작업으로 캡슐화하여 백그라운드 작업 큐에 넣고 로컬 배경에 알리십시오. 작업자가 처리합니다.
  2. 백그라운드 작업에도 해당 소유자가 있으며 로컬 백그라운드 작업자가 백그라운드 소유자 역할이라고 가정하면 백그라운드 작업 큐에서 첫 번째 백그라운드 작업을 수행 한 다음 해당 작업 유형을 수행합니다 (표의 특정 데이터 삭제). 실행이 완료되면 백그라운드 작업 큐에서 작업을 삭제하고 백그라운드 작업 히스토리 큐에 넣습니다. 2 단계와 3 단계는 한 번의 트랜잭션으로 실행해야합니다.

요약하자면

위의 내용은 TiDB의 비동기 스키마 변경 구현에 대한 기본 내용입니다. 명확하게 설명되지 않은 프로세스 세부 정보가있을 수 있습니다. 본인에 대한 설명이 있거나 구현에 대한 질문이있는 경우 문제 토론을 시작하십시오

반응형