스프링 클라우드는 어떤 클라우드에서도 서비스를 구축 가능하다.
스프링 클라우드를 사용하면 클라우드 네이티브 마이크로 서비스를 쉽게 만들 수 있다.
컴포넌트의 아키텍쳐 패턴을 살펴보자.
- Config server
- Service discovery
- Gateway
- Circuit breaker
#
Config server
클라우드가 변경되면 설정도 바뀌어야 하기 때문에 애플리케이션에 설정을 정적으로 할 수는 없다. 서비스에서 요청할 수 있도록 하는 메커니즘이 필요하다.
Config server는 설정에 대해 쿼리할 수 있는 기능을 제공하여 URL, DB, PW 및 그 밖의 설정값을 검색할 수 있따.
Service Discovery
클라우드에서는 다른 서비스를 연결해야 할 수도 있는데, 실제 서비스의 위치, 인스턴스 수 등을 알 수가 없어 이 메커니즘이 필요하다.
모든 서비스의 인스턴스가 생성되면 Service Discovery에 등록된다. 최신 상태가 유지되어야 하기 때문에 Heart-beat 메커니즘을 사용한다. (5분마다 활성화 상태를 체크)
Gateway
애플리케이션이 /customers 경로를 사용하면, 서비스 탐색이나 로드 밸런서를 직접 사용할 필요 없이 내부적으로 동작하는 게이트웨이를 통해 호출하도록 간단한 인터페이스를 구성할 수 있다.
모든 서비스의 진입점이기 때문에 보안, 자격증명, 권한 등을 여기서 해결할 수 있다.
Circuit breaker
각 서비스에서 수행한 동작이 실패할 때가 있다. 그럼에도 사용자에게 응답은 필요하며, 나머지 서비스들은 정상 동작해야 한다.
A, B, C 서비스가 있다. A는 B를 호출해 고객 정보를 얻고 C를 호출해 추천을 받아온다. C가 동작하지 않는다면 A는 매번 C를 호출하기 때문에 결국 A는 오류 내용을 반환하게 된다.
또한 C에 의해 성능저하도 올 수 있다.
이러한 문제가 발생하지 않도록 Circuit breaker를 사용해 C 호출 후 작업이 실패하면 일정기간 C 호출 회로를 차단한 뒤, 다시 동작할때 까지는 회로를 열지않고 기본 값을 반환하도록 한다.
#
스프링 클라우드 넷플릭스
넷플릭스 OSS에 클라우드 아키텍쳐 패턴을 구현하는 많은 컴포넌트가 있어 스프링 클라우드와 함께 사용하면 좋다.
- Eureka: Service discovery
- Ribbon: Load balencer
- Hystrix: Circuit breaker
- Zuul: Gateway server
#
#
Config server
dependencies: Config Server, Web
컨피그 서버는 기본 포트가 8888이므로 바꾸자
server:
port: 8888
@EnableConfigServer 애너테이션을 사용하자
@SpringBootApplication
@EnableConfigServer
class ConfigDemoApplication
fun main(args: Array<String>) }
runApplication<ConfigDemoApplication>(*args)
}
설정 파일의 위치 지정이 필요하다. 일단은 Git이나 Database가 아닌 기본 파일시스템을 사용한다.
spring:
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:config/
http://localhost:8888/application/default 요청하면 다음과 같다
{
"name": "application",
"profiles": [
"default"
],
"label": null,
"version": null,
"state": null,
"propertySources": []
}
이제 설정을 추가해보자 (config/application.yml)
microservice:
example:
greetings: "hello"
다시 http://localhost:8888/application/default 요청하면 다음과 같다
{
"name": "application",
"profiles": [
"default"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "classpath:config/application.yml",
"source": {
"microservice.example.greetings": "hello"
}
}
]
}
(config server 시작시 잘 안되면 캐시 제거를 위해 gradle clean을 해보자)
#
설정을 받도록 마이크로서비스에 RestController를 추가해서 확인해보자
@RestController
class GreetingController {
@Value("\${microservice.example.greetings}")
private lateinit var greetings: String
@GetMapping("/greetings")
fun greetings() = greetings
}
디펜던시도 필요함(책에선 언급이 없네 ㅋ)
implementation("org.springframework.cloud:spring-cloud-starter-config")
application.yml 설정도 필요함
spring:
cloud:
config:
uri: http://localhost:8888
http://localhost:8080/greetings 를 요청하면 hello가 출력된다.
#
이제 설정을 수정해보자
microservice:
example:
greetings: "hello again!!"
컨피그 서버를 시작하고, 마이크로서비스도 다시 시작하면 결과가 바뀐다.
#
책에서는 언급이 없지만 설정값이 바뀌면 자동으로 refresh가 되야 의미가 있다. 아래 등의 블로그를 참고하자.
https://multifrontgarden.tistory.com/237
#
그런데 마이크로서비스는 여러개가 있기 때문에 각 설정을 개별적으로 하는게 좋다.
application.yml (마이크로서비스)
spring:
application:
name: "greetings"
resources/config/greetings.yml (Config server)
microservice:
example:
greetings: "hello greetings!!"
http://localhost:8888/greetings/default 요청하면 다음과 같다
{
"name": "greetings",
"profiles": [
"default"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "classpath:config/greetings.yml",
"source": {
"microservice.example.greetings": "hello greetings!!"
}
},
{
"name": "classpath:config/application.yml",
"source": {
"microservice.example.greetings": "hello again!!"
}
}
]
}
#
암호화가 필요하다면 /resources/bootstrap.yml (Config server)
encrypt.key: "this_is_a_secret"
spring:
cloud:
config:
server:
encrypt:
enabled: false
여기서는 암호화 때 사용할 암호화키를 지정한다. 그 값은 안전하게 보관되어야 한다.
URL을 통해 암호화할 수 있다.
$ curl http://localhost:8888/encrypt -d "secret message"
7b310alk2n1lk2j1jf1vjlkvjl1291029
이제 이 값을 넣자
resources/config/greetings.yml (Config server)
microservice:
example:
greetings: "{cipher} 7b310alk2n1lk2j1jf1vjlkvjl1291029"
http://localhost:8888/greetings/default 요청하면 암호화 된 것을 볼 수 있다.
마지막으로 마이크로서비스에도 bootstrap.yml 파일을 추가해 동일한 키를 사용하도록 한다.
applicaion.yml (마이크로서비스)
encrypt.key: "this_is_a_secret"
#
프로파일을 사용하려면 greetings-production.yml
처럼 파일 이름을 지정하면 된다.
java -jar **.jar --spring.cloud.config.profile=production
#
#
서비스 탐색
mydiscovery project
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-server")
server:
port: 8761
spring:
application:
name: "discovery-server"
@SpringBootApplication
@EnableEurekaServer
class MydiscoveryApplication
...
#
server1 project
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
spring:
application:
name: "service1"
#
http://localhost:8761 에 들어가보면 어떤 인스턴스가 등록되어 있는지 볼 수 있다.
기본적으로 하트비트를 통해 유레카가 알아서 연결을 끊어주고 연결해주지만 가끔 안될때가 있는데, 그땐 Eureka가 제공하는 API를 통해 해결할 수 있다.
https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
#
인스턴스 상태 관련해서 스프링 부트 액추에이터가 더 나은 메커니즘을 제공하기 때문에 사용하자
implementation("org.springframework.boot:spring-boot-starter-actuator")
eureka:
client:
healthcheck:
enabled: true
http://localhost:8080/actuator/health 가서 확인이 가능하다.
{"status":"UP"}
#
GateWay
Zuul은 로드 밸런싱, 히스트릭스, 게이트 웨이 기능을 제공한다. 추가해보자.
implementation("org.springframework.cloud:spring-cloud-starter-config")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-zuul")
service1의 포트를 변경해버리자(게이트웨이를 8080으로 쓰기위함)
server:
port: 0
게이트웨이 이름을 설정하자
spring:
application:
name: "gateway"
key가 없어서 게이트웨이가 안뜨면 키를 추가하자 (bootstrap.yml)
encrypt:
key: "this_is_a_secret"
http://localhost:8761 에 들어가면 게이트웨이가 있음을 알 수 있다.
이제 라우터를 정의하자
@SpringBootApplication
@EnableZuulProxy
class MygatewayApplication
...
http://localhost:8080/service1/greetings 접속해보면 정상동작함을 알 수 있다.
#
- URL /service1/greetings를 요청하면 Zuul이 Eureka에서 service1을 찾음
- Eureka는 available 인스턴스 목록을 반환함
- Zuul은 Circuit breaker를 만듬
- Ribbon을 사용해 round robbin 으로 인스턴스를 선택함
- Zuul이 URL 에서 service1을 지우고 /greetings만 남겨 요청을 보냄
- 요청 실패하면 hystrix가 차단하므로 추가요청은 즉시 오류를 반환할 것임
- Zuul은 결과를 반환함
'프로그래밍 > Kotlin' 카테고리의 다른 글
프로젝트를 docker로 실행해보기(코틀린마이크로서비스#3) (0) | 2020.04.28 |
---|---|
spring-kotlin-reactive(코틀린마이크로서비스#1) (0) | 2020.04.28 |
Kotlin 기초 (0) | 2020.04.16 |