caching

13 개의 포스트

cloudflare3분 읽기큐레이션 요약

캐시 응답 규칙 소개

Cloudflare의 Cache Response Rules는 원본 서버 응답이 도착한 뒤, 캐시에 저장되기 전에 응답 헤더와 캐시 지시사항을 수정하는 기능이다. `Set-Cookie`, 잘못된 `Cache-Control`, 과도한 `ETag` 등으로 캐시되지 않던 콘텐츠를 원본 코드 변경 없이 캐시 가능하게 만들 수 있다. 다만 캐시 키처럼 요청 단계에서 이미 결정된 사항은 변경할 수 없으므로 기존 Cache Rules를 대체하지 않고 보완한다. ## 캐싱 판단이 이루어지는 시점 - CDN은 가능한 한 캐시에서 응답하고, 캐시에서 처리할 수 없을 때만 원본 서버에 요청한다. - 캐시 적중률이 낮으면 원본 서버의 대역폭과 인프라 비용이 증가하고 응답 속도도 느려진다. - 원본 서버의 응답 헤더는 다음과 같은 캐싱 정책을 결정한다. - 얼마나 오래 캐시할지 - 언제 재검증할지 - 애초에 캐시할 수 있는지 - 많은 캐싱 문제는 요청 시점이 아니라 원본 응답이 도착한 뒤에 드러난다. - 정적 파일에 실수로 `Set-Cookie`가 포함됨 - 캐시해도 안전한 리소스에 `Cache-Control: no-cache`가 설정됨 - 브라우저용 지시사항이 Cloudflare 캐싱에도 적용됨 - 지나치게 공격적인 `ETag`로 조건부 요청마다 재검증이 발생함 ## 기존 방식의 한계 - 요청 단계에서는 원본 서버가 반환할 응답 헤더를 알 수 없다. - 따라서 요청 시점에 동작하는 Cache Rules만으로는 `Set-Cookie`, `ETag`, `Last-Modified`, 원본의 `Cache-Control` 문제를 해결할 수 없다. - 기존 선택지는 다음과 같았다. - 원본 서버 코드나 설정 변경 - Worker로 응답을 다시 가져와 헤더 수정 - 낮은 캐시 적중률을 감수 - 특히 원본 서버 담당 팀과 CDN 담당 팀이 다르면 단순한 헤더 하나를 바꾸는 데도 긴 조율이 필요했다. ## Cache Response Rules의 동작 방식 - 실행 시점은 다음과 같다. 1. Cloudflare가 캐시 미스 후 원본 서버에 요청 2. 원본 응답 수신 3. Cache Response Rules 적용 4. 수정된 응답을 Cloudflare 캐시에 저장 - 다음과 같은 응답 변경이 가능하다. - `Set-Cookie` 제거 - `ETag` 및 `Last-Modified` 제거 - `Cache-Control` 지시사항 수정 - 캐시 태그 설정 및 관리 - 모든 변경은 Cloudflare에서 처리되므로 원본 애플리케이션이나 서버 설정을 수정할 필요가 없다. ## Cache Rules와 Cache Response Rules의 역할 차이 - **Cache Rules**는 요청 단계에서 동작한다. - 응답을 캐시할지 여부 - 어떤 캐시 키로 저장할지 - Edge TTL, 브라우저 TTL, stale 응답 제공 여부 - **Cache Response Rules**는 응답 단계에서 동작한다. - 원본 응답이 캐시에 적합한지 조정 - 캐시를 막는 헤더 제거 - 원본의 `Cache-Control` 수정 - 캐시 태그 설정 - 두 규칙이 충돌하면 Cache Response Rules가 우선한다. - 하지만 응답 단계에서는 캐시 키를 변경할 수 없다. 캐시 키는 원본 요청 전에 이미 결정되기 때문이다. ## 응답 단계에서 가능한 것과 불가능한 것 - 가능한 작업: - `Set-Cookie`를 제거해 캐시 가능하게 만들기 - 캐시 가능한 응답에 `no-store`를 설정해 저장하지 않기 - 원본의 캐시 TTL이나 캐시 지시사항 변경 - 캐시 무효화를 위한 태그 지정 - 불가능한 작업: - 이미 정해진 캐시 키 변경 - 요청 단계에서 캐시 대상에서 제외된 요청을 뒤늦게 캐시 대상으로 전환 - 따라서 Cache Response Rules는 Cache Rules의 대체재가 아니라, 원본 응답 헤더를 보정하는 보완 기능이다. ## 실용적인 결론 정적 리소스가 불필요한 `Set-Cookie`나 잘못된 `Cache-Control` 때문에 캐시되지 않는다면, 원본 서버를 수정하기 전에 Cache Response Rules를 활용하는 것이 효율적이다. 다만 캐시 여부의 기본 정책과 캐시 키는 Cache Rules에서 먼저 설계하고, 응답 단계에서는 헤더와 TTL 등 원본 응답의 캐시 관련 정보를 보정하는 방식으로 함께 사용하는 것이 적절하다.

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

선형 탄력적 캐싱으로 클라우드 비용 효율성 최적화

인메모리 캐시는 성능을 높이지만, 고정된 메모리 크기로 운영하면 수요가 낮을 때 비용이 낭비되고 수요가 많을 때 캐시 미스로 성능이 저하된다. 선형 탄력적 캐싱은 메모리 점유 비용과 캐시 미스 비용의 균형을 ‘스키 대여 문제’로 모델링해, 워크로드에 따라 페이지별 보관 시간과 캐시 크기를 동적으로 조정한다. Spanner 실험에서는 메모리 사용량을 15.5%, 총소유비용(TCO)을 약 5% 줄이면서 캐시 미스 증가는 5.5%에 그쳤다. ## 고정 크기 캐시의 비용 문제 - 기존 캐시는 미리 정한 메모리 용량 안에서 LRU 같은 정책으로 데이터를 제거한다. - 캐시가 너무 작으면 디스크나 다른 저장 시스템에 대한 접근이 늘어 성능이 떨어진다. - 반대로 피크 수요에 맞춰 캐시를 크게 잡으면 평상시 사용하지 않는 메모리 비용이 발생한다. - 특히 클라우드와 서버리스 환경에서는 메모리 용량과 사용 시간이 직접 비용으로 연결된다. ## 스키 대여 문제로 모델링한 캐싱 - 각 데이터 페이지는 다음 두 선택지 사이에서 판단된다. - **대여:** 데이터를 RAM에 유지하면서 메모리 비용을 계속 지불한다. - **구매:** 데이터를 제거해 메모리 비용을 아끼지만, 재요청 시 캐시 미스에 따른 지연 및 I/O 비용을 부담한다. - 페이지를 너무 오래 보관하면 메모리 비용이 커지고, 너무 빨리 제거하면 캐시 미스 비용이 커진다. - 전통적인 스키 대여 알고리즘은 누적 대여 비용이 재취득 비용과 같아지는 시점에 데이터를 제거하는 손익분기 전략을 사용한다. - 연구진은 최악의 경우를 보장하는 방식뿐 아니라, 실제 워크로드의 반복적인 접근 패턴을 학습해 더 나은 TTL을 예측하는 방법을 적용했다. ## TTL과 물리적 캐시 용량의 분리 - 이론적으로 캐시의 핵심 문제를 다음 두 부분으로 나눌 수 있음을 보였다. - 각 페이지를 얼마나 오래 보관할지 결정하는 문제 - 캐시가 실제로 가득 찼을 때 어떤 페이지를 제거할지 결정하는 문제 - 페이지 요청 시 스키 대여 알고리즘이 해당 페이지의 TTL을 계산한다. - TTL이 만료되기 전 재접근이 없으면 페이지를 자동으로 제거한다. - 캐시가 물리적으로 가득 차면 LRU 같은 전통적인 제거 정책이 보조적으로 작동한다. - 이 분리 덕분에 동적 캐시 크기 조절을 기존 캐시 시스템에 비교적 간단히 통합할 수 있다. ## Spanner의 경량 머신러닝 적용 - Spanner의 초당 수십억 건 요청을 처리하기 위해 TTL 예측 모델은 매우 가벼워야 했다. - 연구진은 몇 줄의 C++ 코드로 변환 가능한 얕은 결정 트리를 사용했다. - 모델이 고려한 주요 특징은 다음과 같다. - 데이터 페이지의 크기 - 캐시 미스 발생 시 데이터를 다시 가져오는 비용 - 수행되는 데이터베이스 연산의 유형 - 페이지의 과거 접근 패턴 - 결정 트리는 해석 가능하므로, 어떤 데이터가 오래 캐시할 가치가 있는지도 분석할 수 있다. ## Spanner 운영 환경의 실험 결과 - 고정 크기 캐시와 비교했을 때: - 메모리 사용량 **15.5% 감소** - 캐시 미스 **5.5% 증가** - 총소유비용(TCO) 약 **5% 감소** - 캐시 미스 증가는 비용이 낮은 데이터에 집중됐다. - 저장 시스템에 실제로 발생한 I/O 비용 증가는 약 **0.5%**에 불과했다. - 즉, 모든 캐시 미스를 동일하게 줄이기보다, 재취득 비용이 큰 데이터는 유지하고 저렴한 데이터는 적극적으로 제거하는 비용 인식형 전략이 효과적이었다. ## 공개 캐시 트레이스 검증 - Google 인프라에만 특화된 결과인지 확인하기 위해 다양한 공개 캐시 추적 데이터를 사용했다. - 고정 크기 캐시의 기준 정책으로는 페이지 크기가 서로 다른 상황을 처리할 수 있는 GDSF를 사용했다. - 여러 탄력적 캐시 변형을 비교했다. - 손익분기 스키 대여 정책 - 무작위화된 스키 대여 정책 - 학습된 TTL을 사용하는 정책 - 애플리케이션 수준의 특징이 없는 공개 데이터에서는 각 페이지별 최적 TTL을 학습했다. - 트레이스를 학습과 테스트로 나누고, 테스트 전에 일정 기간 캐시를 채우는 워밍업 절차를 적용했다. - 학습 데이터에서 관찰된 페이지는 미리 계산한 TTL을 사용하고, 처음 등장한 페이지는 기본 스키 대여 정책으로 처리했다. ## 다양한 워크로드에서의 효과 - 실험 결과, 탄력적 캐싱은 다양한 워크로드에서 고정 크기 캐시보다 일관되게 낮은 비용을 보였다. - 메모리 비용이 캐시 미스 비용보다 비싸질수록 탄력적 캐싱의 절감 효과가 커졌다. - 비슷한 메모리 규모를 사용하는 경우에도 탄력적 정책이 더 낮은 캐시 미스율을 보였다. - 캐시 크기를 수요에 맞춰 자동 조정하기 때문에 유휴 메모리 낭비를 줄이면서 성능을 유지할 수 있다. 실무에서는 모든 페이지를 동일하게 취급하는 LRU만 사용하기보다, 페이지 크기와 재조회 비용을 반영해 TTL을 차등 설정하는 방식이 유용하다. 특히 메모리 비용이 높고 데이터별 재취득 비용 차이가 큰 클라우드 데이터베이스에서는 선형 탄력적 캐싱을 적용해 비용 절감 효과를 측정해볼 만하다.

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

레이어 패널의 성능 개선 | Figma 블로그

Figma는 대규모 파일에서 레이어 패널의 느린 상호작용을 해결하기 위해 아키텍처를 전면 재설계했다. 행 목록 계산과 노드 상세 정보 계산을 분리하고, 파생 속성(derived properties)을 활용해 변경된 부분만 다시 계산한 결과, 가장 복잡한 파일에서 일부 상호작용이 30~50% 빨라졌다. 핵심은 보이지 않는 레이어까지 계산하지 않고, 필요한 데이터만 지연 계산·캐싱하는 것이다. ## 레이어 패널 성능 저하의 원인 - 레이어 패널은 Figma 파일의 노드 트리를 중첩된 목록으로 표현한다. - 초기 아키텍처는 파일의 각 노드에 대해 이름, 아이콘, 표시 여부, 잠금 상태 등 UI에 필요한 데이터를 하나의 큰 JavaScript 객체로 구성했다. - 레이어가 변경될 때마다 확장된 모든 노드에 대해 데이터를 처음부터 다시 계산했다. - 파일이 수만 개의 레이어를 포함하게 되면서 두 가지 문제가 발생했다. - **계산량 과다:** 화면에 실제로 보이는 행은 보통 20~30개뿐인데, 확장된 모든 노드의 데이터를 계산했다. - **재계산 빈도 과다:** 레이어 하나를 확장하거나 변경해도 전체 데이터를 다시 생성했다. ## 1단계: 두 번에 나누어 계산하기 - 데이터 수집 과정을 두 단계로 분리했다. - 첫 번째 단계에서는 패널에 표시될 **행 ID의 순서**만 계산한다. - 이 과정도 단순하지 않으며 다음과 같은 제품 규칙을 반영해야 한다. - 오토 레이아웃 프레임의 자식은 역순으로 표시될 수 있다. - 위젯이나 FigJam 스티키처럼 자식 노드를 패널에 표시하지 않는 노드가 있다. - 프로토타이핑 프레임의 고정 헤더와 스크롤 헤더는 자식을 두 영역으로 나눈다. - 최상위 프레임과 컴포넌트는 고정된 위치에 표시된다. - 두 번째 단계에서는 첫 단계에서 얻은 행 ID 중 현재 화면에 보이는 노드만 대상으로 상세 데이터를 계산한다. - 기존에도 화면 밖 항목을 렌더링하지 않는 윈도잉(windowing)을 사용했지만, 데이터 계산 자체는 모든 확장 노드에 대해 수행되고 있었다. - 새 구조에서는 이름, 아이콘, 잠금·표시 상태, 선택 상태 등을 실제로 필요한 수십 개 행에 대해서만 계산한다. - 그 결과 수십만 개 노드의 데이터를 계산하던 작업을 화면 주변의 작은 범위로 줄였다. ## 2단계: 파생 데이터 캐싱 - 변경되지 않은 레이어를 다시 그리거나 재계산하지 않고, 바뀐 부분만 갱신하도록 개선했다. - 이를 위해 Figma가 플랫폼 차원에서 개발한 **파생 속성(derived properties)** 기능을 사용했다. - Figma 노드는 직접 저장·조회할 수 있는 필드(fields)를 가진다. - 하지만 일부 속성은 직접 저장하지 않고 다른 필드와 속성으로부터 계산된다. - 예를 들어 노드는 부모 기준의 상대 위치만 저장하고, 절대 위치는 다음과 같이 계산할 수 있다. ```text Self.AbsolutePosition = Parent.AbsolutePosition + Self.RelativePosition ``` - 파생 속성 시스템은 이런 계산 관계를 명시적으로 선언하고, 의존하는 값이 바뀌면 최신 상태를 유지하도록 한다. - 시스템의 장점은 다음과 같다. - 각 파생 속성이 어떤 필드와 다른 파생 속성에 의존하는지 추적한다. - 의존 관계가 최적화된 그래프 형태로 컴파일된다. - 속도와 메모리 사용량 사이의 선택을 고려한 여러 캐싱 정책을 제공한다. - 기본적으로 지연 계산(lazy evaluation) 방식이어서 실제로 읽을 때만 계산한다. - 레이어 패널은 부모-자식 트리 구조를 갖기 때문에 파생 속성과 자연스럽게 결합된다. - 이전에는 트리 어디에서든 변경이 발생하면 노드 데이터를 전체적으로 다시 계산했지만, 새 구조에서는 의존 관계를 바탕으로 영향을 받은 데이터만 갱신할 수 있다. ## 성능 개선의 의미 - 대규모 Figma 파일에서 레이어 패널의 스크롤, 확장·축소, 선택 등의 상호작용이 더 빨라졌다. - 레이어 패널의 계산 비용이 줄어들면서 드래그나 텍스트 입력 같은 에디터의 다른 작업에도 영향을 주던 지연이 완화됐다. - 윈도잉만 적용하는 것보다, **계산 대상 자체를 가시 영역으로 제한하는 것**이 중요하다는 점을 보여준다. - UI 성능을 높이려면 다음 두 문제를 별도로 해결해야 한다. - 불필요한 항목까지 계산하는 문제 - 같은 항목을 반복해서 계산하는 문제 ## 실용적인 결론 대규모 트리형 UI에서는 렌더링만 가상화하는 것으로 충분하지 않다. 먼저 화면에 필요한 항목의 ID나 구조만 계산한 뒤, 실제 표시되는 항목의 상세 데이터만 지연 계산하고, 의존성이 변한 부분만 캐시를 무효화하는 방식이 효과적이다.

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

똑같은 질문에 두 번 답하지 마세요: 넷플릭스 규모의 Druid를 위한 인터벌 인식 캐싱 (새 탭에서 열림)

넷플릭스는 Apache Druid를 통해 초당 1,500만 건 이상의 이벤트를 처리하며 대규모 실시간 분석을 수행하고 있으나, 대시보드의 롤링 윈도우(Rolling Window) 쿼리가 생성하는 중복 부하 문제를 해결해야 했습니다. 이를 위해 쿼리에서 시간 범위를 분리하여 처리하는 '구간 인식 캐싱(Interval-Aware Caching)' 레이어를 구축하여 Druid의 계산 리소스를 효율화했습니다. 이 시스템은 과거의 안정된 데이터는 캐시에서 불러오고 오직 최신 데이터만 Druid에 요청함으로써, 대규모 트래픽 상황에서도 쿼리 성능을 안정적으로 유지합니다. ### 기존 캐싱 방식의 한계와 문제점 * **롤링 윈도우의 비효율성**: 실시간 모니터링 대시보드는 10~30초마다 "최근 3시간"과 같은 쿼리를 반복해서 보냅니다. 시간 범위가 계속 이동하기 때문에 Druid의 기존 전체 결과 캐시(Full-result cache)는 매번 미스(Miss)가 발생합니다. * **실시간 데이터 캐싱 제한**: Druid는 데이터의 정확성을 위해 실시간 인덱싱 중인 세그먼트의 결과는 캐싱하지 않습니다. 이로 인해 대시보드가 갱신될 때마다 동일한 실시간 세그먼트를 반복해서 스캔하는 낭비가 발생합니다. * **하드웨어 확장의 한계**: 수십 명의 엔지니어가 동일한 대시보드를 볼 때 발생하는 수천 개의 중복 쿼리를 처리하기 위해 단순히 하드웨어를 증설하는 것은 비용 효율성이 매우 낮습니다. ### 구간 인식 캐싱의 핵심 아이디어 * **데이터의 안정성 활용**: 3시간 전의 데이터는 이미 확정되어 변하지 않지만, 최근 1분 내의 데이터는 지연 도착 등으로 인해 변할 수 있습니다. 이 차이를 이용해 오래된 데이터는 캐시에서 즉시 반환하고, 최신 구간만 Druid에 쿼리합니다. * **쿼리 구조와 시간의 분리**: 쿼리문에서 시간 범위(Interval)를 제외한 나머지 구조(필터, 집계 등)를 SHA-256으로 해싱하여 캐시 키로 사용합니다. 이를 통해 서로 다른 시간 범위를 가진 동일한 목적의 쿼리들이 동일한 캐시 항목을 참조할 수 있게 합니다. * **버킷팅(Bucketing) 구조**: 데이터를 쿼리 단위(예: 1분)별로 잘게 쪼개어 'Map-of-Maps' 형태로 저장합니다. 쿼리가 들어오면 필요한 시간 범위에 해당하는 버킷들을 캐시에서 조회하고, 없는 부분만 골라냅니다. ### 지수적 TTL을 통한 효율적인 데이터 관리 * **신선도와 부하의 트레이드오프**: 데이터 파이프라인의 지연 시간을 고려해 최신 데이터에 약 5초의 캐시 유지 시간(TTL)을 부여합니다. 이는 대시보드 사용자에게는 거의 실시간으로 느껴지면서도 Druid의 부하를 대폭 줄여줍니다. * **데이터 연령에 따른 TTL 차등화**: 데이터가 생성된 지 얼마 안 된 버킷은 5~10초의 짧은 TTL을 가집니다. 데이터가 오래될수록 나중에 도착하는 이벤트가 적어지므로, TTL을 지수적으로 늘려 최대 1시간까지 캐시에 보관합니다. * **자동 보정**: 짧은 TTL 덕분에 최신 데이터 구간에서 발생하는 수정 사항은 빠르게 캐시에 반영되며, 오래된 구간은 긴 TTL을 통해 캐시 적중률을 극대화합니다. ### 시스템 구현 및 작동 워크플로우 * **투명한 프록시 구조**: Druid Router 단계에서 요청을 가로채는 외부 서비스 형태로 구현되었습니다. 클라이언트 앱을 수정할 필요 없이 캐싱 기능을 끄거나 켤 수 있습니다. * **쿼리 분해 및 병합**: 1. 들어온 쿼리를 파싱하여 시간 구간을 확인하고 캐시 키(해시)를 생성합니다. 2. 캐시 저장소(예: Redis/Memcached)에서 요청된 구간에 해당하는 연속된 버킷들을 확인합니다. 3. 캐시에 없는 '가장 최신의 불안정한 구간'으로 쿼리 범위를 축소하여 Druid에 요청합니다. 4. 캐시된 결과와 Druid에서 새로 가져온 결과를 병합하여 클라이언트에 반환합니다. 롤링 윈도우 기반의 대규모 대시보드를 운영하는 환경이라면, 모든 데이터를 매번 다시 계산하기보다 이처럼 시간 구간을 나누어 캐싱하는 전략이 Druid 클러스터의 비용 절감과 성능 향상에 매우 효과적입니다. 특히 데이터가 확정되는 속도에 따라 TTL을 다르게 가져가는 '지수적 TTL' 방식은 데이터 정확도와 효율성 사이의 균형을 잡는 유용한 기술적 패턴입니다.

figma3분 읽기큐레이션 요약

피그마의 차세대 데이터 캐싱 플랫폼 | 피그마 블로그

Figma는 Redis 기반 캐싱 인프라가 성장하면서 연결 수 한계, 급격한 확장 시 연결 폭주, 관측성 부족 등으로 가용성 위협이 커지자 이를 근본적으로 재설계했다. 그 결과 stateless RESP 프록시인 FigCache를 구축해 Redis 연결과 클라이언트 서비스 규모를 분리하고, 라우팅·보안·관측성을 중앙화했다. 2025년 하반기 핵심 API에 도입한 이후 캐싱 계층은 99.9999% 가동률을 달성했다. ## Redis 캐싱 인프라의 성장통 - Figma의 Redis는 단순한 보조 구성 요소에서 사이트 가용성에 직접 영향을 주는 핵심 의존성으로 발전했다. - Redis 클러스터의 연결 수가 한계에 가까워졌고, 클라이언트 서비스가 빠르게 확장될 때 대규모 연결 생성이 동시에 발생하는 ‘thundering herd’ 문제가 나타났다. - 중앙화된 트래픽 관리와 일관된 접근 방식이 없어 애플리케이션이 서로 다른 클러스터의 데이터를 오염시키거나 손상시킬 위험이 있었다. - 클라이언트 라이브러리마다 관측 기능이 달라 장애 원인 분석과 대응이 어려웠다. - 장애 조치나 토폴로지 변경 시 클라이언트 상태가 올바르게 유지되는지 전체 서비스에 일관된 보장을 제공하기도 어려웠다. - Figma는 일부 API 시스템에서 Redis 의존성을 제거하고, 서비스별 연결 풀링을 도입해 단기적으로 장애 영향을 줄였지만 장기적인 공통 플랫폼이 필요하다고 판단했다. ## 장기적인 설계 목표 - **클라이언트 연결 변동성으로부터 Redis 격리** - Redis가 처리하는 연결 수를 클라이언트 애플리케이션의 규모와 탄력적 확장성에서 분리한다. - 서비스가 급격히 확장될 때 Redis로 연결 요청이 몰리는 현상을 막는다. - **기본 제공 observability** - 서비스 소유자와 플랫폼 운영자가 멀티테넌트 환경에서 개별 워크로드의 가용성과 성능을 확인할 수 있도록 한다. - 여러 계층에서 일관되고 세밀한 모니터링 기능을 제공한다. - **투명한 수평 확장** - 클라이언트가 인프라 확장이나 축소를 직접 알 필요 없도록 한다. - 클러스터 확장·축소, 노드 장애 조치, 샤드 전체 손실 같은 복잡한 Redis Cluster 동작을 클라이언트 라이브러리 아래 계층에서 처리한다. - **단일 범용 엔드포인트** - 여러 Redis 클러스터를 애플리케이션별 개별 설정 없이 중앙 라우팅한다. - 클러스터 격리 수준, 내구성, 중요도, 트래픽 규모가 서로 다른 환경의 분할 결정을 중앙에서 관리한다. - **대체 저장소의 플러그인 가능성** - 같은 프로토콜과 API를 유지하면서 필요에 따라 진정한 내구성을 제공하는 다른 저장 기술을 연결할 수 있도록 한다. - **기본 확장성** - 인라인 데이터 암호화, 보호 장치(guardrail), 트래픽 백프레셔 등 Figma 고유의 데이터 플레인 기능을 애플리케이션마다 반복 구현하지 않도록 한다. ## FigCache의 구조와 역할 - FigCache는 **stateless RESP-wire-protocol 프록시 서비스**다. - Redis 데이터 플레인과 진입 계층 역할을 하며, 애플리케이션에는 언어와 무관한 일관된 Redis 인터페이스를 제공한다. - 여러 Redis 클러스터와 백엔드 사이의 트래픽 라우팅 및 클러스터 관리 복잡성을 애플리케이션에서 숨긴다. - 연결 멀티플렉서로 동작해 클라이언트 서비스의 연결 변동이 Redis에 직접 전달되지 않도록 한다. - FigCache 자체와 함께 Figma가 관리하는 전용 클라이언트 라이브러리를 제공해 캐싱 스택 전반의 동작을 표준화한다. ## 플랫폼 전환의 효과 - Redis 연결 확장성과 클라이언트 서비스의 용량 변동을 분리할 수 있게 됐다. - 중앙화된 라우팅으로 애플리케이션이 여러 클러스터의 엔드포인트를 직접 관리할 필요가 줄었다. - 보안 정책과 트래픽 제어를 공통 계층에서 적용할 기반이 마련됐다. - 전체 캐싱 스택에 걸친 종합적인 관측성을 확보했다. - 2025년 하반기 Figma의 메인 API 서비스에 적용한 뒤 캐싱 계층은 **99.9999% 가동률**이라는 안정성 목표를 달성했다. ## 실용적인 시사점 Redis를 서비스의 핵심 경로에서 사용할 때는 개별 애플리케이션의 연결 풀링만으로 문제를 해결하기보다, 연결 중계·라우팅·클러스터 토폴로지 관리·관측성을 공통 플랫폼으로 분리하는 것이 효과적이다. 특히 클라이언트 수가 탄력적으로 변하는 환경에서는 프록시 계층을 통해 Redis가 직접 연결 폭주를 겪지 않도록 설계하는 것이 중요하다.

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

GitLab 메트릭스 및 레지스트리 기능이 CI/CD 병목 현상을 줄이는 데 도움을 줍니다. (새 탭에서 열림)

GitLab이 새롭게 선보이는 CI/CD 작업 성능 메트릭과 컨테이너 가상 레지스트리 기능은 개발 및 운영 팀이 직면한 인프라 복잡성과 파이프라인 병목 현상을 직접 해결하는 데 중점을 둡니다. 별도의 타사 도구 없이도 GitLab 내부에서 작업별 성능 데이터를 분석하고 여러 외부 소스의 컨테이너 이미지를 통합 관리 및 캐싱함으로써, 전체적인 개발 워크플로우의 속도와 안정성을 동시에 개선할 수 있습니다. ## CI/CD 작업 성능 메트릭을 통한 병목 지점 시각화 그동안 파이프라인의 성능 저하나 실패 원인을 파악하기 위해 별도의 대시보드를 구축하거나 로그를 수동으로 분석해야 했던 번거로움이 해결되었습니다. * **성능 지표 제공**: 각 작업(Job)별로 중앙값(P50) 및 최악의 케이스(P95) 실행 시간을 제공하여, 평상시 속도와 비정상적으로 느려진 시점을 명확히 구분할 수 있습니다. * **실패율 추적**: 특정 작업의 실패 빈도를 파악하여 불안정한(flaky) 작업을 식별하고 파이프라인의 신뢰도를 높일 수 있습니다. * **통합 분석 대시보드**: 프로젝트 수준의 CI/CD 분석 페이지에서 지난 30일간의 데이터를 기반으로 작업 이름, 단계(Stage)별 정렬 및 검색이 가능합니다. * **기술적 요구사항**: GitLab Premium 및 Ultimate 티어에서 사용 가능하며, 셀프 호스팅 환경의 경우 ClickHouse가 구성되어 있어야 합니다. 향후 빌드, 테스트, 배포 단계별 그룹화 기능이 추가될 예정입니다. ## 컨테이너 가상 레지스트리를 활용한 이미지 관리 최적화 Docker Hub, Harbor, Quay 등 여러 레지스트리에 흩어져 있는 이미지를 개별적으로 관리하며 발생하는 인증 및 대역폭 비용 문제를 단일 엔드포인트를 통해 해결합니다. * **단일 엔드포인트 통합**: 여러 업스트림 레지스트리를 하나의 GitLab 가상 레지스트리 주소로 통합하여, 파이프라인 설정에서 번거로운 개별 인증 과정을 줄일 수 있습니다. * **풀스루 캐싱(Pull-through Caching)**: 첫 번째 호출 이후 이미지를 GitLab 내부에 캐싱하여 외부 네트워크 대역폭 비용을 절감하고 이미지 풀 속도를 향상합니다. * **지원 범위**: 현재 Docker Hub, Harbor, Quay 등 장기 토큰 인증을 사용하는 레지스트리를 지원하며, 향후 AWS ECR이나 Google Artifact Registry 같은 클라우드 기반 레지스트리로 확장될 계획입니다. * **운영 방식**: GitLab 18.9 버전부터 API를 통해 설정 가능하며, SaaS 사용자는 기능 플래그 활성화를 통해 베타 버전에 참여할 수 있습니다. 성능 저하로 고민하는 플랫폼 팀이라면 이번 베타 기능을 통해 파이프라인의 병목 구간을 우선적으로 점검해 보길 권장합니다. 특히 여러 외부 레지스트리를 혼용하는 환경에서는 가상 레지스트리를 도입함으로써 관리 포인트를 일원화하고 대역폭 비용을 효과적으로 줄일 수 있습니다. 해당 기능들은 커뮤니티 피드백을 바탕으로 개선되고 있으므로, 실제 도입 후 개선 제안을 공유하는 것도 좋은 방법입니다.

line원문

슬로우 쿼리 해결기: 함수형 인덱스로 비트 연산 쿼리 최적화하기 (새 탭에서 열림)

LINE VOOM 서비스는 헤비 유저의 프로필 조회 시 비트 연산 조건으로 인해 발생하는 30초 이상의 슬로우 쿼리 문제를 해결하기 위해 MySQL 8.0.13의 함수형 인덱스(functional index)를 도입했습니다. 기존의 비트 연산 조건은 인덱스를 무력화하여 수십만 건의 데이터를 풀 스캔하게 만들었으나, 연산 결과를 인덱싱하고 이를 10진수 동등 비교 쿼리로 전환함으로써 스캔 범위를 3% 수준으로 대폭 축소했습니다. 이 과정에서 무중단 인덱스 생성과 점진적 롤아웃을 통해 운영 안정성을 확보하며 시스템 성능을 성공적으로 최적화했습니다. ### 비트 연산 조건에 의한 성능 저하 원인 * LINE VOOM의 포스트 메타데이터 테이블은 `category_flag`와 `access_flag`라는 `bit(64)` 타입 컬럼에 서비스 상태 정보를 압축 저장합니다. * 특정 상태를 필터링하기 위해 `category_flag & 0x0100`과 같은 비트 연산을 사용했는데, 이는 인덱스에 저장된 원본 값이 아닌 연산 결과를 조건으로 활용하므로 기존 인덱스를 타지 못합니다. * 결과적으로 특정 사용자의 모든 포스트를 일일이 순회하며 연산을 수행해야 했고, 포스트가 수십만 건에 달하는 헤비 유저의 경우 쿼리 타임아웃이 빈번하게 발생했습니다. ### 함수형 인덱스를 활용한 최적화 설계 * MySQL 8.0.13에서 도입된 함수형 인덱스는 표현식의 결과를 가상 컬럼 형태로 저장하고 인덱싱하는 기능을 제공합니다. * 팀은 `user_id`와 비트 연산 표현식을 결합한 복합 인덱스 `idx_user_premium_searchable (user_id, (category_flag & 0x0100), (access_flag & 0x0001))`를 설계했습니다. * 이 방식은 기존 테이블 스키마를 크게 변경하지 않으면서도 특정 비트 패턴에 대해 즉각적인 인덱스 조회를 가능하게 합니다. ### 인덱스 활성화를 위한 쿼리 튜닝 및 검증 * 개발 환경 테스트 결과, 단순히 비트 연산을 포함하는 것만으로는 인덱스가 작동하지 않는 것을 확인했습니다. * 인덱스를 타기 위해서는 쿼리의 표현식이 인덱스 정의와 완벽히 일치해야 하며, 특히 비트 연산 결과를 **10진수 값으로 동등 비교**(`= 256`)했을 때만 인덱스가 정상적으로 적용되었습니다. * 최적화 후 스캔 행 수가 805건에서 31건으로 줄어드는 등 극적인 성능 향상을 보였으며, 인덱스 용량 증가(약 24%)는 운영 환경에서 수용 가능한 수준으로 판단되었습니다. ### 운영 환경 적용 및 시행착오 해결 * **무중단 인덱스 생성**: DBA 팀과 협업하여 Online DDL 방식을 사용함으로써 서비스 중단 없이 수십 개의 테이블에 인덱스를 추가했습니다. * **복제 지연 대응**: 인덱스 생성 중 발생한 마스터-슬레이브 복제 지연으로 인해 최신 글이 보이지 않는 이슈가 발생했으나, 캐시 만료 시간을 단축하여 사용자 불편을 최소화했습니다. * **논리 오류 방지**: 비트 연산을 동등 비교로 바꿀 때 OR 조건과 AND 조건의 의미 차이로 인한 버그를 발견했습니다. 이를 방지하기 위해 동적 설정을 활용해 샤드별로 쿼리를 점진적으로 적용하며 안전하게 검증을 마쳤습니다. 비트 연산과 같이 컬럼 가공이 필요한 조건을 상시로 사용해야 한다면, MySQL의 함수형 인덱스는 스키마 변경 부담을 최소화하면서 성능을 극대화할 수 있는 강력한 도구입니다. 다만, 인덱스가 적용되는 정확한 표현식(10진수 비교 등)을 사전에 검증하고, 대규모 테이블 작업 시 발생할 수 있는 복제 지연과 논리적 조건 변화를 세심하게 모니터링하는 것이 중요합니다.

naver원문

@RequestCache: HTTP 요청 범위 캐싱을 위한 커스텀 애너테이션 개발기 (새 탭에서 열림)

웹 애플리케이션에서 하나의 HTTP 요청 내에 발생하는 중복된 API 호출은 성능 저하와 리소스 낭비를 초래하며, 이를 해결하기 위해 요청 범위(Request Scope) 내에서 결과를 캐싱하는 `@RequestCache` 커스텀 애너테이션을 개발했습니다. 이 기능은 Spring의 `RequestAttribute`를 활용해 요청별로 독립적인 캐시 공간을 보장하며, 요청 종료 시 자동으로 메모리가 정리되는 효율적인 생명주기 관리 구조를 가집니다. 이를 통해 복잡한 파라미터 전달이나 부적절한 TTL 설정 문제를 해결하고 시스템의 전반적인 응답 속도를 개선할 수 있습니다. ### 파라미터 전달 및 범용 캐시의 한계 * **응답 객체 전달 방식의 복잡성**: 데이터를 실제 사용하는 말단 서비스까지 객체를 넘기기 위해 중간 계층의 모든 메서드 시그니처를 수정해야 하며, 이는 코드 가독성을 떨어뜨리고 관리를 어렵게 만듭니다. * **전략 패턴의 유연성 저하**: 공통 인터페이스를 사용하는 경우, 특정 구현체에서만 필요한 데이터를 파라미터에 포함해야 하므로 인터페이스의 범용성이 훼손됩니다. * **TTL(Time To Live) 설정의 딜레마**: Redis나 로컬 캐시 사용 시 TTL이 너무 짧으면 동일 요청 내 중복 호출을 막지 못하고, 너무 길면 서로 다른 요청 간에 의도치 않은 데이터 공유가 발생하여 데이터 정합성 문제가 생길 수 있습니다. ### @RequestCache의 특징과 동작 원리 * **RequestAttribute 기반 저장소**: 내부적으로 `ThreadLocal`을 사용하는 `RequestAttribute`에 데이터를 저장하여, 스레드 간 격리를 보장하고 각 HTTP 요청마다 독립적인 캐시 인스턴스를 유지합니다. * **자동 생명주기 관리**: 캐시의 수명이 HTTP 요청의 생명주기와 일치하므로 별도의 만료 시간을 계산할 필요가 없으며, 요청 완료 시 Spring의 `FrameworkServlet`에 의해 자동으로 정리되어 메모리 누수를 방지합니다. * **AOP 기반의 간편한 적용**: 비즈니스 로직을 수정할 필요 없이 캐싱이 필요한 메서드에 `@RequestCache` 애너테이션을 선언하는 것만으로 손쉽게 중복 호출을 제거할 수 있습니다. ### @RequestScope와 프록시 메커니즘 * **프록시 패턴 활용**: `@RequestScope`로 선언된 빈은 Spring 컨테이너에 프록시 객체로 등록되며, 실제 메서드 호출 시점에 현재 요청에 해당하는 실제 인스턴스를 찾아 호출을 위임합니다. * **상태 저장 방식**: `AbstractRequestAttributesScope` 클래스를 통해 실제 객체가 `RequestAttributes` 내에 저장되며, 이를 통해 동일 요청 내에서는 같은 인스턴스를 공유하게 됩니다. 동일 요청 내에서 외부 API 호출이 잦거나 복잡한 연산이 반복되는 서비스라면, 전역 캐시를 도입하기 전 `@RequestCache`와 같은 요청 범위 캐싱을 통해 코드 순수성을 유지하면서도 성능을 최적화할 것을 권장합니다.

slack4분 읽기큐레이션 요약

더 나은 소프트웨어를 만들기

빌드가 60분씩 걸리면 코드 변경에 대한 피드백이 늦어져 개발 생산성이 크게 떨어진다. Slack은 Bazel과 전통적인 성능 최적화 원칙인 캐싱·병렬화를 결합해 빌드 시간을 개선했다. 핵심은 빌드를 명확한 입력·출력 단위의 그래프로 모델링하고, 재사용 가능하고 병렬 실행 가능한 작은 작업으로 나누는 것이다. ## 빌드를 방향성 비순환 그래프로 모델링 - 백엔드와 프런트엔드는 서로 독립적으로 개발·배포될 수 있으며, 각각 필요한 소스 파일에만 의존한다. - 빌드 구성 요소와 배포 산출물 사이의 의존성은 방향성 비순환 그래프(DAG)로 표현된다. - 특정 Python 파일이 변경되면 백엔드만 다시 빌드하고, TypeScript 파일 변경 때문에 백엔드까지 재빌드하지 않도록 의존성을 정확히 정의할 수 있다. - 그래프로 빌드를 표현하면 애플리케이션 코드와 동일하게 다음 최적화를 적용할 수 있다. - 이미 수행한 작업의 결과를 저장해 다시 계산하지 않기 - 여러 컴퓨팅 자원에 작업을 분산해 동시에 처리하기 ## 캐싱을 통한 불필요한 작업 제거 - 캐시는 입력값과 결과값을 연결해 동일한 입력에 대한 작업을 한 번만 수행하도록 한다. - 예를 들어 `factorial(n)`은 입력 `n`에 따라 결과가 항상 같으므로 `functools.cache`를 적용할 수 있다. - 빌드 캐싱이 올바르게 작동하려면 작업이 다음 조건을 만족해야 한다. - **Hermetic**: 명시적으로 전달된 입력만 사용해 결과를 생성해야 한다. - **Idempotent**: 동일한 입력에 대해 항상 동일한 결과를 내야 한다. - 캐시 성능은 전체 호출 중 캐시에서 결과를 가져오는 비율인 캐시 적중률(hit rate)에 좌우된다. ## 작업 단위를 작게 나눠 캐시 적중률 높이기 - 이미지 목록 전체와 변환 목록 전체를 입력으로 받는 `process_images()`에 캐시를 적용하면, 이미지 하나만 추가돼도 전체 입력이 바뀐 것으로 간주된다. - 이 방식은 캐시 키가 지나치게 크고 거칠어, 작은 변경에도 모든 작업을 처음부터 다시 수행해야 한다. - 대신 이미지 하나에 변환 하나를 적용하는 `process_image(image, transform)`처럼 더 작은 단위에 캐시를 적용할 수 있다. - 그러면 새로 추가되거나 변경된 이미지·변환 조합만 처리하고, 이미 계산한 조합은 캐시에서 재사용할 수 있다. - 상위 수준 API는 유지하면서 내부 작업 단위만 세분화하는 방식이 성능과 재사용성을 높인다. ## 병렬화를 통한 작업 분산 - 이미지 처리처럼 서로 독립적인 작업은 여러 CPU 코어나 프로세스, 네트워크상의 다른 컴퓨팅 노드로 분산할 수 있다. - 병렬 실행을 위해서는 다음 조건이 필요하다. - 작업의 입력과 출력이 명확하게 정의되어야 한다. - 입력과 출력을 스레드·프로세스·네트워크 경계 너머로 전달할 수 있어야 한다. - 작업이 어떤 순서로 완료되거나 실패할지 보장할 수 없으므로 결과 처리 규칙을 명확히 해야 한다. - 예시의 스레드 기반 구현은 이미지 결과가 입력 순서와 다르게 반환될 수 있다. - 결과 순서 보장 여부는 API 계약의 일부이며, 사용자가 허용할 수 있는 동작인지 사전에 결정해야 한다. ## 병렬화에서도 작업 단위의 크기가 중요 - 작업 수가 적고 각각의 작업이 너무 크면 사용 가능한 컴퓨팅 자원에 충분히 분산하지 못한다. - 반대로 작업을 지나치게 잘게 나누면 작업 전달·관리 오버헤드가 커질 수 있다. - 적절한 작업 크기와 개수의 균형은 문제마다 다르므로 API와 빌드 단위를 설계할 때 함께 고려해야 한다. - 캐싱과 병렬화 모두 입력·출력이 명확하고 독립적인 작은 작업 단위를 필요로 한다. ## Bazel 빌드로 원칙 확장 - Bazel은 빌드를 방향성 비순환 그래프 형태의 **타깃(target)** 으로 정의한다. - 각 타깃에는 다음 세 가지 핵심 요소가 있다. - 빌드 단계의 입력이 되는 의존 파일 - 빌드 단계가 생성하는 출력 파일 - 입력을 출력으로 변환하는 명령어 - 이러한 명시적 정의를 바탕으로 변경된 타깃만 다시 빌드하고, 결과를 캐시하며, 서로 독립적인 타깃을 병렬 실행할 수 있다. - 따라서 빌드 시스템의 성능 개선은 단순히 더 빠른 도구를 도입하는 문제가 아니라, 코드 성능 최적화와 마찬가지로 작업의 경계와 의존성을 설계하는 문제다. 빌드 시간을 줄이려면 먼저 의존성과 입출력을 명확히 정의하고, 변경 범위가 작은 작업 단위로 빌드를 나누는 것이 좋다. 그 위에 hermetic·idempotent한 작업을 캐시하고 독립 작업을 병렬화하면, 대규모 프로젝트에서도 불필요한 재빌드를 줄이고 개발자 피드백 속도를 높일 수 있다.

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

스트림 뒤편: 라이브 이벤트를 위한 실시간 추천 3부 | 넷플릭스 기술 블로그 | 넷플릭스 테크블로그 (새 탭에서 열림)

넷플릭스는 수천만 명의 시청자가 동시에 접속하는 라이브 이벤트 상황에서 시스템 과부하를 방지하면서도 실시간 개인화 추천을 제공하기 위해 '프리페칭(Prefetching)'과 '실시간 브로드캐스팅'이라는 2단계 전략을 도입했습니다. 이 시스템은 이벤트 시작 전 미리 데이터를 기기에 저장해 두었다가, 실제 시작 시점에는 최소한의 신호만 보내 로컬에서 추천 정보를 활성화함으로써 '천둥 번개 효과(Thundering Herd)' 문제를 효과적으로 해결합니다. 이를 통해 넷플릭스는 클라우드 자원을 무리하게 확장하지 않고도 전 세계 수억 대의 기기에 지연 없는 실시간 스트리밍 경험을 제공할 수 있게 되었습니다. **라이브 이벤트와 시동 시간의 제약** * VOD와 달리 라이브 이벤트는 모든 시청자가 특정 시점에 동시에 접속하므로, 짧은 시간 내에 수억 개의 기기에 업데이트를 전달해야 하는 기술적 난관이 존재합니다. * 단순히 서버를 증설하는 선형적 확장은 비효율적이며, 다른 핵심 서비스의 자원을 고갈시킬 위험이 있습니다. * 성공적인 실시간 추천을 위해서는 업데이트 소요 시간(Time), 서비스 처리 용량(Request Throughput), 요청의 다양성(Compute Cardinality)이라는 세 가지 제약 조건을 동시에 최적화해야 합니다. **프리페칭을 통한 트래픽 분산** * 이벤트 시작 전 사용자가 평소처럼 앱을 탐색하는 동안, 라이브 이벤트와 관련된 메타데이터, 아트워크, 개인화된 추천 리스트를 미리 기기 캐시에 저장합니다. * 이를 통해 서버 요청을 시간에 따라 자연스럽게 분산시켜, 이벤트 직전 발생하는 트래픽 스파이크를 제거하고 시스템 안정성을 확보합니다. * 서버 측에서 미리 계산된 '구체화된 추천(Materialized Recommendations)'을 제공함으로써 기기별 요청의 복잡도를 낮춥니다. **저카디널리티 실시간 브로드캐스팅** * 이벤트가 실제로 시작되거나 일정이 변경될 때, 넷플릭스의 푸시 서비스(Zuul Push)를 통해 연결된 모든 기기에 '저카디널리티(Low-cardinality)' 메시지를 전송합니다. * 이 메시지는 복잡한 데이터를 담지 않고 단순히 미리 캐싱된 데이터를 화면에 표시하라는 트리거 역할만 수행하여 네트워크 부하를 최소화합니다. * '최소 한 번(At-least-once)' 전달 방식을 채택하여 네트워크 상태가 불안정한 기기도 다시 온라인 상태가 되면 누락된 업데이트를 즉시 따라잡을 수 있도록 설계되었습니다. **데이터 기반의 동적 적응** * 라이브 이벤트의 특성상 경기 시간이 지연되거나 일정이 변동될 수 있는데, 브로드캐스팅 시스템은 이러한 실시간 제작 상황에 맞춰 전송 타이밍을 동적으로 조절합니다. * 수천만 대의 기기가 동시에 서버에 데이터를 재요청하는 대신 로컬 데이터를 활용하게 함으로써, 전 세계 모든 사용자가 동일한 순간에 일관된 추천 UI를 볼 수 있게 합니다. 라이브 이벤트와 같은 초고부하 상황에서는 무조건적인 서버 증설보다는 클라이언트의 로컬 자원을 활용하고 서버 부하를 시간적으로 분산하는 아키텍처가 필수적입니다. 실시간성이 중요한 서비스라면 모든 데이터를 실시간으로 전송하기보다, 정적인 데이터는 미리 배치하고 상태 변화를 알리는 최소한의 신호만 실시간으로 처리하는 하이브리드 접근 방식을 권장합니다.

line원문

Flutter Riverpod 200% 활용하기 (새 탭에서 열림)

Riverpod은 기존 Provider 라이브러리의 한계를 극복하고 개발자가 더욱 직관적이고 유연하게 상태를 관리할 수 있도록 설계된 Flutter 상태 관리 라이브러리입니다. 서버 데이터 처리 최적화, 자동 생명 주기 관리, 의존성 주입 등 강력한 기능을 기본으로 제공하여 코드의 복잡성을 대폭 낮춰줍니다. 결과적으로 개발 생산성을 높이고, 성능 저하나 디버깅 오류와 같은 상태 관리의 고질적인 문제들을 효과적으로 해결해 줍니다. **서버 데이터 처리 및 상태 관리 최적화** * 서버에서 데이터를 가져올 때 필수적인 로딩, 에러, 데이터 유무 상태를 별도 로직 없이 기본적으로 제공합니다. * API 호출 도중 해당 데이터가 더 이상 필요하지 않게 되면 요청을 자동으로 취소하거나, 데이터의 유효 기간 및 재사용 설정을 손쉽게 관리할 수 있습니다. * '당겨서 새로 고침(pull to refresh)'과 같은 빈번한 UI 패턴을 `ref.refresh` 기능을 통해 간결하게 구현할 수 있어 반복적인 코드 작성을 줄여줍니다. **자유로운 의존성 주입과 자동 생명 주기 관리** * 위젯 계층 구조에 묶이지 않고 어디서든 Provider에 접근할 수 있어, 복잡한 순서나 구조를 신경 쓰지 않고 데이터를 참조할 수 있습니다. * Riverpod이 Provider의 생성과 소멸 시점을 자동으로 관리하므로 메모리 누수 방지와 같은 자원 관리가 용이합니다. * 개발자는 상태를 정의하는 Model과 이를 관리하는 Provider, 데이터를 소비하는 View를 명확히 분리하여 깔끔한 아키텍처를 유지할 수 있습니다. **효율적인 데이터 연동 및 캐시 활용 기법** * **Provider 간 상태 구독:** 필터 조건이 변경되면 이를 구독 중인 목록 Provider가 자동으로 데이터를 새로 불러오도록 설정할 수 있어 수동 리빌드 로직이 필요 없습니다. * **즉각적인 사용자 경험 제공:** 상세 화면 이동 시 목록에서 미리 불러온 데이터를 즉시 노출하고, 동시에 서버에서 추가 정보를 가져오는 방식으로 로딩 지연을 최소화합니다. * **오프라인 데이터 결합:** 로컬 DB 데이터와 서버 데이터를 유연하게 결합하여 네트워크가 불안정한 환경에서도 사용자에게 끊김 없는 인터페이스를 제공할 수 있습니다. * **화면 간 동기화:** 상세 화면에서 수정된 즐겨찾기 상태나 업데이트 내역이 목록 화면에도 즉각 반영되도록 구현하여 앱 전반의 데이터 일관성을 보장합니다. Riverpod은 단순히 상태를 저장하는 도구를 넘어, 비동기 프로그래밍과 의존성 관리를 우아하게 해결해 주는 솔루션입니다. 특히 서버 통신이 많고 화면 간 데이터 동기화가 복잡한 앱을 개발할 때, Riverpod의 선언적인 코드 스타일과 리액티브한 특징을 활용하면 유지 보수성이 뛰어난 코드를 작성할 수 있습니다.

datadog원문

Datadog APM을 사용하여 Homebrew 성능 개선 (새 탭에서 열림)

이 글은 Datadog의 소프트웨어 엔지니어링 인턴인 Andrew Robert McBurney가 오픈 소스 프로젝트인 Homebrew의 `brew linkage` 명령어 성능을 개선한 과정을 다룹니다. Datadog의 APM 도구와 플레임 그래프를 활용해 병목 지점을 정확히 파악했으며, 캐싱 메커니즘을 도입하여 패키지 검사 속도를 획기적으로 향상시켰습니다. 결과적으로 106개 패키지 처리 시간을 11.5초에서 182밀리초로 단축하며 프로젝트의 요구 성능을 성공적으로 충족했습니다. ### APM을 활용한 성능 병목 지점 탐색 * Datadog의 `ddtrace` 젬(gem)을 사용해 Homebrew의 루비 코드를 인스트루먼테이션(instrumentation)하여 실행 데이터를 수집했습니다. * 수집된 데이터를 플레임 그래프로 시각화하여 분석한 결과, `LinkageChecker::check_dylibs` 함수가 전체 실행 시간의 대부분을 차지하는 병목 지점임을 확인했습니다. * 이 함수는 패키지의 동적 라이브러리 링크를 확인하고 이를 시스템 라이브러리, 깨진 링크, 선언되지 않은 의존성 등으로 분류하는 복잡한 작업을 수행합니다. ### 멀티스레딩의 한계와 캐싱 전략 도입 * 초기에는 루비의 `Thread` 프리미티티브를 이용한 멀티스레딩으로 성능 개선을 시도했으나, 루비의 **GIL(Global Interpreter Lock)** 제한으로 인해 기대했던 성능 향상을 얻지 못했습니다. * 대안으로 SQLite3를 이용한 온디스크(on-disk) 캐싱 메커니즘을 설계하여, 한 번 계산된 연결성 정보를 영구 저장하고 재사용하도록 했습니다. * SQLite3 기반 캐싱 도입 후, `boost` 라이브러리 검사 시간이 1.01초에서 1.38밀리초로 줄어드는 등 전체적인 명령 처리 속도가 비약적으로 개선되었습니다. ### 의존성을 고려한 PStore 기반 최종 최적화 * Homebrew 유지관리자의 피드백을 반영하여, 외부 의존성인 SQLite3 젬 대신 루비 표준 라이브러리인 **PStore**로 캐싱 구현을 교체했습니다. * PStore는 루비 객체를 파일에 영구적으로 저장하는 해시 기반의 메커니즘으로, 추가적인 외부 라이브러리 설치 없이도 SQLite3와 유사한 성능 이점을 제공합니다. * 이 과정을 통해 대규모 오픈 소스 프로젝트에서는 성능 최적화만큼이나 의존성 관리와 표준 라이브러리 활용이 중요하다는 점을 입증했습니다. ### 실용적인 결론 성능 최적화 시 직관에 의존하기보다 APM과 같은 도구를 사용하여 데이터 기반으로 병목을 찾는 것이 중요합니다. 특히 루비 환경에서는 GIL로 인해 병렬 처리가 제한적일 수 있으므로, 연산량이 많은 작업은 캐싱을 통해 중복 계산을 피하는 것이 가장 효과적인 전략이 될 수 있습니다. 또한, 오픈 소스 기여 시에는 프로젝트의 경량성을 유지하기 위해 가급적 표준 라이브러리(예: PStore)를 활용하는 것을 권장합니다.

datadog원문

해커톤 프로젝트: 마인크래프트에서 Datadog 메트릭 보기 (새 탭에서 열림)

Datadog의 엔지니어들은 사내 해커톤을 통해 시스템 모니터링 대시보드를 마인크래프트 게임 내부에서 구현하는 실험적인 프로젝트를 진행했습니다. 파이썬과 Datadog API를 활용해 실시간 인프라 메트릭을 게임 내 블록 형태로 시각화했으며, 이를 통해 온콜(on-call) 업무 중인 엔지니어가 게임을 즐기면서도 시스템 상태를 직관적으로 확인할 수 있는 환경을 구축했습니다. 이 프로젝트는 기술적인 재미와 더불어 대용량 데이터를 게임 환경에 효율적으로 렌더링하기 위한 성능 최적화 과정을 잘 보여줍니다. ### 마인크래프트 제어와 데이터 연동 * 파이썬의 익숙함과 풍부한 라이브러리를 활용하기 위해 `py3minepi`와 Raspberry Juice API를 사용하여 마인크래프트 환경을 제어했습니다. * `mc.setBlock(x, y, z, block_id)`와 같은 간단한 함수 호출을 통해 게임 내 특정 좌표에 블록을 생성하거나 제거하며 시각화의 기초를 마련했습니다. * Datadog 파이썬 라이브러리를 통해 API 및 애플리케이션 키로 인증한 뒤, `Metric.query` 기능을 사용하여 CPU 사용량과 같은 실시간 데이터를 스트리밍했습니다. ### 설정 기반의 대시보드 및 모니터 구현 * 그래프의 위치, 크기, 방향, 색상 및 투명도와 같은 시각적 요소를 코드와 분리하기 위해 YAML 설정 파일을 도입했습니다. * 실시간 데이터를 기반으로 모니터링 상태를 반영하여, 시스템에 경고가 발생하면 빨간색 블록이 켜지고 정상 상태가 되면 초록색으로 돌아오는 시각적 알람 기능을 구현했습니다. * 단순한 그래프를 넘어 여러 메트릭을 동시에 확인할 수 있는 복합 대시보드 레이아웃을 구성하여 게임 내에서도 실제 모니터링 도구와 유사한 경험을 제공했습니다. ### 영속성 관리와 성능 최적화 과제 * **블록 영속성 문제:** 마인크래프트 블록은 한 번 생성되면 계속 유지되므로, 데이터가 갱신될 때마다 이전 블록을 지워주는 '진공(vacuum)' 함수를 작성하여 화면을 정제했습니다. * **대역폭 및 렌더링 최적화:** 웹 기반의 대시보드와 달리 JS나 CSS를 사용할 수 없으므로 데이터를 행 단위로 단순화하여 시각화했습니다. * **캐싱 도입:** 대규모 그래프를 출력할 때 데이터 파이프라인에 과부하가 걸리는 문제를 해결하기 위해, 실제 업무에서 사용하는 것과 유사한 캐싱 메커니즘을 적용하여 성능을 개선했습니다. 이 프로젝트는 엔지니어링의 본질적인 즐거움인 '해킹'을 통해 익숙한 도구를 전혀 새로운 환경에 이식한 사례입니다. 단순히 재미를 넘어 실시간 데이터 처리와 렌더링 최적화라는 기술적 도전을 담고 있으며, 관련 소스 코드는 GitHub에 공개되어 있어 누구나 자신의 메트릭을 마인크래프트 세상에 구현해 볼 수 있습니다.