ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Cloud Gateway][비교] route filter와 default-filters와 GlobalFilter를 actuator dump 기준으로 어디서 나눠 읽나
    백엔드/Spring 2026. 8. 29. 09:18

    IT 리서치 노트

    [Spring Cloud Gateway][비교] route filter와 default-filters와 GlobalFilter를 actuator dump 기준으로 어디서 나눠 읽나

    Spring Cloud Gateway filter incident를 다루다 보면 route filter, default-filters, GlobalFilter가 모두 같은 filter order 문제처럼 보일 때가 많다. 하지만 2026년 8월 29일 KST 기준 Spring Cloud Gateway 5.0.3 공식 문서를 다시 보면 route별 actuator dump, 공통 default-filters 설정, bean으로 등록한 GlobalFilter는 조회 위치와 변경 책임이 다르다. 이 글은 route filter와 default-filters와 GlobalFilter를 actuator dump 기준으로 어디서 나눠 읽어야 하는지 정리한다.

    1. 개요

    결론부터 말하면 특정 route만 다르면 route filter, 여러 route에 같은 추가 동작이 보이면 default-filters, route 정의는 맞는데 전역 동작이 바뀌면 GlobalFilter 순으로 나눠 보는 편이 맞다. combinedfilters는 최종 체인을 보여 주지만, 출처를 설명해 주지는 않기 때문에 config와 bean 코드를 따로 대조해야 한다.

    앞단으로는 handler-mapping.order 분기 글, target-route snapshot 글, RewritePath와 filter order 글, default-filters와 globalfilters 글이 있다. 이번 글은 이 조각들을 한 단계 위에서 다시 정리하는 비교형 허브다.

    2. 어디서 실제로 막히는가

    현장에서 가장 흔한 실패는 combinedfilters에 보였으니 route 설정 문제다라고 단정하는 것이다. 하지만 global filter 문서는 route에 매치되면 GlobalFilter와 route-specific GatewayFilter가 함께 모여 Ordered 기준으로 정렬된다고 적는다. 다시 말해 combinedfilters는 결과 체인이지, 반드시 route YAML 출처만 뜻하지 않는다.

    두 번째 실패는 default-filters를 route 정의의 일부처럼 다루는 것이다. appendix는 spring.cloud.gateway.server.webflux.default-filters를 모든 route에 적용되는 공통 설정으로 설명한다. 그러니 여러 route에서 같은 현상이 보인다면 특정 route의 RewritePath보다 default-filters 쪽이 더 앞단일 수 있다. 반대로 한 route만 다르면 공통 설정보다 route-specific filter가 먼저다.

    세 번째 실패는 custom GlobalFilter bean을 actuator dump 바깥으로 밀어 두는 것이다. developer guide는 custom global filter를 bean으로 등록하는 패턴을 보여 준다. 이 경우 운영자가 route JSON과 application.yml만 보고 있으면 문제를 못 찾는다. 특히 Ordered 구현이 달라지면 pre와 post 실행 순서가 바뀌므로, 로그에는 같은 헤더 조작이어도 전혀 다른 위치에서 일어날 수 있다.

    • 증상: path 결과가 어긋나는데 어떤 filter가 실제 원인인지 모호하다.
    • 실패: combinedfilters 결과를 route YAML 출처로 단정한다.
    • 막힘: default-filters와 GlobalFilter bean을 같은 층으로 적는다.
    • 누락: Ordered 구현과 bean 등록 위치를 incident 메모에 남기지 않는다.
    같아 보이는 현상 실제 층 먼저 볼 곳
    한 route만 path가 다르다 route-specific filter routes/{id}, combinedfilters
    여러 route에 같은 부가 filter가 보인다 default-filters spring.cloud.gateway.server.webflux.default-filters
    route 정의는 맞는데 전역 흐름이 바뀐다 GlobalFilter bean /actuator/gateway/globalfilters와 bean 코드

    3. 실무에서 적용하는 순서

    가장 짧은 triage 순서는 다섯 단계다. 먼저 /actuator/gateway/routes/{id}와 combinedfilters로 특정 route의 최종 체인을 본다. 다음으로 같은 현상이 다른 route에도 있는지 확인한다. 세 번째로 default-filters 설정을 대조한다. 네 번째로 /actuator/gateway/globalfilters를 열어 bean-level 전역 체인을 본다. 마지막으로 custom GlobalFilter 코드와 Ordered 값을 확인한다.

    1. 문제가 난 route의 routes/{id}와 combinedfilters를 저장한다.
    2. 같은 현상이 여러 route에 반복되는지 확인한다.
    3. default-filters 설정과 route별 정의를 분리해 적는다.
    4. globalfilters endpoint와 bean 등록 코드를 대조한다.
    5. custom GlobalFilter의 Ordered 값과 pre/post 위치를 메모에 남긴다.

    실제로는 actuator 응답을 조회하고, route id를 입력해 route detail을 저장하고, 같은 시간의 combinedfilters를 저장하고, application.yml에서 default-filters를 확인하고, 다음으로 globalfilters endpoint를 열고, 마지막에 bean 코드를 읽는 순서가 가장 덜 꼬인다. 이 순서를 고정하면 특정 route 오작동인지, 공통 config drift인지, 전역 bean drift인지 곧바로 구분된다.

    중요한 것은 combinedfilters가 모든 질문의 답이 아니라는 점이다. combinedfilters는 최종 실행 순서를 보여 주는 좋은 증거지만, 그 필터가 route YAML에서 왔는지 default-filters에서 왔는지 custom bean에서 왔는지는 별도 대조가 필요하다. incident 메모가 짧으려면 결과 체인과 구성 출처를 다른 칸으로 적어야 한다.

    triage 메모 순서
    step_1=save route detail
    step_2=save combinedfilters
    step_3=diff default-filters config
    step_4=check globalfilters endpoint
    step_5=read custom GlobalFilter bean and Ordered value

    같은 Spring branch에서 더 좁은 edge case를 다시 보고 싶다면 RewritePath와 filter order 글에서 route-level 문제를 먼저 보고, default-filters와 globalfilters order 글로 내려가는 편이 자연스럽다. 이번 글은 그 둘을 다시 묶어 주는 허브로 두면 된다.

    4. 공식 문서와 예시 화면으로 확인하기

    첫 자료는 2026년 8월 29일 KST 기준 Spring Cloud Gateway Actuator API 문서다. 여기서는 route filters와 global filters 조회 endpoint가 처음부터 분리되어 있다.

    Actuator API 문서는 route filter 조회와 global filter 조회를 별도 endpoint로 나눠 둔다.
    Actuator API 문서는 route filter 조회와 global filter 조회를 별도 endpoint로 나눠 둔다.

    즉 filter incident를 볼 때도 한 덤프만 보면 부족하다. route별 filter chain과 전역 chain을 같은 화면에서 읽으면 원인 층이 쉽게 섞인다.

    두 번째 자료는 global filter 문서의 핵심 설명이다. Spring Cloud Gateway는 route에 매치되면 GlobalFilter와 route-specific GatewayFilter를 함께 모아 Ordered 기준으로 정렬한다고 적는다.

    GlobalFilter와 route-specific GatewayFilter는 최종 체인에서 함께 정렬되지만, 출처와 책임은 다르다.
    GlobalFilter와 route-specific GatewayFilter는 최종 체인에서 함께 정렬되지만, 출처와 책임은 다르다.

    이 문장을 놓치면 combinedfilters 한 덤프를 보고도 어떤 항목이 route 설정이고 어떤 항목이 bean 등록인지 분리하지 못한다. 정렬 결과와 구성 출처는 다른 문제다.

    세 번째 자료는 developer guide다. custom global filter는 bean으로 등록되고 모든 요청에 적용될 수 있으므로, route YAML diff만 보고는 보이지 않는 레이어가 된다.

    custom GlobalFilter는 bean 레이어이므로 route 설정과 다른 소유자와 수정 경로를 가진다.
    custom GlobalFilter는 bean 레이어이므로 route 설정과 다른 소유자와 수정 경로를 가진다.

    따라서 incident note에는 application.yml만이 아니라 bean 등록 위치와 Ordered 구현 여부도 같이 남겨야 한다. route 설정만 깨끗해도 전역 bean이 체인을 바꿀 수 있다.

    네 번째 자료는 공통 속성 appendix다. 여기서 spring.cloud.gateway.server.webflux.default-filters가 모든 route에 적용되는 공통 설정이라는 점을 다시 확인할 수 있다.

    default-filters는 route 내부 정의가 아니라 모든 route에 공통 적용되는 설정 레이어다.
    default-filters는 route 내부 정의가 아니라 모든 route에 공통 적용되는 설정 레이어다.

    그래서 default-filters는 route filter와 같지 않고, custom global filter와도 또 다르다. 실제 incident 대응에서는 이 셋을 한 줄로 쓰는 순간 다시 읽기가 어려워진다.

    실무에서는 filter layer 지도를 먼저 두는 편이 빠르다. 아래 표는 같은 path mismatch가 보여도 어느 레이어를 먼저 의심할지 정리한 것이다.

    route filter, default-filters, GlobalFilter를 구분하는 실무 표다.
    route filter, default-filters, GlobalFilter를 구분하는 실무 표다.

    이미 RewritePath와 filter order 글과 default-filters와 globalfilters 글이 세부 분기를 다뤘다면, 이번 표는 그 위에 있는 허브 역할이다.

    마지막 자료는 incident 메모 예시다. route chain, default config, global bean chain을 서로 다른 블록으로 남기는 편이 재현성이 높다.

    Spring Cloud Gateway filter incident 메모는 세 레이어를 따로 남겨야 한다.
    Spring Cloud Gateway filter incident 메모는 세 레이어를 따로 남겨야 한다.

    같은 cluster에서는 target-route snapshot 글과 handler-mapping.order 글이 앞단이고, 이번 글은 이후 세부 edge post들을 받아주는 비교형 정리판이다.

    5. 주의사항과 리스크

    첫 번째 리스크는 route dump 하나만 저장하고 bean 코드를 보지 않는 것이다. 두 번째 리스크는 default-filters를 공통 설정이 아니라 특정 route의 일부처럼 취급하는 것이다. 세 번째 리스크는 Ordered 값이 실제 pre/post 위치를 바꾸는데도 그 값을 incident 메모에서 빼는 것이다.

    운영 메모에는 최소한 route_id, combinedfilters, default-filters, globalfilters, custom_global_order 다섯 항목을 따로 남기는 편이 좋다. 그래야 나중에 공통 설정 drift와 bean drift를 route 설정 문제로 잘못 회고하는 일을 줄일 수 있다.

    • combinedfilters는 결과 체인이고, 출처 설명은 따로 필요하다.
    • default-filters는 공통 설정 레이어다.
    • GlobalFilter는 bean 코드와 Ordered 값을 같이 봐야 한다.

    6. 결론

    Spring Cloud Gateway filter incident를 짧게 정리하려면 route filter, default-filters, GlobalFilter를 처음부터 다른 레이어로 메모해야 한다. actuator dump, 공통 설정, bean 코드의 역할을 분리해 두면 이후 RewritePath, target snapshot, ordered drift 같은 세부 글도 훨씬 빨리 연결된다.

    이번 허브형 글을 default-filters와 globalfilters 후속편에 연결해 두면 Spring Cloud Gateway cluster가 세부 edge case 위에 더 넓은 진입 글을 갖게 된다.

    세 레이어를 나눈 뒤에도 order drift가 남는다면 새 후속편인 bean-definition drift 검증 글로 넘어가면 된다. route dump와 default-filters 검증을 끝낸 다음 bean 이름, Ordered 값, snapshot 시각을 어떤 표로 남길지까지 바로 이어진다.

    7. 참고 링크

    1. https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/actuator-api.html
    2. https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/global-filters.html
    3. https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/developer-guide.html
    4. https://docs.spring.io/spring-cloud-gateway/reference/appendix.html
Designed by Tistory.