Rental Application (React & Spring boot Microservice) - 10 : Spring Cloud Bus

yellow_note·2021년 8월 23일
0

#1 Spring Cloud Bus

이전 포스트에서는 actuator를 통한 refresh를 사용해보았습니다. refresh는 microservice의 상태값을 재구동 없이 갱신을 해준다는 측면에서 상당히 편리한 기능이었지만 microservice들이 10개 20개와 같이 수적으로 많아진다면 일일이 refresh를 하기 어렵겠죠. 이런 단점을 개선하기 위해 Spring Cloud Bus를 사용해보도록 하겠습니다.

Spring Cloud Bus는 RabbitMQ라는 제품을 이용해 상태, 구성에 대한 변경 사항들을 연결된 노드(Microservices)들에게 전달합니다. RabbitMQ는 메시지 브로커로 node들 사이에서 메시지를 전달해주는 미들웨어입니다. 이 메시지 브로커의 장점은 노드들 사이에서 하나의 queue로써 node에서 날라온 메시지를 저장하였다가 이 queue에서 다른 node가 메시지를 전달받는 방식입니다. 메시지를 송신하는 쪽을 Producer, 메시지를 수신하는 쪽을 Consumer라고 합니다.

예를 들자면 다음과 같은 시나리오가 있을 수 있겠습니다.

1) node-A는 node-B에게 메시지를 보내려고 합니다.
2) 하지만 만약 node-B의 상태가 굉장히 바쁘다면 메시지를 보내도 바로 처리가 안 될 것입니다.
3) 그래서 node-A는 메시지를 관리할 수 있는 queue에 메시지를 보내려고 합니다.
4) queue에 메시지를 보낸다면 node-B가 바쁜 상태여도 모든 처리가 끝났을 때 이 queue에서 메시지를 꺼내오면 될테니까요
5) 이렇게 node-A는 queue로 메시지를 보냈고 모든 처리를 마친 node-B는 이 queue에서 메시지를 꺼내와 잘 전달받을 수 있습니다.

시나리오처럼 Spring Cloud Bus는 RabbitMQ라는 메시지 브로커를 이용하여 상태 변경 값들을 microservice들에게 전달하고 갱신할 수 있도록 하는 기능입니다.

#2 Cloud Bus 연동

https://www.rabbitmq.com/

우선 RabbitMQ가 필요하므로 저는 해당 공식 사이트로 들어가 우분투 리눅스 설치 매뉴얼을 따라서 설치를 진행했습니다.

config-server에 다음 디펜던시를 추가하도록 하겠습니다.

  • pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

그리고 apigateway-service, auth-service에는 다음의 디펜던시를 추가하도록 하겠습니다.

  • pom.xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

config-server, apigateway-service, auth-service의 application.yml파일에는 해당 코드를 공통적으로 적어주겠습니다.

spring:
    rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest
        
management:
   endpoints:
      web:
          exposure:
              include: refresh, health, beans, httptrace, busrefresh

마지막으로 git repository의 파일 이름을 다음과 같이 바꿔주고, auth-service와 apigateway-service의 bootstrap 파일을 다음처럼 변경해주도록 하겠습니다.

  • bootstrap.yml
spring:
  cloud:
    config:
      uri: http://127.0.0.1:8888
      name: config-server

#3 실행

1) rabbitmq server 구동

2) config-server, discovery-service 구동

[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  59:05 min
[INFO] Finished at: 2021-08-23T10:32:53+09:00
[INFO] ------------------------------------------------------------------------
 biuea@linux  ~/Desktop/MyRentalPlatform/config-server   master ±✚  mvn spring-boot:run
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< com.microservices:config-server >-------------------
[INFO] Building config-server 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> spring-boot-maven-plugin:2.4.11-SNAPSHOT:run (default-cli) > test-compile @ config-server >>>
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ config-server ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ config-server ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ config-server ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] skip non existing resourceDirectory /home/biuea/Desktop/MyRentalPlatform/config-server/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ config-server ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] <<< spring-boot-maven-plugin:2.4.11-SNAPSHOT:run (default-cli) < test-compile @ config-server <<<
[INFO] 
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.4.11-SNAPSHOT:run (default-cli) @ config-server ---
[INFO] Attaching agents: []

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::      (v2.4.11-SNAPSHOT)

2021-08-23 10:33:20.393  INFO 28034 --- [           main] c.m.c.ConfigServerApplication            : No active profile set, falling back to default profiles: default
2021-08-23 10:33:21.218  INFO 28034 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=1e260981-4a34-3f68-9610-db9344235dba
2021-08-23 10:33:21.231  INFO 28034 --- [           main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2021-08-23 10:33:21.236  INFO 28034 --- [           main] faultConfiguringBeanFactoryPostProcessor : No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
2021-08-23 10:33:21.240  INFO 28034 --- [           main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2021-08-23 10:33:21.277  INFO 28034 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-23 10:33:21.279  INFO 28034 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthContributor' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthContributor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-23 10:33:21.280  INFO 28034 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthIndicatorListener' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthIndicatorListener] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-23 10:33:21.284  INFO 28034 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.integration.config.IntegrationManagementConfiguration' of type [org.springframework.integration.config.IntegrationManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-23 10:33:21.290  INFO 28034 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationChannelResolver' of type [org.springframework.integration.support.channel.BeanFactoryChannelResolver] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-23 10:33:21.291  INFO 28034 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationDisposableAutoCreatedBeans' of type [org.springframework.integration.config.annotation.Disposables] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-23 10:33:21.466  INFO 28034 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8888 (http)
2021-08-23 10:33:21.473  INFO 28034 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-08-23 10:33:21.474  INFO 28034 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.52]
2021-08-23 10:33:21.535  INFO 28034 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-08-23 10:33:21.535  INFO 28034 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1085 ms
2021-08-23 10:33:22.459  INFO 28034 --- [           main] o.s.c.s.m.DirectWithAttributesChannel    : Channel 'application-1.springCloudBusInput' has 1 subscriber(s).
2021-08-23 10:33:22.701  INFO 28034 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 3 endpoint(s) beneath base path '/actuator'
2021-08-23 10:33:22.769  INFO 28034 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2021-08-23 10:33:22.769  INFO 28034 --- [           main] o.s.i.channel.PublishSubscribeChannel    : Channel 'application-1.errorChannel' has 1 subscriber(s).
2021-08-23 10:33:22.769  INFO 28034 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : started bean '_org.springframework.integration.errorLogger'
2021-08-23 10:33:22.770  INFO 28034 --- [           main] o.s.c.s.binder.DefaultBinderFactory      : Creating binder: rabbit
2021-08-23 10:33:22.852  INFO 28034 --- [           main] o.s.c.s.binder.DefaultBinderFactory      : Caching the binder: rabbit
2021-08-23 10:33:22.853  INFO 28034 --- [           main] o.s.c.s.binder.DefaultBinderFactory      : Retrieving cached binder: rabbit
2021-08-23 10:33:22.932  INFO 28034 --- [           main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: springCloudBus.anonymous.215q-mNTQgCDAEl4DH3hCw, bound to: springCloudBus
2021-08-23 10:33:22.934  INFO 28034 --- [           main] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [127.0.0.1:5672]
2021-08-23 10:33:22.963  INFO 28034 --- [           main] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#12a14b74:0/SimpleConnection@1c628f6a [delegate=amqp://guest@127.0.0.1:5672/, localPort= 33844]
2021-08-23 10:33:23.013  INFO 28034 --- [           main] o.s.c.stream.binder.BinderErrorChannel   : Channel 'springCloudBus.anonymous.215q-mNTQgCDAEl4DH3hCw.errors' has 1 subscriber(s).
2021-08-23 10:33:23.014  INFO 28034 --- [           main] o.s.c.stream.binder.BinderErrorChannel   : Channel 'springCloudBus.anonymous.215q-mNTQgCDAEl4DH3hCw.errors' has 2 subscriber(s).
2021-08-23 10:33:23.027  INFO 28034 --- [           main] o.s.i.a.i.AmqpInboundChannelAdapter      : started bean 'inbound.springCloudBus.anonymous.215q-mNTQgCDAEl4DH3hCw'
2021-08-23 10:33:23.041  INFO 28034 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8888 (http) with context path ''
2021-08-23 10:33:23.145  INFO 28034 --- [           main] c.m.c.ConfigServerApplication            : Started ConfigServerApplication in 3.448 seconds (JVM running for 3.788)

마지막 줄쯤에 Cloud Bus와 rabbitmq가 잘 연동되는 모습을 볼 수 있습니다.

3) auth-service 구동
4) token정보 변경


다음처럼 token정보를 변경하고 Cloud Bus를 이용해 잘 변경되는지 확인해보도록 하겠습니다.

우선 busrefresh요청하기전 현재 상태를 보면 secret값이 여전히 user_token임을 알 수 있습니다.

저는 /actuator/busrefresh로 요청을 하겠습니다 해당 uri로 요청하는 이유는 Cloud Bus의 장점인 어떤 서비스든 cloud bus가 연동된 서비스에busrefresh를 하면 모든 연결된 서비스를 갱신할 수 있기 때문입니다.

busrefresh를 하고난 후 하기전 토큰 값으로 /auth-service/health_check를 요청한 결과 401 메시지가 반환된 것을 볼 수 있습니다. 즉, 토큰 값이 바뀌어 이전의 토큰 값은 허용하지 않겠다는 의미겠죠.

다시 로그인을 진행하고 토큰값을 얻어오겠습니다.

바뀐 토큰 값으로 /auth-service/health_check를 요청한 결과 앞서 바꾸었던 user_token_changed값으로 바뀐 모습을 볼 수 있습니다.

기존의 refresh 요청은 개별적으로 모든 서비스에게 refresh 요청을 진행하고 갱신을 해야하는 번거로움이 있었지만 Cloud Bus를 이용하니 한 번의 요청으로 연결된 모든 서비스들이 갱신되는 장점을 볼 수 있었습니다.

다음 포스트에서는 설정 정보 암호화를 진행해보도록 하겠습니다.

참고

인프런: Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) - 이도원

0개의 댓글