LLM 엔지니어링19장 · MLOps 와 LLMOps, 워크플로 자동화12 / 23← 이전목차다음 →MetaContents

19장. MLOps 와 LLMOps, 워크플로 자동화

다시 돌려도 안전한 작업

엘리베이터 버튼은 열 번 눌러도 엘리베이터가 한 번 옵니다. 밤 작업도 이래야 합니다. 서버가 멈춰 작업을 다시 돌렸더니 문서가 두 번 들어가거나, 쓰다 만 색인을 서비스가 읽으면 안 됩니다.

내용의 지문으로 바뀐 것만 고르고, 새 판 폴더에 다 쓰고, 다 쓴 뒤 가리킴만 바꾸는 세 가지를 견준 비교 그림

그림의 세 카드가 다시 돌려도 안전하게 만드는 방법입니다. 왼쪽은 지문으로 바뀐 문서만 골라 일을 줄입니다(증분 처리). 가운데는 지금 쓰는 색인을 고치지 않고 새 판 폴더에 따로 씁니다. 오른쪽은 다 쓴 뒤에 "지금 판은 이것"이라는 가리킴 파일만 한 번에 바꿉니다. 버튼을 여러 번 눌러도 같은 층에 서는 것처럼, 같은 내보내기로 다시 돌리면 같은 판이 됩니다.

나쁜 예와 좋은 예

다시 돌리면 탈이 나는 작업다시 돌려도 안전한 작업
데이터 넣기받은 것을 뒤에 덧붙인다(두 번 들어간다)지문을 열쇠로 넣는다(있으면 덮는다)
색인 쓰기서비스가 읽는 색인을 그 자리에서 고친다새 판 폴더에 쓰고 가리킴을 바꾼다
처리 범위"지금까지 새로 온 것""이 날짜의 내보내기"
바뀐 것이 없을 때같은 판을 또 만든다판을 만들지 않고 끝낸다

가리킴을 한 번에 바꾸기

os.replace 는 파일 이름을 한 번에 바꿉니다. 새 가리킴을 임시 파일에 다 쓴 뒤 바꾸면, 읽는 쪽은 옛 판 아니면 새 판만 봅니다.

Python
import os
import tempfile
from pathlib import Path

with tempfile.TemporaryDirectory() as root:          # 예시가 끝나면 지워지는 임시 폴더
    root = Path(root)

    def publish(version, chunks):
        """새 판 폴더에 다 쓴 뒤, 가리킴 파일을 한 번에 바꾼다"""
        folder = root / version
        folder.mkdir(exist_ok=True)                  # 같은 판을 다시 써도 오류 없이 덮는다
        (folder / "chunks.txt").write_text("\n".join(chunks), encoding="utf-8")
        tmp = root / "CURRENT.tmp"
        tmp.write_text(version, encoding="utf-8")
        os.replace(tmp, root / "CURRENT")            # 이름 바꾸기는 한 번에 일어난다

    publish("v001", ["대출 기간은 14일입니다."])
    publish("v001", ["대출 기간은 14일입니다."])      # 두 번 돌려도
    # 결과: 판 폴더 하나, 가리킴은 v001
    print(sorted(p.name for p in root.iterdir()), (root / "CURRENT").read_text(encoding="utf-8"))

코드에 나오는 함수

코드쉬운 뜻
tempfile.TemporaryDirectory()임시 폴더를 만들고, with 블록이 끝나면 안의 파일까지 지운다
Path(root)경로 글자를 Path(경로) 객체로 바꾼다. / 로 경로를 이어 붙일 수 있다
root / version임시 폴더 안의 v001 폴더 경로를 만든다
folder.mkdir(exist_ok=True)make directory(폴더 만들기)다. exist_ok 는 "이미 있어도 괜찮다"는 뜻으로, 있으면 오류 없이 넘어간다
.write_text(…, encoding="utf-8")파일에 글을 통째로 쓴다. 같은 파일이 있으면 덮어쓴다
os.replace(tmp, root / "CURRENT")CURRENT.tmp 의 이름을 CURRENT 로 바꾼다. 같은 이름의 파일이 있으면 그 자리를 차지한다
root.iterdir()iterate directory(폴더 안을 하나씩 돌기)다. 폴더 안의 파일과 폴더를 하나씩 내준다

이 코드가 뜻하는 것

식당 입구의 메뉴판을 떠올려 봅니다. 칠판을 지우고 새로 쓰면, 쓰는 동안 손님은 반쯤 지워진 메뉴를 봅니다. 새 메뉴판을 안에서 다 만든 뒤 액자에 한 번에 바꿔 끼우면, 손님은 옛 메뉴 아니면 새 메뉴만 봅니다. 여기서 새 메뉴판이 판 폴더(v001), 액자가 가리킴 파일 CURRENT, 바꿔 끼우기가 os.replace 입니다.

줄하는 일쉽게 말하면
with tempfile.TemporaryDirectory() as root끝나면 지워지는 임시 폴더에서 연습한다연습용 빈 벽
folder.mkdir(…), (folder / "chunks.txt").write_text(…)판 폴더에 조각 글을 다 쓴다새 메뉴판을 안에서 다 만든다
tmp.write_text(version, …)판 이름을 임시 가리킴 파일에 쓴다액자에 넣을 종이를 준비한다
os.replace(tmp, root / "CURRENT")임시 파일의 이름을 CURRENT 로 바꾼다액자에 한 번에 바꿔 끼운다
둘째 publish("v001", …)같은 판을 다시 써도 같은 폴더를 덮을 뿐이다같은 메뉴판을 또 끼워도 벽은 그대로

결과 ['CURRENT', 'v001'] v001 은 두 번 돌려도 판 폴더가 하나이고 가리킴이 v001 이라는 뜻입니다. CURRENT.tmp 가 목록에 없는 것은 이름이 CURRENT 로 바뀌었기 때문입니다. 비유와 다른 점은, 식당은 바꿔 낀 옛 메뉴판을 버리지만 여기서는 옛 판 폴더를 남겨 두어 가리킴을 되돌릴 수 있게 한다는 것입니다.

주의할 점

  • 판 폴더를 바로 지우지 않습니다. 앞 판이 있어야 가리킴을 되돌릴 수 있습니다. 오래된 판은 몇 개만 남기고 정리합니다.
  • 지문은 내용으로 만듭니다. 파일의 수정 시각은 복사만 해도 바뀌어 믿을 수 없습니다.
← 이전 절19장 · Airflow 로 일정 돌리기다음 절 →19장 · 자동 배포의 관문