-
[Spring Cloud Gateway][운영] /actuator/gateway/refresh가 200인데 route가 안 바뀔 때 access 설정, metadata refresh, routes.count를 어떤 순서로 다시 보나기타개발지식/풀스택개발 2026. 8. 20. 20:17
IT 리서치 노트
[Spring Cloud Gateway][운영] /actuator/gateway/refresh가 200인데 route가 안 바뀔 때 access 설정, metadata refresh, routes.count를 어떤 순서로 다시 보나
Spring Cloud Gateway에서 `POST /actuator/gateway/refresh`가 200을 돌려주는데도 route가 기대대로 안 바뀌면 많은 팀이 actuator가 먹었다고 착각한다. 하지만 2026년 8월 20일 기준 Spring Cloud Gateway 공식 문서를 다시 보면, gateway actuator access 설정이 먼저 맞아야 하고, refresh 200은 빈 응답 본문만 주는 수락 신호이며, metadata selective refresh와 `spring.cloud.gateway.routes.count` 같은 별도 증거를 함께 봐야 한다. 이 글은 refresh가 200인데 route가 안 바뀔 때 무엇부터 다시 봐야 하는지 정리한다.
1. 개요
결론부터 말하면 Spring Cloud Gateway refresh triage는
actuator access 설정 확인 → 현재 route 목록과 특정 route 조회 → refresh 200 확인 → metadata 대상 여부 확인 → routes.count로 실제 반영 여부 확인순으로 가는 편이 가장 빠르다. 200은 반영 증명이 아니라 요청 수락이다.즉
refresh가 먹었다는 말은 최소 두 조각으로 나뉘어야 한다. 하나는 endpoint 접근과 호출 수락, 다른 하나는 실제 route 정의 변화다. 이 두 증거를 섞으면 업그레이드 이슈와 운영 이슈를 구분하기 어려워진다.같은 Spring Cloud Gateway 흐름에서 더 자주 막히는 지점은 refresh 200 뒤 live route set은 다르지만 원인이 include-expression인지 route order인지 헷갈리는 후속 글이다. 이 글이
refresh 수락과 반영 증거를 나누는 단계라면, 후속 글은route 누락과 order drift를 분기하는 단계를 정리한다.2. 어디서 실제로 막히는가
실무에서 흔한 막힘은 네 가지다. 첫째,
/actuator/gateway/refresh가 200을 돌려주면 route가 실제로 바뀌었다고 생각한다. 둘째,read-onlyaccess로 열어 둔 상태와unrestricted쓰기 동작 가능 상태를 구분하지 않는다. 셋째, metadata selective refresh를 쓰면서 실제 route metadata 값과 query parameter를 대조하지 않는다. 넷째, route source가application.yml, discovery locator, Java DSL 중 어디서 왔는지 분리하지 않은 채 actuator만 두드린다.공식 actuator 문서는 gateway endpoint가 기본 비활성이고 access와 expose 설정이 필요하다고 적는다. 또 refresh는 200과 빈 본문을 주고, metadata 필터 refresh는 특정 key:value 대상에만 적용되며, 비동기 오류가 나면 기존 route를 수정하지 않는다고 설명한다. configuration 문서는
spring.cloud.gateway.routes.countgauge를 metrics로 볼 수 있다고 적는다. 이 셋을 합치면 triage 핵심은호출 가능 여부,호출 대상,실제 결과세 층위다.특히 업그레이드 직후에는 route source 자체가 달라졌을 수 있다. actuator refresh는 캐시를 흔드는 도구이지, 없는 route를 새로 만들어 주는 마법이 아니다. locator 결과가 바뀐 건지, Java DSL 정의가 그대로인 건지, metadata가 달라졌는지 먼저 구분해야 한다.
- 증상: refresh는 200인데 route 결과는 그대로다.
- 실패: 200을 반영 완료로 읽는다.
- 막힘: metadata 대상과 실제 route metadata를 대조하지 않는다.
- 누락: route source 차이와 actuator 캐시 갱신을 같은 문제로 본다.
보이는 현상 먼저 볼 곳 판단 기준 200이 오는데 route가 그대로다 routes.count, GET /routes 정의 수와 상세가 실제로 바뀌는지 본다 일부 그룹만 안 바뀐다 metadata=key:value query parameter가 실제 route metadata와 맞는지 본다 refresh 동작 자체가 제한적이다 gateway access 설정 read-only와 unrestricted를 구분한다 3. 실무에서 적용하는 순서
가장 실용적인 실행 순서는 다섯 단계다. 1단계에서
management.endpoint.gateway.access와 노출 설정을 확인한다. 2단계에서GET /actuator/gateway/routes와GET /actuator/gateway/routes/{id}로 현재 상태를 캡처한다. 3단계에서POST /actuator/gateway/refresh또는 metadata selective refresh를 호출한다. 4단계에서 같은 route 조회와spring.cloud.gateway.routes.count를 다시 본다. 5단계에서 변화가 없으면 actuator가 아니라 route source 또는 metadata 설계 문제로 분리한다.- gateway actuator access와 노출 설정을 먼저 확인한다.
- 현재 route 목록과 특정 route 상태를 저장한다.
- refresh 또는 metadata refresh를 호출한다.
- routes.count와 route 상세를 다시 조회한다.
- 변화가 없으면 source diff와 metadata 설계를 본다.
이 순서의 장점은
수락과반영을 문서로 분리해 남길 수 있다는 점이다. 운영 채널에도refresh 200 OK,routes.count unchanged,metadata group mismatch처럼 짧고 정확한 문장으로 남길 수 있다. 업그레이드 대응에서는 이런 사실 기록이 없으면 locator, yml, DSL 이슈가 모두 actuator 문제처럼 보인다.이 메모를 기준으로 보면 200은 단지 한 칸일 뿐이다. 실제 route 변화는 별도 칸에서 검증해야 한다.
4. 공식 문서와 예시 화면으로 확인하기
첫 공식 화면은 gateway actuator access 기본값이다. 문서는 `/gateway` actuator endpoint가 기본적으로 비활성이고, `read-only` 또는 `unrestricted` 접근과 노출 설정을 명시해야 한다고 적는다.
여기서 `read-only`로 열어 둔 상태를 모르면, 200이 보였더라도 실제로 어떤 쓰기 동작이 가능한지 잘못 해석할 수 있다. access 계층을 먼저 고정해야 route triage가 시작된다.
두 번째 자료는 refresh 동작의 기본 설명이다. 문서는 `POST /actuator/gateway/refresh`가 200과 빈 응답 본문을 돌려준다고 적는다.
실무에서 200만 보고 끝내면 여기서 길어진다. 이 응답은 `수락`이지 `결과 변화 증명`이 아니다.
세 번째 자료는 metadata 기반 selective refresh를 운영 메모 형태로 다시 그린 것이다. route 그룹별 key:value를 입력하고, 특정 그룹만 새로고침한 뒤 결과를 다시 조회해야 `대상이 틀렸는지`, `반영이 없는지`를 분리할 수 있다.
즉 200이 왔는데 route가 그대로라면 metadata 값을 다시 확인하고, refresh 대상 route를 다시 조회하고, routes.count를 다시 비교하는 순서를 고정해야 한다.
네 번째 자료는 RouteDefinition metrics다. 문서는 actuator를 붙이면 `spring.cloud.gateway.routes.count` gauge가 생기고 `/actuator/metrics/spring.cloud.gateway.routes.count`에서 볼 수 있다고 적는다.
refresh가 성공했다고 해도 route 개수가 그대로라면 결과는 바뀌지 않은 것이다. 200과 count는 서로 다른 층위의 증거다.
실무에서는 호출 순서를 한 번에 정리한 메모가 필요하다. routes 조회, 특정 route 조회, refresh 호출, metrics 조회를 같은 세션에서 남겨야 `수락`과 `반영`을 분리할 수 있다.
이미 predicate template와 lowerCaseServiceId 글, Java DSL route source 글이 route source 분기를 다뤘다면, 이번 코드는 refresh 이후 관측성 분기다.
마지막 자료는 triage 표다. access 설정 문제, metadata 대상 문제, route source 자체 문제는 모두 `refresh가 안 먹는다`처럼 보이지만 먼저 볼 증거가 다르다.
이 표가 있어야 `route가 안 바뀐다`는 한 문장을 access, source, count, metadata 네 갈래로 자를 수 있다.
5. 주의사항과 리스크
첫 번째 리스크는 200만 보고 성공으로 처리하는 것이다. 두 번째는
read-onlyaccess 상태를 모른 채 쓰기 동작을 기대하는 것이다. 세 번째는 metadata selective refresh 대상을 잘못 적고도refresh가 안 먹는다고 말하는 것이다. 네 번째는 actuator 캐시 갱신과 route source 차이를 분리하지 않는 것이다.운영 전에 최소한
현재 route 목록,특정 route 상세,routes.count,metadata key:value,gateway access다섯 항목을 같은 티켓에 남기는 편이 좋다. 그래야 업그레이드 후 route drift가 생겼을 때도 증거가 한곳에 모인다.- refresh 200은 결과 변화 증명이 아니다.
- metadata selective refresh는 대상 key:value가 정확해야 한다.
- routes.count와 GET /routes가 실제 반영 증거다.
6. 결론
Spring Cloud Gateway에서
/actuator/gateway/refresh가 200인데 route가 안 바뀔 때는 endpoint가 먹었는지보다 결과가 달라졌는지를 따로 봐야 한다. access 설정, metadata 대상, routes.count, route source를 순서대로 구분하면refresh가 안 먹는다는 모호한 문장이 훨씬 정확해진다.- access 설정과 노출 범위를 먼저 고정한다.
- refresh 200 뒤에는 routes.count와 route 상세를 다시 본다.
- 변화가 없으면 actuator보다 source diff를 먼저 의심한다.
refresh 200과 routes.count까지 본 뒤에도 live route set이 어긋난다면 2026년 8월 21일 후속 글처럼 include-expression과 route order를 따로 분리해 보는 편이 빠르다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글