Swift 리드·아키텍트 CS 기초 면접
새 면접Q. 대규모 모바일 앱에서 수백만 건의 사용자 이벤트 로그를 메모리 효율적으로 관리하면서, 최근 N개의 이벤트를 빠르게 조회하고 특정 시간대의 이벤트를 효율적으로 검색해야 합니다. 어떤 자료구조 조합을 선택하시겠습니까? 각 자료구조의 선택 이유와 시간/공간 복잡도 트레이드오프를 설명해주세요.
링 버퍼와 인덱싱 구조를 함께 고려해보세요.
Circular Buffer(링 버퍼)와 B-Tree 또는 Skip List의 조합을 선택하겠습니다. 링 버퍼는 고정된 메모리 공간에서 O(1)로 최근 N개 이벤트를 관리하며, 오래된 데이터를 자동으로 덮어쓰기 때문에 메모리 오버플로우를 방지합니다. 시간 기반 검색을 위해서는 타임스탬프를 키로 하는 B-Tree를 보조 인덱스로 사용하여 범위 쿼리를 O(log n + k)에 수행할 수 있습니다. 메모리가 극도로 제한적인 경우 디스크 기반 LSM Tree를 고려할 수 있으나, 모바일 환경에서는 쓰기 증폭으로 인한 배터리 소모와 플래시 메모리 수명 단축을 고려해야 합니다. 실시간 조회 성능이 중요하다면 메모리 내 Skip List로 O(log n) 검색과 O(1) 삽입의 균형을 맞출 수 있습니다.
- • Circular Buffer로 고정 메모리 사용과 O(1) 최근 데이터 접근
- • B-Tree 또는 Skip List를 통한 시간 범위 검색 최적화
- • 모바일 환경 특성(배터리, 플래시 메모리 수명)을 고려한 트레이드오프 분석
- • 쓰기 패턴과 읽기 패턴의 빈도에 따른 자료구조 선택 근거
분석 SDK나 크래시 리포팅 시스템에서 제한된 모바일 리소스 내에서 대량의 이벤트를 효율적으로 관리할 때 사용됩니다.
만약 이벤트 로그가 디스크에 영구 저장되어야 하고, 앱 재시작 후에도 빠른 복구가 필요하다면 어떤 전략을 추가하시겠습니까?
Q. 글로벌 서비스에서 사용자의 위치 정보를 기반으로 가장 가까운 배달 가능한 매장 10개를 실시간으로 찾아야 합니다. 수십만 개의 매장 위치 데이터가 있고, 매장 정보는 자주 변경되지 않지만 사용자 쿼리는 초당 수천 건입니다. 어떤 알고리즘과 자료구조를 사용하시겠으며, 그 이유와 복잡도를 설명해주세요.
공간 분할 기법과 우선순위 큐를 함께 생각해보세요.
R-Tree 또는 Quadtree 기반의 공간 인덱싱과 K-Nearest Neighbor 알고리즘을 사용하겠습니다. Quadtree는 2D 공간을 재귀적으로 분할하여 O(log n)의 검색 성능을 제공하며, 데이터 분포가 불균등해도 적응적으로 동작합니다. KNN 검색 시 Min-Heap을 사용해 현재까지 찾은 k개 후보를 유지하면서 탐색 범위를 점진적으로 좁혀나가 불필요한 영역 탐색을 가지치기할 수 있습니다. Geohash를 사용한 근사 검색도 고려할 수 있으나, 경계 지점에서의 정확도 문제가 있어 주변 셀까지 검색해야 합니다. 매장 데이터 변경이 드물다면 인덱스를 메모리에 캐싱하고, 변경 시에만 증분 업데이트하여 쿼리 성능을 최적화합니다. 실제 구현에서는 Haversine 공식으로 구면 거리를 계산하되, 초기 필터링에는 Euclidean 거리로 근사하여 연산량을 줄일 수 있습니다.
- • Quadtree/R-Tree 같은 공간 분할 자료구조로 O(log n) 검색
- • Min-Heap 기반 KNN 알고리즘으로 Top-K 유지 및 가지치기
- • Geohash의 장단점과 경계 문제 인지
- • 읽기 중심 워크로드에 대한 캐싱 전략과 증분 업데이트
배달 앱, 차량 공유 서비스, 위치 기반 추천 시스템에서 대규모 지리 데이터를 실시간으로 검색할 때 사용됩니다.
만약 매장마다 영업 시간, 재고 상태 등 동적 속성이 추가되어 필터링이 필요하다면 인덱스 구조를 어떻게 확장하시겠습니까?
Q. 글로벌 iOS 앱에서 특정 지역(예: 동남아시아)의 사용자들이 이미지 업로드 시 간헐적으로 타임아웃이 발생합니다. TCP 3-way handshake는 성공하지만 데이터 전송 중 지연이 발생하며, 특히 모바일 네트워크에서 심합니다. 네트워크 계층 관점에서 원인을 진단하고 해결 방안을 제시해주세요.
TCP의 혼잡 제어 메커니즘과 패킷 손실 시나리오를 고려해보세요.
주요 원인은 높은 패킷 손실률과 긴 RTT 환경에서 TCP의 혼잡 제어 알고리즘이 과도하게 보수적으로 동작하는 것입니다. TCP는 패킷 손실을 네트워크 혼잡 신호로 해석해 윈도우 크기를 급격히 줄이는데, 모바일 네트워크의 무선 구간 손실은 혼잡이 아닌 채널 품질 문제인 경우가 많습니다. Slow Start와 AIMD로 인해 대역폭 활용도가 낮아지고, 특히 BDP(Bandwidth-Delay Product)가 큰 장거리 연결에서 파이프를 채우는데 시간이 오래 걸립니다. 해결책으로는 첫째, TCP BBR 같은 최신 혼잡 제어 알고리즘 사용을 서버에서 활성화하고, 둘째, 청크 단위 업로드로 실패한 부분만 재전송하며, 셋째, HTTP/3(QUIC)로 전환해 HOL blocking을 제거하고 빠른 재전송을 구현합니다. 넷째, 지역별 CDN 엣지 서버를 배치해 RTT를 근본적으로 줄이는 인프라 개선도 필요합니다.
- • TCP 혼잡 제어가 무선 패킷 손실을 혼잡으로 오인하는 문제
- • 높은 RTT와 BDP 환경에서 Slow Start의 비효율성
- • TCP BBR, HTTP/3(QUIC) 등 최신 프로토콜의 이점
- • 청크 업로드와 CDN을 통한 아키텍처 레벨 해결
글로벌 서비스에서 네트워크 품질이 낮은 지역의 대용량 파일 업로드 성능을 개선할 때 직면하는 문제입니다.
HTTP/3(QUIC)로 전환할 때 기존 HTTP/2 대비 고려해야 할 운영상의 리스크나 제약사항은 무엇입니까?
Q. 멀티스레드 iOS 앱에서 백그라운드 스레드에서 이미지 처리 작업을 수행하는 중 메모리 사용량이 예상보다 2-3배 높게 측정되고, 작업 완료 후에도 메모리가 즉시 해제되지 않습니다. ARC는 정상 동작하며 메모리 릭은 없습니다. OS의 메모리 관리 관점에서 원인과 해결 방안을 설명해주세요.
가상 메모리와 물리 메모리의 차이, 그리고 스레드별 메모리 할당 패턴을 생각해보세요.
주요 원인은 멀티스레드 환경에서 메모리 할당자(malloc)가 스레드별 캐시를 유지하며, fragmentation과 할당자의 지연된 해제 정책 때문입니다. iOS의 메모리 할당자는 성능을 위해 스레드 로컬 캐시(magazine)를 사용하는데, 대량 할당 후 해제된 메모리가 즉시 OS로 반환되지 않고 캐시에 남아 재사용을 대기합니다. 또한 Virtual Memory와 Resident Memory의 차이로 인해, 페이지가 할당되었다가 일부만 해제되면 페이지 전체는 여전히 물리 메모리에 상주합니다. Autorelease pool이 스레드별로 드레인되는 시점도 영향을 줍니다. 해결책으로는 첫째, 백그라운드 스레드에서 명시적으로 @autoreleasepool 블록을 사용해 즉시 해제하고, 둘째, 큰 메모리 블록은 mmap 기반 할당(NSData, UnsafeMutableRawPointer 등)을 사용해 할당자 캐시를 우회하며, 셋째, 작업 단위를 작게 나눠 peak memory를 줄이고, 넷째, DispatchQueue의 autoreleaseFrequency를 .workItem으로 설정합니다.
- • 메모리 할당자의 스레드 로컬 캐싱과 지연 해제 메커니즘
- • Virtual Memory와 Resident Memory 차이로 인한 단편화
- • Autorelease pool의 스레드별 드레인 시점
- • mmap 기반 할당과 명시적 메모리 관리 전략
이미지 필터링, 비디오 인코딩 등 대용량 데이터를 멀티스레드로 처리하는 앱에서 메모리 사용량을 최적화할 때 겪는 문제입니다.
Memory Warning을 받았을 때 앱 레벨에서 어떤 우선순위로 메모리를 해제해야 하며, 각 계층별 전략은 무엇입니까?
Q. 모바일 앱에서 로컬 SQLite DB를 사용 중인데, 사용자가 수만 건의 데이터를 저장한 후 특정 쿼리(다중 조인과 정렬 포함)가 수 초씩 걸려 UI가 블로킹됩니다. 인덱스는 이미 적용되어 있습니다. 쿼리 플랜 분석 결과 인덱스는 사용되지만 여전히 느립니다. 데이터베이스 아키텍처 관점에서 원인 진단과 해결 방안을 제시해주세요.
모바일 환경의 I/O 특성과 쿼리 실행 계획의 비용 모델을 고려해보세요.
주요 원인은 첫째, 다중 조인 시 중간 결과 집합이 커져 임시 테이블이 디스크에 생성되며, 모바일 플래시 스토리지의 랜덤 I/O 성능이 제한적이기 때문입니다. 둘째, SQLite는 단일 쓰기 잠금을 사용해 동시성이 낮고, 쿼리 옵티마이저가 복잡한 조인 순서 최적화에 제한적입니다. 셋째, 커버링 인덱스가 아닌 경우 인덱스 스캔 후 테이블 룩업(random access)이 반복되어 I/O 증폭이 발생합니다. 해결책으로는 첫째, 쿼리를 분해해 필요한 데이터만 단계적으로 가져오고 앱 레벨에서 조합(denormalization)하며, 둘째, 자주 조회되는 뷰를 materialized table로 미리 계산해두고 증분 업데이트합니다. 셋째, 커버링 인덱스를 생성해 테이블 접근을 제거하고, 넷째, VACUUM으로 DB 파일 단편화를 제거하며, 다섯째, WAL 모드를 활성화해 읽기 성능을 개선합니다. 근본적으로는 쿼리 복잡도를 줄이는 스키마 재설계나 읽기 전용 복제본 사용을 고려해야 합니다.
- • 다중 조인의 중간 결과와 디스크 기반 임시 테이블 비용
- • 모바일 스토리지의 랜덤 I/O 특성과 인덱스 룩업 패턴
- • 커버링 인덱스와 Materialized View를 통한 I/O 감소
- • WAL 모드, VACUUM 등 SQLite 특화 최적화 기법
오프라인 우선 앱에서 대량의 로컬 데이터를 복잡한 조건으로 조회할 때 성능 병목을 해결하는 상황입니다.
SQLite를 Core Data나 Realm 같은 ORM/객체 DB로 마이그레이션할 때 고려해야 할 기술적 리스크와 비용은 무엇입니까?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!