지금 내가 만드는 백엔드 서비스 개선하기 1

이재훈·2025년 12월 19일
post-thumbnail

백엔드 개발자로서 항상 자신이 만들고 있는 서비스가 안정적인지, 이게 최선인지 고민해 보아야 한다.

나 역시 곧 1차 릴리즈를 앞두고 있다. 많은 고민 끝에 기술을 결정하고 서비스를 만들었지만, 예상치 못한 문제가 발생할 수도 있다는 것을 알고 있다. ChatGPT에게 현재 내가 만들고 있는 서비스를 설명해주고 더 안정적인 운영을 하기 위해 어떻게 해야할지 같이 고민해달라고 요청했다.

현재 만들고 있는 서비스

  • 웹으로 접속하여 해당 서버의 네트워크, 시스템, 방화벽 등 설정을 할 수 있는 서비스.
  • 백엔드와 실질적인 명령어를 내리는 서비스들이 존재.

GPT 답변

개요

현재 운영 중이거나 개발 중인 서비스는 웹 화면을 통해 서버의 네트워크 설정, 방화벽 정책, 시스템 설정, IPSec VPN 설정 등을 적용하는 관리형 서비스이다.

기술 스택은 다음과 같다.

  • Frontend: React
  • Backend: Spring Boot
  • Database: PostgreSQL
  • Inter-service communication: gRPC
  • Domain services: Go 기반 모듈
  • Logging: journald → Vector → OpenObserve

이 글에서는 백엔드 시니어 관점에서 안정적인 서비스 운영을 위해 반드시 고려해야 할 사항과 임팩트 있는 개선 포인트를 정리한다.


1. 이 서비스의 본질: “설정을 바꾸는 서비스”

이 서비스는 일반적인 CRUD 웹 서비스와 본질적으로 다르다.

  • 설정 변경은 즉시 장애로 이어질 수 있음
  • 잘못된 정책 적용은 네트워크 단절, 보안 사고로 직결
  • 부분 실패, 중복 적용, 상태 불일치가 치명적

따라서 모든 설계는 다음 질문을 중심으로 이루어져야 한다.

이 버튼을 잘못 누르거나, 적용 도중 실패하면 어떻게 되는가?


2. 정책 적용(Apply) 흐름 설계

2.1 정책 상태 머신 정의

정책은 반드시 상태 기반으로 관리되어야 한다.

DRAFT
 → READY
 → APPLYING
 → APPLIED
 → FAILED
 → ROLLBACKING
 → ROLLED_BACK

반드시 DB에 저장해야 할 정보

  • policy_id
  • 대상 서버 또는 장비
  • 요청자
  • 요청 시각
  • 현재 상태
  • 실패 사유 (error code + message)
  • 재시도 횟수

DB만 보고도 다음 질문에 답할 수 있어야 한다.

  • 지금 이 서버는 어떤 상태인가?
  • 마지막 성공 적용은 언제인가?
  • 실패한 이유는 무엇인가?

2.2 gRPC 호출 실패 시나리오 분해

gRPC 통신은 “성공/실패”만으로는 부족하다.

상황실제 의미대응
gRPC timeout적용 중인지, 미수신인지 불명Idempotency 필수
일부 모듈 성공반쪽짜리 적용Rollback 또는 보정
Go 모듈 panic상태 불명상태 조회 API 필요
네트워크 단절결과 미확인재조회 기반 판단

👉 Go 모듈에는 반드시 “현재 적용 상태 조회 API”가 존재해야 한다.


2.3 Idempotency (중복 적용 방지)

정책 적용 요청은 반드시 멱등성(Idempotency) 을 가져야 한다.

  • 모든 Apply 요청에 request_id (UUID) 부여
  • Go 모듈은 request_id 기준으로 처리
    • 이미 처리한 요청 → 즉시 성공 응답
    • 신규 요청 → 실제 적용

Idempotency가 없으면 재시도는 곧 중복 설정이 된다.

특히 방화벽, VPN 설정에서는 치명적이다.


3. Rollback 전략 (없으면 운영 불가)

3.1 이전 설정은 어디에 있는가?

Rollback이 가능하려면 다음 중 하나는 반드시 존재해야 한다.

  • DB에 정책 버전 이력 저장
  • Go 모듈에서 적용 전 설정 스냅샷 보관
  • 최소한 diff 기반 복원 전략

3.2 Rollback 트리거

Rollback은 명확한 조건을 가져야 한다.

  • 정책 적용 실패 시 자동 실행
  • 운영자 수동 Rollback 버튼
  • APPLYING 상태가 일정 시간 이상 지속될 경우

Rollback 없는 Apply는 운영 서비스로서 매우 위험하다.


4. 트랜잭션 경계 재설계

4.1 DB 트랜잭션과 실세계는 다르다

다음과 같은 코드는 매우 위험하다.

@Transactional
savePolicy();
grpc.apply();

권장 패턴 (Saga 스타일)

  1. 정책 상태를 APPLYING으로 저장 (DB commit)
  2. gRPC 호출
  3. 결과 수신
  4. 상태를 APPLIED 또는 FAILED로 갱신

DB는 의도(intent) 를 기록하고,

실제 적용은 외부 세계에서 이루어진다.


5. 관측 가능성(Observability) 강화

5.1 로그 표준화

이미 OpenObserve를 사용 중이라면, 로그 필드 표준화가 핵심이다.

공통 로그 필드

  • request_id
  • policy_id
  • target_host
  • domain (firewall, vpn, network 등)
  • result_code

Spring → gRPC → Go → journald → Vector → OpenObserve

전 구간에서 동일한 request_id 유지가 필수다.


5.2 메트릭은 로그보다 중요하다

다음 메트릭이 없으면 “감으로 운영”하게 된다.

  • 정책 적용 성공/실패 횟수
  • 평균 적용 시간
  • APPLYING 상태 체류 시간
  • Rollback 발생 빈도
  • Go 모듈별 오류율

Prometheus + Grafana 조합을 강력히 권장한다.

(OpenObserve는 로그, 메트릭은 분리하는 것이 안정적)


6. 장애 대응 관점 체크리스트

6.1 자동 감지 가능한 이상 상태

다음 상황은 반드시 감지되어야 한다.

  • APPLYING 상태가 일정 시간 이상 지속
  • 동일 서버에 동시 정책 적용 시도
  • 특정 시간대 실패율 급증

최소한 Alert는 떠야 하며, 가능하면 자동 조치도 고려한다.


6.2 운영자를 위한 필수 화면

운영 관점에서 다음 정보는 반드시 제공되어야 한다.

  • 서버별 마지막 성공 적용 시점
  • 현재 적용 중인 정책
  • 실패 이력 타임라인
  • 재시도 / Rollback 버튼

7. 보안 관점 고려사항

7.1 권한 분리

API 권한은 반드시 분리한다.

  • 조회 권한
  • 정책 수정 권한
  • 실제 Apply 권한

Apply 권한은 관리자 중에서도 제한해야 한다.


7.2 Audit Log

삭제 불가능한 감사 로그는 필수다.

  • 누가
  • 언제
  • 무엇을
  • 어떤 서버에
  • 어떤 결과로

보안 사고 및 감사 대응을 위해 반드시 필요하다.


8. 임팩트 큰 개선 우선순위 TOP 5

  1. 정책 적용 상태 머신 + DB 기록
  2. Idempotent gRPC 설계
  3. Rollback 전략 명문화
  4. request_id 기반 전 구간 트레이싱
  5. APPLYING 상태 감지 및 알림

이 다섯 가지만 제대로 갖춰도

“운영 가능한 서비스” → “신뢰 가능한 서비스” 로 도약한다.


9. 마무리

이 서비스는 단순한 백엔드 API가 아니라 Control Plane에 가깝다.

이 영역을 제대로 경험하면:

  • SRE
  • 플랫폼 엔지니어
  • 아키텍트

로 성장하는 데 매우 큰 자산이 된다.


정말 다양한 내용이 들어있다. 해당 내용을 가지고 현재 내가 진행하고 있는 프로젝트에 잘 적용되어있는지 체크를 해보았다.

profile
부족함을 인정하고 노력하자

0개의 댓글