사전 롤백
개념

롤백

gabury1

이미 한 변경을 취소해 그 전 상태로 되돌리는 일입니다. 되돌리려면 이전 상태를 어딘가에 남겨둬야 합니다. 무엇을 남겨두느냐가 어디까지 되돌릴 수 있는지를 정합니다.

상세

문서를 고치다가 마지막 저장 지점으로 되돌리는 것과 같습니다. 저장 지점을 안 남겼으면 되돌아갈 곳도 없습니다.

롤백은 변경을 취소해 이전 상태로 되돌리는 일입니다. 골격은 셋입니다. 되돌아갈 지점을 남깁니다. 변경합니다. 필요하면 그 지점으로 되돌립니다.

flowchart TD
    A["되돌아갈 지점을 남긴다"] --> B["변경한다"]
    B --> C{"그대로 둘 것인가"}
    C -->|둔다| D["확정"]
    C -->|아니다| E["남긴 지점으로 되돌린다"]

되돌릴 수 있는 범위는 남겨둔 지점까지입니다. 남긴 것을 지우면 그만큼 되돌릴 수 없게 됩니다. 되돌리려는 변경이 이미 확정돼 밖으로 나간 뒤일 수도 있습니다. 되돌리는 것으로 끝나는 자리만 있는 것은 아닙니다. 되감은 지점부터 다시 계산하는 갈래도 있습니다. 그 차이는 아래 갈래가 받습니다.

배경

여러 단계를 거치는 변경은 도중에 실패할 수 있습니다. 앞 단계는 반영되고 뒤 단계는 안 된 상태가 남습니다. 그 절반짜리 상태는 어느 쪽으로도 맞지 않습니다.

전부 되거나 전부 안 되게 하려면 시작 지점으로 물러설 수단이 있어야 합니다. 물러서려면 시작 지점이 어땠는지를 미리 남겨둬야 합니다. 남기는 비용을 치르는 대신 실패한 변경을 없던 일로 만듭니다.

되감아 앞선 상태로 돌아간다는 뜻에서 이 동작을 롤백이라 부릅니다. 되돌리는 대상은 자리마다 다릅니다. 데이터베이스의 갱신일 수도 있습니다. 내보낸 배포판일 수도 있습니다. 게임의 한 프레임일 수도 있습니다. 부르는 이름은 같습니다.

갈래

갈리는 자리는 둘입니다. 되돌릴 변경이 이미 확정돼 밖으로 나갔는지, 그리고 되돌린 뒤에 다시 계산하는지입니다.

갈래 되돌리는 대상 확정 전인가 되돌린 뒤 다시 계산하나
트랜잭션 롤백 아직 커밋 안 된 갱신 확정 전 안 한다
배포 롤백 이미 내보낸 판 확정 후 안 한다
넷코드 롤백 예측으로 진행한 프레임 확정 후 한다

트랜잭션 롤백

트랜잭션 안에서 한 갱신은 커밋할 때까지 확정되지 않습니다. ROLLBACK 은 현재 트랜잭션을 중단합니다. 그 트랜잭션이 만든 갱신은 전부 버려집니다. 트랜잭션 블록 밖에서 ROLLBACK 을 실행하면 경고가 납니다. 그 밖에는 아무 일도 일어나지 않습니다.

전체가 아니라 일부만 되돌릴 수도 있습니다. 세이브포인트는 트랜잭션 안에 찍는 표식입니다. 그 표식을 찍은 뒤에 실행된 명령을 전부 되돌려 트랜잭션 상태를 표식을 찍던 시점으로 되돌립니다. ROLLBACK TO SAVEPOINT 는 되돌린 뒤 같은 트랜잭션 수준에서 새 하위 트랜잭션을 시작합니다. 그 세이브포인트는 그대로 남아 나중에 다시 되돌아갈 수 있습니다. 대신 그 뒤에 찍은 세이브포인트들은 함께 사라집니다.

배포 롤백

이미 내보낸 판은 버릴 대상이 아닙니다. 대신 이전 리비전으로 다시 굴립니다. 쿠버네티스 디플로이먼트 문서는 롤아웃이 불안정할 때 되돌린다고 적습니다. 컨테이너가 죽었다 다시 뜨기를 되풀이하는 상태가 그 예입니다. 되돌리는 것 자체도 새 리비전이 됩니다. 되돌아가는 것은 파드 템플릿 부분뿐입니다. 레플리카 수를 조정하는 것 같은 변경은 리비전을 만들지 않습니다.

되돌릴 수 있는 범위는 남아 있는 이력이 정합니다. 쿠버네티스는 기본적으로 롤아웃 이력을 전부 보관합니다. .spec.revisionHistoryLimit 이 남겨둘 옛 레플리카셋의 개수를 정합니다. 기본값은 10입니다. 이 옛 레플리카셋들은 etcd 의 자원을 씁니다. 옛 레플리카셋이 지워지면 그 리비전으로 되돌아갈 능력도 같이 사라집니다. 값을 0으로 두면 이력이 정리되어 새 롤아웃을 되돌릴 수 없습니다.

넷코드 롤백

대전 게임에서 두 참가자는 각자 게임 사본을 통째로 돌립니다. 프레임마다 게임 상태 전체를 주고받는 것은 비용이 너무 큽니다. 그래서 입력만 서로 보냅니다. 각 참가자는 받은 입력으로 자기 게임을 한 프레임씩 진행시킵니다. 상대 입력이 아직 안 왔으면 예측한 값으로 먼저 진행합니다. 예측이 어긋나면 저장해 둔 이전 프레임 상태를 불러와 실제 입력으로 다시 계산합니다.

sequenceDiagram
    participant 로컬
    participant 원격
    Note over 로컬: 원격 입력을 예측해 프레임 진행
    원격->>로컬: 실제 입력 도착
    Note over 로컬: 예측과 어긋남
    로컬->>로컬: 저장해 둔 프레임 상태를 불러온다
    로컬->>로컬: 실제 입력으로 다시 계산한다

이 갈래는 게임 엔진에 전제 셋을 요구합니다. 시뮬레이션이 완전히 결정론적이어야 합니다. 같은 상태와 같은 입력이면 한 프레임 진행한 결과가 모든 참가자에게 똑같아야 합니다. 게임 상태가 한군데에 온전히 담겨야 합니다. 그리고 직렬화될 수 있어야 합니다. 그리고 화면에 그리지 않고 한 프레임을 저장·불러오기·실행할 수 있어야 합니다. 되감는 구간이 길수록 잘못된 예측 프레임을 잠깐 실행한 흔적을 사용자가 알아챌 확률이 올라갑니다. 프레임 지연을 크게 두는 것이 그 흔적을 없애는 한 방법입니다.

예시

PostgreSQL 세이브포인트

SQL
BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

이 트랜잭션은 값 1과 3을 넣습니다. 2는 넣지 않습니다. my_savepoint 를 찍은 뒤에 실행된 명령만 되돌아갔기 때문입니다. RELEASE SAVEPOINT 로 바꾸면 반대가 됩니다. 표식만 없애고 그 뒤 명령의 결과는 남깁니다. 커서 위치는 세이브포인트 롤백의 영향을 받지 않습니다. 되돌리기 전에 한 건을 읽었으면 되돌린 뒤에는 그다음 건이 나옵니다.

쿠버네티스 되돌리기

kubectl rollout undo deployment/nginx-deployment

출력은 deployment.apps/nginx-deployment rolled back 입니다. 바로 앞 리비전으로 돌아갑니다. 특정 리비전을 지목할 수도 있습니다.

kubectl rollout undo deployment/nginx-deployment --to-revision=2

되돌린 뒤에는 디플로이먼트 컨트롤러가 리비전 2로 되돌아갔다는 DeploymentRollback 이벤트를 냅니다.

관련 항목

갈래가 속하는 기술 분야

트랜잭션 · 배포 · 넷코드

트랜잭션 롤백을 이루는 구성 요소

커밋 · 세이브포인트 · 하위 트랜잭션 · 커서

배포 롤백을 이루는 구성 요소

디플로이먼트 · 디플로이먼트 컨트롤러 · 롤아웃 · 리비전 · 레플리카셋 · 파드 템플릿 · kubectl · etcd · DeploymentRollback

넷코드 롤백을 이루는 구성 요소

프레임 지연 · 추측 실행 · 지연

롤백이 지키는 성질

원자성 · 결정론 · 직렬화

이것을 실제로 구현·채택한 제품

PostgreSQL · 쿠버네티스(Kubernetes) · GGPO

롤백이 실제로 되돌리는 대상

데이터베이스 · 배포판 · 프레임

다른 이름: rollback