안녕하세요. 오늘은 Spring Cloud의 구성요소 중 Eureka에 대해서 알아보도록 하겠습니다.
Eureka 란
개요
Eureka는 AWS와 같은 Cloud 시스템에서 서비스의 로드 밸런싱과 실패처리 등을 유연하게 가져가 위해 각 서비스들의 IP / Port / InstanceId를 가지고 있는 REST 기반의 미들웨어 서버입니다.
Eureka는 마이크로 서비스 기반의 아키텍처의 핵심 원칙 중 하나인 Service Discovery의 역할을 수행합니다. MSA에서는 Service의 IP와 Port가 일정하지 않고 지속적을 변화합니다. 그렇기 때문에 Client에 Service의 정보를 수동으로 입력하는 것은 한계가 분명합니다. Service Discovery란 이런 MSA의 상황에 적합합니다.
아키텍처 및 플로우
위의 이미지는 Eureka가 MSA에서 사용되는 방법을 나타낸 것입니다.
Eureka는 Client-Server의 방식으로 Eureka Server는 모든 Client 서버들이 본인의 IP와 Port, InstanceId를 Eureka-Server로 전달합니다. 그리고 Eureka에 있는 정보를 Fetch하여 Eureka-Client간 통신에 사용합니다.
그렇다면 Eureka Server와 Client의 상호작용하는 interface에 대해서 알아보도록 하겠습니다.
Eureka Server와 Client의 상호작용
Eureka-Server와 Eureka-Client는 REST 통신하여 상호작용을 합니다. 그렇기 때문에 java application이 아니더라도 통신할 수 있습니다. 지금부터 그 상호작용에 대해서 알아보도록 하겠습니다.
- HTTP Operation 테이블에서
appID
는 서비스의 이름입니다.instanceID
는 서비스 중에서 특정 서버의 id입니다. Content-Type으로 application/xml 또는 application/json을 지원합니다.
ereka github에서 지원하는 docs와 실제로 eureka-server와 eureka-client가 통신하는것을 wireshark로 찍어보았습니다.
Register(등록)
Eureka Client는 실행중인 instance의 정보(IP, Port 등)를 Eureka Server로 새로 등록합니다. 1번째 heartbeat에 등록됩니다.
Operation | HTTP action | Description |
Register | POST /eureka/apps/{appID} HTTP/1.1 | Input: JSON/XML payload, 아래 참조 HTTP Code: 204 on success |
class를 참조하면 instance Register class는 아래와 같은 형상입니다. 그리고 등록에 대해서 wireshark로 찍어보았습니다.
eureka-client -> eureka-servercom.netflix.appinfo.InstanceInfo
http://localhost:8761/eureka/apps/sabarada-service
{
"instance": {
"instanceId": "392d9569-3a3a-4da0-9447-bfdcc14d8b30",
"hostName": "x.x.x.x",
"app": "sabarada-service",
"ipAddr": "x.x.x.x",
"status": "UP",
"overriddenStatus": "UNKNOWN",
"port": {
"$": 8081,
"@enabled": "true"
},
"securePort": {
"$": 443,
"@enabled": "false"
},
"countryId": 1,
"dataCenterInfo": {
"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
"name": "MyOwn"
},
"leaseInfo": {
"renewalIntervalInSecs": 30,
"durationInSecs": 90,
"registrationTimestamp": 0,
"lastRenewalTimestamp": 0,
"evictionTimestamp": 0,
"serviceUpTimestamp": 0
},
"metadata": {
"@class": "java.util.Collections$EmptyMap"
},
"homePageUrl": "http://192.168.4.91:8081/",
"statusPageUrl": "http://192.168.4.91:8081/actuator/info",
"healthCheckUrl": "http://192.168.4.91:8081/actuator/health",
"vipAddress": "sabarada-service",
"secureVipAddress": "sabarada-service",
"isCoordinatingDiscoveryServer": "false",
"lastUpdatedTimestamp": "1580878819825",
"lastDirtyTimestamp": "1580878820311"
}
}
Eureka-Client에서 Eureka-Server로 위와 같은 REST 통신을 통해 등록할 수 있습니다. 등록하게 되면 Eureka-Server에서는 Registered instance sabarada-service/392d9569-3a3a-4da0-9447-bfdcc14d8b30 with status UP (replication=false)
로그와 함께 등록되게 됩니다.
Renew(갱신)
Eureka Client는 30초를 주기로 Eureka Server에 heartbeats를 보냅니다. 만약 Server가 90초 동안 heartheats를 받지 못하면 Server의 정보 저장소에서 제거됩니다(register시 leaseInfo
해당부분을 참조).
Operation | HTTP action | Description |
heartbeat | PUT /eureka/apps/appID/instanceID | HTTP Code: * 200 on success * 404 if instanceID doesn’t exist |
wireshark로 찍어본 명령어는 아래와 같습니다.
PUT /eureka/apps/sabarada-service/392d9569-3a3a-4da0-9447-bfdcc14d8b30?status=UP&lastDirtyTimestamp=1580878820311 HTTP/1.1
Fetch Registry(등록 정보 획득)
Eureka Client는 서버가 올라올 때 eureka Server에 있는 모든 정보를 가져와 local Cache에 저장합니다. 그 후 이 정보를 http 통신에 이용합니다. 이 정보는 매 주기 30초마다 변경점에 대해서 부분업데이트(delta)를 진행합니다.
처음 모든 정보 가져오기 요청
Operation | HTTP action | Description |
전체 업데이트 | GET /eureka/apps | HTTP Code: 200 on success Output: JSON/XML |
GET /eureka/apps HTTP/1.1
30초에 한번씩 변경된 정보 가져오기 요청
Operation | HTTP action | Description |
부분 업데이트 | GET /eureka/apps/delta | HTTP Code: 200 on success Output: JSON/XML |
GET /eureka/apps/delta HTTP/1.1
응답
{
"applications": {
"versions__delta": "21",
"apps__hashcode": "UP_2_",
"application": [
{
"name": "sabarada-service",
"instance": [
{
...[중략]
"status": "UP",
...[중략]
},
{
...[중략]
"status": "DOWN",
...[중략]
}
]
}
]
}
}
위의 예제 응답은 2개의 서버 UP 상태에서 1개의 서버를 Down한 후 살아있는 서버에서 요청한 갱신사항 요청에 대한 응답입니다. 1개의 서버는 UP(본인), 죽은 서버는 DOWN으로 해서 응답이 돌아오는 것을 알 수 있었습니다.
위의 명령어를 통해 처음에는 모든 정보를 가져오고, 30초에 한번씩은 변경된 정보를 가져오기위한 요청을 별도로 진행합니다. 만약 delta를 했을 시 service의 상태가 DOWN이라면 Client에서는 해당 Service를 local cache에서 삭제합니다.
Cancel(취소)
Cancle의 경우 Eureka에 있는 본인의 instance를 삭제합니다. 서비스가 종료될 때 Eureka-Client에서 Eureka-Server로 전송합니다. 그리고 evictionDurationInSecs
를 설정해서 eureka-server에 등록한다면 해당 시간동안 renew가 없다면 자동적으로 삭제됩니다.
Operation | HTTP action | Description |
De-register | DELETE /eureka/apps/appID/instanceID | HTTP Code: 200 on success |
요청
DELETE /eureka/apps/sabarada-service/5a7af17d-8800-4408-9855-ac55246d070d HTTP/1.1
Time Lag(지연)
새로운 서버의 등록 및 기존 서버의 삭제에 대해서 모든 Client가 알기 까지는 시간적인 지연이 발생합니다. eureka server가 정보 변경에 대해서 push하는 것이 아닌 각 client가 주기적으로 polling하기 때문입니다. Eureka 문서에서는 모든 서버에 전송되기 까지는 최대 2분정도 걸릴 수 있다고 말합니다.
마무리
오늘은 이렇게 Spring Cloud Eureka의 이론과 wireshark를 통해 실제 Eureka-Client와 Eureka-Server가 주고받는 request와 response에 대해서 알아보았습니다.
다른 Spring Cloud 기술들과는 다르게 Eureka는 큰 버전 갱신은 앞으로 없을거라고 12월 Pivotal MeetUp에서 들었습니다. 이유는 서버를 등록하고 그 서버를 반환하는 간단한 역할만 하기 때문이라고 하는데 지켜봐야 할 것 같습니다.
다음 시간에는 eureka-client와 eureka-server를 실제로 등록하는 방법을 알아보도록 하겠습니다.
감사합니다.
참조
https://cloud.spring.io/spring-cloud-netflix/reference/html/#service-discovery-eureka-clients
'language, framework, library > Spring Cloud' 카테고리의 다른 글
[MSA] Spring Cloud Feign - 기본 사용 및 기본 설정편 (0) | 2020.09.27 |
---|---|
[MSA] Spring Cloud Eureka - 실습편 (0) | 2020.02.10 |
[MSA] Spring Cloud Zuul 1.x - 실습편 (0) | 2020.01.22 |
[MSA] Spring Cloud Zuul 1.x - 개념편 (0) | 2020.01.20 |
[MSA] Spring Cloud Ribbon - 개념과 실습편 (0) | 2020.01.12 |
댓글