pile·
백엔드·마켓컬리마켓컬리 Hello World·

nginx 설정 없이 우아하게 서비스 점검하기 (下)

별도 게이트웨이 없이 프론트·서버가 각각 nginx를 CORS로 쓰는 컬리 환경에서, 비기술자도 접근 차단을 설정하고 클러스터·권한 단위로 세밀하게 제어할 수 있는 AccessBlock 시스템을 업무 RDBMS 의존 없이 재설계한 기록이다.

핵심 포인트
  • nginx 설정은 인프라팀 의존이 크고 비기술자가 못 다뤄, 기획자·QA·운영도 쓸 수 있는 접근 차단 시스템이 필요했다.
  • 메타데이터(무엇을 차단)는 구글시트→BigQuery→Redis로, 실행데이터(언제·누구를)는 API 직접 호출→Redis로 분리했다.
  • BigQuery는 작은 쿼리도 수백 ms라 매 라우팅마다 질의하면 성능이 저하돼 Redis 캐싱 + 정확히 3분 주기 동기화 배치로 처리했다.
  • 저장 타입을 용도로 분리해 메타데이터는 List, 빈번한 추가·삭제인 실행데이터는 Hash로 저장했다.
  • 화면은 VueRouter beforeEach, API는 Spring AOP로 인터셉트하고 클러스터·창고·권한(excludeRoles) 조합으로 차단을 판정한다.
상세 정리
  • 기존 문제: nginx는 강력하나 인프라팀 의존이 크고, 서버 엔지니어 아닌 사람이 접근 불가하며, 특정 클러스터/센터만 차단하되 슈퍼마스터는 허용하는 세밀 제어가 필요하고, 업무 RDBMS 종속을 제거하려 했다.
  • 저장소 선택: 표 형태로 직관적인 구글시트를 입력 UI로, BigQuery로 업무 RDBMS와 독립, Redis로 저지연 캐싱을 구성했다.
  • BigQuery 한계: 작은 테이블·간단한 쿼리도 수백 ms라 매 라우팅·API마다 직접 질의하면 지연돼 Redis로 캐싱했고, 기존 N번 호출마다 동기화는 트래픽에 따라 주기 예측이 안 돼 정확히 3분 주기 배치로 교체했다.
  • 데이터 분리: 메타데이터는 어떤 path를 차단하는지(path+group, cluster 컬럼 삭제, Redis List), 실행데이터는 언제·누구·어떤 path인지(휘발성이 강해 API 직접 호출, Redis Hash)로 나눴다.
  • 실행데이터 필드: id(자동 채번), cluster(빈 값이면 전체), warehouse(센터 단위), excludeRoles(제외 권한 배열), groupName(차단 그룹)으로, 예컨대 평택클러스터·warehouse=null이면 평택 전체를 차단하고 김포는 미차단이다.
  • 화면 접근제어: VueRouter beforeEach에서 to.path가 차단 대상인지 확인해 true면 /unavailable로 리다이렉트하고, 로그인·로그아웃·unavailable은 제외한다.
  • API 접근제어: Spring AOP로 RestController 요청을 인터셉트하고 @ExcludeAccessBlock 어노테이션으로 제외 대상을 표시하며, 차단 시 InboundServiceException을 던지고 RequestURI·getUserCluster/Warehouse/Roles로 isBlocked를 판정한다.
  • 사용법: 구글시트→데이터팀 확장 프로그램으로 BigQuery 업로드→3분 배치가 전체 삭제 후 재저장→Redis List 동기화, 실행데이터는 Swagger/Postman으로 등록(응답 id)·조회·삭제(id로 즉시 해제)한다.
  • 트레이드오프: nginx·직접 UI·BigQuery 직접 질의·호출 기반 동기화·데이터 통합을 각각 기각하고, 구글시트+BigQuery·Redis 캐싱·3분 동기화·메타/실행 분리·실행데이터 API 직접 호출을 채택했다.
  • 결과·한계: 비기술자도 관리 가능하고 업무 RDBMS와 독립하며 세밀한 권한/클러스터 차단이 가능하나, 코드 전체 공개는 방대해 생략했고 기업 특화라 일반화는 어렵다.
왜 읽나게이트웨이 없이 서비스 점검 모드·접근 차단을 구현해야 하는 백엔드 개발자에게 메타/실행 데이터 분리와 BigQuery·Redis·Spring AOP 설계 레퍼런스.
마켓컬리
마켓컬리 Hello World 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·github-engGitHub Engineering·

    조기 종료를 없애야 벡터화된다 — 메모리 속도 소스 코드 케이스 폴딩

    GitHub의 코드 검색 엔진 Blackbird는 480TB 이상의 소스 코드를 인덱싱하기 전 모든 바이트에 case folding을 적용한다. 이 글은 Rust로 구현한 case folding을 메모리 대역폭 한계(45+ GiB/s)까지 끌어올린 두 가지 반직관적 최적화를 상세히 다룬다. 핵심은 루프 조기 종료(break) 제거로 LLVM 벡터화를 유도하고, UTF-8을 디코딩하지 않고 바이트 공간 산술만으로 fold를 수행하는 것이다.

    #rust#unicode#simd+2
  2. 백엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    트랜잭션 스크립트에서 숙소 메타 + 가격 계산 모듈로 — 전시 아키텍처 개선기 (2/3)

    여기어때 전시개발팀이 숙소 상세(PDP) API를 해부한 결과, 코드상으로는 DB 호출 3번처럼 보이던 요청이 실제로는 MongoDB $lookup 체인으로 컬렉션을 19회 접근하는 구조였다. 이 트랜잭션 스크립트 방식의 핵심 문제는 "aggregation이 I/O를 가린다"는 점으로, 독립적인 쿼리 10개가 단일 파이프라인에 직렬화되어 병렬화 기회를 잃고, 가격 때문에 거의 안 바뀌는 이미지까지 매 요청마다 읽어야 하는 읽기 증폭이 발생했다. V3에서는 "조회 시점 조립"을 "쓰기 시점 사전 조립"으로 전환하고, 화면별로 복제되던 가격 계산 로직을 goodsprice 단일 모듈로 수렴했다. 4개 API(PLP/PDP/RDP/ILP)의 반복 마이그레이션은 Claude Code skill로 절차를 고정하고 쉐도잉 + 동일성 검증으로 안전망을 마련하는 방식으로 진행됐다.

    #architecture#migration#caching+2