"Glue Code" 위기: 분산 워크플로 오케스트레이션이 어려운 이유
SchemaBridge Team · 2025-12-01 · Distributed Systems, Architecture, DevOps
API 배관 작업에 엔지니어링 시간을 낭비하지 마세요. 2026년, 분산 워크플로 오케스트레이션이 파편화된 시스템을 확장하는 열쇠인 이유를 알아봅니다.
아키텍처 병목: 생산성을 조용히 죽이는 것
시니어 개발자나 아키텍트라면 이 사이클을 겪어 봤을 것입니다. 처음에는 Shopify 주문을 레거시 ERP와 동기화하는 것 같은 "간단한" 연동으로 시작합니다. 50줄짜리 스크립트를 작성하고, Lambda나 cron 작업으로 감싸서 배포합니다. 첫날에는 잘 동작합니다. 열흘째에도 잘 동작합니다. 그런데 세상이 바뀝니다. Shopify API에 레이트 리밋이 추가됩니다. 레거시 ERP는 새벽 2시에 데이터베이스 락 경합을 일으킵니다. 외부 배송 업체가 JSON 응답 구조를 변경합니다.
어느새 그 "간단한 스크립트"는 미션 크리티컬한 인프라가 되어 있습니다. 하지만 그것은 인프라처럼 만들어지지 않았습니다. 스크립트처럼 만들어졌습니다. 제대로 된 에러 처리가 없고, 상태라는 개념을 이해하지 못하며, 내장된 복원력도 없습니다. 실패할 때는 조용히 실패하거나, 더 나쁘게는 부분적으로 실패해서 데이터를 손상된 상태로 남겨 두고, 이를 바로잡는 데 며칠의 수작업이 듭니다.
3개월 후, 그 50줄짜리 스크립트는 5,000줄짜리 괴물로 변이해 있습니다. 이제 재시도를 (무한 루프와 함께, 형편없이) 처리하고, 세 군데에 로그를 남기며(그중 한 곳은 꽉 찼습니다), 실제 에러를 감추는 중첩된 try-except 블록을 품고 있습니다. 이런 스크립트 20개가 인프라 곳곳에서 돌아가고 있습니다. 이것이 조직의 "Glue Code"입니다. 이것은 엔지니어링이 아니라 사후 대응식 배관 공사입니다.
이것이 바로 Glue Code 위기입니다. 엔지니어링 속도를 조용히 죽이는 원인입니다. 더 이상 비즈니스를 움직이는 기능을 만드는 것이 아니라, 데이터가 새고, 부하가 걸리면 막히고, 새벽 3시에 터져서 최고의 엔지니어들을 깨우는 알림을 울리는 취약한 "파이프"를 만들고 유지보수하고 있는 것입니다. 파편화된 마이크로서비스와 끝없는 SaaS API의 세계에서 내구성 있는 오케스트레이션 전략이 없다면, 그것은 속건성 시멘트 위에 집을 짓는 것과 같습니다. 일주일 동안은 견고해 보이지만, 균열은 피할 수 없습니다.
위기의 역사적 뿌리: CGI-BIN에서 클라우드까지
왜 이런 위기에 처했는지 이해하려면 소프트웨어 통합의 역사를 살펴봐야 합니다. 1990년대에는 CGI 스크립트와 Perl이 있었습니다. 요청을 응답으로 변환하는 작고 상태 없는 명령이었습니다. 이것이 원조 "Glue Code"였습니다. 당시로서는 훌륭했지만, 현대 디지털 비즈니스의 여러 단계, 여러 날에 걸친 여정을 처리하도록 만들어진 것은 결코 아니었습니다. 아직 항상 연결되어 있지도, 전 세계적으로 연결되어 있지도 않은 세상을 위한 "실행하고 잊어버리는(fire and forget)" 도구였습니다.
2000년대에는 Tibco나 BizTalk 같은 거대하고 무거운 미들웨어인 ESB(Enterprise Service Bus)로 옮겨 갔습니다. 강력했지만 믿을 수 없을 만큼 복잡하고 비쌌습니다. 모든 것을 중앙화하려 한 결과 "버스 아키텍트"가 병목이 되었습니다. 변경할 때마다 위원회 회의가 필요했습니다. 버스는 결국 자신이 해결하려던 바로 그 문제, 즉 단일 장애 지점이자 거대한 조직적 마찰의 원천이 되었습니다.
2010년대에는 ESB를 버리고 마이크로서비스를 택했습니다. REST API와 가벼운 스크립트(Python, Go, Node.js)로 옮겨 갔습니다. 자유를 얻었다고 생각했습니다. 하지만 실제로 한 일은 복잡성을 "버스"에서 "서비스 사이의 공간"으로 옮긴 것뿐이었습니다. 하나의 무거운 미들웨어를 환경 곳곳에 흩어진 수천 개의 작고 취약한 스크립트로 바꿔 놓았습니다. 이제 우리는 복잡성이 서비스 수에 대해 O(N^2)로 증가하는 세상에 살고 있습니다. 중앙 집중식 병목을 분산된 혼돈과 맞바꾼 것입니다.
스크립트의 심리학: 왜 우리는 계속 취약한 길을 선택하는가
왜 우리는 계속 스크립트를 작성할까요? 분산 시스템의 함정을 잘 아는 시니어 엔지니어조차 "내구성 있는 오케스트레이터"보다 "간단한 스크립트"에 손을 뻗는 경우가 많습니다. 그 이유는 심리적인 것입니다.
1. "빠른 성과"라는 오류
비즈니스 이해관계자가 새로운 연동을 요청할 때, 그들은 그것을 "어제" 원합니다. 스크립트는 빠르게 느껴집니다. 한 시간이면 작성할 수 있습니다. 생산적이라고 느낍니다. "체크박스를 채웁니다". 하지만 이것은 가짜 생산성입니다. 미래의 역량을 담보로 고금리 대출을 받는 것입니다. 오늘 아낀 시간은 다음 달 프로덕션의 부분 장애를 디버깅하느라 몇 배로 되돌아옵니다. 스크립트는 장기적인 안정성보다 단기 지표를 중시하는 엔지니어링 매니저에게 중독성 있는 마약입니다.
2. 분산 시스템의 더닝-크루거 효과
많은 개발자는 "재시도는 쉽다"고 믿습니다. API 호출을 sleep 타이머가 있는 while 루프로 감싸면 충분하다고 생각합니다. 실제 프로덕션 환경에서 일어나는 재시도 폭풍(Retry Storm), 고아가 된 아이덴티티(Orphaned Identity), 상태 손상(State Corruption)을 아직 겪어 보지 못한 것입니다. 장애를 다루는 자신의 능력에 대해 "부풀려진 기대의 정점"에 서 있는 셈입니다. 새벽 3시의 첫 대형 장애를 겪고 나서야 분산 상태가 인프라 수준의 해법이 필요한 문제라는 것을 깨닫게 됩니다.
3. 더 나은 작업 단위의 부재
최근까지 우리에게는 오케스트레이션을 위한 표준 작업 단위가 없었습니다. "함수"와 "서비스"는 있었지만 "여정(Journey)"은 없었습니다. SchemaBridge는 그 작업 단위로 Durable Workflow를 도입합니다. 여러 단계로 이루어진 여정을 상태가 영속화되는 하나의 엔티티로 표현할 수 있으므로, 워커가 크래시되거나 재시작되어도 여정을 잃는 대신 진행 중이던 단계를 다시 가져옵니다.
실패의 해부학: 왜 "스크립트"는 확장되지 않는가
사용자 10명에게 동작하는 스크립트가 10,000명에서 실패하는 데에는 분산 시스템의 본질에 내재된 세 가지 주요 이유가 있습니다. 이 문제들은 "더 좋은 코드"만으로는 해결할 수 없으며, 인프라로 해결해야 합니다.
1. 부분 성공 문제: "설익은" 상태
분산 시스템에서 성공은 이분법적이지 않습니다. 스크립트가 세 단계를 수행한다고 해 봅시다. 1) Stripe로 고객에게 결제를 청구합니다. 2) 내부 재고 데이터베이스를 업데이트합니다. 3) SendGrid로 확인 이메일을 보냅니다. 1단계 이후에 프로세스가 크래시되면 어떻게 될까요?
고객에게는 결제가 청구되었지만, 재고는 여전히 "재고 있음"으로 표시되어 있고, 사용자는 영수증을 받지 못했습니다. 이를 순수 코드로 해결하려면 복잡한 Saga 패턴을 직접 작성해야 합니다. 사실상 스크립트마다 미니 오케스트레이터를 작성하는 셈입니다. 결제가 이루어졌는지 확인하고, 재고 상태를 확인하고, 롤백을 처리해야 합니다. 이 보일러플레이트가 결국 개발 시간의 대부분을 차지하고, 분산 상태는 어렵기 때문에 그래도 가끔은 틀립니다.
2. 멱등성 격차: 재시도의 위험
연결은 불안정합니다. 스크립트가 API의 타임아웃을 잡아 재시도합니다. 그런데 API는 실제로 성공했고, 타임아웃된 것은 응답뿐이었다면요? 멱등성이 없으면 재시도는 이중 결제나 중복 배송으로 이어집니다. 대부분의 "Glue Code" 개발자는 고객에게 500달러 대신 5,000달러가 청구되는 첫 사고가 날 때까지 이 문제를 무시합니다.
수십 개 서비스에 걸친 모든 API 호출에 멱등성 키를 붙이는 일은 일관되게 해내는 팀이 거의 없는 물류적 부담입니다. 연동이 100개라면 키를 빠뜨릴 곳도 100곳입니다. 오케스트레이션 엔진은 이 부담의 일부를 덜어 줄 수 있지만, 어느 부분인지는 정확히 알아야 합니다. SchemaBridge는 인바운드 트리거를 (페이로드의 콘텐츠 해시나 사용자가 제공한 키로) 중복 제거하므로, 공급자가 같은 웹훅을 다시 보내도 같은 여정이 두 번 시작되지 않습니다. 그러나 아웃바운드 부수 효과는 at-least-once로 실행됩니다. 즉, 크래시 후 단계가 다시 실행될 수 있습니다. 멱등하지 않은 대상에 대해서는 안정적인 비즈니스 필드(주문 ID, payment intent 등)에서 도출한 멱등성 키를 호출 자체에 전달하세요.
여덟 가지 오류: 실패의 토대
Glue Code가 왜 실패하는지 제대로 이해하려면, Sun Microsystems의 Peter Deutsch 등이 처음 정리한 분산 컴퓨팅의 여덟 가지 오류(Fallacies of Distributed Computing)로 돌아가야 합니다. 이것들은 모든 개발자가 네트워크 코드를 처음 작성할 때 하는 잘못된 가정입니다. 엔지니어링의 "거짓 낙원"이라 할 수 있습니다.
1. 네트워크는 신뢰할 수 있다: 그렇지 않습니다. 패킷은 유실되고, 라우터는 재부팅되며, 케이블은 끊깁니다. 클라우드 환경에서는 규모가 커지면 간헐적인 네트워크 장애가 매일 발생한다고 예상해야 합니다.
2. 지연 시간은 0이다: 그렇지 않습니다. 가장 빠른 글로벌 광섬유 네트워크조차 수천 번의 호출에 걸쳐 누적되는 밀리초 단위의 지연을 만듭니다. 이 지연은 들쭉날쭉하고 예측할 수 없어서, 로컬에서 디버깅하려고 하면 사라지는 경쟁 조건을 일으킵니다.
3. 대역폭은 무한하다: 그렇지 않습니다. 큰 페이로드는 파이프를 막고 타임아웃을 유발합니다. 클라우드 공급자에게는 엄격한 대역폭 할당량도 있어서, 경고 없이 "Glue Code"를 스로틀링합니다.
4. 네트워크는 안전하다: 그렇지 않습니다. 중간자 공격, DNS 포이즈닝, 유출된 토큰은 상존하는 위협입니다. 제대로 격리되지 않은 "Glue Code" 스크립트는 자격 증명 탈취의 주요 표적입니다.
5. 토폴로지는 변하지 않는다: 변합니다. 로드 밸런서는 이동하고, 노드는 죽고, IP 주소는 재활용됩니다. 스크립트의 "하드코딩된 IP"는 시한폭탄입니다.
6. 관리자는 한 명이다: 그렇지 않습니다. 여러분은 AWS, Cloudflare, 그리고 스택의 모든 SaaS 공급자에게 좌우됩니다. 그들이 API를 바꾸면 가장 먼저 희생되는 것은 여러분의 스크립트입니다.
7. 전송 비용은 0이다: 그렇지 않습니다. 대규모로 JSON을 직렬화하고 역직렬화하는 데에는 실제 CPU와 메모리 비용이 듭니다. 스크립트는 json.loads()에서 페이로드를 파싱하고 다시 파싱하는 데에만 놀라울 만큼 많은 시간을 쓸 수 있습니다.
8. 네트워크는 균질하다: 그렇지 않습니다. 스택은 Linux, Windows, JVM, Node, 레거시 SOAP 서비스가 뒤섞여 있습니다. 이런 환경에서 고정된 동작을 기대하는 것은 망상입니다.
기술 심층 분석: 이벤트 소싱과 영속성 확장성
내구성 있는 오케스트레이션 엔진을 구축할 때 가장 어려운 부분 중 하나는 상태의 영속성을 관리하는 것입니다. 대량의 워크플로가 동시에 실행되고 각 워크플로가 많은 단계를 수행하면, 영속성 계층에 걸리는 쓰기 부하가 빠르게 증가합니다.
데이터베이스 병목
순진한 스키마, 즉 단계마다 전체 상태로 다시 쓰이는 넓고 변경 가능한 workflow_history 행은 결국 이 부하를 견디지 못합니다. 핫 로우(hot row)에 대한 인덱스와 락 경합이 주요 병목이 되기 때문입니다. SchemaBridge는 PostgreSQL 위에서 이 문제를 둘로 나눕니다. 변경되는 작은 현재 상태 레코드와, 늘어나기만 하는 이력입니다.
1. 작고 보호된 상태 행: 각 실행과 각 단계의 현재 상태는 compare-and-set 방식의 조건부 쓰기로 업데이트되는 간결한 상태 행에 저장됩니다(다른 누구도 먼저 가져가지 않은 경우에만 단계가 DISPATCHED에서 EXECUTING으로 전환됩니다). 큰 페이로드는 이 행에서 완전히 분리되어 SeaweedFS(S3 호환) 오브젝트 스토어로 오프로드되며, 단계 간 작업 전달은 Valkey Streams가 담당합니다.
2. 추가 전용(append-only) 실행 트레이스: 각 단계는 불변의 트레이스 레코드도 추가하므로, 실행의 단계별 기록을 얻을 수 있습니다. 트레이스 테이블은 월 단위로 시간 파티셔닝되어 있어, 보존 기간이 지난 오래된 파티션은 행 단위로 삭제하는 대신 저렴하게 폐기됩니다.
3. 재수화(rehydration) 없는 크래시 복구: 현재 상태가 영속적이므로 워커가 이를 메모리에서 다시 구성할 필요가 없습니다. 워커가 단계 도중에 죽으면 해당 단계의 클레임이 만료되고, 다른 워커가 이를 다시 가져가 재실행합니다. 이것이 at-least-once 실행이며, 바로 그렇기 때문에 앞서 설명한 아웃바운드 멱등성에 관한 조언이 중요합니다.
거버넌스 격차: 배관은 누구의 것인가?
기술적 과제 너머에는 문화적 과제가 있습니다. 바로 거버넌스 격차입니다. 전통적인 마이크로서비스 아키텍처에서 소유권은 사일로화되어 있습니다. "Product Service" 팀은 제품 데이터베이스를 소유합니다. "Shipping Service" 팀은 FedEx 연동을 소유합니다.
그렇다면 그 사이의 다리는 누구의 것일까요?
대개는 아무의 것도 아닙니다. "Glue Code" 스크립트는 빠른 수정이 필요했던 개발자가 작성하고 나서 방치됩니다. 문제가 생기면 Product 팀은 Shipping 팀을 탓하고, Shipping 팀은 API 공급자를 탓합니다. 비즈니스 프로세스가 실제로 어떻게 연결되어 있는지에 대한 중앙의 "단일 진실 공급원(Source of Truth)"이 없습니다.
SchemaBridge는 연동을 전사적 자산으로 만들어 이 문제를 해결합니다.
- 공유 앱: 중앙 팀(DevOps 또는 Platform Engineering)이 Stripe나 Salesforce용 워크스페이스 앱(기본 URL, 인증, 시크릿 참조)을 정의하면 모든 팀이 이를 재사용할 수 있습니다. 개별 개발자는 연결을 다시 구현하는 대신 그 앱을 자신의 그래프에 끌어다 놓기만 하면 됩니다.
- 가시적인 소유권: 로직이 시각적이므로 보안 팀이 감사하고 프로덕트 오너가 검토할 수 있습니다. 연동은 더 이상 숨겨진 스크립트가 아니라, 공개적으로 드러나 있는 가시적이고 관리되는 비즈니스 프로세스입니다.
생물학적 비유: 신경계로서의 소프트웨어
우리는 소프트웨어가 더 이상 정적인 도구의 모음이 아니라 살아 있는 신경계가 되는 세상으로 나아가고 있습니다. 생물학적 신경계에서 신호는 손가락(센서)에서 뇌(로직)로 이동했다가 근육(행동)으로 돌아옵니다. 경로 일부가 막히면 시스템은 적응합니다. 반사 작용이 있고, 기억이 있습니다.
내구성 있는 오케스트레이션은 기업의 신경계입니다. 파편화된 서비스들이 하나의 응집된 유기체처럼 작동하게 해 줍니다.
1. 반사 작용: 백오프가 적용된 자동 재시도가 작은 "통증"(일시적인 5xx, 레이트 리밋 응답, HTTP 호출 중 끊긴 연결)을 뇌(개발자)를 개입시키지 않고 흡수합니다.
2. 기억: 실행 상태가 영속화되므로, 재시작 후에도(클러스터 전체 재시작이라도) 진행 중이던 단계는 잊히지 않고 다시 가져와 재실행됩니다. 이 재실행은 at-least-once이므로, 부수 효과는 여전히 대상 쪽에서 멱등해야 합니다.
3. 인지: 시각적 관측성(관측성 격차 참고)을 통해 각 실행을 실시간으로 볼 수 있습니다. 어떤 단계가 실행 중인지, 어떤 단계가 실패했는지, 그리고 어떤 페이로드가 들어오고 나갔는지 확인할 수 있습니다.
예시 시나리오: 조용한 대사(reconciliation) 붕괴
이 위기의 심각성을 이해하기 위해, 대규모 Python 스크립트 모음을 사용해 내부 원장과 여러 제휴 은행 API 간의 일일 거래를 대사하는 핀테크 기업을 생각해 봅시다.
장애
어느 금요일, 한 제휴 은행이 대사 API의 인증 방식을 변경했다고 가정해 봅시다. Python 스크립트는 크래시되지 않습니다. 단지 거부당하고, 예외를 잡고, 그날의 대사를 "조용히" "Pending"으로 표시할 뿐입니다. 시각적인 대시보드가 없기 때문에 장애는 며칠 동안 아무도 모릅니다.
누군가 마침내 들여다봤을 때는 원장과 은행 사이에 크고 점점 커지는 불일치가 쌓여 있습니다. 감사인이 투입되고, 경영진에게 보고되며, 엔지니어링 팀은 대사 타임라인을 수작업으로 재구성하는 데 며칠을 써야 합니다. 스크립트는 "해피 패스"에서는 완벽하게 동작했지만, "자가 치유" 능력도 "시각적 진실"도 전혀 없었습니다.
SchemaBridge 대안
이제 같은 대사 로직이 SchemaBridge에서 실행된다고 상상해 보세요. 비슷한 인증 변경이 발생하면 Gateway vertex(은행으로의 아웃바운드 HTTP 호출)가 실패하고, 실행은 모니터에서 빨간색으로 바뀌며 실패한 단계에는 거부된 응답이 첨부됩니다. SchemaBridge가 스스로 누군가를 호출하지는 않지만, 팀은 이 상황이 눈에 확실히 띄도록 만들 수 있습니다. Gateway의 clientErrorMode를 complete로 설정하면 거부된(4xx) 호출은 invalid_input 결과가 되고, 이를 기준으로 라우팅해 곧바로 Slack 알림 단계로 보낼 수 있습니다. 어느 쪽이든 장애는 며칠 뒤가 아니라 당일에 드러납니다. 팀은 자격 증명을 수정하고, 실패한 단계에서 Retry(재시도)를 클릭하면 대사는 수작업으로 재구성되는 대신 멈췄던 지점부터 다시 진행됩니다.
오류 없는 오케스트레이션을 위한 추천 자료
내구성 있는 실행의 기술을 익히고 싶다면, 다음의 엄선된 읽을거리를 추천합니다.
- Designing Data-Intensive Applications: Martin Kleppmann 저. 현대 분산 시스템의 바이블입니다.
- Saga 패턴 백서: 오늘날에도 분산 트랜잭션을 정의하는 1987년의 원조 연구입니다.
- Reactive Design Patterns: Roland Kuhn 저. 복원력 있는 메시지 기반 아키텍처를 구축하는 데 필수적입니다.
- Distributed Systems for Fun and Profit: Mikito Takada의 필수 웹 가이드입니다.
- SchemaBridge 문서: Gateway 및 Spawner 패턴에 대한 저희의 심층 분석입니다.
결론: 아키텍트의 새로운 사명
Glue Code 위기는 전환기의 증상입니다. 우리는 "사일로와 스크립트"의 세계에서 "연결된 생태계"의 세계로 이동하고 있습니다. 이 새로운 세계에서는 서비스 간의 연결이 서비스 자체만큼이나 중요합니다.
아키텍트로서 여러분의 사명은 더 이상 신뢰할 수 있는 서비스를 만드는 것에 그치지 않습니다. 신뢰할 수 있는 연결을 만드는 것입니다. Glue Code는 신뢰성의 정반대입니다. 임시방편의 패치가 결국 영구적인 짐이 됩니다. 이제 취약한 파이프를 만드는 일을 멈추고 디지털 신경계를 만들기 시작할 때입니다.
SchemaBridge 같은 내구성 있는 오케스트레이션 엔진을 도입하면 엔지니어링의 미래를 되찾을 수 있습니다. 자신의 상태를 인식하고, 장애에 강하며, 조직 전체가 볼 수 있는 시스템을 구축하게 됩니다. 이것이 속도를 되찾고 오래가는 시스템을 만드는 방법입니다.
이 글은 Building the Bridge 시리즈의 일부입니다. 함께 읽어 보세요: 속도를 위한 설계: 스키마리스 이벤트 수집을 지지하는 이유 — 이벤트 수집에 대한 레이트 바인딩 접근 방식.