백엔드 면접을 준비하다 보면 개념을 하나씩 따로 외우게 되기 쉬워요. 그런데 실제 면접에서는 자료구조, 운영체제, JVM, 스프링, 데이터베이스, 배포가 서로 연결된 상태로 질문이 이어지는 경우가 많아요.
그래서 이번 글은 질문 목록을 그대로 옮기는 대신, 백엔드 개발자가 알아야 할 핵심 개념을 학습 흐름에 맞게 다시 정리한 문서로 구성했어요. 기본기부터 운영 경험, 그리고 스프링과 데이터 접근, 배포까지 한 번에 연결해서 볼 수 있게 정리해볼게요.
자료구조와 탐색부터 정리하기#
백엔드 개발에서는 자료를 빠르게 찾고, 충돌을 잘 처리하고, 탐색 비용을 줄이는 사고가 중요해요. 이런 기본기는 면접에서도 자주 확인하는 영역이에요.
해시 충돌 해결 방식으로는 오픈 어드레싱과 세퍼레이트 체이닝이 대표적이에요.
- 오픈 어드레싱(Open Addressing) 은 충돌이 발생하면 해시 테이블 배열 내부의 다른 빈 공간을 찾아 저장해요.
- 세퍼레이트 체이닝(Separate Chaining) 은 하나의 버킷에 연결 리스트나 트리 같은 별도 구조를 두고, 충돌한 데이터를 그 안에 저장해요.
오픈 어드레싱은 배열 기반이라 캐시 친화적일 수 있지만, 적재율이 높아질수록 성능이 급격히 떨어질 수 있어요. 반대로 세퍼레이트 체이닝은 메모리를 더 쓰지만 충돌 처리 면에서 상대적으로 안정적이에요. 자바 HashMap도 기본적으로는 체이닝 기반으로 동작해요.
탐색 알고리즘으로는 DFS와 BFS를 꼭 구분해서 이해해야 해요.
- DFS(Depth-First Search) 는 한 경로를 깊게 내려간 뒤, 더 갈 곳이 없으면 되돌아와요.
- BFS(Breadth-First Search) 는 가까운 노드부터 넓게 확장하면서 탐색해요.
DFS는 보통 재귀나 스택으로 구현하고, BFS는 큐를 써요. 실전에서는 DFS가 경로 탐색이나 백트래킹에 자주 쓰이고, BFS는 가중치가 없는 최단 거리 문제에 강해요.
메모리와 운영체제 관점에서 이해하기#
자료구조와 알고리즘을 넘어서면, 이제 프로그램이 실제로 메모리 위에서 어떻게 동작하는지 이해해야 해요. 이 부분은 장애 대응이나 성능 문제와 직접 연결돼요.
대표적인 개념이 LRU예요. LRU는 페이지 교체 알고리즘 중 하나로, 가장 오랫동안 사용되지 않은 페이지를 교체하는 방식이에요. 최근에 사용한 데이터는 다시 사용할 가능성이 높다는 지역성 원리에 기반해요.
FIFO와 비교하면 차이가 더 분명해져요. FIFO는 먼저 들어온 것을 먼저 내보내지만, LRU는 최근 사용 이력을 고려해서 더 실용적인 선택을 해요. 다만 순수한 LRU는 구현 비용이 커서, 실제 시스템에서는 이를 근사하는 방식으로 구현하는 경우가 많아요.
메모리 문제를 추적할 때는 힙덤프도 중요해요. 힙덤프는 JVM 힙 메모리 상태를 파일로 남겨서, 어떤 객체가 메모리를 많이 점유하고 있는지 확인하는 방식이에요.
이런 상황에서 특히 유용해요.
OutOfMemoryError가 발생했을 때- 객체가 계속 쌓여서 메모리 누수가 의심될 때
- GC가 자주 돌지만 메모리가 잘 회수되지 않을 때
보통 jmap, jcmd 같은 도구로 덤프를 뜨고, Eclipse MAT로 dominator tree나 leak suspects를 분석해요. 중요한 건 단순히 "힙덤프를 떠봤다"가 아니라, 어떤 객체가 메모리를 붙잡고 있었고 왜 누수가 생겼는지 설명할 수 있는지예요.
JVM 안정성을 이해하려면 GC와 동시성을 같이 봐야 해요#
백엔드 서버는 요청을 계속 처리해야 하니까, 메모리 회수와 동시성 제어를 함께 이해해야 안정적인 서비스를 만들 수 있어요.
먼저 GC(Garbage Collection) 는 더 이상 참조되지 않는 객체를 회수해서 JVM 메모리를 관리하는 기능이에요. 기본적으로 Young 영역과 Old 영역을 나눠서 관리하고, Minor GC와 Major GC 또는 Full GC 같은 개념으로 설명할 수 있어요.
대표적인 GC는 다음 정도로 정리할 수 있어요.
- Serial GC: 단일 스레드 기반, 단순하지만 멈춤 시간이 길 수 있어요.
- Parallel GC: 처리량 중심이에요.
- CMS: 응답 지연을 줄이기 위한 방식이었지만 지금은 많이 대체됐어요.
- G1 GC: region 단위로 관리하고, 현재 실무에서 자주 봐요.
- ZGC, Shenandoah: pause time을 매우 짧게 가져가려는 목적이 강해요.
GC와 함께 자주 나오는 주제가 스레드 세이프(Thread Safe) 예요. 여러 스레드가 동시에 접근해도 데이터 정합성이 깨지지 않게 만드는 게 핵심이에요.
대표적인 접근 방법은 이래요.
- 공유 상태를 줄이고, 가능하면 불변 객체를 사용해요.
- 꼭 필요한 임계영역만
synchronized,Lock,ReentrantLock으로 보호해요. ConcurrentHashMap같은 동시성 컬렉션을 사용해요.AtomicInteger,AtomicLong처럼 원자적 연산을 활용해요.- 스레드별 독립 상태가 필요하면
ThreadLocal을 고려해요.
여기서 중요한 건 "락을 많이 쓰는 것"이 아니라, 공유 자원 자체를 줄이는 설계가 우선이라는 점이에요. 락은 병목과 데드락 위험을 만들 수 있기 때문이에요.
테스트와 어노테이션은 프레임워크 이해로 이어져요#
면접에서 테스트 경험을 묻는 이유는 단순히 테스트 문법을 아는지 보려는 게 아니에요. 코드를 얼마나 안전하게 바꾸고, 검증 가능한 구조로 만들었는지를 보려는 경우가 많아요.
테스트는 보통 다음처럼 나눠서 생각하면 좋아요.
- 단위 테스트: 서비스나 유틸 로직을 빠르게 검증해요.
- 통합 테스트: 스프링 컨텍스트, DB, 외부 시스템 연동을 확인해요.
- API 테스트: 컨트롤러의 요청과 응답을 검증해요.
실무에서는 JUnit, Mockito, MockMvc, Testcontainers 조합을 자주 보게 돼요. 특히 실패 비용이 큰 결제, 주문, 재고, 쿠폰 영역일수록 테스트의 가치가 더 커져요.
테스트와 연결해서 이해하면 좋은 개념이 어노테이션 동작 방식이에요. 예를 들어 JUnit 4 기준으로 보면,
@BeforeClass는 테스트 클래스 전체에서 한 번 실행돼요.@Before는 각 테스트 메서드 실행 전에 매번 호출돼요.@Test는 실제 테스트 메서드예요.
즉 보통은 @BeforeClass -> (@Before -> @Test -> @After) 반복 -> @AfterClass 순서로 동작해요.
조금 더 깊게 들어가면, 자바 어노테이션은 메타데이터예요. 런타임 유지 정책이 있는 어노테이션은 리플렉션으로 읽을 수 있고, 프레임워크나 테스트 러너가 이 메타데이터를 해석해서 특정 시점에 메서드를 호출해요. 결국 어노테이션은 문법 설탕이 아니라, 프레임워크가 동작하는 규칙을 표현하는 수단이라고 이해하면 좋아요.
자바 문법 이해는 함수형 인터페이스와 디자인 패턴에서 드러나요#
자바를 사용하는 백엔드 개발자라면 객체지향과 함수형 스타일을 함께 다룰 줄 알아야 해요.
먼저 함수형 인터페이스(Functional Interface) 는 추상 메서드가 하나만 있는 인터페이스예요. 람다와 메서드 참조를 받을 때 사용돼요. java.util.function 패키지의 대표 타입은 꼭 익혀두는 게 좋아요.
Supplier<T>: 입력 없이 결과를 반환해요.Consumer<T>: 값을 받아 소비하고 반환은 없어요.Function<T, R>: 입력을 받아 다른 타입의 결과를 반환해요.Predicate<T>: 참/거짓을 반환해요.
이 외에도 UnaryOperator, BinaryOperator, BiFunction, BiConsumer, BiPredicate 같은 확장형이 있어요.
디자인 패턴도 자주 묻는 주제예요. 하지만 이름을 많이 아는 것보다 어떤 문제를 해결하기 위해 쓰는지 설명할 수 있어야 해요.
자주 이야기하는 패턴은 이 정도예요.
- 싱글턴: 인스턴스를 하나만 유지하고 싶을 때 사용해요.
- 전략 패턴: 알고리즘을 교체 가능하게 만들어요.
- 템플릿 메서드 패턴: 공통 흐름을 상위 클래스에 두고 세부 동작을 하위 클래스에 맡겨요.
- 프록시 패턴: 접근 제어, 지연 로딩, 부가 기능 적용에 활용돼요.
- 데코레이터 패턴: 기능을 동적으로 확장해요.
- 어댑터 패턴: 다른 인터페이스를 맞춰줘요.
- 빌더 패턴: 복잡한 객체 생성을 단순하게 해요.
- 옵저버 패턴: 상태 변화를 구독하고 통지해요.
- 팩토리 패턴: 생성 책임을 분리해요.
이 패턴들은 스프링 안에서도 자주 보여요. 예를 들어 AOP는 프록시 패턴 관점으로 볼 수 있고, 각종 Builder 클래스는 빌더 패턴, 이벤트 리스너는 옵저버 패턴과 연결해서 설명할 수 있어요.
스프링을 공부할 때는 빈 스코프와 AOP를 같이 이해하면 좋아요#
스프링은 객체를 생성하고 관리하는 컨테이너예요. 그래서 빈 스코프를 이해하는 것이 기본이에요. 빈 스코프는 빈이 생성되고 유지되는 범위를 의미해요.
주요 스코프는 다음과 같아요.
singleton: 기본값이고, 컨테이너당 하나예요.prototype: 요청할 때마다 새 객체가 생성돼요.request: HTTP 요청마다 하나예요.session: HTTP 세션마다 하나예요.application: 서블릿 컨텍스트 단위예요.websocket: 웹소켓 세션 단위예요.
실무에서는 대부분 싱글턴을 기본으로 쓰고, 상태를 가지는 request/session 범위 객체는 신중하게 다뤄야 해요.
스프링을 설명할 때 빼놓기 어려운 개념이 AOP(Aspect Oriented Programming) 예요. AOP는 로깅, 트랜잭션, 권한 체크, 실행 시간 측정처럼 여러 곳에 반복되는 공통 관심사를 분리하는 방식이에요.
핵심 개념은 이렇게 정리할 수 있어요.
- Aspect: 공통 기능 모듈이에요.
- Advice: 언제 실행할지 정의해요.
- Pointcut: 어디에 적용할지 정의해요.
- Join Point: 적용 가능한 지점이에요.
스프링 AOP는 보통 프록시 기반으로 동작해요. 그래서 실무에서는 API 실행 시간 로깅, 특정 패키지의 메서드 추적, 공통 트랜잭션 처리 같은 용도로 많이 연결돼요. 다만 너무 남용하면 흐름이 숨겨져서 디버깅이 어려워질 수 있어요.
API와 네트워크는 HTTP 메서드와 프로토콜 변화까지 같이 봐야 해요#
RESTful API를 설계할 때는 HTTP 메서드의 의미를 분명하게 이해하고 있어야 해요.
특히 PUT과 PATCH는 자주 비교돼요.
- PUT은 리소스를 전체 교체하는 관점이에요.
- PATCH는 리소스 일부 수정에 더 잘 맞아요.
예를 들어 사용자 전체 정보를 덮어쓰는 건 PUT, 닉네임만 바꾸는 건 PATCH가 더 자연스러워요. 물론 실무에서는 시스템 특성상 PUT을 부분 수정처럼 쓰는 경우도 있지만, 의미적으로는 PATCH가 더 적절한 경우가 많아요.
네트워크 관점에서는 HTTP/2도 기본 개념을 알아두면 좋아요. HTTP/2는 HTTP/1.1의 비효율을 개선하려고 등장했어요.
핵심 변화는 다음과 같아요.
- 하나의 연결에서 여러 요청을 동시에 처리하는 멀티플렉싱
- 중복 헤더 비용을 줄이는 헤더 압축
- 필요한 리소스를 먼저 보낼 수 있는 서버 푸시
- 텍스트 대신 효율적인 바이너리 프레이밍
실무에서는 직접 프로토콜을 구현하기보다, 보통 Nginx, CDN, 로드밸런서, 웹서버 설정을 통해 HTTP/2 환경을 사용하게 돼요. 그래서 이 주제는 "개념을 이해하고 인프라 설정과 연결할 수 있는지" 정도로 정리해두면 좋아요.
데이터 접근은 N+1과 모델링 설명 능력이 핵심이에요#
실무 면접에서 자주 나오는 문제 중 하나가 N+1 문제예요. 연관 엔티티를 조회할 때, 처음 한 번 조회한 뒤 연관 데이터를 읽는 과정에서 추가 쿼리가 N번 더 발생하는 문제예요.
예를 들어 주문 100건을 조회하고, 각 주문마다 회원 정보를 지연 로딩하면 총 101번의 쿼리가 나갈 수 있어요. 이런 문제는 데이터 양이 늘수록 성능에 큰 영향을 줘요.
대표적인 해결 방법은 다음과 같아요.
fetch join사용EntityGraph사용@BatchSize,default_batch_fetch_size같은 배치 조회 전략 적용- DTO 직접 조회
- 로딩 전략 자체 재검토
중요한 건 무조건 즉시 로딩으로 바꾸는 게 아니라, 필요한 조회 상황에 맞게 전략을 선택하는 것이에요.
또 하나 자주 묻는 주제가 DB 구조 설명이에요. 이건 정답이 정해진 질문이 아니라, 내가 다뤄본 서비스를 얼마나 구조적으로 설명할 수 있는지를 보는 질문이에요.
예를 들어 이커머스 도메인이라면 다음처럼 설명할 수 있어요.
- 회원
- 상품
- 주문
- 주문 상세
- 결제
- 쿠폰
- 리뷰
그리고 각 관계를 이어서 설명해요. 회원과 주문은 1:N, 주문과 주문 상세도 1:N, 주문 상세와 상품은 N:1 같은 식이에요. 여기서 더 나아가 인덱스, 정규화와 반정규화, 대용량 테이블 관리, 트랜잭션 경계까지 연결할 수 있으면 훨씬 깊이 있는 답변이 돼요.
운영 경험은 모니터링과 배포 전략에서 드러나요#
운영 경험을 묻는 질문은 도구 이름을 나열하는 것보다, 어떤 신호를 보고 어떤 문제를 추적했는지를 설명하는 게 중요해요.
모니터링 도구는 보통 이렇게 나눠서 볼 수 있어요.
- Prometheus + Grafana: 메트릭 수집과 시각화
- ELK / OpenSearch: 로그 수집과 검색
- Pinpoint / Datadog / New Relic / SkyWalking: APM과 트레이싱
- Spring Boot Actuator: 애플리케이션 상태 노출
핵심은 메트릭, 로그, 트레이스를 함께 보면서 장애를 빠르게 감지하고 원인을 좁혀가는 거예요.
배포 전략도 같은 관점에서 중요해요. 특히 서버가 여러 대일 때는 한 번에 덮어쓰는 방식보다, 무중단 배포와 롤백이 가능한 구조가 더 중요해져요.
대표적인 방식은 다음과 같아요.
- 롤링 배포: 서버를 조금씩 교체해요.
- 블루그린 배포: 기존 버전과 신규 버전을 분리한 뒤 전환해요.
- 카나리 배포: 일부 서버나 일부 트래픽에 먼저 적용해요.
예를 들어 서버가 20대라면, CI에서 빌드와 테스트를 거친 뒤 일부 서버부터 순차 배포하고, 헬스체크와 모니터링 지표를 확인하면서 나머지 서버로 확장하는 흐름이 안전해요. 문제가 생기면 빠르게 롤백할 수 있어야 하고요.
쿠버네티스를 쓴다면 rolling update, readiness probe, liveness probe를 같이 설명할 수 있고, VM 기반 환경이라면 Jenkins나 Ansible 같은 자동화 도구와 연결해 설명할 수 있어요.
마지막으로는 내가 써본 기술 스택을 설명할 수 있어야 해요#
어떤 버전의 스프링, 스프링 부트, MySQL을 써봤는지 묻는 질문은 단순 암기보다는 실제 경험한 기술 생태계를 파악하려는 질문에 가까워요.
예를 들면 이런 식으로 정리할 수 있어요.
- Spring Framework 5.x, 6.x
- Spring Boot 2.x, 3.x
- MySQL 5.7, 8.0
이때 단순 버전 나열에서 끝나지 않고, 차이점까지 연결하면 더 좋아요. 예를 들어 Spring Boot 3는 자바 17 이상을 기반으로 하고, javax에서 jakarta로 네임스페이스가 바뀌었어요. MySQL 8.0은 윈도우 함수나 CTE 같은 기능이 강화됐고요.
추가로 개발 서적 경험도 함께 정리해두면 좋아요. 이펙티브 자바, 오브젝트, 클린 코드, 단위 테스트, 대규모 시스템 설계 같은 책을 읽고, 무엇을 실무에 연결했는지 설명할 수 있으면 학습 방식까지 보여줄 수 있어요.
정리#
백엔드 면접 준비는 질문과 답을 따로 외우는 방식보다, 기본 개념이 실제 서비스 운영과 어떻게 연결되는지 이해하는 방향이 훨씬 효과적이에요.
자료구조와 탐색은 문제 해결의 출발점이 되고, 운영체제와 JVM 지식은 장애 대응 능력으로 이어져요. 스프링과 테스트는 구현의 안정성을 보여주고, 데이터베이스와 배포 전략은 실무 감각을 드러내요.
결국 중요한 건 개념 자체보다도 다음 네 가지예요.
- 이 개념이 무엇인지
- 왜 필요한지
- 언제 쓰는지
- 장단점이 무엇인지
이 흐름으로 정리해두면 면접 질문이 어떤 형태로 나와도 훨씬 안정적으로 설명할 수 있어요.