Backend

Enterprise Go 시리즈 #2: 견고한 HTTP 서버 구축

2026-01-013 min read

Enterprise Go 시리즈 #2: 견고한 HTTP 서버 구축

다른 생태계 경험자를 위한 매핑

  • Java: Spring MVC Filter, HandlerInterceptor
  • Node.js: Express Middleware
  • Python: Django Middleware, FastAPI Middleware

미들웨어 체인: 순서가 중요하다

실행 흐름

권장 순서와 이유

순서미들웨어Spring 대응위치 이유
1Recover@ControllerAdvice패닉 → 500 변환
2Request IDMDC 설정로깅 전 ID 필요
3LoggerAccessLogFilter인증 실패도 로깅
4CORSCorsFilterpreflight 처리
5AuthSecurityFilter핸들러 보호

경험담

빠른 프로토타이핑을 위해 미들웨어 순서를 고려하지 않았으나, 정식 채택 후:

Recover를 Auth 뒤에 두었더니, 인증 로직 패닉 시 응답 없이 연결 끊김

Logger를 RequestID 앞에 두었더니, 로그에서 요청 추적 불가


에러 핸들링

일관된 응답 구조

도메인 에러 → HTTP 매핑

Domain ErrorHTTP StatusSpring 대응
ErrNotFound404@ResponseStatus
ErrValidation400MethodArgumentNotValidException
ErrUnauthorized401AuthenticationException
기타500@ExceptionHandler

Graceful Shutdown

왜 필요한가?

Spring vs Go

측면Spring BootGo Echo
설정server.shutdown=graceful직접 구현
타임아웃spring.lifecycle.timeout-per-shutdown-phaseWithTimeout
시그널자동 처리signal.NotifyContext

run.Group 패턴 (Prometheus 방식)

서버가 여러 고루틴(웹 서버, 워커, 헬스체크 등)으로 구성될 때:

import "github.com/oklog/run"

var g run.Group

// HTTP 서버
g.Add(func() error {
    return server.ListenAndServe()
}, func(err error) {
    server.Shutdown(ctx)
})

// 백그라운드 워커
g.Add(func() error {
    return worker.Run()
}, func(err error) {
    worker.Stop()
})

// 하나라도 종료되면 전체 종료
if err := g.Run(); err != nil {
    log.Error(err)
}

장점: 시그널 처리, 에러 전파, 종료 순서를 한 곳에서 관리


정리

요소핵심
미들웨어 순서Recover → RequestID → Logger → Auth
에러 핸들링도메인 에러 → HTTP 상태 매핑
Graceful ShutdownSIGTERM 처리, run.Group 패턴

다음 편 예고

3편: Context로 요청 생명주기 관리에서는 Java의 ThreadLocal, Node.js의 AsyncLocalStorage에 대응하는 Context 패턴을 다룹니다.


참고 자료

Share

Related Articles

Comments

이 블로그는 제가 알고 있는 것들을 잊지 않기 위해 기록하는 공간입니다.
직접 작성한 글도 있고, AI의 도움을 받아 정리한 글도 있습니다.
정확하지 않은 내용이 있을 수 있으니 참고용으로 봐주세요.

© 2026 Seogyu Kim