부드러운 데이터베이스 변경을위한 거위 마이그레이션

부드러운 데이터베이스 변경을위한 거위 마이그레이션

안녕하세요, 메이트!

오늘날 데이터베이스 마이그레이션이 무엇인지, 왜 중요한지에 대해 이야기합시다. 오늘날의 세계에서는 데이터베이스에 대한 변경 사항이 특정 프로세스에 따라 신중하게 수행되어야한다는 것은 놀라운 일이 아닙니다. 이상적으로는 이러한 단계가 CI/CD 파이프 라인에 통합되어 모든 것이 자동으로 실행되도록합니다.

다음은 우리의 의제입니다:

  1. 문제는 무엇입니까?
  2. 우리는 그것을 어떻게 고치나요?
  3. 간단한 예
  4. 더 복잡한 예
  5. 권장 사항
  6. 결과
  7. 결론

문제는 무엇입니까?

팀이 데이터베이스 마이그레이션을 다루지 않았고 필요한 이유를 완전히 확신하지 못한 경우 정렬하겠습니다. 기본 사항을 이미 알고 있다면 자유롭게 건너 뛰십시오.

괜찮아요

주요 도전

데이터베이스를 “계획”및 “매끄럽게”변경하면 서비스 가용성을 유지하고 SLA 요구 사항을 충족시켜야합니다 (사용자가 다운 타임이나 지연으로 어려움을 겪지 않도록해야합니다). 5 백만 명의 사용자가있는 테이블에서 열 유형을 변경하고 싶다고 상상해보십시오. 이 “정면”을한다면 (예 : 단순히 실행하십시오 ALTER TABLE 준비하지 않으면 테이블이 상당한 시간 동안 잠겨있을 수 있으며 사용자는 서비스없이 남겨집니다.

이러한 두통을 피하려면 두 가지 규칙을 따르십시오.

  1. 테이블을 잠그지 않는 방식으로 마이그레이션 적용 (또는 적어도 잠금을 최소화합니다).
  2. 열 유형을 변경 해야하는 경우먼저 올바른 유형으로 새 열을 만들고 나중에 기존 열을 떨어 뜨리는 것이 종종 더 쉽습니다.

또 다른 문제 : 버전 제어 및 롤백

때로는 마이그레이션을 롤백해야합니다.

이 작업을 수동으로 수행 (프로덕션 데이터베이스에 들어가서 데이터에 대한 피해를 입히는 것은 위험 할뿐만 아니라 직접 액세스 할 수 없다면 불가능할 수 있습니다. 전용 마이그레이션 도구가 유용한 곳입니다. 그들은 당신이 변경을 깨끗하게 적용하고 필요한 경우 복귀시킬 수 있도록합니다.

우리는 그것을 어떻게 고치나요? 올바른 도구를 사용하십시오

각 언어와 생태계에는 자체 마이그레이션 도구가 있습니다.

  • Java의 경우, 리큐베이스 또는 플라이 웨이 일반적입니다.
  • GO를 위해 인기있는 선택은입니다 거위 (우리가 여기서 볼 것).
  • 등.

거위 : 그것이 무엇인지 그리고 그것이 유용한 이유입니다

거위

거위는 가벼운 GO 유틸리티로 자동으로 마이그레이션을 관리하는 데 도움이됩니다. 그것은 제공 :

  • 간단. 최소 의존성 및 마이그레이션을위한 투명 파일 구조.
  • 다재. 다양한 DB 드라이버 (PostgreSQL, MySQL, Sqlite 등)를 지원합니다.
  • 유연성. SQL 또는 GO 코드로 마이그레이션을 작성하십시오.

거위 설치

go install github.com/pressly/goose/v3/cmd/goose@latest

작동 방식 : 마이그레이션 구조

기본적으로 거위는 마이그레이션 파일을 찾습니다 db/migrations. 각 마이그레이션은이 형식을 따릅니다.

NNN_migration_name.(sql|go)

  • NNN 마이그레이션 번호입니다 (예 : 001,,, 002등.).
  • 그런 다음 설명 이름을 가질 수 있습니다. init_schema.
  • 확장은 될 수 있습니다 .sql 또는 .go.

SQL 마이그레이션의 예

파일: 001_init_schema.sql:

-- +goose Up
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT now()
);

-- +goose Down
DROP TABLE users;

첫 번째 예

열 유형 변경 (문자열 → int)

우리가 있다고 가정 해 봅시다 users 열이있는 테이블 age 유형 VARCHAR(255). 이제 우리는 그것을 바꾸고 싶습니다 INTEGER. 마이그레이션의 모습은 다음과 같습니다 (파일 005_change_column_type.sql) : :

-- +goose Up
ALTER TABLE users ALTER COLUMN age TYPE INTEGER USING (age::INTEGER);

-- +goose Down
ALTER TABLE users ALTER COLUMN age TYPE VARCHAR(255) USING (age::TEXT);

여기서 일어나는 일 :

  1. UP 마이그레이션

    • 우리는 변경합니다 age 열로 INTEGER. 그만큼 USING (age::INTEGER) 절은 PostgreSQL에 기존 데이터를 새 유형으로 변환하는 방법을 알려줍니다.
    • 데이터가 있으면이 마이그레이션이 실패합니다. age 그것은 숫자가 아닙니다. 이 경우보다 복잡한 전략이 필요합니다 (아래 참조).
  2. 다운 마이그레이션

    • 우리가 롤백하면 우리는 돌아옵니다 age 에게 VARCHAR(255).
    • 우리는 다시 사용합니다 USING (age::TEXT) 전환합니다 INTEGER 텍스트로 돌아갑니다.

두 번째 및 복잡한 사례 : 다단계 마이그레이션

만약 age 열은 지저분한 데이터 (숫자뿐만 아니라)를 포함 할 수 있으며 여러 단계 로이 작업을 수행하는 것이 더 안전합니다.

  1. 새 열 추가 (age_int) 유형 INTEGER.
  2. 유효한 데이터를 새 열로 복사하여 유효하지 않은 항목을 처리하거나 제거합니다.
  3. 이전 열을 떨어 뜨립니다.
-- +goose Up
-- Step 1: Add a new column
ALTER TABLE users ADD COLUMN age_int INTEGER;

-- Step 2: Try to move data over
UPDATE users 
SET age_int = CASE
    WHEN age ~ '^[0-9]+$' THEN age::INTEGER
    ELSE NULL
END;

-- (optional) remove rows where data couldn’t be converted
-- DELETE FROM users WHERE age_int IS NULL;

-- Step 3: Drop the old column
ALTER TABLE users DROP COLUMN age;

-- +goose Down
-- Step 1: Recreate the old column
ALTER TABLE users ADD COLUMN age VARCHAR(255);

-- Step 2: Copy data back
UPDATE users 
SET age = age_int::TEXT;

-- Step 3: Drop the new column
ALTER TABLE users DROP COLUMN age_int;

적절한 롤백을 허용하기 위해 Down 섹션은 동작을 반대로 반영합니다.

자동화가 핵심입니다

시간을 절약하기 위해 MakeFile (또는 다른 빌드 시스템)에 마이그레이션 명령을 추가하는 것이 정말 편리합니다. 아래는 PostgreSQL의 기본 거위 명령이 포함 된 MakeFile의 예입니다.

가정하자 :

  • 데이터베이스의 DSN은 다음과 같습니다 postgres://user:password@localhost:5432/dbname?sslmode=disable.
  • 마이그레이션 파일이 있습니다 db/migrations.
# File: Makefile

DB_DSN = "postgres://user:password@localhost:5432/dbname?sslmode=disable"
MIGRATIONS_DIR = db/migrations

# Install Goose (run once)
install-goose:
	go install github.com/pressly/goose/v3/cmd/goose@latest

# Create a new SQL migration file
new-migration:
ifndef NAME
	$(error Usage: make new-migration NAME=your_migration_name)
endif
	goose -dir $(MIGRATIONS_DIR) create $(NAME) sql

# Apply all pending migrations
migrate-up:
	goose -dir $(MIGRATIONS_DIR) postgres $(DB_DSN) up

# Roll back the last migration
migrate-down:
	goose -dir $(MIGRATIONS_DIR) postgres $(DB_DSN) down

# Roll back all migrations (be careful in production!)
migrate-reset:
	goose -dir $(MIGRATIONS_DIR) postgres $(DB_DSN) reset

# Check migration status
migrate-status:
	goose -dir $(MIGRATIONS_DIR) postgres $(DB_DSN) status

그것을 사용하는 방법?

1. 새 마이그레이션 생성 (SQL 파일). 파일을 생성합니다 db/migrations/002_add_orders_table.sql.

make new-migration NAME=add_orders_table

2. 모든 마이그레이션을 적용하십시오. 거위는 a schema_migrations 데이터베이스의 테이블 (아직 존재하지 않는 경우)의 테이블을 올라가는 순서로 새 마이그레이션을 적용하십시오.

3. 마지막 마이그레이션을 롤백하십시오. 마지막으로.

4. 모든 마이그레이션 롤백 (생산에주의 사용). 전체 재설정.

5. 마이그레이션 상태를 확인하십시오.

출력 예 :

$ goose status
$   Applied At                  Migration
$   =======================================
$   Sun Jan  6 11:25:03 2013 -- 001_basics.sql
$   Sun Jan  6 11:25:03 2013 -- 002_next.sql
$   Pending                  -- 003_and_again.go

요약

마이그레이션 도구와 makefile을 사용하면 다음을 수행 할 수 있습니다.

  1. 생산 데이터베이스에 대한 직접 액세스를 제한하여 마이그레이션을 통해서만 변경합니다.
  2. 데이터베이스 버전을 쉽게 추적하고 문제가 발생하면 다시 롤백하십시오.
  3. 데이터베이스 변경의 일관된 일관된 기록을 유지하십시오.
  4. 마이크로 서비스 세계에서 달리기 생산 환경을 깨지 않는 “매끄러운”마이그레이션을 수행하십시오.
  5. 추가 유효성 검증을 얻으십시오 – 모든 변경 사항은 PR 및 코드 검토 프로세스를 거치게됩니다 (해당 설정이 있다고 가정).

또 다른 장점은 이러한 모든 명령을 CI/CD 파이프 라인에 쉽게 통합 할 수 있다는 것입니다. 그리고 무엇보다도 보안을 기억하십시오.

예를 들어:

jobs:
  migrate:
    runs-on: ubuntu-latest

    steps:
      - name: Install Goose
        run: |
          make install-goose

      - name: Run database migrations
        env:
          DB_DSN: ${{ secrets.DATABASE_URL }}
        run: |
          make migrate-up

결론과 팁

주요 아이디어는 매우 간단합니다.

  • 마이그레이션을 작고 빈번하게 유지하십시오. 필요한 경우 검토, 테스트 및 복귀하기가 더 쉽습니다.
  • 모든 환경에서 동일한 도구를 사용하십시오 따라서 Dev, Stage 및 Prod는 동기화됩니다.
  • 마이그레이션을 CI/CD로 통합합니다 따라서 한 사람이 수동으로 달리는 사람에게 의존하지 않습니다.

이런 식으로, 데이터베이스 구조를 변경하기위한 신뢰할 수 있고 제어 된 프로세스가있을 것입니다. 생산을 중단하지 않고 무언가 잘못되면 신속하게 응답 할 수 있습니다.

당신의 마이그레이션에 행운을 빕니다!

읽어 주셔서 감사합니다!

출처 참조

Post Comment

당신은 놓쳤을 수도 있습니다