Ruby on Rails 미드레벨 CS 기초 면접
새 면접Q. 해시 테이블의 충돌(Collision) 해결 방법 중 체이닝(Chaining)과 오픈 어드레싱(Open Addressing)의 차이점과 각각의 장단점을 설명해주세요.
각 방식이 충돌 발생 시 데이터를 어디에 저장하는지 생각해보세요.
체이닝은 같은 해시값을 가진 데이터를 연결 리스트로 관리하는 방식이고, 오픈 어드레싱은 충돌 시 다른 빈 버킷을 찾아 저장하는 방식입니다. 체이닝은 테이블 크기를 초과하는 데이터를 저장할 수 있고 삭제가 간단하지만, 포인터를 위한 추가 메모리가 필요합니다. 오픈 어드레싱은 메모리 효율이 좋고 캐시 친화적이지만, 테이블이 가득 차면 성능이 급격히 저하되고 삭제 시 특별한 처리가 필요합니다. 일반적으로 데이터 개수가 불확실하거나 삭제가 빈번한 경우 체이닝을, 메모리 효율이 중요하고 로드 팩터를 낮게 유지할 수 있다면 오픈 어드레싱을 선택합니다.
- • 체이닝은 연결 리스트 사용, 오픈 어드레싱은 빈 버킷 탐색
- • 체이닝은 메모리 오버헤드, 오픈 어드레싱은 캐시 효율
- • 로드 팩터와 삭제 연산 빈도가 선택 기준
Rails의 ActiveSupport::Cache나 Memcached 같은 캐시 시스템에서 키-값 저장 시 해시 테이블의 충돌 해결 전략이 성능에 직접적인 영향을 미칩니다.
Rails의 Hash 자료구조는 내부적으로 어떤 방식을 사용할까요? 그리고 Ruby 해시의 시간 복잡도는 어떻게 되나요?
Q. 대용량 로그 파일에서 가장 빈번하게 등장하는 상위 K개의 IP 주소를 찾아야 합니다. 메모리가 제한적일 때 어떤 알고리즘과 자료구조를 사용하시겠습니까? 시간 복잡도와 함께 설명해주세요.
해시맵으로 빈도를 세고, 상위 K개를 유지하는 효율적인 자료구조를 생각해보세요.
해시맵과 Min Heap을 조합하여 해결할 수 있습니다. 먼저 해시맵으로 각 IP의 출현 빈도를 O(N) 시간에 계산합니다. 그 다음 크기 K의 Min Heap을 유지하면서 해시맵을 순회하는데, 현재 원소가 힙의 최소값보다 크면 최소값을 제거하고 현재 원소를 삽입합니다. 이 과정의 시간 복잡도는 O(N log K)입니다. 메모리가 매우 제한적이라면 외부 정렬이나 MapReduce 방식을 고려할 수 있으며, 로그를 여러 청크로 나누어 처리한 후 결과를 병합합니다. 최종적으로 힙에 남은 K개 원소가 가장 빈번한 IP 주소들입니다.
- • 해시맵으로 빈도 계산 O(N)
- • Min Heap으로 상위 K개 유지 O(N log K)
- • 메모리 제한 시 외부 정렬이나 분할 정복 활용
웹 서버 로그 분석에서 가장 많은 트래픽을 발생시키는 IP를 찾거나, 애플리케이션에서 인기 검색어를 추출할 때 이 알고리즘을 사용합니다.
만약 실시간 스트리밍 로그에서 지속적으로 상위 K개를 업데이트해야 한다면 어떤 자료구조를 추가로 사용하시겠습니까?
Q. TCP의 3-way handshake와 4-way handshake 과정을 설명하고, TIME_WAIT 상태가 왜 필요한지 설명해주세요.
연결 수립과 종료 시 각 단계에서 어떤 플래그가 교환되는지 생각해보세요.
3-way handshake는 연결 수립 과정으로 클라이언트가 SYN을 보내고, 서버가 SYN-ACK으로 응답하며, 클라이언트가 ACK을 보내 완료됩니다. 4-way handshake는 연결 종료 과정으로 클라이언트가 FIN을 보내면 서버가 ACK으로 응답하고, 서버가 FIN을 보내면 클라이언트가 ACK으로 응답합니다. TIME_WAIT 상태는 마지막 ACK이 손실될 경우를 대비해 일정 시간(2MSL) 동안 연결을 유지하는 상태입니다. 이를 통해 지연된 패킷이 새로운 연결에 영향을 주는 것을 방지하고, 상대방이 FIN을 재전송할 경우 올바르게 응답할 수 있습니다. TIME_WAIT이 너무 많으면 포트 고갈 문제가 발생할 수 있어 SO_REUSEADDR 같은 옵션으로 관리합니다.
- • 3-way: SYN, SYN-ACK, ACK
- • 4-way: FIN, ACK, FIN, ACK
- • TIME_WAIT은 지연 패킷 처리와 재전송 대응을 위해 2MSL 유지
Rails API 서버에서 외부 서비스와 빈번한 HTTP 연결을 맺고 끊을 때 TIME_WAIT 소켓이 쌓여 포트 부족 현상이 발생할 수 있습니다.
Puma나 Unicorn 같은 Rails 서버에서 동시 연결 수가 많을 때 TIME_WAIT 소켓이 성능에 미치는 영향은 무엇인가요?
Q. 데이터베이스 인덱스의 B-Tree와 Hash 인덱스의 차이점을 설명하고, 각각 어떤 쿼리 패턴에 적합한지 설명해주세요.
범위 검색과 정확한 매칭 검색에서 각 인덱스의 성능을 비교해보세요.
B-Tree 인덱스는 정렬된 트리 구조로 범위 검색, 정렬, 부분 일치 검색에 효율적이며 O(log N)의 시간 복잡도를 가집니다. Hash 인덱스는 해시 함수를 사용해 정확한 값 매칭에 O(1)로 매우 빠르지만, 범위 검색이나 정렬에는 사용할 수 없습니다. B-Tree는 WHERE, ORDER BY, BETWEEN, LIKE 'prefix%' 같은 쿼리에 적합하고, Hash는 등호(=) 비교만 사용하는 단순 조회에 적합합니다. 대부분의 RDBMS는 범용성 때문에 B-Tree를 기본으로 사용하며, PostgreSQL은 Hash 인덱스를 지원하지만 제한적입니다. Rails에서 복합 인덱스를 설계할 때는 쿼리 패턴을 분석해 B-Tree의 최좌측 prefix 규칙을 고려해야 합니다.
- • B-Tree는 범위 검색과 정렬 지원, O(log N)
- • Hash는 정확한 매칭만 가능, O(1)
- • 쿼리 패턴에 따라 인덱스 타입 선택
사용자 검색 기능에서 이메일로 정확한 매칭을 하는 경우와 생성일 범위로 필터링하는 경우에 각각 다른 인덱스 전략이 필요합니다.
Rails의 ActiveRecord에서 add_index 메서드로 인덱스를 추가할 때, 어떤 기준으로 단일 컬럼 인덱스와 복합 인덱스를 선택하시나요?
Q. 프로세스와 스레드의 차이점을 설명하고, 멀티 프로세스와 멀티 스레드 방식의 장단점을 비교해주세요.
메모리 공유 방식과 컨텍스트 스위칭 비용 측면에서 생각해보세요.
프로세스는 독립적인 메모리 공간을 가진 실행 단위이고, 스레드는 프로세스 내에서 메모리를 공유하는 실행 단위입니다. 멀티 프로세스는 각 프로세스가 독립적이어서 안정성이 높고 한 프로세스의 오류가 다른 프로세스에 영향을 주지 않지만, 메모리 사용량이 크고 IPC를 통한 통신 오버헤드가 있습니다. 멀티 스레드는 메모리를 공유해 자원 효율적이고 컨텍스트 스위칭이 빠르지만, 동기화 문제와 하나의 스레드 오류가 전체 프로세스에 영향을 줄 수 있습니다. Rails의 Puma는 멀티 스레드를, Unicorn은 멀티 프로세스를 사용하며, 각각의 트레이드오프를 고려해 선택합니다.
- • 프로세스는 독립 메모리, 스레드는 메모리 공유
- • 멀티 프로세스는 안정성, 멀티 스레드는 효율성
- • 컨텍스트 스위칭과 동기화 이슈 고려
Sidekiq 같은 백그라운드 작업 처리 시스템은 멀티 스레드로 동작하므로 공유 자원 접근 시 동기화 처리가 필수적입니다.
Rails 애플리케이션에서 Thread-safe 하지 않은 코드를 작성하면 어떤 문제가 발생할 수 있나요?
Q. HTTP/1.1, HTTP/2, HTTP/3의 주요 차이점을 설명하고, 각 버전에서 해결하려고 한 성능 문제가 무엇인지 설명해주세요.
HOL blocking, 멀티플렉싱, 전송 프로토콜 변화를 중심으로 생각해보세요.
HTTP/1.1은 파이프라이닝을 지원하지만 HOL(Head-of-Line) blocking 문제가 있어 앞선 요청이 지연되면 뒤 요청도 대기해야 합니다. HTTP/2는 바이너리 프레이밍과 멀티플렉싱으로 하나의 TCP 연결에서 여러 스트림을 동시에 처리해 HOL blocking을 애플리케이션 레벨에서 해결했지만, TCP 레벨 HOL blocking은 여전히 존재합니다. HTTP/3는 TCP 대신 QUIC(UDP 기반)을 사용해 TCP 레벨 HOL blocking을 완전히 제거하고, 연결 수립 시간을 단축했습니다. HTTP/2는 서버 푸시와 헤더 압축(HPACK)을, HTTP/3는 개선된 혼잡 제어와 연결 마이그레이션을 제공합니다. Rails 애플리케이션에서는 리버스 프록시(nginx, CDN)에서 이러한 프로토콜을 지원하도록 설정할 수 있습니다.
- • HTTP/1.1은 HOL blocking, HTTP/2는 멀티플렉싱으로 해결
- • HTTP/3는 QUIC으로 TCP 레벨 HOL blocking 제거
- • 각 버전은 레이턴시와 동시성 개선에 집중
API 서버에서 여러 리소스를 동시에 로드하는 SPA 애플리케이션의 성능 개선을 위해 HTTP/2 멀티플렉싱을 활용합니다.
Rails API 서버 앞에 nginx를 두고 HTTP/2를 활성화했을 때, 백엔드 성능 향상을 위해 추가로 고려해야 할 점은 무엇인가요?
Q. 데이터베이스의 ACID 속성을 각각 설명하고, 분산 시스템에서 CAP 정리와의 관계를 설명해주세요. 실무에서 어떤 트레이드오프를 고려해야 하나요?
일관성(Consistency)이 ACID와 CAP에서 의미하는 바가 다르다는 점을 생각해보세요.
ACID는 Atomicity(원자성), Consistency(일관성), Isolation(격리성), Durability(지속성)를 의미하며 트랜잭션의 신뢰성을 보장합니다. CAP 정리는 분산 시스템에서 Consistency(일관성), Availability(가용성), Partition Tolerance(분할 내성) 중 최대 2가지만 보장할 수 있다는 이론입니다. ACID의 일관성은 데이터 무결성 규칙을, CAP의 일관성은 모든 노드가 같은 데이터를 보는 것을 의미합니다. 네트워크 분할이 발생하면 CP(일관성 우선) 또는 AP(가용성 우선)를 선택해야 하며, PostgreSQL 같은 전통적 RDBMS는 CP를, Cassandra는 AP를 선택합니다. Rails에서 금융 거래처럼 일관성이 중요하면 RDBMS를, 소셜 피드처럼 가용성이 중요하면 NoSQL을 고려할 수 있습니다.
- • ACID는 트랜잭션 신뢰성, CAP는 분산 시스템 제약
- • 네트워크 분할 시 CP 또는 AP 선택
- • 비즈니스 요구사항에 따라 일관성과 가용성 트레이드오프
마이크로서비스 아키텍처에서 각 서비스의 데이터베이스 독립성과 전체 시스템의 일관성 사이에서 Eventual Consistency 같은 전략을 선택해야 합니다.
Rails 애플리케이션에서 읽기 복제본(Read Replica)을 사용할 때 발생할 수 있는 일관성 문제와 해결 방법은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!