사전 에포크
용어함정

에포크

gabury1고친 사람 github-actions[bot]

에포크는 무언가를 셀 때 삼는 출발점을 가리킵니다. 그런데 무엇을 세느냐에 따라 다른 물건이 됩니다. 시간을 다루는 곳에서는 시각을 수 하나로 세려고 못 박아 둔 출발 시점입니다. 여러 대가 함께 도는 시스템에서는 리더가 바뀔 때마다 하나씩 오르는 세대 번호입니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 세기 시작할 지점을 하나 못 박는 이름입니다. 컴퓨터는 시각을 「1970-01-01 0시부터 몇 초 지났나」라는 수 하나로 들고 있습니다. 그 1970-01-01 0시가 에포크입니다.

왜 이렇게 하나 — 날짜와 시·분을 따로 들고 있으면 두 시각을 빼거나 견주는 데 달력 규칙이 끼어듭니다. 출발점을 하나 정해 두고 거기서 흐른 초만 세면 뺄셈 한 번으로 끝납니다.

어떻게 도나

  1. 주고받는 쪽이 같은 출발점을 씁니다
  2. 지금이 그 출발점에서 몇 초 뒤인지를 수 하나로 적습니다
  3. 사람에게 보일 때만 그 수를 날짜와 시·분으로 되돌립니다

대가 — 수를 받은 쪽이 출발점을 모르면 그 수는 뜻을 잃습니다. 담는 그릇이 좁으면 언젠가 넘칩니다. 게다가 이 낱말은 분산 시스템에서 리더 세대를, 머신러닝에서 학습 한 회차를 가리키기도 합니다. 어느 세계 이야기인지 먼저 가려야 합니다.

상세

「에포크」라고 부르는 것들을 먼저 나란히 놓고, 시간 쪽 뜻 · 리더 세대 번호 · 학습 회차를 차례로 봅니다.

에포크가 가리키는 것들

세 맥락에서 이 낱말이 무엇을 가리키는지를 나란히 놓습니다. 세 뜻 모두 「여기서부터 센다」는 점은 같습니다. 무엇을 세느냐가 다릅니다.

맥락 에포크가 가리키는 것 값의 생김새
운영체제 · 데이터베이스 · 로그 시각을 수 하나로 셀 때의 출발 시점 1970-01-01 0시 같은 한 시점
여러 대가 함께 도는 분산 시스템 리더가 바뀔 때마다 하나씩 오르는 세대 번호 1 · 2 · 3 으로 오르는 정수
머신러닝 학습 학습 데이터를 처음부터 끝까지 한 번 다 훑는 한 회차 3 에포크처럼 세는 횟수

시간 쪽 에포크는 시점이고, 나머지 둘은 횟수입니다. 값이 날짜로 되돌려지는 수인지 그냥 세어 올린 수인지를 보면 어느 뜻인지 바로 갈립니다.

시각을 수 하나로 세는 출발점

시각을 컴퓨터에 담는 방법은 둘입니다. 하나는 연 · 월 · 일 · 시 · 분 · 초를 따로 들고 있는 것이고, 다른 하나는 정해 둔 한 시점에서 몇 초 지났는지를 수 하나로 들고 있는 것입니다. 컴퓨터 안에서 쓰는 것은 뒤쪽입니다.

앞쪽이 불편한 까닭은 달력이 고르지 않아서입니다. 달마다 날수가 다르고 윤년이 끼어듭니다. 두 시각의 차이를 구하려면 이 규칙들을 전부 따라가야 합니다.

뒤쪽은 뺄셈 한 번이면 끝납니다. 대신 「어디서부터 센 수인가」를 모두가 알고 있어야 합니다. 그 출발 시점이 에포크입니다.

유닉스 계열이 널리 쓰는 에포크는 1970-01-01 0시입니다. 기준은 세계가 시각을 맞출 때 쓰는 협정 세계시입니다. 이 에포크로 센 값을 유닉스 시간이라고 부릅니다.

수 가리키는 시각
0 1970-01-01 00:00:00
86400 1970-01-02 00:00:00
음수 에포크보다 앞선 시각

수 하나가 시각이 되려면 에포크가 양쪽에 있어야 합니다. 값만 건네고 에포크를 안 밝히면 받는 쪽은 그 수를 날짜로 되돌릴 수 없습니다. 서로 다른 출발점으로 읽으면 같은 수가 다른 날짜가 됩니다.

flowchart TD
    V["건네받은 수 하나 · 1700000000"]
    V --> A["출발점을 1970-01-01 로 아는 쪽이 읽는 시각"]
    V --> B["출발점을 다른 시점으로 아는 쪽이 읽는 시각"]
    A --> D["같은 수인데 다른 날짜가 된다"]
    B --> D

에포크가 1970-01-01 이어야 할 이유는 없습니다. 값을 담을 비트가 빠듯하면 더 늦은 시점을 에포크로 잡습니다. 어제 만든 서비스가 반세기 전 시각을 적을 일은 없습니다. 그 사이의 초를 세는 데 비트를 쓰는 것이 아깝습니다.

스노우플레이크가 그렇게 합니다. 여러 대가 서로 묻지 않고도 겹치지 않는 식별자를 만들어 내는 방식입니다. 식별자 하나 안에 시각과 기계 번호를 같이 욱여넣어야 해서 시각에 쓸 비트가 마흔 남짓밖에 없습니다.

block-beta
columns 2
  id["식별자 하나"]:2
  t["시각 · 40비트 남짓"] m["기계 번호"]

그래서 서비스를 연 해를 자기 에포크로 잡고 거기서 흐른 밀리초를 셉니다. 그 값을 다시 시각으로 읽으려면 어느 에포크를 썼는지 알아야 합니다.

에포크가 정해져도 문제가 하나 남습니다. 흐른 초를 담는 그릇의 폭이 표현할 수 있는 마지막 시각을 정합니다. 32비트 부호 있는 정수에 초를 담으면 2038-01-19 에 넘칩니다. 2038 문제가 그 이야기입니다.

리더 세대를 세는 번호

여러 대가 함께 도는 시스템에서는 한 대를 리더로 뽑아 결정을 맡깁니다. 리더가 죽으면 남은 서버들이 새 리더를 뽑습니다. 이 일이 리더 선출입니다.

여기서 고약한 상황이 하나 생깁니다. 옛 리더가 죽은 것이 아니라 잠깐 끊겼던 것이라면, 다시 이어졌을 때 자기가 아직 리더인 줄 압니다. 리더가 둘이 되어 서로 다른 결정을 내리는 이 상태를 스플릿 브레인이라고 합니다.

막는 방법은 리더에게 세대 번호를 붙이는 것입니다. 첫 리더가 1세대, 그다음 리더가 2세대입니다. 새 리더를 뽑을 때마다 이 번호가 하나 오릅니다. 이 번호가 에포크입니다.

따르는 쪽은 지금까지 본 가장 큰 번호를 기억해 둡니다. 그보다 작은 번호를 달고 온 명령은 거절합니다.

sequenceDiagram
    participant 옛리더 as 1세대 리더
    participant 따르는쪽 as 따르는 쪽
    participant 새리더 as 2세대 리더
    새리더->>따르는쪽: 2세대 리더가 됐다
    Note over 따르는쪽: 본 번호를 2로 올려 기억한다
    옛리더->>따르는쪽: 1세대 이름으로 명령
    따르는쪽-->>옛리더: 거절한다 · 지금은 2세대다

번호가 늘 오르기만 한다는 것이 이 방법의 전부입니다. 시계가 필요 없어서 서버들의 시각이 서로 어긋나도 판정이 흔들리지 않습니다. 「누가 더 최근인가」를 실제 시각을 알려 주는 벽시계 대신 번호 크기로 정하는 셈입니다.

같은 장치를 프로토콜마다 다른 이름으로 부릅니다. Raft는 이것을 텀이라고 부릅니다. 여러 대를 묶어 쓸 때 조율을 맡는 주키퍼는 이것을 에포크라고 부릅니다. 이름만 다르고 하는 일은 같습니다.

학습 데이터를 한 바퀴 도는 회차

머신러닝 학습에서 에포크 하나는 가진 학습 데이터를 처음부터 끝까지 한 번 다 훑는 것입니다. 학습은 데이터를 작은 묶음으로 나눠 조금씩 진행합니다. 그 묶음을 미니배치라고 합니다. 미니배치를 모두 한 번씩 돌면 한 에포크가 끝납니다.

flowchart TD
    subgraph E1["1 에포크"]
        B1["미니배치 1"] --> B2["미니배치 2"] --> B3["미니배치 3"] --> BR["나머지 묶음"]
    end
    E1 --> E2["2 에포크 · 같은 데이터를 한 번 더"]

같은 데이터를 여러 번 되풀이해 훑으므로 「3 에포크 돌렸다」처럼 셉니다. 앞의 두 뜻과 달리 시점도 세대도 아니고, 한 바퀴를 세는 단위입니다.

뜻이 헷갈릴 때 던지는 질문

어느 뜻인지 가리는 질문은 하나입니다. 그 에포크가 날짜로 되돌려지나.

되돌려지면 시간 쪽 뜻입니다. 안 되돌려지고 그냥 커지기만 하는 정수면 리더 세대이거나 학습 회차입니다.

둘 사이는 문맥이 갈라 줍니다. 리더와 합의가 오가는 글이면 세대 번호입니다. 학습과 데이터가 오가는 글이면 회차입니다.

flowchart TD
    Q["그 에포크가 날짜로 되돌려지나"]
    Q -->|예| T["시각을 수 하나로 세는 출발점"]
    Q -->|아니오| N["그냥 커지는 정수"]
    N -->|"리더·합의가 오가는 글"| L["리더 세대 번호"]
    N -->|"학습·데이터가 오가는 글"| M["학습 회차"]

관련 항목

에포크를 기준으로 삼아 시각을 담는 값

유닉스 시간 · 타임스탬프 · time_t · 율리우스일 · 틱

이 값을 읽어 주는 시계

벽시계 · 단조 시계 · 시스템 클록 · 실시간 시계 · 수정 진동자

에포크 기준 값을 사람이 읽는 표기로 옮기는 규격

ISO 8601 · RFC 3339 · 시간대 · 그레고리력 · 서머타임

이 값을 실제 시각에 맞추는 기준과 그것이 어긋나는 현상

NTP · 협정 세계시 · 국제원자시 · 윤초 · 클록 드리프트 · 클록 스큐

에포크 기준 값을 담는 그릇이 좁아 터지는 문제

2038 문제 · 정수 오버플로 · 부호 있는 정수 · Y2K 문제

자체 에포크 위에 식별자를 만드는 방식

스노우플레이크 · ULID · UUID · 시퀀스 번호 · 비트 마스크

세대 번호를 써서 옛 리더를 막는 절차

리더 선출 · 텀 · Raft · ZAB · 주키퍼 · 합의 · 정족수 · 펜싱 토큰 · 스플릿 브레인 · 가십

세대 번호와 같이 순서를 표시하는 다른 수단

논리 시계 · 램포트 시계 · 벡터 시계 · 버전 벡터 · 리비전 · 시퀀스 · 하이브리드 논리 시계

학습을 회차로 끊어 도는 머신러닝 개념

머신러닝 · 미니배치 · 학습률 · 경사 하강법 · 과적합 · 체크포인트

다른 이름: epoch · 에폭