트래픽을 일정 비율로 안전하게 나누는 방법: 해시 코호트와 구성 기반 롤아웃

개요 운영 중인 서비스에서 전체 트래픽을 한 번에 신규 기능이나 신규 인프라로 전환하지 않고, 일정 비율만 점진적으로 이동하는 전략이 필요함 주요 활용 맥락 A/B 테스트로 실험군과 통제군 분리 카나리 배포로 신규 버전을 소수 사용자에게만 적용 신규 데이터베이스, 캐시, 인덱스 전환 검증 신규 알고리즘, 추천 엔진, 정책 점진 적용 서버 비용 최적화를 위한 점진적 트래픽 이동 아래는 대부분의 시나리오에 적용 가능한 일반화된 트래픽 분배 기법 정리 요구 조건 Deterministic — 같은 사용자나 리소스는 항상 같은 그룹에 속해야 함 요청마다 그룹이 바뀌면 실험 신뢰성이 떨어지고 디버깅이 어려움 안정적 해시 기반 결정 방식 필요 ...

December 29, 2025

Observer 패턴 제대로 이해하기 — 동작 원리와 RxJS 확장

개념/배경 한 객체의 상태 변화나 이벤트를 여러 객체가 자동으로 감지하고 반응하게 만드는 구조를 Observer 패턴이라 부름 발행자와 구독자의 관계로도 설명됨. Publisher가 이벤트를 내보내고 Subscribers가 이를 받는 흐름 핵심은 느슨한 결합과 자동 알림 흐름 유지 핵심 개념과 구성요소 Subject 또는 Observable 이벤트를 발생시키는 주체 Observer 목록을 관리 상태가 변하면 observers에 알림 전파 Observer 상태 변화를 알고 싶은 소비자 update 같은 콜백 보유 notify Subject가 모든 Observer에게 브로드캐스트하는 동작 동작 원리 Observer가 Subject에 구독 등록 Subject 상태 변화 발생 Subject가 notify 실행, 등록된 Observer의 콜백 호출 Observer는 전달된 값에 따라 자체 로직 수행 필수 인터페이스의 최소 형태는 아래와 같음 ...

December 28, 2025

Object.entries 사용법과 주의사항

개요 Object.entries는 객체의 키-값 쌍을 [key, value] 형태의 배열 리스트로 반환하는 표준 메서드임. 객체를 배열로 바꿔 순회, 변환, 자료구조 간 변환 같은 작업을 단순화하는 데 유용함 문법 Object.entries(obj) 매개변수 obj: 키-값 쌍을 가진 객체 값 반환값: [key, value] 쌍의 2차원 배열 기본 예시 const user = { name: 'Alice', age: 25 } Object.entries(user) // [['name', 'Alice'], ['age', 25]] 배열로 변환되므로 for…of, map 같은 배열 API에 바로 연결 가능 순회와 변환 for…of로 키와 값을 동시에 순회 가능 ...

December 27, 2025

백프레셔 Backpressure 개념 정리와 스트림·큐·RxJS 적용 패턴

개념/배경 백프레셔 Backpressure는 소비자가 생산자의 처리 속도를 따라가지 못할 때, 소비자가 생산자의 속도를 조절하도록 피드백을 주는 흐름 제어 메커니즘을 의미함 직관적 비유로 좁은 깔때기 소비자에 높은 수압 생산자를 연결했을 때, 깔때기 내부에 물이 차며 더 유입되지 않도록 압력이 올라가거나 수도를 잠그라는 신호를 보내는 상황과 동일함 왜 중요한가 처리 속도 불균형이 누적되면 메모리 초과와 지연 폭증으로 이어짐 생산자 1000 req/s, 소비자 100 req/s 가정 매초 900개가 버퍼에 쌓여 메모리 증가, 결국 OOM 위험 큐 대기열이 길어져 tail-latency 증가, 사실상 영구 대기 상태 발생 가능 백프레셔는 이런 누적을 초기에 억제해 시스템 안정성 확보와 자원 보호에 기여함 핵심 개념과 정의 Producer: 데이터를 생성·전송하는 주체 Consumer: 데이터를 수신·처리하는 주체 Backpressure: 소비자가 처리 가능한 속도로 생산자에 역방향 피드백을 전달해 유량을 제어하는 행위 전략 축: 조절 Control, 버퍼링 Buffering, 드롭 Dropping 동작 원리/전략 A. 조절 Control/Throttling ...

December 26, 2025

API ErrorCode Enum 설계 베스트 프랙티스

개요 API 에러 규격의 핵심은 에러를 안정적으로 식별할 수 있는 Code 체계 확보임 HTTP Status만으로는 부족하고 메시지는 언어·맥락에 따라 바뀔 수 있음 실제로 계약으로서 신뢰할 수 있는 값은 error.code 임 아래는 다수의 글로벌 서비스에서 공통적으로 쓰는 Error Code 설계 원칙 정리 설계 원칙 error.code 는 서비스 전반의 안정적인 식별자여야 함 메시지나 HTTP Status는 변경 가능하지만 error.code 는 변경 불가 구버전 클라이언트도 동일 코드를 신뢰해야 하므로 호환성 보장 필수 숫자형 대신 의미가 드러나는 문자열 기반 Enum 권장 숫자형은 의미 파악 어려움, 매뉴얼 의존, 협업 비용 증가 문자열 Enum은 가독성, 검색성, 커뮤니케이션 효율 우수 예시 ...

December 25, 2025

Kubernetes 스케줄링 제어를 위한 Taints와 Tolerations 개념과 사용법

개요 Kubernetes에서 Taints는 노드에 거는 출입 제한 설정이고 Tolerations는 파드가 가진 출입 허용 키에 해당함 이 조합으로 스케줄러가 특정 파드를 특정 노드에서 배제하거나 허용하도록 제어 가능 비용이 높은 노드 보호, 장애 노드 격리, 점검 중 노드 비우기 같은 운영 시나리오에서 효과적임 비유로 이해하기 노드가 VIP 라운지, Taint는 라운지 입구의 안내 표지, 파드는 손님, Toleration은 출입증에 해당함 Taint가 있는 노드에는 아무 파드나 배치되지 않음 해당 Taint를 허용하는 Toleration을 가진 파드만 스케줄링 가능 ...

December 24, 2025

자바스크립트에서 균등한 배열 셔플 구현 피셔‑예이츠와 sort+random 편향 이슈

개념과 배경 배열을 무작위로 섞을 때 Array.prototype.sort와 Math.random을 조합한 패턴이 흔히 보임 array.sort(() => Math.random() - 0.5) 형태는 간단해 보이지만 결과 분포가 한쪽으로 치우치는 편향이 발생함 간단한 실험으로 [1, 2, 3]을 백만 회 섞어 빈도를 집계해 보면 특정 순열이 과도하게 많이 나오거나 적게 나오는 경향 관찰됨 핵심은 Math.random 자체보다 sort에 전달된 비교 함수가 랜덤하게 일관성 없이 값을 내놓는 구조라는 점임 왜 sort + random이 편향되는가 정렬 알고리즘은 비교 함수가 다음 성질을 만족한다고 가정함 ...

December 23, 2025

Kubernetes 아키텍처와 핵심 컴포넌트 정리

개요 쿠버네티스는 명령을 조율하는 Control Plane과 실제 워크로드가 실행되는 Data Plane으로 구성됨 각 컴포넌트의 역할과 흐름을 이해하면 트러블슈팅, 성능 최적화, 보안 구성에 필요한 기준이 생김 클라우드 매니지드 쿠버네티스의 경우 Control Plane은 보통 제공자가 관리하지만 동작 원리 이해는 필수 Control Plane API Server 클러스터 유일 진입점 모든 컴포넌트와 사용자는 API Server를 통해 통신 인증과 권한 확인 수행 etcd 클러스터 상태와 스펙을 보관하는 분산 키밸류 저장소 API Server만 직접 접근 가능 상태 복구의 근간이 되는 데이터 원장 Scheduler ...

December 22, 2025

JavaScript에서 객체 대신 Map/Set을 선택해야 하는 경우와 이유

개요 객체는 만능처럼 보이지만 모든 키-값 저장에 적합한 도구는 아님 키를 자주 추가·삭제하고 임의 키로 조회하는 해시맵 유사 패턴에서는 Map이 더 안전하고 일관된 성능을 제공함 중복 없는 집합 연산에는 Set이 자연스러운 선택지 언제 객체 대신 Map을 고려할까 키를 자주 추가·삭제하는 동적 해시맵 패턴 안전한 반복과 구조 분해가 필요한 경우 키의 삽입 순서 유지가 중요한 경우 비문자열 키가 필요한 경우 // 객체 기반 임의 키-값 해시맵 패턴은 delete에서 성능 불리할 수 있음 const mapOfThingsObj = {}; mapOfThingsObj[thing.id] = thing; delete mapOfThingsObj[thing.id]; // Map은 동적 추가·삭제에 최적화 const mapOfThings = new Map(); mapOfThings.set(thing.id, thing); mapOfThings.delete(thing.id);성능 배경 객체는 VM이 숨은 클래스/셰이프를 가정해 최적화하는 경향이 있어 구조가 변동하면 디옵티마이즈 유발 가능성 존재 Map은 해시맵 사용에 맞춰 키 추가·삭제가 빈번한 경우를 목표로 설계됨 마이크로벤치마크는 한계가 있으므로 실제 워크로드에서 측정 권장, 다만 Map이 해당 패턴에 맞춰 설계된 점은 문서로 확인 가능 ...

December 21, 2025

EIP-712 기반 signTypedData 가이드와 지갑 연동 핵심

개요 signTypedData는 EIP-712 표준을 구현한 서명 메서드로 구조화된 데이터에 서명하기 위한 표준 인터페이스를 제공함 지갑은 사람이 읽을 수 있는 형태로 서명 내용을 표시하고, 서명은 특정 도메인과 체인에 귀속되어 재사용 공격을 줄임 signTypedData와 EIP-712의 관계 정의 signTypedData는 EIP-712 규격을 따르는 구조화 데이터 서명 메서드 이더리움 지갑 및 제공자에서 eth_signTypedData, eth_signTypedData_v3, eth_signTypedData_v4 형태로 노출 버전 signTypedData 최초 버전 signTypedData_v3 signTypedData_v4 가장 널리 사용되는 최신 버전 라이브러리 사용 ethers에서는 _signTypedData로 제공 const signature = await signer._signTypedData(domain, types, value) 지갑 연동은 일반적으로 provider에 직접 요청하는 방식 사용 const signature = await ethereum.request({ method: 'eth_signTypedData_v4', params: [account, JSON.stringify({ domain, types, message: value })], })동작 원리 요약 타입화된 구조체 정의 예시 구조체와 필드 타입을 정형화해 명세 도메인 분리자 사용 이름, 버전, 체인 ID, 검증 컨트랙트 주소를 포함해 서명 범위 고정 타입 해시와 데이터 해시 생성 타입 정의를 keccak256으로 해싱 후 데이터 인코딩 해시 생성 최종 해시에 서명 및 검증 지갑에서 서명 생성, 컨트랙트에서 도메인과 타입을 동일하게 재현해 검증 사용 예시 간단한 도메인, 타입, 메시지 구성 예시 const domain = { name: 'MyApp', version: '1', chainId, verifyingContract } const types = { Action: [ { name: 'user', type: 'address' }, { name: 'amount', type: 'uint256' } ] } const value = { user: userAddress, amount } // ethers 서명 const sig = await signer._signTypedData(domain, types, value) // 지갑 요청 v4 서명 const sig2 = await ethereum.request({ method: 'eth_signTypedData_v4', params: [account, JSON.stringify({ domain, types, message: value })], }) 컨트랙트 검증 예시 요약 // OpenZeppelin EIP712, ECDSA 사용 가정 bytes32 digest = _hashTypedDataV4( keccak256(abi.encode( keccak256("Action(address user,uint256 amount)"), user, amount )) ) require(ECDSA.recover(digest, signature) == signer, "Invalid signature")EIP-712 핵심 개념 정리 목적 사람이 읽을 수 있는 서명 메시지 제공 도메인에 귀속된 서명으로 리플레이 공격 저감 구조 타입화된 데이터 스키마와 도메인 분리자 타입 해시와 데이터 해시를 조합한 최종 해시 장점 지갑 UI에서 의미 있는 정보 노출로 UX 개선 다른 dApp이나 체인에서 재사용 어려움으로 보안 강화 주의사항과 팁 v4 사용 권장 v4는 가장 널리 지원되고 구조체 및 배열 표현이 안정적임 provider 요청 방식 web3 라이브러리 함수보다 ethereum.request의 eth_signTypedData_v4 사용이 호환성 측면에서 안전함 타입 정의 일치 컨트랙트와 클라이언트의 타입 이름, 필드 순서, 정수 크기 등 완전 일치 필요 도메인 정합성 chainId와 verifyingContract가 실제 네트워크와 배포 주소와 일치해야 검증 성공 데이터 인코딩 JS 측 정수값은 문자열 또는 BigNumber 형태 사용 권장, 오버플로와 반올림 이슈 회피 ethers 사용 시 types에 EIP712Domain을 포함하지 않음, _signTypedData가 도메인을 별도로 처리함 v4 메시지 포맷 params에 JSON.stringify로 { domain, types, message } 형태 전달 필요 마무리 signTypedData는 곧 EIP-712 사용을 의미하며 구조화된 데이터에 대한 안전한 서명을 가능하게 함 ethers의 _signTypedData 또는 지갑의 eth_signTypedData_v4를 사용해 서명하고, 컨트랙트에서는 동일한 도메인과 타입으로 해시를 재현해 검증하면 됨 명세 일치와 도메인 정합성만 확보하면 안전하고 예측 가능한 서명 흐름을 구현 가능 ...

December 20, 2025