케이블을 뽑고 출발 — xGrid의 Hub-Spoke 토폴로지, 역할 승격, 5분 페일오버
Blog/
||||||

케이블을 뽑고 출발 — xGrid의 Hub-Spoke 토폴로지, 역할 승격, 5분 페일오버

어떤 Spoke든 몇 분 안에 Hub가 될 수 있습니다. 장애가 발생한 Hub는 5분 안에 교체됩니다. 모든 Raspberry Pi에 전체 스택이 사전 설치되어 있으며, 역할은 구성 파일 하나로 결정됩니다. xGrid가 단절 환경에서 토폴로지 변경을 처리하는 방법을 소개합니다.

이미 알고 계신 패턴

"Hub-Spoke 토폴로지"라는 용어를 들어본 적이 없을 수도 있지만, 매일 사용하고 계십니다.

아무 항공사의 노선도나 열어보십시오. 몇 개의 대형 노드(인천, 김포, 제주)가 수십 개의 소도시로 연결을 뻗어나갑니다. 대형 노드가 Hub이고, 소도시가 Spoke입니다. 모든 도시에서 모든 도시로 직항을 운항하는 대신(30개 도시에 435개 노선이 필요), 모든 트래픽이 몇 개의 허브를 경유합니다. 더 적은 노선, 더 많은 조정, 훨씬 더 높은 효율성입니다.

Comparison of point-to-point network (top) versus hub-and-spoke network (bottom) — the hub-spoke model reduces the number of connections by routing through a central node

Point-to-point(위) vs Hub-and-spoke(아래): 중앙 허브를 경유한 라우팅으로 연결 수를 획기적으로 줄입니다. 출처: Wikipedia (퍼블릭 도메인)

물류도 같은 원리입니다. FedEx는 모든 것을 멤피스를 경유하여 라우팅합니다. 타이베이에서 가오슝으로 가는 패키지가 먼저 멤피스를 경유할 수도 있습니다. 얼핏 불합리해 보이지만, 중앙 집중 분류가 지점 간 릴레이보다 효율적입니다.

그러나 전통적인 Hub-Spoke에는 치명적인 가정이 있습니다. Hub가 항상 온라인이라는 것입니다. 항공편은 허브 공항이 다시 열릴 때까지 기다릴 수 있습니다. 패키지는 분류 센터를 기다릴 수 있습니다. 그러나 대량 사상자 사건에서 Hub가 다운되면 환자는 기다릴 수 없습니다.

xGrid의 Hub-Spoke는 두 가지 핵심적 변경을 가합니다. 모든 Spoke는 단순한 터미널이 아닌 완전한 시스템입니다. 그리고 어떤 Spoke든 몇 분 안에 새로운 Hub로 승격할 수 있습니다.

물리적 레이아웃: 하나의 백본, 여러 위성

xGrid의 배치는 Ethernet 스위치를 중심으로 구축된 확장 가능한 토폴로지입니다:

                 ┌─────────────────────┐
                 │  Hub A               │
                 │  CIRS + MIRS + HIRS  │
                 │  WiFi Hotspot        │
                 │  mDNS broadcast      │
                 └──────────┬──────────┘
                            │
                  ┌─────────┴─────────┐
                  │  Ethernet Switch   │
                  └──┬────┬────┬────┬─┘
                     │    │    │    │
                  ┌──┴┐┌──┴┐┌──┴┐┌──┴┐
                  │ B ││ C ││ D ││ E │  ← Spokes
                  └───┘└───┘└───┘└───┘
                  각각 자체 WiFi 핫스팟 보유
                  각각 전체 MIRS 실행
                  각각 최신 CIRS 스냅샷 보관

Hub는 자원 시스템(CIRS), 임상 시스템(MIRS), 재고 관리(HIRS)를 실행합니다. Spoke들은 Ethernet 스위치를 통해 Hub에 연결되며, 각각 MIRS를 실행하여 자체 스테이션의 재고를 관리합니다.

설계에 의한 두 개의 독립된 네트워크 계층: 스테이션 간 데이터 동기화에는 Ethernet. 각 스테이션 내 임상 업무에는 WiFi. 하나가 장애를 일으켜도 다른 하나에 영향을 주지 않습니다.

모든 RPi는 완전한 시스템 — 골든 이미지

전체 아키텍처에서 가장 중요한 설계 결정입니다. 모든 Raspberry Pi에 모든 것이 사전 설치되어 있습니다.

CIRS(자원), MIRS(임상), HIRS(재고) 모두 모든 SD 카드에 존재합니다. 역할은 하드웨어가 아니라 단일 구성 파일 /etc/xgrid/role.conf로 결정됩니다. 하나의 필드를 변경하면 Spoke가 Hub가 됩니다.

"Hub 유닛"과 "Spoke 유닛"을 따로 비축할 필요가 없습니다. 동일한 예비품을 비축합니다. 어떤 유닛이든 다른 어떤 유닛이든 대체할 수 있습니다.

단계별 배치 — 전방 스테이션부터 의료 센터까지

단계구성연결동시 태블릿
의료 센터1 Hub + 4 Spoke8포트 스위치약 75
지역 병원1 Hub + 3 Spoke5포트 스위치약 60
구 병원1 Hub + 1 Spoke직접 케이블약 30
전방 스테이션1대 독립형필요 없음약 15

동일한 골든 이미지가 모든 단계에서 작동합니다. 차이는 배치하는 유닛 수와 할당하는 역할이지, 탑재된 소프트웨어가 아닙니다.

단절은 장애가 아닙니다 — 예상된 상태입니다

xGrid에서 네트워크 연결 손실은 임상 직원에게 보이는 어떤 것도 트리거하지 않습니다. 두 시스템 모두 완전한 기능으로 계속 운영됩니다. 자체 데이터베이스, 자체 임상 인터페이스, 자체 태블릿 스테이션.

기본 설계 원칙: 모든 Spoke는 완전한 시스템입니다. Hub는 능력이 아니라 조정을 제공합니다. 조정이 상실되어도 변경되는 것은 동기화 타이밍뿐입니다.

3단계 동기화

1단계 — 검증: Hub가 각 Spoke의 상태를 확인합니다. 30초 내 응답 없으면 건너뜁니다. 시계 정렬 확인으로 두 장치의 현재 시간이 일치하는지 확인합니다. 30초 이상 차이가 나면 타임스탬프 손상 방지를 위해 동기화가 거부됩니다.

2단계 — 푸시(Hub에서 Spoke로): 임상 이벤트가 외부로 흐릅니다. Hub는 5분마다 CIRS의 전체 스냅샷을 각 Spoke에 푸시합니다. 이 스냅샷은 각 Spoke에 로컬 저장됩니다. 최근 12개 사본으로 1시간의 롤링 백업 윈도우입니다.

3단계 — 풀(Spoke에서 Hub로): 자원 이벤트가 내부로 흐릅니다. 재고 변경, 혈액 은행 운영, 수술 기록, 불출 로그.

6가지 충돌 해결 전략

전략데이터 유형로직
양쪽 추가활력 징후, 인수인계, 불출 기록불변 이벤트 — 양쪽 버전 모두 보관
최신 우선환자 인적 사항타임스탬프 비교, 최신 업데이트 우선
Hub 우선등록, 처방, 수술 기록CIRS(Hub)가 권위 있는 정보원
양쪽 합산재고 수량양쪽 소비량을 합산
항상 차단혈액 제제, 규제 약물자동 해결 불가 — 인간 검증 필요
현장 우선장비 상태물리적으로 현장에 있는 운영자 우선

양쪽 합산(재고의 경우): Hub가 붕대 5개를 소비하고 Spoke가 3개를 소비했습니다. 정답은 "마지막에 업데이트한 쪽"이 아닙니다. 정답은 5 + 3 = 8개 소비입니다.

항상 차단(혈액 제제의 경우): 양쪽 스테이션에서 동시에 "발행됨"으로 표시된 혈액 단위는 어떤 자동 규칙으로도 해결할 수 없습니다. 누군가가 그 혈액 단위가 실제로 어디에 있는지 물리적으로 확인해야 합니다.

케이블을 뽑고 출발 — Spoke가 Hub로 승격

이것은 아키텍처 전체에서 가장 강력한 기능입니다.

대량 사상자 사건에서 1 Hub + 3 Spoke 배치를 운영하고 있습니다. 2시간 후 지휘관이 10킬로미터 떨어진 두 번째 사상자 수집 지점을 보고합니다. 지금 당장 그곳에 기능하는 의료 스테이션이 필요합니다.

Spoke 중 하나로 걸어갑니다. Ethernet 케이블을 뽑습니다. 배터리와 iPad와 함께 가방에 넣습니다. 새 현장으로 이동합니다. 전원을 연결합니다. SSH로 명령 하나를 실행합니다:

sudo xgrid-promote

승격 프로세스는 원자적 상태 머신입니다. 어떤 단계라도 실패하면 전체 작업이 롤백되며, 유닛은 Spoke 모드로 돌아갑니다.

성공하면 iPad가 새 WiFi 네트워크에 연결되고, PWA를 열면 원본 Hub의 환자 데이터를 담고 있는 완전히 작동하는 의료 스테이션이 표시됩니다. 데이터는 최대 5분 전의 것입니다.

Hub 다운 — 5분 이내 인수인계

모든 Spoke는 Hub의 하트비트를 30초마다 지속적으로 모니터링합니다. 3회 연속 실패(90초 침묵)가 빨간색 배너를 트리거합니다: "Hub offline."

운영자가 결정합니다: 어떤 Spoke가 인수인계합니까? 승격 스크립트가 latest.good 스냅샷을 로드합니다. 이것은 가장 최근에 검증된 백업을 항상 가리키는 심볼릭 링크입니다.

환자 데이터의 최대 손실은 5분입니다. 스냅샷 푸시 간격입니다.

왜 자동으로 승격하지 않습니까? 단절 환경에서 "Hub가 파괴되었다"와 "Ethernet 케이블이 느슨하다"를 구별할 수 없기 때문입니다. 자동 승격은 둘 다 자신이 리더라고 생각하는 두 개의 Hub를 만들 위험이 있습니다. 이것이 스플릿 브레인 상태입니다. 승격은 인간의 결정이어야 합니다.

스플릿 브레인 보호 — 신뢰가 아닌 Epoch

Spoke가 Hub로 승격될 때마다 role.conf의 epoch 카운터가 증가합니다. epoch는 모든 스냅샷, 모든 mDNS 브로드캐스트, 모든 동기화 핸드셰이크에 내장됩니다.

좀비 감지. Hub A(epoch 1)가 크래시하고 Spoke B가 승격합니다(epoch 2). 나중에 누군가 Hub A를 다시 연결합니다. 시작 시 네트워크를 스캔하여 epoch 2를 브로드캐스트하는 Hub를 발견합니다. 자신의 epoch 1보다 높으므로 Hub A는 자동으로 Spoke로 강등합니다.

Spoke 검증. Spoke가 서로 다른 epoch의 두 Hub를 발견하면 주황색 경고를 발생시키고, 사람이 모호성을 해결할 때까지 자동 재연결을 거부합니다.

클러스터 격리. 각 배치는 고유한 cluster_id를 가집니다. Spoke는 일치하는 cluster_id의 Hub만 수락합니다.

서비스 디스커버리 — 하드코딩된 IP 없음

xGrid는 avahi-daemon을 통한 mDNS(멀티캐스트 DNS)를 사용합니다. Hub가 시작되면 로컬 네트워크에서 _xgrid-hub._tcp를 브로드캐스트합니다. Spoke는 이 브로드캐스트를 수신합니다. 유효한 클러스터 ID와 더 높은 epoch를 가진 새 Hub를 감지하면 연결 대상을 자동으로 업데이트합니다.

구성 파일 업데이트 불필요. IP 주소 기억 불필요. 네트워크가 스스로를 기술합니다.

헤드리스 — iPad가 제어판

xGrid의 Raspberry Pi에는 모니터가 없습니다. 키보드도 없습니다. 모든 임상 업무는 WiFi를 통한 PWA로 이루어집니다. 시스템 관리는 SSH를 통해 수행합니다.

스테이션당 총 하드웨어: Raspberry Pi 1대, 전원 케이블 1개, Ethernet 케이블 1개(독립형이 아닌 경우). 배치 공간은 배낭 하나에 들어갈 정도로 작습니다.

스테이션 통합 — 현장 철수 시

4가지 병합 모드가 다양한 시나리오를 처리합니다:

  • 전체 병합: 모든 데이터가 대상 스테이션으로 흐름
  • 부분 병합: 선택된 자원 카테고리만 전송
  • 백업 가져오기: 포터블 백업에서 복원
  • 긴급 폐쇄: 완전한 데이터 보존을 동반한 스테이션 셧다운

각 병합은 무엇이 이동했는지 정확히 기록합니다. 이 감사 추적은 재난 후 반드시 제기되는 질문에 답합니다: "그 스테이션이 철수했을 때, 모든 것은 어디로 갔는가?"

단절을 전제로 한 설계

대부분의 분산 시스템은 "네트워크는 신뢰할 수 있다"는 전제에서 시작하고, 그렇지 않을 때를 위한 예외 처리를 추가합니다.

xGrid는 "네트워크는 신뢰할 수 없다"는 전제에서 시작하고, 우연히 작동할 때를 위해 최적화합니다.

이 반전이 근본적으로 다른 설계를 만들어냅니다:

  • 모든 노드가 완전한 시스템(서버에 의존하는 씬 클라이언트가 아님)
  • 모든 유닛에 전체 소프트웨어가 사전 설치(역할은 구성 파일이지 하드웨어 변형이 아님)
  • 어떤 Spoke든 Hub로 승격 가능
  • 동기화는 주기적 배치(실시간 스트리밍이 아님)
  • 충돌 해결이 기본 동작(예외 처리가 아님)
  • 오래된 Hub는 스스로 강등(epoch 카운터는 정책이 아니라 사실이므로)

케이블은 걷어차일 것입니다. 스위치는 테이블에서 떨어질 것입니다. Hub는 피해를 입을 것입니다.

이 중 어떤 것도 장애 모드가 아닙니다. 토폴로지 전환입니다.


관련 글: Offline-First Is Not a Fallback · ISBAR Is More Than a Handoff Format