분산 시스템

34 개의 포스트

figma3분 읽기큐레이션 요약

딥 서치 심층 분석 | 피

Figma의 Deep Search는 파일명이나 폴더명을 몰라도 파일 내부의 텍스트와 내용을 검색할 수 있도록 만든 기능이다. 일반 검색이 데이터베이스의 메타데이터를 색인하는 것과 달리, Deep Search는 S3에 저장된 `.fig` 파일을 직접 읽고 객체 트리를 순회해야 한다. 이를 위해 기존 Design System Analytics 인프라를 확장하고, 처리 비용과 최신성 사이에서 타협해 변경 사항을 시간 단위로 모아 색인하는 방식을 선택했다. ## 브라우저 기반 제품이 제공하는 검색 가능성 - Figma는 데스크톱 애플리케이션이 아닌 브라우저 기반 도구이므로, 사용자가 접근할 수 있는 파일에 대한 풍부한 정보를 수집하고 분석할 수 있다. - 파일의 조회 빈도, 컴포넌트 사용량, 파일 구조 등 웹 환경에 적합한 데이터를 활용할 수 있다. - 이러한 특성은 협업을 강화한다. - 별도 파일을 내보내지 않아도 이해관계자가 진행 중인 작업을 확인할 수 있다. - 프로토타입 공유와 핸드오프가 간소화된다. - 작업 중인 결과물을 쉽게 공유할 수 있다. - Deep Search는 파일명보다 프로젝트의 아이디어, 문구, 해결하려던 문제를 기억하는 사용자의 검색 방식에 맞춘 기능으로 기획됐다. ## Design System Analytics에서 얻은 기술적 기반 - Figma는 앞서 Design System Analytics(DSA)를 출시해 팀 간 디자인 시스템과 공유 라이브러리의 사용 현황을 분석했다. - DSA와 Deep Search 모두 다음과 같은 공통 처리가 필요했다. - 최근 수정된 파일을 식별한다. - 스토리지에서 파일을 내려받는다. - 파일 내부를 순회한다. - 목적에 맞는 정보를 추출한다. - DSA는 공유 라이브러리 사용량을 추출하고, Deep Search는 파일 내부의 텍스트를 추출한다. - Figma는 DSA를 위해 만든 파일 분석 인프라와 워커를 일반화해 Deep Search의 기반으로 활용했다. ## 일반 검색의 색인 파이프라인 - 기존 Unified Search를 포함한 일반 검색은 데이터베이스에 저장된 메타데이터를 대상으로 한다. - 예시로 파일 ID, 폴더 ID, 팀 ID, 파일명, 폴더명, 생성자 등의 정보를 사용한다. - 처리 과정은 다음과 같다. - 데이터베이스의 관련 테이블 변경 사항을 감시한다. - 변경된 항목의 ID를 메시징 시스템으로 전달한다. - 검색 색인기가 최신 데이터를 데이터베이스에서 가져온다. - 가져온 메타데이터를 Elasticsearch 클러스터에 색인한다. - 데이터베이스 조회는 비교적 저렴하기 때문에 변경될 때마다 빠르게 색인을 갱신할 수 있다. ## Deep Search가 더 복잡한 이유 - Figma 파일의 실제 표현은 데이터베이스가 아니라 Amazon S3에 저장된 `.fig` 문서다. - `.fig` 파일은 트리 구조로 구성된다. - 각 노드는 타원, 프레임, 벡터, 텍스트 같은 Figma 객체를 나타낸다. - 노드에는 객체의 속성과 콘텐츠가 함께 저장된다. - Deep Search는 파일의 메타데이터만 확인하는 것이 아니라, S3에서 파일을 가져온 뒤 전체 객체 트리를 순회해야 한다. - 하나의 파일에 수천 개의 노드가 있을 수 있어 파일을 읽고 분석하는 작업은 일반적인 데이터베이스 조회보다 훨씬 계산 비용이 크다. ## 처리 비용과 검색 최신성 사이의 타협 - Figma 파일은 편집 중에도 약 30초마다 자동 저장될 수 있다. - 저장될 때마다 Deep Search 색인을 갱신하면 같은 파일을 반복적으로 내려받고 분석하게 되어 서버 비용이 크게 증가한다. - Figma는 이를 해결하기 위해 파일 변경 사항을 한 시간 동안 중복 제거한다. - 이후 변경된 파일을 파일 분석 워커로 보내 주기적으로 처리한다. - 그 결과 Deep Search 결과가 일반 검색보다 잠시 오래된 상태일 수 있지만, 반복적인 파일 분석을 줄여 상당한 서버 자원을 절약할 수 있다. - 이는 검색 결과의 즉시성보다 시스템 비용과 확장성을 우선한 제품·인프라상의 결정이다. ## 실용적인 결론 대용량 문서나 복잡한 구조를 검색할 때는 모든 변경을 즉시 처리하기보다 변경 사항을 모아 중복 작업을 제거하는 방식이 효율적이다. 검색 결과가 수초 또는 수분 정도 지연되어도 괜찮다면, 배치 처리와 주기적 색인을 통해 계산 비용과 인프라 부담을 크게 줄일 수 있다.

원문 읽기(새 탭에서 열림)
figma3분 읽기큐레이션 요약

Figma의 인프라: 웹

Figma는 웹 기반 디자인 도구도 데스크톱 애플리케이션 수준의 속도와 안정성을 제공해야 한다고 주장한다. 이를 위해 클라우드 기반의 단일 진실 공급원, 실시간 협업, 프로토타이핑과 개발자 핸드오프를 통합했으며, 사용자와 데이터가 증가함에 따라 인프라를 확장 가능한 구조로 전환하고 있다. 핵심 과제는 불필요한 데이터 로딩을 줄이고, 데이터베이스를 수평 확장하며, 전 세계 사용자의 지연 시간을 낮추는 것이다. ## Figma가 해결하려는 문제 - 기존 디자인 작업은 특정 데스크톱 애플리케이션과 플랫폼에 종속됐다. - 파일을 내보내거나 여러 도구 사이에서 옮기는 과정에서 최신 버전 관리와 협업이 어려웠다. - Figma는 디자인 파일을 클라우드에 저장하고 고유 URL을 부여해 팀 전체의 단일 진실 공급원으로 만든다. - 프로토타이핑과 개발자 핸드오프 기능을 제품 안에 포함해 별도 도구와 파일 변환의 필요성을 줄였다. ## 실시간 협업과 인프라 요구사항 - 여러 사용자가 하나의 파일을 동시에 보고 편집할 수 있는 멀티플레이어 기능을 제공한다. - 디자인 파일에는 복잡한 도형과 대용량 이미지가 포함될 수 있어 백엔드와 네트워크로 전송되는 데이터가 많다. - 사용자는 데스크톱 도구와 같거나 더 나은 상호작용 성능을 기대한다. - 따라서 인프라는 다음 요구사항을 동시에 충족해야 한다. - 낮은 상호작용 지연 시간 - 높은 가용성 - 대규모 파일과 동시 접속 처리 - 실시간 변경사항 동기화 ## 초기 인프라의 한계 - 초기 Figma는 단순한 백엔드 구조를 사용해 빠르게 제품을 개발하고 운영했다. - 예를 들어 파일을 로드할 때 사용자가 접근 가능한 공유 컴포넌트를 모두 미리 불러왔다. - 공유 디자인 요소가 수천 개일 때는 효과적이었지만, 조직의 라이브러리가 약 1만 개에 가까워지면 백엔드에 큰 부담이 발생했다. - Microsoft, Uber 같은 대규모 조직의 도입과 글로벌 사용자 증가로 이러한 문제가 일반적인 확장성 문제로 나타났다. ## 필요한 데이터만 불러오는 구조 - 기존 시스템은 사용자가 실제로 즉시 필요로 하지 않는 데이터까지 파일 로드 시점에 미리 가져오는 경우가 있었다. - 이 방식은 초기 진입 속도와 백엔드 부하 모두에 악영향을 준다. - 단순히 서버 성능만 개선하는 것으로는 해결되지 않으며, 클라이언트와 서버 간 상호작용 방식을 다시 설계해야 한다. - 클라이언트가 필요한 정보만 요청하도록 제품의 데이터 로딩 방식과 사용자 경험을 함께 바꿔야 한다. - 인프라 팀뿐 아니라 제품과 클라이언트 개발팀의 협업이 필요한 문제다. ## 단일 데이터베이스에서 수평 확장으로 - 당시 Figma의 전체 인프라는 AWS의 매우 강력한 단일 데이터베이스 인스턴스에 의존했다. - 단순한 구조를 선호하는 KISS 원칙 덕분에 초기에는 운영이 쉬웠고 빠르게 성장할 수 있었다. - 그러나 단일 인스턴스는 성능과 용량 확장에 한계가 있다. - 다음 단계에서는 여러 노드로 확장할 수 있는 수평 확장형 데이터베이스 계층을 구축하려 했다. - 데이터베이스를 거의 모든 시스템과 서비스가 사용하므로, 일관성·장애 처리·서비스 의존성까지 함께 재설계해야 하는 대규모 작업이다. ## 글로벌 사용자의 지연 시간 개선 - 주간 활성 사용자의 80% 이상이 미국 외 지역에 있었다. - 당시 요청은 미국 오리건의 데이터센터까지 왕복해야 했기 때문에, 사용자 경험이 물리적 네트워크 거리에 영향을 받았다. - 이를 개선하기 위해 사용자와 가까운 곳에 인프라 구성 요소를 배치하려 했다. - 첫 단계로 전 세계 주요 지역에 원격 프록시를 전략적으로 배치해 데이터센터까지의 네트워크 지연을 줄이는 방안을 추진했다. - 장기적으로는 글로벌 사용자에게 더 가까운 위치에서 요청을 처리하는 방향으로 인프라를 발전시키려 했다. ## 실용적인 결론 웹 기반 협업 도구의 확장은 서버를 더 큰 장비로 교체하는 것만으로 해결되지 않는다. 필요한 데이터만 지연 로딩하고, 데이터베이스를 수평 확장하며, 사용자가 가까운 위치에서 서비스를 이용하도록 네트워크 구조를 개선하는 등 제품 경험과 시스템 아키텍처를 함께 재설계해야 한다.

원문 읽기(새 탭에서 열림)
figma4분 읽기큐레이션 요약

속도 제한에 대한 대안

Figma는 스팸 공격으로부터 서비스를 보호하기 위해 Redis 기반의 자체 레이트 리미터를 구축했다. 토큰 버킷과 고정 윈도 카운터는 메모리 효율이 좋지만 정확성이나 동시성 문제가 있었고, 슬라이딩 윈도 로그는 정확하지만 메모리를 많이 사용한다. Figma는 여러 기법을 조합해 분산 환경에서 빠르고 정확하며 메모리 효율적인 방식으로 요청량을 제한했다. ## 레이트 리미팅의 요구사항 - 사용자나 IP 주소별로 일정 시간 동안 허용할 요청 수를 제한한다. - 예: 1분에 25회 요청 허용 - 여러 웹 서버가 동일한 제한 정보를 공유해야 하므로 외부 저장소가 필요하다. - 웹 요청 처리 속도를 크게 저하시켜서는 안 된다. - 오래된 추적 데이터를 효율적으로 삭제해야 한다. - 과도한 요청을 정확하게 차단하면서 메모리 사용량도 최소화해야 한다. - Figma는 PostgreSQL보다 읽기·쓰기 속도가 빠르고 만료 키를 지원하는 Redis를 추적 데이터 저장소로 선택했다. ## 토큰 버킷의 장점과 동시성 문제 - 사용자마다 다음 두 값을 Redis 해시에 저장한다. - 마지막 요청 시각 - 현재 남아 있는 토큰 수 - 시간이 지나면 설정된 보충 속도에 따라 토큰을 다시 채운다. - 토큰이 0개가 되면 요청을 제한한다. - 장점: - 구현 개념이 단순하다. - 사용자별로 작은 해시 하나만 저장하므로 메모리 효율이 높다. - 일정한 요청 속도와 일시적인 버스트를 모두 처리할 수 있다. - 문제점: - Redis에서 값을 읽고 계산한 뒤 다시 쓰는 과정이 원자적이지 않다. - 두 서버가 동시에 같은 토큰 수를 읽으면, 둘 다 요청을 허용하는 경쟁 조건이 발생할 수 있다. - 결과적으로 실제 허용량보다 많은 요청이 통과할 수 있다. - Redis 락이나 Lua 스크립트로 원자성을 보장할 수 있지만, 락은 지연과 복잡성을 늘리고 Lua는 코드베이스에 별도 언어를 추가해야 한다. ## 고정 윈도 카운터의 단순성과 경계 문제 - 요청이 발생한 시간 구간을 키로 삼아 Redis 카운터를 증가시킨다. - 예: `user:1:2017-03-30T10:00`에 해당 분의 요청 수 저장 - 카운터가 제한값을 넘으면 요청을 거부한다. - 각 키에 만료 시간을 설정해 오래된 카운터를 자동 삭제한다. - `INCR` 같은 Redis 연산을 사용하므로 토큰 버킷보다 동시성 처리가 안전하다. - 메모리 사용량도 적고 구현과 동작을 이해하기 쉽다. - 하지만 윈도 경계에서 허용량보다 최대 두 배 많은 요청이 통과할 수 있다. - 예를 들어 분당 5회 제한에서 10:00:59에 5회, 10:01:00에 다시 5회를 보내면 실제로는 2초 안에 10회가 허용된다. - 따라서 고정 윈도만으로는 요청량을 정확하게 제한하기 어렵다. ## 슬라이딩 윈도 로그의 정확성과 메모리 비용 - 각 요청의 정확한 타임스탬프를 저장한다. - 새 요청이 들어오면 제한 시간보다 오래된 기록을 삭제하고, 현재 윈도 안의 요청 수를 계산한다. - 윈도가 계속 이동하므로 고정 윈도 경계에서 발생하는 폭주 문제가 없다. - 가장 정확한 방식이지만 모든 요청 기록을 보관해야 한다. - 요청 빈도가 높은 사용자나 공격자가 많아지면 저장해야 할 타임스탬프 수가 급증한다. - 따라서 정확성은 높지만 Redis 메모리를 많이 사용한다. ## Figma의 절충 방식 - Figma는 고정 윈도 카운터의 낮은 메모리 사용량과 슬라이딩 윈도의 정확성을 결합하는 방식을 사용했다. - 전체 제한 구간을 더 작은 시간 단위의 카운터들로 나누고, 현재 구간과 직전 구간의 요청량을 이용해 이동 중인 윈도의 사용량을 계산한다. - 개별 요청의 타임스탬프를 모두 저장하지 않고 카운터만 유지하므로 슬라이딩 윈도 로그보다 메모리 효율적이다. - Redis의 원자적 카운터 증가 연산을 활용해 여러 애플리케이션 서버가 동시에 요청을 처리해도 경쟁 조건을 줄일 수 있다. - Redis 키에 만료 시간을 지정해 오래된 시간 구간의 데이터가 자동으로 제거되도록 한다. - 이 방식은 완벽한 요청 단위 정확성보다는 약간의 근사치를 허용하는 대신, 다음 특성을 균형 있게 제공한다. - 분산 환경에서의 안전성 - 낮은 지연 시간 - 적은 메모리 사용량 - 고정 윈도보다 나은 제한 정확도 ## 스팸 공격 방어 효과 - 공격자는 다수의 이메일 주소로 문서 초대 요청을 반복해서 보냈다. - 레이트 리미터가 비정상적인 요청 증가를 조기에 감지해 추가 요청을 차단했다. - 그 결과 이메일 발송 비용의 급증과 발신자 평판 하락을 막을 수 있었다. - 레이트 리미팅은 단순한 성능 보호 장치뿐 아니라 이메일 초대, 비밀번호 재설정, 결제 등 악용되기 쉬운 기능의 스팸 방어 수단으로도 활용할 수 있다. 서비스 규모가 크고 여러 서버가 요청을 처리한다면 Redis 기반의 원자적 카운터와 만료 키를 우선 고려하는 것이 실용적이다. 높은 정확성이 필요하면 슬라이딩 윈도 로그를, 메모리와 성능을 중시하면 슬라이딩 윈도 카운터나 세분화된 고정 윈도 방식을 선택하는 것이 적절하다.

원문 읽기(새 탭에서 열림)
figma3분 읽기큐레이션 요약

순서가 지정된 시퀀

Figma는 실시간 협업에서 여러 사용자가 객체의 순서를 동시에 변경해도 모든 클라이언트가 동일한 최종 상태에 도달하도록 해야 했다. 처음에는 Operational Transformation(OT)을 고려했지만, 텍스트 편집에 필요한 고급 기능과 구현 복잡도가 Figma에는 과도하다고 판단했다. 대신 각 객체에 순서를 나타내는 분수형 인덱스를 부여하고 정렬하는 방식을 사용해, 단순성과 안정성을 확보했다. ## 실시간 순서 편집의 문제 - Figma의 문서, 그룹, 컴포넌트 등은 자식 객체의 순서가 있는 목록을 가진다. - 사용자는 객체를 삽입·삭제하거나 드래그해 순서를 변경할 수 있다. - 각 클라이언트는 편집을 즉시 로컬에 적용한 뒤 서버로 전송한다. - 네트워크 상황에 따라 각 클라이언트가 작업을 서로 다른 순서로 받을 수 있다. - 따라서 작업 적용 순서가 달라도 모든 클라이언트의 문서가 동일해지는 eventual consistency가 필요하다. ## Operational Transformation의 접근법 - OT는 동시 작업이 서로의 위치와 의미를 깨뜨리지 않도록 작업을 변환한다. - 예를 들어 텍스트 `bcde`에 대해 한 사용자가 앞에 `x`를 삽입하고 다른 사용자가 `bc`를 삭제하면, 삭제 위치를 삽입만큼 보정한다. - 서버와 클라이언트는 다른 작업을 기준으로 각 연산을 변환해 같은 결과를 만든다. - OT는 오래된 협업 편집 알고리즘이며 텍스트 편집기에서 널리 사용됐다. ### OT의 장단점 - 장점 - 매우 큰 시퀀스에서도 성능과 메모리 효율이 좋다. - 같은 위치에 동시에 삽입된 문자열을 서로 끼워 넣지 않고 연속된 덩어리로 정렬할 수 있다. - 단점 - 구현과 정확성 검증이 어렵다. - 일반적으로 객체 이동을 삭제 후 삽입으로 처리한다. - 연산 종류가 늘어날수록 모든 연산 쌍 간 변환 규칙이 필요해 복잡도가 크게 증가한다. - Figma는 거대한 시퀀스나 삽입 결과의 비인터리빙이 필요하지 않았고, 객체 이동이 빈번했기 때문에 OT를 선택하지 않았다. ## 분수형 인덱싱 - 각 객체에 `0과 1 사이의 위치값`을 부여하고, 이 값을 기준으로 자식 객체를 정렬한다. - 두 객체 사이에 삽입할 때는 양쪽 인덱스의 평균을 새 객체의 인덱스로 사용한다. - 예를 들어 `0.2`와 `0.6` 사이에 삽입하면 `0.4`를 사용할 수 있다. - 인덱스는 64비트 부동소수점 대신 임의 정밀도 분수로 저장해 반복 삽입으로 정밀도가 고갈되는 문제를 피한다. - Figma는 인덱스를 문자열로 저장하고 문자열 조작으로 평균을 계산한다. - 저장 공간을 줄이기 위해 `0.`을 생략하고, 숫자만이 아니라 전체 ASCII 범위를 사용한 base 95 표현을 적용한다. ## 분수형 인덱싱의 장단점 - 장점 - 알고리즘이 단순하고 이해·구현하기 쉽다. - 객체를 이동할 때 위치값 하나만 변경하면 된다. - 이동을 삭제와 삽입으로 나눌 필요가 없다. - 단점 - 반복적인 삽입과 재배치로 인덱스 문자열이 길어질 수 있다. - 여러 클라이언트가 같은 위치에 동시에 삽입하면 새 객체들이 서로 섞일 수 있다. - 동일한 두 인덱스 사이의 평균을 다시 계산할 수 없다. ## 동시 삽입 충돌 처리 - 동일한 위치에 두 클라이언트가 동시에 객체를 삽입하면 두 객체가 같은 인덱스를 가질 수 있다. - 서버가 두 객체에 동일한 위치값이 생기지 않도록 두 번째 삽입에 고유한 위치를 부여한다. - 인덱스 길이 증가는 Figma에서 객체 수와 사용자 활동이 실용적인 범위로 제한되므로 큰 문제가 되지 않는다. - 디자인 문서에서는 동시에 삽입된 객체가 서로 겹치지 않는 경우가 많아, 순서가 일부 인터리빙되는 것도 허용 가능하다. Figma의 사례는 가장 정교한 알고리즘보다 제품의 요구사항에 맞는 단순한 알고리즘이 더 유리할 수 있음을 보여준다. 대규모 텍스트 편집처럼 강한 순서 보장이 필요하지 않다면, 분수형 인덱싱은 구현·유지보수 비용이 낮고 객체 이동에도 효율적인 실용적 선택이다.

원문 읽기(새 탭에서 열림)