Spring Cloud - Spring Cloud Eureka (상세 설정편)
in DEV on MSA(Spring), Spring-cloud-eureka
이 포스트는 유레카 상세 설정값에 대해 기술한다.
- 1. 유레카 설정 구분
- 2. 자기 보호 모드
- 3. 레지스트리 등록 여부/캐싱 여부
- 4. 레지스트리 갱신 - 서비스 등록 관련
- 5. 레지스트리 갱신 - 서비스 해제 관련
- 6. IP 주소 우선하기
- 7. 유레카 피어링 설정
- 참고 사이트 & 함께 보면 좋은 사이트
1. 유레카 설정 구분
유레카 설정 구분
eureka.server. : Eureka Server 관련 설정
eureka.client. : 클라이언트가 레지스트리에서 다른 서비스의 정보를 얻을 수 있는 설정
eureka.instance. : 포트나 이름 등 현재 Eureka Client 의 행동을 재정의하는 설정
2. 자기 보호 모드
2.1. 서버 측 설정
eureka.server.enable-self-preservation
- 일시적인 네트워크 장애로 인한 서비스 해제 막기 위한 자기 보호 모드 (디폴트 true, 운영에선 반드시 true 로 설정 필요)
- 원래는 해당 시간안에 하트비트가 일정 횟수 이상 들어오지 않아야 서비스 해제하는데 false 설정 시 하트비트가 들어오지 않으면 바로 서비스 제거
eureka:
server:
enable-self-preservation: false
3. 레지스트리 등록 여부/캐싱 여부
3.1. 서버/클라이언트 측 모두 설정
eureka.client.register-with-eureka
- 레지스트리에 자신을 등록할지에 대한 여부 (디폴트 true)
- 클러스터링 모드의 Eureka Server구성은 서로 peering 구성이 가능. (Eureka Server 설정에 정의된 peering 노드를 찾아서 레지스트리 정보의 sync 를 맞춤)
- 독립 실행형 모드(standalone)에서는 peering 실패가 발생하므로 Eureka Client측 동작을 끔
eureka.client.fetch-registry
- 레지스트리에 있는 정보를 가져올지에 대한 여부 (디폴트 true)
- true 로 설정 시 검색할 때마다 Eureka Server 를 호출하는 대신 레지스트리가 로컬로 캐싱됨
- 30초마다 Eureka Client 가 유레카 레지스트리 변경 사항 여부 재확인함
eureka:
client:
register-with-eureka: true
fetch-registry: true
3.2. 설정 확인
Eureka Server/Client 모두 eureka.client.register-with-eureka
와 eureka.client.fetch-registry
를 false 로 설정 후 http://peer1:8762/eureka/apps 호출 시 아무런 클라이언트도 등록되지 않은 것을 확인할 수 있다.
이제 Eureka Client측의 eureka.client.register-with-eureka
와 eureka.client.fetch-registry
를 true 로 설정 후 http://peer1:8762/eureka/apps 호출 시 해당 클라이언트가 등록된 것을 확인할 수 있다.
Eureka Server 로그
c.n.e.registry.AbstractInstanceRegistry : Fetching applications registry with remote regions: false, Regions argument []
c.n.e.registry.AbstractInstanceRegistry : Processing override status using rule: [com.netflix.eureka.registry.rule.DownOrStartingRule, com.netflix.eureka.registry.rule.OverrideExistsRule, com.netflix.eureka.registry.rule.LeaseExistsRule, com.netflix.eureka.registry.rule.AlwaysMatchInstanceStatusRule]
c.n.e.registry.rule.LeaseExistsRule : There is already an existing lease with status UP for instance xx.xx.xx.xx.:zuulserver:5555
c.n.eureka.resources.InstanceResource : Found (Renew): ZUULSERVER - xx.xx.xx.xx.:zuulserver:5555; reply status=200
c.n.d.shared.MonitoredConnectionManager : Get connection: {}->http://peer1:8762, timeout = 200
c.n.d.shared.NamedConnectionPool : [{}->http://peer1:8762] total kept alive: 1, total issued: 0, total allocated: 1 out of 1000
c.n.d.shared.NamedConnectionPool : Getting free connection [{}->http://peer1:8762][null]
c.n.d.util.DeserializerStringCache : clearing global-level cache with size 0
c.n.d.util.DeserializerStringCache : clearing app-level serialization cache with size 0
c.n.e.registry.AbstractInstanceRegistry : Fetching applications registry with remote regions: false, Regions argument []
c.n.e.registry.AbstractInstanceRegistry : Processing override status using rule: [com.netflix.eureka.registry.rule.DownOrStartingRule, com.netflix.eureka.registry.rule.OverrideExistsRule, com.netflix.eureka.registry.rule.LeaseExistsRule, com.netflix.eureka.registry.rule.AlwaysMatchInstanceStatusRule]
c.n.e.r.r.AlwaysMatchInstanceStatusRule : Returning the default instance status UP for instance xx.xx.xx.xx.:zuulserver:5555
c.n.eureka.resources.InstanceResource : Found (Renew): ZUULSERVER - xx.xx.xx.xx.:zuulserver:5555; reply status=200
c.n.d.shared.MonitoredConnectionManager : Released connection is reusable.
c.n.d.shared.NamedConnectionPool : Releasing connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Pooling connection [{}->http://peer1:8762][null]; keep alive for 60000 MILLISECONDS
c.n.d.shared.NamedConnectionPool : Notifying no-one, there are no waiting threads
c.n.d.util.DeserializerStringCache : clearing global-level cache with size 0
c.n.d.util.DeserializerStringCache : clearing app-level serialization cache with size 0
c.n.eureka.registry.ResponseCacheImpl : Updating the client cache from response cache
c.n.eureka.registry.ResponseCacheImpl : Updating the client cache from response cache for key : Application ALL_APPS V2 JSON
Eureka Client 로그
c.n.d.shared.MonitoredConnectionManager : Closing connections idle longer than 30 SECONDS
c.n.d.shared.NamedConnectionPool : Closing connections idle longer than 30 SECONDS
com.netflix.discovery.DiscoveryClient : Disable delta property : false
com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
com.netflix.discovery.DiscoveryClient : Application is null : false
com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true
com.netflix.discovery.DiscoveryClient : Application version is -1: false
com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
c.n.d.shared.MonitoredConnectionManager : Get connection: {}->http://peer1:8762, timeout = 5000
c.n.d.shared.MonitoredConnectionManager : Get connection: {}->http://peer1:8762, timeout = 5000
c.n.d.shared.NamedConnectionPool : [{}->http://peer1:8762] total kept alive: 1, total issued: 0, total allocated: 1 out of 200
c.n.d.shared.NamedConnectionPool : Getting free connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : [{}->http://peer1:8762] total kept alive: 0, total issued: 1, total allocated: 1 out of 200
c.n.d.shared.NamedConnectionPool : No free connections [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Available capacity: 49 out of 50 [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Creating new connection [{}->http://peer1:8762]
c.n.d.shared.MonitoredConnectionManager : Released connection is reusable.
c.n.d.shared.NamedConnectionPool : Releasing connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Pooling connection [{}->http://peer1:8762][null]; keep alive for 60000 MILLISECONDS
c.n.d.shared.NamedConnectionPool : Notifying no-one, there are no waiting threads
n.d.s.t.j.AbstractJerseyEurekaHttpClient : Jersey HTTP PUT http://peer1:8762/eureka//apps/ZUULSERVER/xx.xx.xx.xx.:zuulserver:5555; statusCode=200
com.netflix.discovery.DiscoveryClient : DiscoveryClient_ZUULSERVER/xx.xx.xx.xx.:zuulserver:5555 - Heartbeat status: 200
c.n.d.shared.MonitoredConnectionManager : Released connection is reusable.
c.n.d.shared.NamedConnectionPool : Releasing connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Pooling connection [{}->http://peer1:8762][null]; keep alive for 60000 MILLISECONDS
c.n.d.shared.NamedConnectionPool : Notifying no-one, there are no waiting threads
c.n.d.util.DeserializerStringCache : clearing global-level cache with size 1
c.n.d.util.DeserializerStringCache : clearing app-level serialization cache with size 8
n.d.s.t.j.AbstractJerseyEurekaHttpClient : Jersey HTTP GET http://peer1:8762/eureka//apps/?; statusCode=200
com.netflix.discovery.DiscoveryClient : The response status is 200
com.netflix.discovery.DiscoveryClient : Got full registry with apps hashcode UP_1_
com.netflix.discovery.DiscoveryClient : The total number of all instances in the client now is 1
com.netflix.discovery.DiscoveryClient : Completed cache refresh task for discovery. All Apps hash code is Local region apps hashcode: UP_1_, is fetching remote regions? false
4. 레지스트리 갱신 - 서비스 등록 관련
Eureka Client 등록 시 최장 딜레이 시간
eureka.server.response-cache-update-interval-ms (Eureka Server 의 캐싱 업데이트 주기, 30초)
+ eureka.client.registry-fetch-interval-seconds (서비스 목록을 캐싱할 주기, 30초)
= 60초
4.1. 클라이언트 측 설정
eureka.client.registry-fetch-interval-seconds
- 서비스 목록을 설정한 시간마다 캐싱 (디폴트 30초)
eureka.client.disable-delta
- 캐싱 시 변경된 부분만 업데이트할 지 여부 (디폴트 false)
- false 로 설정 서 대역폭 낭비이므로 true 로 설정할 것
eureka:
client:
registry-fetch-interval-seconds: 10
disable-delta: true
클라이언트 측 로그 (10초마다 로그 업데이트)
com.netflix.discovery.DiscoveryClient : Disable delta property : true
com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
com.netflix.discovery.DiscoveryClient : Application is null : false
com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : false
com.netflix.discovery.DiscoveryClient : Application version is -1: false
com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
c.n.d.shared.MonitoredConnectionManager : Get connection: {}->http://peer1:8762, timeout = 5000
c.n.d.shared.NamedConnectionPool : [{}->http://peer1:8762] total kept alive: 1, total issued: 0, total allocated: 1 out of 200
c.n.d.shared.NamedConnectionPool : Getting free connection [{}->http://peer1:8762][null]
c.n.d.shared.MonitoredConnectionManager : Released connection is reusable.
c.n.d.shared.NamedConnectionPool : Releasing connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Pooling connection [{}->http://peer1:8762][null]; keep alive for 60000 MILLISECONDS
c.n.d.shared.NamedConnectionPool : Notifying no-one, there are no waiting threads
c.n.d.util.DeserializerStringCache : clearing global-level cache with size 1
c.n.d.util.DeserializerStringCache : clearing app-level serialization cache with size 8
n.d.s.t.j.AbstractJerseyEurekaHttpClient : Jersey HTTP GET http://peer1:8762/eureka//apps/?; statusCode=200
com.netflix.discovery.DiscoveryClient : The response status is 200
com.netflix.discovery.DiscoveryClient : Got full registry with apps hashcode UP_1_
com.netflix.discovery.DiscoveryClient : The total number of all instances in the client now is 1
com.netflix.discovery.DiscoveryClient : Completed cache refresh task for discovery. All Apps hash code is Local region apps hashcode: UP_1_, is fetching remote regions? false
4.2. 서버 측 설정
eureka.server.response-cache-update-interval-ms
- Eureka Server 의 캐싱 업데이트 주기 (디폴트 30,000ms)
- Eureka Server 실행 후 /eureka/apps API 실행 시 아무것도 나오지 않음 클라이언트 인스턴스 실행 수 /eureka/apps 실행 시 여전히 아무것도 나오지 않음 30초가 지나고 /eureka/apps 실행 시 클라이언트 인스턴스 조회됨.
- Eureka Server 의 대시보드(유레카서버:8761/) 에 등록된 인스턴스가 표시될때에는 캐시 사용하지 않음
eureka.client.registry-fetch-interval-seconds
와 비교하여 볼 것
eureka:
server:
response-cache-update-interval-ms: 5000
Eureka Server 로그 (5초마다 로그 업데이트)
c.n.eureka.registry.ResponseCacheImpl : Updating the client cache from response cache
5. 레지스트리 갱신 - 서비스 해제 관련
위의 자기 보호 모드(eureka.server.enable-self-preservation
)를 false 로 설정하여도 레지스트리에서 서버가 등록 해지되는 시간은 오래 걸린다.
그 이유는 아래와 같다.
lease-renewal-interval-in-seconds
에 의해 클라이언트는 서버로 30초 (디폴트 값) 마다 하트비트 전송하고,
lease-expiration-duration-in-seconds
에 의해 서버는 하트비트를 받지 못하면 90초 (디폴트 값) 동안 하트비트가 수신되지 않으면 서비스 등록을 해지하기 때문이다.
실제로 자기 보호 모드 false 인 상태에서 클라이언트 종료 시 109 초 이후에 서비스 등록 해지가 되는 부분을 확인했다.
이 두 값은 서버 내부적으로 클라이언트를 관리하는 로직에 영향을 미칠 수 있으므로 설정을 변경하지 않는 것을 권장한다.
Eureka Client 등록 해제 시 최장 딜레이 시간
eureka.server.response-cache-update-interval-ms (Eureka Server 의 캐싱 업데이트 주기, 30초)
+ eureka.instance.lease-expiration-duration-in-seconds (Eureka Server 가 마지막 하트비트로부터 서비스 등록 해제 전 대기 시간, 90초)
= 120초
5.1. 클라이언트 측 설정
eureka.instance.lease-renewal-interval-in-seconds
- Eureka Server 로 설정된 시간(second)마다 하트비트 전송 (디폴트 30초)
eureka.instance.lease-expiration-duration-in-seconds
- 디스커버리는 서비스 등록 해제 하기 전에 마지막 하트비트에서부터 설정된 시간(second) 동안 하트비트가 수신되지 않으면 서비스 등록 해제 (디폴트 90초)
- 단, 유레카 인스턴스가 정상적으로 종료된 경우는 레지스트리에서 바로 제거
- 이 값은
lease-renewal-interval-in-seconds
보다 커야 함
eureka:
instance:
lease-renewal-interval-in-seconds: 3
lease-expiration-duration-in-seconds: 10
서버 측 로그 (3초마다 로그 업데이트)
c.n.d.shared.MonitoredConnectionManager : Closing connections idle longer than 30 SECONDS
c.n.d.shared.NamedConnectionPool : Closing connections idle longer than 30 SECONDS
c.n.e.registry.AbstractInstanceRegistry : Fetching applications registry with remote regions: false, Regions argument []
c.n.e.registry.AbstractInstanceRegistry : Processing override status using rule: [com.netflix.eureka.registry.rule.DownOrStartingRule, com.netflix.eureka.registry.rule.OverrideExistsRule, com.netflix.eureka.registry.rule.LeaseExistsRule, com.netflix.eureka.registry.rule.AlwaysMatchInstanceStatusRule]
c.n.e.registry.rule.LeaseExistsRule : There is already an existing lease with status UP for instance xx.xx.xx.xx:zuulserver:5555
c.n.eureka.resources.InstanceResource : Found (Renew): ZUULSERVER - xx.xx.xx.xx:zuulserver:5555; reply status=200
c.n.d.shared.MonitoredConnectionManager : Get connection: {}->http://peer1:8762, timeout = 200
c.n.d.shared.NamedConnectionPool : [{}->http://peer1:8762] total kept alive: 1, total issued: 0, total allocated: 1 out of 1000
c.n.d.shared.NamedConnectionPool : Getting free connection [{}->http://peer1:8762][null]
c.n.d.util.DeserializerStringCache : clearing global-level cache with size 0
c.n.d.util.DeserializerStringCache : clearing app-level serialization cache with size 0
c.n.e.registry.AbstractInstanceRegistry : Fetching applications registry with remote regions: false, Regions argument []
c.n.e.registry.AbstractInstanceRegistry : Processing override status using rule: [com.netflix.eureka.registry.rule.DownOrStartingRule, com.netflix.eureka.registry.rule.OverrideExistsRule, com.netflix.eureka.registry.rule.LeaseExistsRule, com.netflix.eureka.registry.rule.AlwaysMatchInstanceStatusRule]
c.n.e.r.r.AlwaysMatchInstanceStatusRule : Returning the default instance status UP for instance xx.xx.xx.xx:zuulserver:5555
c.n.eureka.resources.InstanceResource : Found (Renew): ZUULSERVER - xx.xx.xx.xx:zuulserver:5555; reply status=200
c.n.d.shared.MonitoredConnectionManager : Released connection is reusable.
c.n.d.shared.NamedConnectionPool : Releasing connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Pooling connection [{}->http://peer1:8762][null]; keep alive for 60000 MILLISECONDS
c.n.d.shared.NamedConnectionPool : Notifying no-one, there are no waiting threads
c.n.d.util.DeserializerStringCache : clearing global-level cache with size 0
c.n.d.util.DeserializerStringCache : clearing app-level serialization cache with size 0
클라이언트 측 로그 (3초마다 로그 업데이트)
c.n.d.shared.MonitoredConnectionManager : Get connection: {}->http://peer1:8762, timeout = 5000
c.n.d.shared.NamedConnectionPool : [{}->http://peer1:8762] total kept alive: 1, total issued: 0, total allocated: 1 out of 200
c.n.d.shared.NamedConnectionPool : Getting free connection [{}->http://peer1:8762][null]
c.n.d.shared.MonitoredConnectionManager : Released connection is reusable.
c.n.d.shared.NamedConnectionPool : Releasing connection [{}->http://peer1:8762][null]
c.n.d.shared.NamedConnectionPool : Pooling connection [{}->http://peer1:8762][null]; keep alive for 60000 MILLISECONDS
c.n.d.shared.NamedConnectionPool : Notifying no-one, there are no waiting threads
n.d.s.t.j.AbstractJerseyEurekaHttpClient : Jersey HTTP PUT http://peer1:8762/eureka//apps/ZUULSERVER/xx.xx.xx.xx:zuulserver:5555; statusCode=200
com.netflix.discovery.DiscoveryClient : DiscoveryClient_ZUULSERVER/xx.xx.xx.xx:zuulserver:5555 - Heartbeat status: 200
하지만 자기 보호 모드(eureka.server.enable-self-preservation
) 와 위 2개 설정을 한다 해도 서비스 등록 해지가 바로 되는 것은 아닌데, 그 이유는 아래 서버 측 설정을 보면 알 수 있다.
5.2. 서버 측 설정
서버 측에서도 변경을 해주어야 하는데 Evict 백그라운드 태스크 때문이다.
클라이언트로부터 하트비트가 계속 수신되는지 점검을 하는 태스크인데 기본값인 60초 마다 실행되기 때문에 클라이언트 측 위의 두 값을 작은 값으로 설정해도 서비스 인스턴스를 제거하는데 최대 60초가 소요된다.
eureka.server.eviction-interval-timer-in-ms
- 클라이언트로부터 하트비트가 계속 수신 되는지 점검 (디폴트 60초)
eureka:
server:
eviction-interval-timer-in-ms: 10000
lease-expiration-duration-in-seconds
(디스커버리는 서비스 등록 해제 하기 전에 마지막 하트비트에서부터 설정된 시간(second) 동안 하트비트가 수신되지 않으면 서비스 등록 해제 (디폴트 90초)) 를 10초로 설정,
eureka.instance.eviction-interval-timer-in-ms
(클라이언트로부터 하트비트가 계속 수신 되는지 점검 (디폴트 60초)) 를 10초로 설정 후 클라이언트 종료 시 약 20초 후에 서비스 등록 해제가 되는 부분을 확인함
6. IP 주소 우선하기
인스턴스는 기본적으로 호스트명으로 등록되는데 DNS 가 없는 경우 hosts 파일에 IP를 등록하지 않으면 인스턴스를 찾지 못하게 된다.
eureka.instance.prefer-ip-address
속성을 통해 서비스의 IP 주소를 사용할 수 있지만 만일 장비에서 하나 이상의 네트워크 인터페이스가 있는 경우 문제가 발생할 수 있으므로 아래와 같이 무시할 패턴 또는 선호하는 네트워크 주소를 설정하여 해결할 수 있다.
6.1. 클라이언트 측 설정
eureka.instance.prefer-ip-address
- 서비스의 호스트 이름이 아닌 IP 주소를 Eureka Server 에 등록하도록 지정 (디폴트 false)
- 기본적으로 유레카는 호스트 이름으로 접속하는 서비스를 등록하는데 DNS 가 지원된 호스트 이름을 할당하는 서버 기반 환경에서는 잘 동작하지만, 컨테이너 기반의 배포에서 컨테이너는 DNS 엔트리가 없는 임의의 생성된 호스트 이름을 부여받아 시작하므로 컨테이너 기반 배포에서는 해당 설정값을 false 로 하는 경우 호스트 이름 위치를 정상적으로 얻지 못함
spring.cloud.inetutils.ignored-interfaces
- 해당 인터페이스 무시
spring.cloud.inetutils.preferred-networks
- 선호하는 IP 주소 설정
spring:
cloud:
inetutils:
ignored-interfaces: eth1*
preferred-networks: 192.168
eureka:
instance:
prefer-ip-address: true
7. 유레카 피어링 설정
해당 설정은 Eureka Server 를 피어링하여 사용하는 경우에만 설정한다.
7.1. 서버 측 설정
eureka.server.wait-time-in-ms-when-sync-empty
- Eureka Server 가 시작되고 유레카 피어링 노드로부터 Instance 들을 가져올 수 없을 때 기다릴 시간 (디폴트 3000ms)
- registry 를 갱신할 수 없을 때 재시도를 기다리는 시간
- 테스트 시 짧은 시간으로 등록해놓으면 유레카 서비스의 시작 시간과 등록된 서비스를 보여주는 시간 단축 가능
- 유레카는 등록된 서비스에서 10초 간격으로 연속 3회의 상태 정보(heartbeat)를 받아야 하므로 등록된 개별 서비스를 보여주는데 30초 소요
eureka.server.registry-sync-retries
- 유레카 피어 노드로부터 registry 를 갱신할 수 없을 때 재시도 횟수 (디폴트 5)
eureka:
server:
wait-time-in-ms-when-sync-empty: 3000
registry-sync-retries: 5