ELK 스택에서 ELK가 각각 무슨 역할을 하나요?
답 보기
- Elasticsearch
- 데이터 저장소 및 검색/분석 엔진
- Logstash
- 데이터 수집 및 처리
- 데이터를 가공(필터링, 변환, 형식화)하여 Elasticsearch에 전송
- Kibana
- 데이터 시각화 및 대시보드
- Elasticsearch에 저장된 데이터를 시각화해서 사용자에게 제공
Prometheus, Grafana, Loki, Promtail 대해서 설명해주세요
답 보기
-
Prometheus
- 모니터링 및 경고 시스템으로, 주로 시계열 데이터(시간에 따라 변하는 값)를 수집하고 저장하는 데 사용
- Polling 방식으로 동작
- Prometheus는 설정된 타겟(Endpoints)으로 주기적으로 요청을 보내 데이터를 가져옴
- 장점 : Prometheus가 데이터를 제어하므로 장애 관리 용이.
- 단점 : 타겟 엔드포인트가 반드시 데이터를 노출해야 함
-
Grafana
- 데이터 시각화 및 대시보드 도구로, 다양한 데이터 소스에서 정보를 가져와 시각적으로 표현하는 역할
-
Loki
- 로그 데이터 저장 및 검색 엔진
-
Promtail
- Loki와 함께 사용되는 로그 수집기
- Pushing 방식으로 동작
- Promtail은 서버의 로그 파일을 읽고, 필터링 및 파싱한 후 데이터를 Loki로 전송
- 장점: 로그 데이터를 실시간으로 전송 가능하며, Loki와의 통합에 최적화됨
- 단점: Push 모델이므로 Promtail 설정 및 Loki 연동이 필요
템플릿엔진의 동작 방식을 생각해보고 ROR에서 MVC의 V를 Vue로 하는게 왜 말이 안되는건지 100자로 답해주세요.
꼬리 질문
- 지금 당장 몰라도 됨
RoR에서 Vue를 사용하는 방법?
답 보기
템플릿 엔진은 서버에서 HTML을 생성해 클라이언트로 전달하지만, Vue는 클라이언트에서 DOM을 동적으로 렌더링합니다. ROR의 V는 서버 측 View를 의미하므로 Vue와 역할이 충돌합니다.
-
HTML (HyperText Markup Language)
- HTML은 웹 페이지의 구조와 내용을 정의하는 마크업 언어입니다.
- 웹 페이지의 텍스트, 이미지, 링크, 폼 등 다양한 요소를 배치하고 구성합니다.
- 정적 문서입니다.
-
DOM (Document Object Model)
- DOM은 HTML 문서를 프로그래밍적으로 조작할 수 있게 해주는 트리 구조의 객체 모델입니다.
- 자바스크립트와 같은 프로그래밍 언어를 사용하여 웹 페이지의 구조, 스타일, 내용을 동적으로 변경할 수 있습니다.
- 동적 문서 모델입니다.
-
꼬리 질문 답
임베디드 템플릿(erb, ejs, php, ...)으로 마크업 짜놓고, 마크업 짜놓은거 기반으로 vuejs로 동적인 UI 제공하는게 의외로 해볼만한 트릭이에요.
Wait Free와 Lock Free에 대해서 설명해주세요
답 보기
- 동시성 문제를 겪을 때 Lock을 사용하면 반드시 느려질 수 밖에 없음
- 이 때 동시성 문제를 해결하면서도 좀 더 빠르게 동작하게 하기 위해서 사용하는게 Lock Free와 Wait Free임
- Lock을 사용하지 않고 CAS 연산을 통해서 동시성을 보장하는데, 이 때 Java에서는 Atomic을 활용해서 CAS 연산을 한다.
- 예시 👇
AtomicInteger atomic = new AtomicInteger(0);
while(!atomic.compareAndSet(value, update)) {
doSomethig();
}
- Lock Free
- 적어도 하나의 스레드가 진행됨을 보장
- 일부 스레드는 무한정 대기할 수 있음
- Wait Free보다 구현이 상대적으로 단순
- 여러 스레드가 경쟁하지 않는 상황이라면 CAS 연산은 항상 성공하고, 여러 스레드가 경쟁을 한다고 해도 최소한 하나의 스레드는 반드시 성공하기 때문에 성공한 스레드는 작업을 진행되기 때문
- Wait Free
- 모든 스레드가 정해진 시간 내에 작업을 완료할 수 있음을 보장
- 다른 스레드의 진행 상태와 관계없이 작업 완료 가능
- Wait-Free는 Lock-Free의 상위 집합으로 볼 수 있음
- 모든 Wait-Free 알고리즘은 Lock-Free이지만, 모든 Lock-Free 알고리즘이 Wait-Free인 것은 아님
Redis Sentinel과 Redis Cluster의 차이점은 무엇이고 장단점이 무엇일까요?
답 보기
- Redis Sentinel
목적: 단일 마스터-복제본 구조에서 고가용성(High Availability) 제공
주요 특징:
- 마스터 노드 장애 감지 및 자동 복제본 승격
- 클라이언트 서비스 디스커버리 제공
- 모니터링 및 알림 기능
- 데이터 샤딩 없음 - 모든 데이터가 마스터 한 곳에 저장
장점 ✅:
- 설정과 관리가 간단함
- 자동 장애 조치로 다운타임 최소화
- 기존 단일 Redis 인스턴스에서 쉽게 마이그레이션 가능
- 클라이언트 투명성 (failover 시 자동 재연결)
단점 ❌:
- 단일 마스터 병목: 모든 쓰기가 하나의 마스터로 집중
- 수평 확장 불가능 - 데이터가 한 노드 메모리 용량에 제한
- 대용량 데이터셋 처리 한계
- 높은 처리량(high throughput) 시나리오에 부적합
- Redis Cluster
목적: 수평 확장(Horizontal Scaling)과 데이터 분산을 통한 성능 향상
주요 특징:
- 자동 데이터 샤딩 (16,384개 해시 슬롯 사용)
- 다중 마스터 노드로 쓰기 분산
- 각 마스터마다 복제본 운영으로 고가용성도 제공
- 온라인 리샤딩 지원
장점 ✅:
- 무제한 수평 확장: 노드 추가로 용량과 처리량 증가
- 대용량 데이터셋 처리 가능
- 높은 처리량과 성능
- 단일 실패 지점(SPOF) 없음
- 온라인으로 노드 추가/제거 가능
단점 ❌:
- 설정과 관리가 복잡함
- 트랜잭션이 여러 노드에 걸치면 제한적
- 클라이언트에서 클러스터 인식 로직 필요
- 작은 데이터셋에는 오버헤드
- 언제 사용해야 할까?
Redis Sentinel을 선택하는 경우:
- 📊 중소규모 애플리케이션에서 고가용성이 필요할 때
- 🔒 단일 노드 메모리 용량으로 충분한 데이터량
- 💾 캐싱 용도로 주로 사용할 때
- 🛠️ 단순한 설정과 관리를 원할 때
- 🔄 기존 단일 Redis에서 점진적 마이그레이션이 필요할 때
# 적합한 시나리오 예시
- 웹 애플리케이션 세션 저장소
- 소규모 캐싱 시스템
- 실시간 리더보드 (데이터량이 적은 경우)
Redis Cluster를 선택하는 경우:
- 🚀 대용량 데이터셋을 처리해야 할 때
- ⚡ **높은 처리량(high throughput)**이 필요할 때
- 📈 수평 확장이 필요한 성장하는 서비스
- 🌐 글로벌 서비스에서 지역별 데이터 분산이 필요할 때
- 💪 고성능과 가용성을 모두 요구할 때
# 적합한 시나리오 예시
- 대규모 전자상거래 상품 카탈로그
- 실시간 분석 데이터 처리
- IoT 데이터 수집 및 처리
- 대규모 게임 서버 데이터
- 요약 비교표
구분 | Redis Sentinel | Redis Cluster |
---|---|---|
주목적 | 고가용성 | 수평 확장 + 고가용성 |
데이터 분산 | ❌ (단일 마스터) | ✅ (자동 샤딩) |
확장성 | 수직 확장만 | 수평 확장 |
설정 복잡도 | 간단 | 복잡 |
적합한 규모 | 중소규모 | 대규모 |
클라이언트 지원 | 간단 | 클러스터 인식 필요 |
Redis Cluster에서 Split Brain 현상에 대해서 설명해보세요.
답 보기
- Split Brain 현상
네트워크 파티션으로 클러스터가 분할되어 여러 개의 독립적인 제어 중심이 동시에 존재하면서 데이터 일관성이 깨지는 현상입니다.
-
Redis Cluster 동작 원리
-
16,384개 해시 슬롯을 마스터 노드들이 분할 관리
-
쿼럼 기반 의사결정: 과반수 마스터가 통신 가능해야 정상 동작
-
Gossip 프로토콜로 노드 상태와 슬롯 정보 실시간 동기화
-
Configuration Epoch로 클러스터 설정 버전 관리
-
Split Brain 발생 시나리오
- 짝수 개 노드의 2분할 (최악의 경우)
- 6개 마스터 → 3:3 분할
- 양쪽 모두 과반수 미달이지만 각자 "정당한 클러스터"로 착각
- 동일한 키에 서로 다른 값 저장 → 데이터 일관성 파괴
- 홀수 개 노드의 3분할
-
7개 마스터 → 3:2:2 분할
-
모든 그룹이 과반수 미달 → 전체 클러스터 쓰기 불가
-
Redis Cluster의 방지 메커니즘
- 쿼럼 기반 상태 관리
- 과반수 미만 시 자동으로 읽기 전용 모드 전환
CLUSTERDOWN
상태로 쓰기 작업 거부
- Write Safety 보장
- 비동기 복제로 인한 데이터 손실 가능성 인정
- Last Failover Wins 정책으로 최종 선출된 마스터 데이터 우선
- Replica Election 과정
-
마스터 장애 시 과반수 마스터의 동의로만 복제본 승격
-
Configuration Epoch 증가로 새로운 클러스터 설정 전파
-
방지를 위한 모범 사례
- 노드 구성
- 홀수 개 마스터 (최소 3개, 권장 5~7개)
- 마스터당 최소 1개 복제본 구성
- 지리적 분산
- 주 데이터센터에 과반수 노드 배치
- 부 데이터센터들에 나머지 노드 분산
- 타임아웃 설정
-
cluster-node-timeout
: 15초 (기본값) -
cluster-replica-validity-factor
: 10 -
CAP 정리 관점
Redis Cluster는 CP(Consistency + Partition Tolerance) 선택:
-
일관성 우선: 과반수 미달 시 가용성 희생
-
분산 허용: 파티션 감지 후 안전 모드 전환
-
실무 대응 방안
- 모니터링
CLUSTER NODES
,CLUSTER INFO
로 상태 감시- Node Timeout 및 Fail State 알림 설정
- 애플리케이션 레벨
CLUSTERDOWN
예외 처리- Fallback 저장소 (DB, 다른 캐시) 준비
- 복구 절차
-
네트워크 복구 후 데이터 일관성 검증
-
필요시 수동 슬롯 재할당 및 복제본 재동기화
-
한계점과 대안
- Redis Cluster 한계
- 복잡한 파티션에서는 완전한 해결 불가
- 수동 개입 필요한 상황 발생 가능
- 대안적 해결책
- Redis Sentinel: 단순한 HA 구조에서 더 나은 가용성
- Strong Consistency 시스템: Zookeeper, etcd 활용
- 애플리케이션 샤딩: 클라이언트 레벨 데이터 분산 제어
실제 프로덕션 환경에서 회원 테이블의 검색 성능을 개선하려고 합니다. 어떤 컬럼에 인덱스를 생성하는 것이 효과적일까요? 카디널리티 관점에서 설명해주세요.
꼬리 질문
- 복합 인덱스를 생성한다면 컬럼 순서는 어떻게 정하시겠습니까?
- 카디널리티가 낮은 컬럼에 인덱스를 생성하면 어떤 문제가 발생하나요?
- 인덱스 생성 후 성능이 오히려 저하되는 경우는 언제인가요?
답변 보기
- 카디널리티가 높은 컬럼부터 우선적으로 인덱스를 생성해야 합니다 📈
- 회원 테이블 기준 카디널리티 순서:
- 높음: email, user_id, phone_number (거의 유니크)
- 중간: birth_date, join_date, last_login_date
- 낮음: gender, user_status, user_grade (값의 종류가 적음)
- WHERE 절에 자주 사용되는 컬럼 중 카디널리티가 높은 것을 선택
- 예:
WHERE email = 'user@example.com'
→ email 인덱스 생성 - 예:
WHERE user_status = 'active'
→ 비효율적 (전체 회원의 90%가 active일 수 있음)
- 예:
- 꼬리질문: 복합 인덱스를 생성한다면 컬럼 순서는 어떻게 정하시겠습니까?
- 카디널리티가 높은 컬럼을 앞에 배치하는 것이 일반적 ✅
- 예: (email, user_status) > (user_status, email)
- 단, 쿼리 패턴에 따라 달라질 수 있음
WHERE user_status = 'active' AND created_at > '2024-01-01'
같은 쿼리가 많다면- (user_status, created_at) 인덱스가 더 효율적일 수 있음
- = 조건이 > < 조건보다 앞에 오는 것이 좋음
- 꼬리질문: 카디널리티가 낮은 컬럼에 인덱스를 생성하면 어떤 문제가 발생하나요?
- 인덱스 스캔이 테이블 풀 스캔보다 느려질 수 있음 🐌
- 예시: gender 컬럼 (M/F 두 값만 존재)
- 인덱스로 50%만 걸러냄 → 나머지 50%는 랜덤 액세스 발생
- 차라리 풀 스캔이 순차 I/O라 더 빠를 수 있음
- 인덱스 저장 공간만 낭비하고 성능 개선 효과는 미미
- INSERT/UPDATE 시 인덱스 업데이트 오버헤드만 증가
- 꼬리질문: 인덱스 생성 후 성능이 오히려 저하되는 경우는 언제인가요?
- 쓰기 작업이 많은 테이블의 경우 ⚠️
- 인덱스가 많을수록 INSERT/UPDATE/DELETE 시 모든 인덱스 업데이트 필요
- 예: 로그 테이블, 실시간 채팅 메시지 테이블
- 작은 테이블의 경우 (수백 건 이하)
- 인덱스 탐색보다 풀 스캔이 더 빠름
- 인덱스 선택도(Selectivity)가 나쁜 경우
- 조회 결과가 전체 데이터의 15-20% 이상이면 풀 스캔이 유리
- 복합 인덱스의 첫 번째 컬럼을 사용하지 않는 쿼리
- 쓰기 작업이 많은 테이블의 경우 ⚠️
게시판 서비스를 운영 중인데, 메인 페이지는 5초가 걸리는데 상세 페이지는 0.1초 만에 로딩됩니다. 어떤 문제가 있을 수 있고, 어떻게 해결하시겠습니까?
꼬리 질문
- N+1 문제를 해결하는 구체적인 쿼리를 작성해보세요
- 페이지네이션 구현 시 OFFSET vs CURSOR 방식의 장단점은?
- 캐싱을 적용한다면 어떤 전략을 사용하시겠습니까?
답변 보기
- 메인 페이지와 상세 페이지의 속도 차이는 주로 N+1 쿼리 문제 때문입니다 🔍
- 문제 진단:
- 메인: 게시글 목록 조회(1) + 각 게시글의 댓글 수 조회(N) = N+1번 쿼리
- 상세: 단일 게시글 조회(1) + 해당 댓글 조회(1) = 2번 쿼리
- 추가 가능한 원인들:
- 페이지네이션에서 OFFSET 사용으로 인한 성능 저하
- 인덱스 미사용 또는 잘못된 인덱스 설계
- 불필요한 컬럼까지 모두 SELECT하는 경우
- 복잡한 서브쿼리나 여러 테이블 JOIN
- 꼬리질문: N+1 문제를 해결하는 구체적인 쿼리를 작성해보세요
- 문제가 되는 쿼리:
-- 1. 게시글 목록 조회 SELECT * FROM posts ORDER BY created_at DESC LIMIT 20; -- 2. 각 게시글마다 댓글 수 조회 (20번 실행) SELECT COUNT(*) FROM comments WHERE post_id = ?;
- 해결 방법 1 - JOIN 사용:
SELECT p.*, COUNT(c.id) as comment_count FROM posts p LEFT JOIN comments c ON p.id = c.post_id GROUP BY p.id ORDER BY p.created_at DESC LIMIT 20;
- 해결 방법 2 - 서브쿼리 사용:
SELECT p.*, (SELECT COUNT(*) FROM comments c WHERE c.post_id = p.id) as comment_count FROM posts p ORDER BY p.created_at DESC LIMIT 20;
- 꼬리질문: 페이지네이션 구현 시 OFFSET vs CURSOR 방식의 장단점은?
- OFFSET 방식:
- 장점: 구현이 간단, 특정 페이지로 바로 이동 가능 📄
- 단점: 페이지가 뒤로 갈수록 성능 저하 (앞의 모든 데이터 스캔)
- 예:
LIMIT 20 OFFSET 10000
→ 10,020개 조회 후 20개만 반환
- CURSOR(키셋) 방식:
- 장점: 일정한 성능 보장, 대용량 데이터에 적합 🚀
- 단점: 특정 페이지 점프 불가, 구현 복잡도 증가
- 예:
WHERE id < ? ORDER BY id DESC LIMIT 20
- 추천: 무한 스크롤은 CURSOR, 페이지 번호가 필요하면 OFFSET
- OFFSET 방식:
- 꼬리질문: 캐싱을 적용한다면 어떤 전략을 사용하시겠습니까?
- Redis를 활용한 페이지 단위 캐싱 💾
- 키:
main_page:1
, 값: 직렬화된 게시글 목록 - TTL: 1-5분 (실시간성과 성능의 균형)
- 키:
- 캐시 무효화 전략:
- 새 게시글 작성 시: 첫 페이지 캐시만 삭제
- 댓글 작성 시: 해당 게시글이 포함된 페이지 캐시 삭제
- 또는 짧은 TTL로 자동 갱신
- 캐시 워밍(Cache Warming):
- 첫 1-3페이지는 미리 캐싱
- 트래픽이 적은 시간에 주기적으로 갱신
- 부분 캐싱 전략:
- 댓글 수만 별도 캐싱:
comment_count:post_id
- 조회수는 별도 캐싱하여 실시간성 확보
- 댓글 수만 별도 캐싱:
- Redis를 활용한 페이지 단위 캐싱 💾
일일 방문자 100만명인 뉴스 사이트에서 조회수를 실시간으로 업데이트하고 있습니다. DB 부하가 심한데 어떻게 개선하시겠습니까?
꼬리 질문
- Redis와 DB 간 동기화는 어떻게 처리하시겠습니까?
- 캐시 미스(Cache Miss)가 발생했을 때 대응 방안은?
- 정확도와 성능 사이의 트레이드오프를 어떻게 조절하시겠습니까?
답변 보기
- 매 요청마다 DB UPDATE는 비현실적이므로 메모리 기반 캐싱이 필수입니다 💡
- 즉시 적용 가능한 해결책:
- Redis를 활용한 조회수 캐싱
- 키:
view_count:article_id
- 값: 현재 조회수
- 조회 시: Redis INCR 명령어로 원자적 증가
- 키:
- 주기적 DB 동기화 (예: 5분마다)
- 예상 부하 감소: 100만 요청 → 288회 업데이트 (하루 기준)
- Redis를 활용한 조회수 캐싱
- 구현 예시:
# 조회수 증가 redis.incr(f"view_count:{article_id}") # 배치로 DB 동기화 (5분마다) for key in redis.scan_iter("view_count:*"): article_id = key.split(":")[1] count = redis.getdel(key) # 가져오고 삭제 db.execute("UPDATE articles SET view_count = view_count + ? WHERE id = ?", [count, article_id])
- 꼬리질문: Redis와 DB 간 동기화는 어떻게 처리하시겠습니까?
- 동기화 전략 1 - 주기적 배치 처리 ⏰
- 크론잡으로 5-10분마다 실행
- Redis의 조회수 증분을 DB에 일괄 업데이트
- 장점: 구현 간단, DB 부하 최소화
- 단점: 최대 동기화 주기만큼의 데이터 손실 가능성
- 동기화 전략 2 - 이벤트 기반 처리
- 조회수가 특정 단위(100, 1000)에 도달할 때마다 동기화
- 메시지 큐(Kafka, RabbitMQ)를 통한 비동기 처리
- 동기화 전략 3 - Write-Behind 캐싱
- 변경사항을 큐에 저장하고 배치로 처리
- 실패 시 재시도 로직 포함
- 데이터 정합성 보장:
- Redis 스냅샷과 AOF 활성화
- 동기화 전 Redis 값을 임시 백업
- 트랜잭션으로 원자성 보장
- 동기화 전략 1 - 주기적 배치 처리 ⏰
- 꼬리질문: 캐시 미스(Cache Miss)가 발생했을 때 대응 방안은?
- Cache-Aside 패턴 적용 🔄
def get_view_count(article_id): # 1. 캐시 확인 count = redis.get(f"view_count:{article_id}") if count is not None: return int(count) # 2. DB에서 조회 count = db.query("SELECT view_count FROM articles WHERE id = ?", [article_id]) # 3. 캐시에 저장 redis.set(f"view_count:{article_id}", count, ex=3600) return count
- 캐시 스탬피드(Stampede) 방지:
- 분산 락 사용: 첫 요청만 DB 조회, 나머지는 대기
- 확률적 조기 만료: TTL 전에 미리 갱신
- 페일오버 전략:
- Redis 클러스터 구성으로 가용성 확보
- 장애 시 DB 직접 조회 (Circuit Breaker 패턴)
- Cache-Aside 패턴 적용 🔄
- 꼬리질문: 정확도와 성능 사이의 트레이드오프를 어떻게 조절하시겠습니까?
- 서비스 특성에 따른 전략 선택 📊
- 뉴스/블로그: 대략적인 조회수 OK → 10-30분 동기화
- 실시간 랭킹: 정확도 중요 → 1-5분 동기화
- 유료 컨텐츠: 매우 정확해야 함 → 즉시 동기화
- 하이브리드 접근:
- 일반 조회: Redis에서만 증가 (빠름)
- 중요 임계값(1만, 10만): 즉시 DB 동기화
- 표시는 근사치 사용: "조회수 1.2만" (정확한 숫자 불필요)
- 모니터링 지표:
- Redis-DB 간 차이율 추적
- 동기화 지연 시간 측정
- 사용자 만족도 vs 시스템 부하 균형점 찾기
- 서비스 특성에 따른 전략 선택 📊