Go 미드레벨 코딩 기술면접

Go 미드레벨 (3~7년) 코딩 · 알고리즘 5문항 조회수 109 · 2026-06-19 (금) 11:10:58
1 동시성 패턴
Medium

Q. Worker Pool 패턴을 Go로 구현할 때 고려해야 할 핵심 설계 요소들을 설명하고, 작업 큐에 버퍼 크기를 설정하는 기준과 워커 수를 결정하는 방법을 실무 관점에서 제시해주세요.

A. 모범답안

Worker Pool 패턴 구현 시 작업 채널(job channel), 결과 채널(result channel), 워커 고루틴 수, Graceful Shutdown 메커니즘을 고려해야 합니다. 버퍼 크기는 메모리와 처리 지연 간 트레이드오프를 고려하여 평균 작업 생성 속도와 처리 속도의 차이를 기반으로 설정합니다. 워커 수는 작업이 CPU-bound인 경우 runtime.NumCPU()를, I/O-bound인 경우 더 많은 수를 설정하며, 부하 테스트를 통해 최적값을 찾습니다. WaitGroup이나 Context를 활용해 모든 워커의 작업 완료를 추적하고, 채널을 닫아 워커들이 정상 종료되도록 합니다.

핵심 포인트
  • • 작업 채널과 결과 채널의 버퍼 크기 설정 기준
  • • CPU-bound vs I/O-bound 작업에 따른 워커 수 결정
  • • WaitGroup과 Context를 활용한 Graceful Shutdown 구현
  • • 채널 닫기 타이밍과 고루틴 종료 시그널 처리
Follow-up 질문

Worker Pool에서 특정 워커가 패닉으로 종료되었을 때 이를 복구하고 워커 수를 유지하는 방법을 설명해주세요.

2 메모리 관리
Hard

Q. Go에서 대용량 파일을 읽어 처리할 때 메모리 효율적인 스트리밍 방식의 구현 전략을 설명하고, bufio.Scanner와 bufio.Reader의 차이점 및 각각의 적절한 사용 시나리오를 제시해주세요.

A. 모범답안

대용량 파일 처리 시 전체 파일을 메모리에 로드하지 않고 청크 단위로 읽는 스트리밍 방식을 사용해야 합니다. bufio.Scanner는 줄 단위 또는 토큰 단위로 자동 분할하며 내부 버퍼 크기 제한(기본 64KB)이 있어 로그 파일이나 텍스트 처리에 적합합니다. bufio.Reader는 더 낮은 수준의 제어를 제공하며 Read, ReadBytes, ReadString 등의 메서드로 유연한 읽기가 가능하고, 버퍼 크기를 직접 설정할 수 있어 바이너리 파일이나 큰 레코드 처리에 적합합니다. 메모리 사용을 최소화하려면 io.Reader 인터페이스를 활용한 파이프라인 패턴으로 읽기-처리-쓰기를 스트리밍으로 연결합니다.

핵심 포인트
  • • 스트리밍 방식으로 청크 단위 처리하여 메모리 사용 최소화
  • • bufio.Scanner는 줄 단위 처리에 편리하나 버퍼 크기 제한 존재
  • • bufio.Reader는 낮은 수준 제어와 유연한 버퍼 관리 제공
  • • io.Reader 인터페이스 기반 파이프라인으로 효율적인 스트림 처리
Follow-up 질문

Scanner의 기본 버퍼 크기를 초과하는 긴 줄을 처리해야 할 때 어떻게 해결할 수 있는지 설명해주세요.

3 리플렉션과 성능
Medium

Q. Go의 Reflection을 사용할 때 발생하는 성능 오버헤드의 원인을 설명하고, JSON 직렬화/역직렬화나 ORM 같은 라이브러리에서 리플렉션 사용이 불가피한 경우 성능을 개선할 수 있는 대안적 접근 방법들을 제시해주세요.

A. 모범답안

Reflection은 런타임에 타입 정보를 조회하고 값을 조작하므로 컴파일 타임 최적화가 불가능하고, 인터페이스 변환, 메모리 할당, 간접 참조 등으로 인해 일반 코드 대비 10~100배 느립니다. 성능 개선 방법으로는 코드 생성(code generation)을 통해 컴파일 타임에 타입별 직렬화 코드를 미리 생성하거나, 자주 사용되는 타입 정보를 캐싱하여 reflect.TypeOf 호출을 줄이는 방법이 있습니다. easyjson, ffjson 같은 라이브러리는 코드 생성 방식으로 표준 encoding/json보다 3~5배 빠른 성능을 제공합니다. 또한 sync.Pool을 활용해 리플렉션 과정에서 생성되는 임시 객체를 재사용하여 GC 압력을 줄일 수 있습니다.

핵심 포인트
  • • 리플렉션은 런타임 타입 조회와 간접 참조로 인한 성능 오버헤드 발생
  • • 코드 생성(code generation)으로 컴파일 타임에 타입별 코드 미리 생성
  • • 타입 정보 캐싱으로 반복적인 reflect.TypeOf 호출 최소화
  • • sync.Pool로 임시 객체 재사용하여 GC 압력 감소
Follow-up 질문

reflect.Value와 reflect.Type의 차이점과 각각을 언제 사용해야 하는지 설명해주세요.

4 에러 처리 패턴
Medium

Q. 대규모 Go 프로젝트에서 일관성 있는 에러 처리를 위한 커스텀 에러 타입 설계 전략을 설명하고, 센티널 에러(Sentinel Error)와 커스텀 에러 타입의 장단점 및 각각의 적절한 사용 시나리오를 제시해주세요.

A. 모범답안

커스텀 에러 타입은 구조체로 정의하여 에러 코드, 메시지, 컨텍스트 정보(사용자 ID, 요청 ID 등)를 포함하고 Error() 메서드를 구현합니다. 센티널 에러(var ErrNotFound = errors.New)는 간단하고 비교가 쉬우나 추가 컨텍스트를 담을 수 없어 패키지 레벨의 고정된 에러 상태 표현에 적합합니다. 커스텀 에러 타입은 동적 정보를 포함할 수 있고 타입 어설션으로 세부 정보 추출이 가능하나 정의와 사용이 복잡하여 도메인별 상세한 에러 처리가 필요한 경우에 적합합니다. 실무에서는 공통 에러는 센티널로, 비즈니스 로직 에러는 커스텀 타입으로 구분하고, 에러 래핑으로 호출 스택 정보를 보존합니다.

핵심 포인트
  • • 커스텀 에러 타입은 구조체로 에러 코드와 컨텍스트 정보 포함
  • • 센티널 에러는 간단하나 추가 정보 담을 수 없어 고정 상태 표현에 적합
  • • 커스텀 타입은 동적 정보 포함 가능하나 복잡도 증가
  • • 공통 에러는 센티널, 비즈니스 로직 에러는 커스텀 타입으로 구분
Follow-up 질문

HTTP API에서 커스텀 에러 타입을 적절한 HTTP 상태 코드와 JSON 응답으로 변환하는 미들웨어 설계 방법을 설명해주세요.

5 동시성 제어
Hard

Q. Rate Limiting을 Go로 구현할 때 Token Bucket 알고리즘과 Leaky Bucket 알고리즘의 차이를 설명하고, golang.org/x/time/rate 패키지의 내부 동작 원리와 실무에서 분산 환경에서의 Rate Limiting 구현 전략을 제시해주세요.

A. 모범답안

Token Bucket은 일정 속도로 토큰을 생성하여 버킷에 채우고 요청 시 토큰을 소비하는 방식으로 버스트 트래픽을 허용하며, Leaky Bucket은 고정된 속도로 요청을 처리하여 평활화된 출력을 보장합니다. golang.org/x/time/rate는 Token Bucket 기반으로 limiter.Allow(), limiter.Wait() 등의 메서드를 제공하며, 내부적으로 마지막 토큰 생성 시간과 현재 토큰 수를 추적하여 동시성 안전하게 동작합니다. 분산 환경에서는 Redis를 활용한 중앙집중식 카운터 방식이나 Sliding Window 알고리즘을 사용하며, Lua 스크립트로 원자적 연산을 보장하거나, 각 인스턴스별로 전체 제한의 일부를 할당하는 분산 토큰 방식을 사용합니다.

핵심 포인트
  • • Token Bucket은 버스트 허용, Leaky Bucket은 평활화된 처리
  • • time/rate 패키지는 Token Bucket 기반으로 동시성 안전한 구현 제공
  • • 분산 환경에서는 Redis 기반 중앙집중식 카운터 또는 Sliding Window 사용
  • • Lua 스크립트로 원자적 연산 보장 또는 인스턴스별 토큰 분배
Follow-up 질문

API Gateway에서 사용자별, IP별, 엔드포인트별로 다른 Rate Limit을 적용해야 할 때 효율적인 구조 설계 방법을 설명해주세요.

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!