단순한 것이 아름답다

1.
In defense of simple architectures을 번역한 글입니다. OpenML의 번역입니다. Geeknews에 올라온 단순한 아키텍처를 옹호하며 (2022)을 보고 마음에 들어서 번역한 글입니다.

마지막 문장이 마음에 듭니다.

By keeping our application architecture as simple as possible, we can spend our complexity (and headcount) budget in places where there’s complexity that it benefits our business to take on.

항상 드는 생각이지만 소프트웨어는 비지니스에 우선할 수 없습니다. 시스템이 존재하여야 하는 이유가 우선이고 소프트웨어는 이를 뒷받침하는 도구입니다. Geeknews에 올라온 서버리스 기술의 공포 사례들도 재미있습니다.

얼마전 페북에 올렸던 글입니다.

우연한 만남으로 방문한 생활지원센터….
디지탈도어락관리시스템을 운용하는 서버의 루트 패스워크를 모른다고 도와달라네요.
서버를 보니까 Centos 4입니다. 2010년에 설치한 시스템입니다. 관련 웹서비스를 실행하니까 돌아갑니다. 그런데 세션관리를 엉망으로 했는지 메뉴중 하나를 선택하니 새롭게 로그인하라고 합니다. 쩝….
건물이나 아파트 모두 다양한 시스템이 들어갑니다. 어느 곳도 IT엔지니어를 채용해서 관리할 생각을 하지 않습니다. 외주를 맡기면 된다고 하지만 외주업체가 망하면 ….
결국 일정한 시간이 지나면 아무도 모르는 시스템이 됩니다. 어찌보면 단순한 것이 오래갑니다. 자동화? 시간이 지나면 비용입니다..

무언가 새로운 것이 좋은 건 아닙니다. 단순한 것이 나쁜 건 아닙니다. 목표에 충실하면 최선의 선택입니다. 그래서 목표를 잘 나열하여야 합니다.

2.
단순한 아키텍처를 지키기 위해 | Patreon

Wave는 70명의 엔지니어1를 보유한 17억 달러 규모의 회사로, 숫자를 더하고 빼는 CRUD 앱이 주력 제품입니다. 이에 따라 당사의 아키텍처는 표준 CRUD 앱 아키텍처로, Postgres 위에 Python 모놀리스를 기반으로 합니다. 단순한 아키텍처로 시작하여 가능한 한 간단한 방법으로 문제를 해결한 덕분에 엔지니어들이 주로 사용자에게 가치를 제공하는 작업에 집중하는 동안 이 정도 규모로 확장할 수 있었습니다.

Stackoverflow는 모놀리스를 효과적으로 확장하여(2013년 아키텍처 / 2016년 아키텍처) 결국 18억 달러에 인수되었습니다. 시가총액 대신 트래픽을 기준으로 보면 Stackoverflow는 인터넷에서 가장 트래픽이 많은 100대 사이트 중 하나입니다(모놀리스 위에 세워진 가치 있는 기업의 다른 많은 사례는 이 트위터 스레드의 답글을 참조하세요). 저희는 모바일 앱이기 때문에 웹 트래픽이 많지 않지만, 웹사이트는 기본적으로 사람들이 앱을 찾기 위한 수단일 뿐이고 대부분의 사람들이 웹사이트를 통해 앱을 찾지도 않는데도 Alexa는 여전히 저희 웹사이트를 상위 75,000위 안에 들게 합니다).

지루한 데이터베이스 위에 단순한 모놀리스를 얹는 것이 부적절할 정도의 요구 사항을 가진 애플리케이션도 있지만, 대부분의 애플리케이션의 경우 트래픽이 상위 100위권인 사이트 수준에서도 컴퓨터는 충분히 빠르기 때문에 일반적으로 복잡한 아키텍처보다 더 저렴하고 쉽게 만들 수 있는 단순한 아키텍처로 트래픽이 많은 앱을 서비스할 수 있습니다.

단순 아키텍처의 비합리적인 효과에도 불구하고 대부분의 언론은 복잡한 아키텍처로 이동합니다. 예를 들어, 최근 한 일반 기술 컨퍼런스에서 복잡한 마이크로서비스 기반 아키텍처를 구축하거나 부작용에 대처하는 방법에 대한 강연은 6건이었지만, 단순한 모놀리스를 구축하는 방법에 대한 강연은 0건이었습니다. 양자 컴퓨팅에 대한 강연(1건)이 모놀리스에 대한 강연(0건)보다 더 많았습니다. 최근 SF에서 열린 기업 대상 컨퍼런스에서도 정교한 아키텍처의 복잡성을 다루는 강연은 두 자릿수였고, 단순한 모놀리스를 구축하는 방법에 대한 강연은 0건이었습니다. 지난번 그 컨퍼런스에 참석했을 때 인상적이었던 점은 단순한 아키텍처로 구축할 수 있는 소규모 애플리케이션을 사용하는 기업에서 일하는 많은 참석자가 컨퍼런스 서킷과 HN에서 유행하는 최신의 가장 정교한 기술을 모방하고 있었다는 점입니다.

저희 아키텍처는 너무 단순해서 아키텍처 다이어그램은 굳이 설명하지 않겠습니다. 대신 지루하지 않게 하기 위해 우리가 하는 몇 가지 지루한 일에 대해 설명하겠습니다.

우리는 현재 지루한 동기식 Python을 사용하고 있는데, 이는 네트워크 요청과 같은 I/O를 기다리는 동안 서버 프로세스가 차단된다는 것을 의미합니다. 이론상으로는 Python의 효율성을 높일 수 있는 비동기 프레임워크인 Eventlet을 사용해 보았지만, 버그가 너무 많아서 이벤트 대기로 인한 CPU 및 지연 시간 비용이 Eventlet 문제를 처리하기 위해 감수해야 하는 운영상의 고통에 비해 가치가 없다고 판단했습니다. 잘 알려진 다른 비동기 Python 프레임워크도 있지만, 이러한 프레임워크를 대규모로 사용하는 사용자들은 종종 이러한 프레임워크를 대규모로 사용했을 때 심각한 부작용을 보고합니다. 동기식 Python을 사용하면 네트워크 요청 중에 대기만 하는 CPU에 비용을 지불한다는 점에서 비용이 많이 들지만, 현재로서는 한 달에 수십억 건의 요청만 처리하기 때문에 Python처럼 느린 언어를 사용하고 퍼블릭 클라우드 가격을 지불하더라도 비용이 적게 듭니다. 엔지니어링 팀의 비용이 우리가 운영하는 시스템의 비용을 완전히 지배합니다.

모놀리스를 비동기로 만드는 복잡한 작업을 수행하는 대신 응답을 차단하지 않으려는 장기 실행 작업을 대기열에 팜아웃합니다.

우리가 원하는 만큼 지루할 수 없는 곳은 온프레미스 데이터센터입니다. 세네갈과 코트디부아르에서만 운영할 때는 전적으로 클라우드에서 운영했지만, 우간다(그리고 앞으로 더 많은 국가로 확장할 예정)로 확장하면서 현지 데이터 보존 법규를 준수하기 위해 백엔드를 분할하고 온프레미스에 배포해야 합니다. 간단한 작업은 아니지만, 복잡한 서비스 지향 아키텍처로 같은 작업을 해본 사람이라면 누구나 알겠지만, 이 작업은 복잡한 서비스 지향 아키텍처를 사용했을 때보다 훨씬 간단합니다.

또 다른 영역은 구매가 아닌 직접 구축해야 하는 소프트웨어입니다. 처음 시작할 때는 엔지니어 몇 명으로 구성된 팀에서 모든 것을 구축하는 데 드는 시간적 비용을 감당할 수 없었기 때문에 소프트웨어를 구축하는 것보다 구매하는 것을 선호했습니다. ‘구매’ 옵션은 일반적으로 작동하지 않는 도구를 제공하지만 당시에는 올바른 선택이었습니다. 공급업체가 우리에게 중요한 장애물이 되는 눈에 띄는 버그를 수정할 수 없다고 확신할 수 없는 경우에는 회사가 핵심 역량 분야에서만 “구축”을 선택해야 한다는 일반적인 조언과 달리 자체 도구를 더 많이 구축하고 더 많은 영역에서 사내 전문성을 유지하는 것이 합리적입니다. 이러한 복잡성의 대부분은 우리가 감당하고 싶지 않은 복잡성이지만, 일부 제품 카테고리에서는 상당히 광범위한 조사 후에도 우리에게 적합한 제품을 제공할 수 있는 공급업체를 찾지 못했습니다. 공정하게 말하자면, 공급업체는 모든 고객의 문제를 해결해야 하는 복잡성을 떠안고 있는 반면 우리는 한 고객, 즉 우리 자신의 문제만 해결하면 되기 때문에 공급업체가 해결해야 하는 문제는 우리가 해결해야 하는 문제보다 훨씬 더 복잡합니다.

운영 초기 몇 달 동안 저지른 실수 중 현재 비용이 발생하고 있는 것은 데이터베이스 트랜잭션의 경계를 신중하게 구분하지 않은 것입니다. Wave의 코드베이스에서 SQLAlchemy 데이터베이스 세션은 요청-글로벌 변수로, DB 객체의 속성에 액세스할 때마다 암시적으로 새 데이터베이스 트랜잭션을 시작하며, Wave 코드베이스의 모든 함수는 세션에서 커밋을 호출하여 보류 중인 모든 업데이트를 커밋하도록 만들 수 있습니다. 이로 인해 데이터베이스 업데이트가 발생하는 시간을 제어하기가 어려워져 미묘한 데이터 무결성 버그 발생률이 높아질 뿐만 아니라 데이터베이스에 의존하여 비활성 키 또는 트랜잭션 단계별 작업 드래그와 같은 것을 구축하기가 더 어려워집니다. 또한 실수로 장기간 실행 중인 데이터베이스 트랜잭션을 열어두게 될 위험이 높아져 스키마 마이그레이션이 운영상 어려워질 수 있습니다.

(변경을 고려 중이거나 다른 접근 방식을 고려하기 위해 처음부터 시작하는 다른 팀에게 권장할 만한 선택이라는 점에서) 확실하지 않은 몇 가지 선택은 RabbitMQ 사용(우리의 목적상 Redis가 작업 큐와 똑같이 잘 작동할 것이며 Redis만 사용하면 운영 부담을 줄일 수 있음), Celery 사용(우리 사용 사례에는 너무 복잡하고 여러 번의 중단과 관련이 있음). 버전 업그레이드 중 이전 버전과의 호환성 문제로 인해), SQLAlchemy 사용(개발자가 코드가 어떤 데이터베이스 쿼리를 생성할지 이해하기 어려워 디버깅이 어렵고 불필요한 운영상의 고통, 특히 데이터베이스 트랜잭션 경계에 관한 위의 지적과 관련된 다양한 상황을 초래), Python 사용(창립 CTO의 기술적 배경 때문에 초기에는 올바른 선택이었지만 동시성 지원, 성능 및 광범위한 동적 기능으로 인해 대규모 백엔드 코드베이스에 적합한 선택인지 의문을 갖게 되었습니다) 등이 있습니다. 이 중 어느 것도 큰 실수는 아니었고, 일부(예: Python)의 경우 단점이 미미하여 이론적으로 더 나은 것으로 마이그레이션하는 데 투자하는 것보다 늘어난 유지보수 부담을 계속 지불하는 것이 더 저렴하지만, 지금 비슷한 코드베이스를 처음부터 다시 시작한다면 이것이 올바른 선택인지에 대해 깊이 생각해 볼 것입니다.

가장 간단한 솔루션처럼 들리지는 않지만 우리의 선택에 만족하는 몇 가지 영역은 GraphQL을 사용하는 API, 한동안 사용자 정의 프로토콜을 사용했던 전송 프로토콜, Kubernetes를 사용하는 호스트 관리입니다. 전송 프로토콜의 경우, 이 강연에서 설명한 성능상의 이유로 UDP 기반에서 실행되는 사용자 정의 프로토콜과 SMS 및 USSD 폴백을 사용했습니다. HTTP/3이 출시되면서 사용자 정의 프로토콜을 HTTP/3으로 대체할 수 있게 되었고, 일반적으로 최근 말리에서 발생한 인터넷 중단과 같은 이벤트에 대해서만 USSD가 필요합니다.

GraphQL 사용의 경우, 저희는 단점보다 장점이 더 크다고 생각합니다:
장점

정확한 반환 유형에 대한 자체 문서화
정확한 반환 유형의 코드 생성으로 클라이언트가 더 안전해집니다.
GraphiQL 대화형 탐색기는 생산성 향상에 도움이 됩니다.
다양한 앱(사용자 앱, 지원 앱, Wave 에이전트 앱 등)이 대부분 하나의 API를 공유하여 복잡성을 줄일 수 있습니다.
구성 가능한 쿼리 언어를 통해 클라이언트는 많은 수의 특수 목적 엔드포인트를 구축할 필요 없이 단일 패킷 왕복으로 필요한 데이터를 정확하게 가져올 수 있습니다.
RESTful API로 간주되는 항목에 대한 바이크쉐딩 제거

단점:
GraphQL을 도입할 당시 GraphQL 라이브러리는 좋지 않았습니다(기본 Python 라이브러리는 Python이 아닌 Javascript의 포트로, Graphene은 많은 상용구가 필요했고, Apollo-Android는 매우 최적화되지 않은 코드를 생성했습니다).
기본 GQL 인코딩은 중복적이며 많은 고객들의 대역폭이 낮기 때문에 크기를 제한하는 데 많은 신경을 썼습니다.

Kubernetes의 경우, 비즈니스가 성공하고(실제로 성공했고) 계속 확장하면 결국 서비스를 해당 국가에서 운영해야 하는 국가로 확장할 수 있다는 것을 알고 있었기 때문에 Kubernetes를 사용했습니다. 정확한 규정은 국가마다 다르지만, 이미 아프리카의 한 주요 시장으로 확장하고 있는데, 해당 국가에서 ‘기본 데이터센터’를 운영해야 하는 규정이 있고, 다른 국가에서는 해당 국가에 있는 데이터센터로 페일오버할 수 있어야 하는 규정이 있는 곳도 있습니다.

우리에게 피할 수 없는 복잡성이 있는 영역은 통신 통합입니다. 이론적으로는 모든 것을 SaaS SMS 제공업체를 이용하면 되지만, 주요 SaaS SMS 제공업체가 아프리카의 모든 곳에서 운영되는 것은 아니며 모든 곳에서 사용하려면 비용이 엄청나게 많이 들 것입니다3. 앞서 엔지니어의 보상 비용이 시스템 비용의 대부분을 차지한다는 언급은 모든 SMS 요구 사항에 대해 SaaS SMS 제공업체를 사용하면 통신 통합을 제공하는 팀이 몇 배의 비용을 지불하기 때문에 사실이 아닙니다.

애플리케이션 아키텍처를 가능한 한 단순하게 유지하면 복잡성(및 인력) 예산을 비즈니스에 도움이 되는 곳에 투자할 수 있습니다. 복잡성을 추가할 강력한 이유가 없는 한 가능한 한 단순하게 하자는 생각 덕분에 일반적으로 진입하기 어려운 사업으로 여겨지는 아프리카 금융 사업을 운영하면서도 많은 엔지니어 없이도 상당히 큰 규모의 비즈니스를 구축할 수 있었습니다(향후 포스트에서 설명할 예정입니다). Wave의 성공에 중요한 조언을 해준 초창기 가장 도움이 되었던 고문 중 한 명은 처음에는 Wave가 나쁜 사업 아이디어이며 많은 잠재적 어려움을 예견했으므로 창업자들이 다른 사업을 선택하는 것이 좋겠다고 조언했습니다.

Leave a Comment

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.