ASP.NET 시니어 기술면접
새 면접Q. ASP.NET Core의 미들웨어 파이프라인에서 Use, Run, Map의 차이점과 내부 동작 방식을 설명하고, 대규모 엔터프라이즈 애플리케이션에서 커스텀 미들웨어를 설계할 때 고려해야 할 성능 및 아키텍처 측면의 핵심 사항들을 설명해주세요.
각 메서드가 다음 미들웨어를 호출하는 방식과 요청 파이프라인의 분기 처리 방식을 생각해보세요.
Use는 next 델리게이트를 받아 다음 미들웨어로 제어를 전달할 수 있는 체인형 미들웨어이며, Run은 터미널 미들웨어로 파이프라인을 종료시킵니다. Map은 요청 경로에 따라 파이프라인을 분기시키는 역할을 합니다. 커스텀 미들웨어 설계 시 Singleton 라이프사이클로 등록되므로 상태를 저장하지 않도록 설계해야 하며, 의존성 주입이 필요한 경우 InvokeAsync 메서드의 파라미터로 받아야 합니다. 성능을 위해 비동기 처리를 기본으로 하고, 무거운 작업은 미들웨어 외부로 분리하며, 요청 컨텍스트에 대한 접근은 최소화해야 합니다. 또한 예외 처리 미들웨어는 파이프라인 최상단에 배치하고, CORS나 인증 미들웨어는 정확한 순서로 등록하여 보안 이슈를 방지해야 합니다.
- • Use는 체인형, Run은 터미널, Map은 분기형 미들웨어
- • 미들웨어는 Singleton 라이프사이클이므로 상태 저장 금지
- • 의존성은 InvokeAsync 파라미터로 주입
- • 미들웨어 순서가 보안과 성능에 중요한 영향
인증, 로깅, 예외 처리, 요청 변환 등 모든 횡단 관심사를 처리하는 핵심 메커니즘으로 활용됩니다.
미들웨어에서 HttpContext를 다음 미들웨어 실행 후에도 접근할 때 발생할 수 있는 문제와 해결 방법은 무엇인가요?
Q. ASP.NET Core의 Transient, Scoped, Singleton 서비스 라이프타임 간의 차이를 설명하고, 각각을 잘못 사용했을 때 발생할 수 있는 Captive Dependency 문제와 메모리 누수 시나리오를 구체적으로 설명해주세요. 또한 대규모 시스템에서 이를 방지하기 위한 설계 원칙을 제시해주세요.
라이프타임이 긴 서비스가 짧은 라이프타임의 서비스를 의존할 때 무슨 일이 발생하는지 생각해보세요.
Transient는 요청마다 새 인스턴스를 생성하고, Scoped는 HTTP 요청당 하나의 인스턴스를 공유하며, Singleton은 애플리케이션 생명주기 동안 하나의 인스턴스만 유지합니다. Captive Dependency는 Singleton 서비스가 Scoped 서비스를 의존할 때 발생하며, Scoped 서비스가 첫 요청 이후 계속 재사용되어 잘못된 데이터나 상태를 반환하는 문제가 생깁니다. DbContext를 Singleton으로 등록하면 스레드 안전성 문제와 연결 누수가 발생하며, Transient로 등록된 IDisposable 서비스는 컨테이너가 추적하여 메모리 누수를 일으킬 수 있습니다. 방지 원칙으로는 ValidateScopes 옵션을 활성화하고, 상태를 가진 서비스는 Scoped 이하로 등록하며, Factory 패턴으로 라이프타임이 다른 의존성을 해결하고, IDisposable 구현 시 라이프타임을 신중히 선택해야 합니다.
- • Transient는 매번 생성, Scoped는 요청당 하나, Singleton은 앱당 하나
- • Captive Dependency는 긴 라이프타임이 짧은 라이프타임을 캡처하는 문제
- • DbContext는 반드시 Scoped로 등록
- • ValidateScopes와 Factory 패턴으로 문제 예방
잘못된 서비스 라이프타임 설정으로 인한 동시성 버그나 메모리 누수는 프로덕션에서 진단하기 가장 어려운 문제 중 하나입니다.
백그라운드 서비스에서 Scoped 서비스를 사용해야 할 때 어떻게 처리해야 하나요?
Q. ASP.NET Core 애플리케이션의 처리량과 응답 속도를 개선하기 위한 고급 최적화 기법들을 설명해주세요. 특히 Response Caching, Output Caching, Memory Cache의 차이점과 적용 시나리오, 그리고 Kestrel 서버의 성능 튜닝 옵션과 대규모 트래픽 환경에서의 아키텍처 설계 전략을 포함해서 답변해주세요.
캐싱 레이어의 위치와 Kestrel의 스레드 풀 및 연결 관리 설정을 중심으로 생각해보세요.
Response Caching은 HTTP 헤더 기반으로 클라이언트나 프록시에서 캐싱되며 공개 데이터에 적합하고, Output Caching은 서버 측에서 렌더링된 결과를 캐싱하여 동일 요청에 즉시 응답하며, Memory Cache는 애플리케이션 내부에서 객체를 메모리에 보관하는 방식입니다. Kestrel 성능 튜닝은 Limits.MaxConcurrentConnections로 동시 연결 수를 제한하고, Limits.MaxRequestBodySize로 요청 크기를 제한하며, MinThreads 설정으로 스레드 풀을 사전 할당하는 것이 중요합니다. 대규모 트래픽 환경에서는 Kestrel 앞단에 Reverse Proxy를 두고, 정적 파일은 CDN으로 분리하며, 데이터베이스 연결 풀 크기를 적절히 조정하고, 비동기 처리를 철저히 적용해야 합니다. 또한 분산 캐시로 Redis를 활용하고, Health Check와 Circuit Breaker 패턴으로 장애 전파를 방지하며, APM 도구로 병목 지점을 지속적으로 모니터링해야 합니다.
- • Response Caching은 클라이언트 측, Output Caching은 서버 측 렌더링 결과, Memory Cache는 객체 캐싱
- • Kestrel의 MaxConcurrentConnections, MaxRequestBodySize, MinThreads 튜닝 필수
- • Reverse Proxy, CDN, 연결 풀, 비동기 처리로 확장성 확보
- • 분산 캐시와 Circuit Breaker로 안정성 강화
트래픽이 급증하는 이벤트나 프로모션 기간에 시스템이 안정적으로 동작하도록 사전에 성능 튜닝과 캐싱 전략을 수립해야 합니다.
ASP.NET Core에서 async/await를 사용할 때 ConfigureAwait(false)를 언제 사용해야 하며, 웹 애플리케이션에서는 왜 일반적으로 필요하지 않은가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!