23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
클라이언트 사이드 로드 밸런서에 대해서는 이전에 잠시 이야기 했었습니다.
로드 밸런서는 들어오는 요청을 특정 라우팅 정책에 따라 대상 서버로 분배 해 주는 역할을 합니다.
이번 과정에서 우리는 Ribbon 을 이용할 것입니다. 참고로 Ribbon 은 로드밸런서 정책을 RoundRobin 방색으로 순처작으로 라우팅 됩니다.
우리가 사용할 클라이언트 사이드 로드밸런서는 Education Service 에 등록하여 사용합니다.

위 그림으로 보면 eudcation service 에서 유레카에 서비스 정보들을 획득하고, 요청이 들어오면 Student service 로 갈지 professor service 로 갈지 결정하여 라우팅 합니다.
package com.eunkong.eschool.educationservice.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApiConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
}
Ribbon 설정은 RestTemplate 에 @LoadBalanced 를 설정해주면 Client Side Load Balancer 로 동작하게 됩니다.
참고) 위에서 등록한 RestTemplate 은 Ribbon 용으로 사용하는 것입니다. 우리 서비스 이외에 외부 서비스를 호출한다면 RestTemplate 를 추가적으로 빈을 생성하여 등록해서 사용해야합니다.
설정이 완료 되었으면 실제 사용은 다음과 같이 수행 합니다.
...
private List findProfessorsBySubjectName(String subjectName) {
UriComponents uri = UriComponentsBuilder.newInstance()
.scheme("http")
// .host(professorHost)
// .port(professorPort)
.host("professor-service")
.path("/professors/subjects/{subjectName}")
.build()
.expand(subjectName)
.encode();
ResponseEntity> exchange = restTemplate.exchange(uri.toUriString(), HttpMethod.GET, null, new ParameterizedTypeReference>() {
});
List body = exchange.getBody();
return body;
}
...
보시는 바와 같이 이제 properties 를 통해서 host와 port 를 로드하는 방식은 필요 없게 되었습니다.
host("professor-serivce") 와 같이 작업을 하면 Ribbon 이 서비스로 라우팅을 진행해 주게 됩니다.
이제 education-service 를 실행하고, 테스트를 한번 해 보겠습니다.
###
GET http://localhost:8281/educations/subjects/Math
결과를 보면 잘 나오네요.
GET http://localhost:8281/educations/subjects/Math
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 13 May 2020 06:37:00 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"subjectName": "Math",
"professors": [
{
"id": 3,
"name": "Alibaba",
"major": "Math",
"joinedAt": "2020-05-13T15:10:53.380035"
}
],
"students": [
{
"id": 2,
"name": "ManDo",
"major": "Math",
"enteranceAt": "2020-05-13T14:46:14.695366"
}
]
}
Response code: 200; Time: 1921ms; Content length: 213 bytes
지금까지 리본을 통해서 작업을 해 보았습니다.
현재 작업 과정만으로 student-service 3개 서비스중 2개를 갑자기 중지하면 어떤일이 벌어질까요?
이런 일은 일반적으로 서비스 배포 때에도 많이 발생합니다.
GET http://localhost:8281/educations/subjects/Math
HTTP/1.1 500
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 13 May 2020 06:38:45 GMT
Connection: close
{
"timestamp": "2020-05-13T06:38:45.675+0000",
"status": 500,
"error": "Internal Server Error",
"message": "I/O error on GET request for \"http://student-service/students/subjects/Math\": Connection refused; nested exception is java.net.ConnectException: Connection refused",
"path": "/educations/subjects/Math"
}
Response code: 500; Time: 313ms; Content length: 302 bytes
위와 같은 결과가 나타납니다.
이런경우 education-service 가 eureka 로 부터 새로 제거된 student-service 목록을 받아오지 못한다면 계속해서 발생됩니다.
client side loadbalancer 가 eureka 에 접속해서 새로운 요청 정보를 가져가면 그때 다음과 같이 정상 서비스가 가능하게 됩니다.
일정 시간이후로 정상 기동 확인
GET http://localhost:8281/educations/subjects/Math
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 13 May 2020 06:38:56 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"subjectName": "Math",
"professors": [
{
"id": 3,
"name": "Alibaba",
"major": "Math",
"joinedAt": "2020-05-13T15:10:58.622349"
}
],
"students": [
{
"id": 2,
"name": "ManDo",
"major": "Math",
"enteranceAt": "2020-05-13T14:36:21.705983"
}
]
}
Response code: 200; Time: 1165ms; Content length: 213 bytes
ribbon 은 이러한 이슈를 해결하기 위해서 retry 정책을 가지고 있고, 요청이 실패하면 다른 서버로 다시 수 회 재시도를 할 수 있습니다.
retry 를 수행하기 위해서는 재시도를 위한 의존성을 아래와 같이 추가해 줍니다.
org.springframework.retry spring-retry 1.2.5.RELEASE
education-service 에서 application.properties 에 아래와 같이 추가해 줍니다.
# Ribbon Config
# Eureka 사용여부
ribbon.eureka.enabled=true
# Max number of retries on the same server (excluding the first try)
# 동일한 서버로 리트라이를 수행할 최대 횟수 (첫번째 시도는 제외)
ribbon.MaxAutoRetries=2
# Max number of next servers to retry (excluding the first server)
# 다음 서버들로 리트라이를 수행할 최대 횟수 (첫번째 서버는 제외)
ribbon.MaxAutoRetriesNextServer=2
# Whether all operations can be retried for this client
# 현재 클라이런트에서 모든 오퍼레이션에 리트라이 되도록 적용할지 여부, true이면 동작하며, 이때에는 POST 요청처럼 멱등성이 있는 케이스는 서버에 이미 요청이 들어가 있으면 오동작 하게 된다.
ribbon.OkToRetryOnAllOperations=true
# Interval to refresh the server list from the source
# 소스(유레카)로 부터 서버 리스트를 갱신하는 주기
ribbon.ServerListRefreshInterval=2000
# Connect timeout used by Apache HttpClient
# 커넥션 타임아웃
ribbon.ConnectTimeout=3000
# Read timeout used by Apache HttpClient
# 리드 타임아웃
ribbon.ReadTimeout=3000
# Initial list of servers, can be changed via Archaius dynamic property at runtime
# Eureka 를 사용하지 않을때 정적으로 서버 목록을 등록할 수 있다.
#ribbon.listOfServers=www.microsoft.com:80,www.yahoo.com:80,www.google.com:80
위와 같이 수행하고 다시 테스트를 수행합니다.
지금까지 Ribbon 을 이용하여 Client Side LoadBalance 를 구현해 보았습니다.
이제는 서버가 수평으로 확장되어도, 배포를 해도 이슈 없이 동작하는 것을 알 수 있습니다.
점점더 MSA 에 다가가는 것을 확인할 수 있네요.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.