데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Spring Cloud Ribbon Cloud and Retry Policy

      KIDO 20.09.09
      1,094 3 0

      Client Side Load Balancer

      클라이언트 사이드 로드 밸런서에 대해서는 이전에 잠시 이야기 했었습니다.

      로드 밸런서는 들어오는 요청을 특정 라우팅 정책에 따라 대상 서버로 분배 해 주는 역할을 합니다.

      이번 과정에서 우리는 Ribbon 을 이용할 것입니다. 참고로 Ribbon 은 로드밸런서 정책을 RoundRobin 방색으로 순처작으로 라우팅 됩니다.

      클라이언트 사이드 로드밸런서 사용하기.

      우리가 사용할 클라이언트 사이드 로드밸런서는 Education Service 에 등록하여 사용합니다.

      위 그림으로 보면 eudcation service 에서 유레카에 서비스 정보들을 획득하고, 요청이 들어오면 Student service 로 갈지 professor service 로 갈지 결정하여 라우팅 합니다.

      Ribbon 설정하기.

      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
      

      지금까지 리본을 통해서 작업을 해 보았습니다.

      Ribbon 서비스 안정화 시키기

      현재 작업 과정만으로 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 설정하기.

      ribbon 은 이러한 이슈를 해결하기 위해서 retry 정책을 가지고 있고, 요청이 실패하면 다른 서버로 다시 수 회 재시도를 할 수 있습니다.

      retryable 의존성 추가하기.

      retry 를 수행하기 위해서는 재시도를 위한 의존성을 아래와 같이 추가해 줍니다.

      		
      			org.springframework.retry
      			spring-retry
      			1.2.5.RELEASE
      		

      ribbon retry policy 적용하기.

      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
      

      위와 같이 수행하고 다시 테스트를 수행합니다.

      • student-service 를 모두 기동합니다.
      • education-service 를 기동하고, 과목 이름으로 교수, 학생 정보를 가져오는 쿼리를 보내 봅니다.
      • 이후 student-service 를 동시에 2대 내리고, 다시 쿼리를 보내보면, 정상으로 응답이 오는 것을 확인할 수 있습니다.

      지금까지 Ribbon 을 이용하여 Client Side LoadBalance 를 구현해 보았습니다.

      이제는 서버가 수평으로 확장되어도, 배포를 해도 이슈 없이 동작하는 것을 알 수 있습니다.

      점점더 MSA 에 다가가는 것을 확인할 수 있네요.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      KIDO 님의 최신 블로그

      더보기
      동영상 기고하기