ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • golang: 그레이스풀 셧다운(Graceful Shutdown)
    Back-End/Golang 2024. 10. 25. 14:40
    반응형

    그레이스풀 셧다운의 개념

     그레이스풀 셧다운은 서버가 종료 요청을 받았을 때, 즉시 모든 연결을 끊지 않고 현재 처리 중인 요청들을 완료한 후 안전하게 종료하는 방식입니다. 이렇게 하면 클라이언트 요청이 비정상적으로 끊기는 것을 방지할 수 있고, 데이터 손실이나 요청 실패를 줄일 수 있습니다. 일반적으로, 서버가 종료할 때 남은 작업을 완료하기 위한 시간 제한(타임아웃)을 설정하여 요청이 무기한 지속되는 것을 방지합니다.

    Golang에서 그레이스풀 셧다운

     Golang의 경우, net/http 패키지를 통해 웹 서버를 간단하게 실행하고 그레이스풀 셧다운을 구현할 수 있습니다. Golang의 비동기 특성과 context 패키지는 이러한 셧다운을 쉽게 처리할 수 있게 해줍니다.

    Golang 그레이스풀 셧다운 예시

    package main
    
    import (
        "context"
        "log"
        "net/http"
        "os"
        "os/signal"
        "time"
    )
    
    func main() {
        srv := &http.Server{
            Addr:    ":8080",
            Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                time.Sleep(2 * time.Second) // 요청 처리 시 딜레이를 추가
                w.Write([]byte("Hello, World!"))
            }),
        }
    
        // 서버 실행
        go func() {
            if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
                log.Fatalf("서버 시작 실패: %v", err)
            }
        }()
        log.Println("서버 실행 중...")
    
        // 종료 시그널 대기
        quit := make(chan os.Signal, 1)
        signal.Notify(quit, os.Interrupt)
        <-quit
        log.Println("서버 종료 시도 중...")
    
        // 그레이스풀 셧다운을 위한 컨텍스트 생성
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()
    
        if err := srv.Shutdown(ctx); err != nil {
            log.Fatalf("서버 종료 실패: %v", err)
        }
        log.Println("서버가 안전하게 종료되었습니다.")
    }

    이 코드는 기본적인 서버 실행과 함께, 종료 시그널을 감지하여 그레이스풀 셧다운을 구현합니다. 여기서 중요한 포인트는 srv.Shutdown(ctx) 호출로 서버가 새로운 연결을 거부하고, 기존 요청을 처리할 시간을 준다는 것입니다. context.WithTimeout은 타임아웃을 설정해 너무 오래 걸리는 요청을 강제로 종료시킵니다.

    다른 언어와의 비교

    Node.js

    Node.js에서의 그레이스풀 셧다운은 비슷하게 process 객체를 통해 SIGINT 시그널을 받아 처리할 수 있습니다. 하지만 Golang과 달리 Node.js는 단일 스레드 기반 비동기 처리로, 특히 이벤트 루프가 처리 중인 모든 요청을 끝내기 전까지 종료되지 않는 특징이 있습니다. 또한, 직접적인 타임아웃 처리가 필요할 수 있습니다.

    Node.js 예시:

    const http = require('http');
    
    const server = http.createServer((req, res) => {
      setTimeout(() => {
        res.end('Hello, World!');
      }, 2000);
    });
    
    server.listen(8080);
    
    process.on('SIGINT', () => {
      console.log('서버 종료 중...');
      server.close(() => {
        console.log('서버가 안전하게 종료되었습니다.');
      });
    });

     

    Java (Spring Boot)

    Java의 경우 Spring Boot 프레임워크에서는 기본적으로 그레이스풀 셧다운을 지원합니다. Spring Boot 2.x 버전부터는 설정 파일에서 server.shutdown 옵션을 graceful로 설정하는 것으로 간단히 구현할 수 있습니다. Java는 JVM의 메모리 관리 및 스레드 관리의 특성상 Golang보다 더 많은 설정이 필요할 수 있습니다.

    Spring Boot 설정:

    server:
      shutdown: graceful

    왜 Golang인가?

    Golang은 경량화된 고루틴채널 기반의 동시성 처리 덕분에 매우 효율적인 서버 운영이 가능합니다. Go의 그레이스풀 셧다운은 기본 라이브러리만으로도 쉽게 구현할 수 있으며, 간결하면서도 성능 최적화가 용이합니다. 또한, Go의 컨텍스트 패키지는 타임아웃과 취소 기능을 일관되게 관리할 수 있어, 다른 언어들보다 직관적이고 성능에 유리한 면이 있습니다.

    반응형
Designed by Tistory.