Spring Cloud Netflix - llb1026/spring_cloud_netflix_practice GitHub Wiki
TOC
Intro
Spring Cloud Netflix๋ ์๋ ํ๊ฒฝ ์ค์ ๊ณผ Spring Environment ๋ฐ ๋ค๋ฅธ Spring ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ ๊ด๋ ์ ๋ฐ์ธ๋ฉ์ ๋ฐํ์ผ๋ก Spring Boot ์ดํ๋ฆฌ์ผ์ด์ ์ ์ํ Netflix OSS (Open Source Software) ํตํฉ์ ์ ๊ณตํฉ๋๋ค. ๋ช ๊ฐ์ง ๊ฐ๋จํ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์ดํ๋ฆฌ์ผ์ด์ ๋ด๋ถ์ ๊ณตํต ํจํด์ ์ ์ํ๊ฒ ์ฌ์ฉํ๊ณ ์ค์ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ battle-test๋ฅผ ๊ฑฐ์น Netflix ์ปดํฌ๋ํธ๋ฅผ ํตํด ๋๊ท๋ชจ ๋ถ์ฐ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ ๊ณต๋๋ ํจํด์๋ Service Discovery (Eureka), Circuit Breaker (Hystrix), Intelligent Routing (Zuul), ๊ทธ๋ฆฌ๊ณ Client Side Load Balancing (Ribbon) ๋ฑ์ ์ ๊ณตํฉ๋๋ค. โ ์ถ์ฒ: https://spring.io/projects/spring-cloud-netflix#overview
์ ์ ์กฐ๊ฑด
์ฌ๊ธฐ์์๋ ์๋์ ๊ฐ์ ๋ชฉํ/๋์ฆ๊ฐ ์๋ ํด๋ผ์ฐ๋ ํ๊ฒฝ์ MSA ๊ธฐ๋ฐ ์์คํ ์ ๊ฐ์ ํฉ๋๋ค.
- ์ ์ ํฌ๊ธฐ โ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ ์ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ์ฒด ์ดํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฐ์ ์ธ ์ฅ์ ๋ฅผ ์ค์ผ ์ ์๋๋ก ๋ง์ดํฌ๋ก์๋น์ค ํ๋ ๋น ํ ๊ฐ์ง ์ฑ ์ ์์ญ์ ์ง์คํจ
- ์์น ํฌ๋ช ์ฑ โ ๋๊ณ ๊ฐ ์๋น์ค์ ์ํฅ์ ์ฃผ์ง ์๊ณ ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค๋ฅผ ๋น ๋ฅด๊ฒ ์ถ๊ฐ/์ญ์ ํ ์ ์๋๋ก ์ธ์คํด์ค์ ๋ฌผ๋ฆฌ์ ์์น๋ฅผ ๊ด๋ฆฌํจ
- ํ๋ณต์ฑ โ ์๋น์ค์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ๋๊ณ ๊ฐ ์๋น์ค์ ์ํฅ์ ์ต์ํํ๊ธฐ ์ํ์ฌ ์ฅ์ ๊ฐ ๋ฐ์ํ ์ธ์คํด์ค๋ฅผ ์ฐํํ๊ณ '๋นจ๋ฆฌ ์คํจ'ํ๊ฒ ํจ
- ๋ฐ๋ณต์ฑ โ ์๋ก์ด ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค๊ฐ ์์๋ ๋๋ง๋ค ๋ณ๋์ ๋ณต์กํ ๋งค๋ด์ผ ์์ ์์ด ๊ธฐ์กด ์ธ์คํด์ค์ ๋์ผํ ์ฝ๋์ ๊ตฌ์ฑ์ผ๋ก ์์๋๋๋ก ํจ
- ํ์ฅ์ฑ โ ์๋น์ค ๊ฐ ์์กด์ฑ์ ์ต์ํํ๋ฉด์ ์ดํ๋ฆฌ์ผ์ด์ ์ด ์ ์ํ๊ฒ ํ์ฅํ ์ ์๋๋ก ๋น๋๊ธฐ ํ๋ก์ธ์ฑ๊ณผ ์ด๋ฒคํธ๋ฅผ ํ์ฉํจ
์ด๋ฅผ ์ํด์ ์ด๋ก ์ ์ผ๋ก ๋ค์ 6๊ฐ์ง ๋ง์ดํฌ๋ก์๋น์ค ํจํด์ ๋ฐ๋ฆ ๋๋ค.
- ํต์ฌ ๊ฐ๋ฐ ํจํด (core development patterns) โ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ด๋ป๊ฒ ์ ์ ํฌ๊ธฐ๋ก ๋๋ ๊ฒ์ธ์ง
- ๋ผ์ฐํ ํจํด (routing patterns) โ ์ดํ๋ฆฌ์ผ์ด์ ๊ฐ์ ์์น ํฌ๋ช ์ฑ์ ์ด๋ป๊ฒ ๋ณด์ฅํ ๊ฒ์ธ์ง
- ํด๋ผ์ด์ธํธ ํ๋ณต์ฑ ํจํด (client resiliency patterns) โ ํ๋ณต์ฑ์ ์ด๋ป๊ฒ ๋ณด์ฅํ ๊ฒ์ธ์ง
- ๋ณด์ ํจํด (security patterns) โ AAA (Authentication, Authorization, Accounts) ๋ฅผ ์ด๋ป๊ฒ ๋ณด์ฅํ ๊ฒ์ธ์ง
- ๋ก๊น ๋ฐ ์ถ์ ํจํด (logging and tracing patterns) โ ์ด๋ป๊ฒ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋๋ฒ๊น ํ๊ณ ์ถ์ ํ ๊ฒ์ธ์ง
- ๋น๋ ๋ฐ ๋ฐฐํฌ ํจํด (build and deployment pattern) โ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ฐ๋ณต์ฑ๊ณผ ํ์ฅ์ฑ์ ์ด๋ป๊ฒ ๋ณด์ฅํ ๊ฒ์ธ์ง
์ฌ๊ธฐ์ ์ ๋ฆฌํ Spring Cloud Netflix์ Eureka, Ribbon, Zuul, Hystrix๋ ์ ํจํด๊ณผ ๊ฐ๊ฐ ์๋์ ๊ฐ์ด ๋งค์นญ๋ ์ ์์ต๋๋ค.
| Name | Patterns |
|---|---|
| Zuul | ๋ผ์ฐํ ํจํด, ๋ณด์ ํจํด, ๋ก๊น ๋ฐ ์ถ์ ํจํด |
| Eureka | ๋ผ์ฐํ ํจํด |
| Ribbon | ๋ผ์ฐํ ํจํด |
| Hystrix | ํด๋ผ์ด์ธํธ ํ๋ณต์ฑ ํจํด |
Eureka as Service Discovery
๊ธฐ์กด์ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ
์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ์ญํ ์ ํฌ๊ฒ ์๋ 2๊ฐ์ง๋ก ๊ผฝ์ ์ ์์ต๋๋ค.
- ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค(API Callee)์ ๋ฌผ๋ฆฌ์ ์ฃผ์๋ฅผ ํด๋ผ์ด์ธํธ(API Caller)์๊ฒ ๋๋ฌ๋ด์ง ์์์ผ ํ๋ค
๋ง์ฝ ํด๋ผ์ด์ธํธ๊ฐ ์ธ์คํด์ค์ real IP์ ์์ฒญ์ ๋ณด๋ธ๋ค๋ฉด, ์ธ์คํด์ค๊ฐ ์ถ๊ฐ๋์์ ๋ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ผ ์ ์๋ ์ธ์คํด์ค ๋ชฉ๋ก์ ์ ๊ท ์ถ๊ฐ๋ IP๋ฅผ ๋งค๋ฒ ์ ๋ฐ์ดํธํด์ค์ผ ํ๋ค
- ์ดํ๋ฆฌ์ผ์ด์ ์ ํ๋ณต์ฑ์ ์ํด ์ ์์ ์ธ ์ํ๊ฐ ์๋ ์ธ์คํด์ค๋ ๊ฐ์ฉ ์ธ์คํด์ค ๋ชฉ๋ก์์ ์ ๊ฑฐํด์ผ ํ๋ค
์ฌ๊ธฐ๊น์ง ๋ณด๋ฉด ๊ธฐ์กด์ L4๋ DNS๋ฅผ ์ฌ์ฉํด๋ ๋ฌด๋ฐฉํ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค. ๊ทธ๋ฌ๋ ์๋์ ๊ฐ์ ํ๊ณ์ ์ ๊ฐ๊ณ ์์ต๋๋ค.
- ๋ก๋๋ฐธ๋ฐ์๋ฅผ ๋ค์คํํ๋ค๊ณ ํด๋, ์ฌ์ ํ SPOF(Single Point Of Failure, ๋จ์ผ ์ฅ์ ์ง์ )์ด ๋ ์ ์๋ค โ ๋ก๋๋ฐธ๋ฐ์๊ฐ ๋ป์ผ๋ฉด ๋ชจ๋ ์ดํ๋ฆฌ์ผ์ด์ ๋ ๋ค์ด๋จ
- ๋ณดํต ์์ฉ ๋ก๋๋ฐธ๋ฐ์๋ hot-swap ์ด์คํ๋ฅผ ์ง์ํ๋ค (active ํ ๋, stand-by ํ ๋)
- ์๋ก์ด ์ธ์คํด์ค์ ์ถ๊ฐ/์ญ์ ๊ณผ์ ์ด ๋๋ฆฌ๋ค (์๋ํ X, ์ฌ๋ ์์์ ํ์) โ ์์น ํฌ๋ช ์ฑ ๋ณด์ฅ์ด ๋ถํฌ๋ช
ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์์ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ
ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ์ MSA ํ๊ฒฝ์์๋ ์๋ ๊ธฐ๋ฅ์ ๊ฐ์ถ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ๊ฐ ์ ํฉํฉ๋๋ค.
- ๊ธฐ์กด ๋ก๋๋ฐธ๋ฐ์๋ณด๋ค ๊ณ ๊ฐ์ฉ์ฑ์ ๋ณด์ฅํ๋ค โ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ํด๋ฌ์คํฐ ๊ตฌ์ถ
- ๊ธฐ์กด ๋ก๋๋ฐธ๋ฐ์๊ฐ ํ๋ ๋ถํ ๋ถ์ฐ ์ญํ ๋ ๋น์ฐํ ์ํํ๋ค
- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ํด๋ฌ์คํฐ์ ๊ฐ ๋ ธ๋๋ ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค์ ์ํ๋ฅผ ๊ณต์ ํ๋ค
- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ๋ ๊ฐ ์ธ์คํด์ค์ ์ํ๋ฅผ ์ง์์ ์ผ๋ก ๊ฐ์งํ๋ฉฐ ํน์ ์ธ์คํด์ค๊ฐ ์ ์์ ์ด์ง ์์ ๋ ๊ฐ์ฉ ์๋น์ค ๋ชฉ๋ก์์ ํด๋น ์ธ์คํด์ค๋ฅผ ์ ๊ฑฐํ๋ค
- ๋ชจ๋ ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค๋ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ๊ฐ์ฉ ์๋น์ค ๋ชฉ๋ก์ ๋ก์ปฌ์ ์บ์ฑํด ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ๊ฐ ์ฃฝ์์ ๋ ์บ์ฑ๋ ๋ชฉ๋ก์ ํ์ฉํด ๊ณ์ ๋์ํ ์ ์๋๋ก ํ๋ค
๊ฐ๋จํ ์ ๋ชฉ๋ก์ ๋์ํํ ๊ทธ๋ฆผ์ ์๋์ ๊ฐ์ต๋๋ค.

Eureka Server ๊ตฌ์ฑ
๊ธฐ๋ณธ์ ์ผ๋ก ์๋์ 3๊ฐ ์ดํ๋ฆฌ์ผ์ด์ ์ด ํ์ํฉ๋๋ค.
- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ๋ ธ๋๊ฐ ๋ Eureka Server ์ดํ๋ฆฌ์ผ์ด์
- Eureka๋ฅผ ํตํด API๋ฅผ ์์ฒญํ API Caller ์ดํ๋ฆฌ์ผ์ด์ A
- A์ ์์ฒญ์ ๋ํด ์๋ต์ ์ค API Callee ์ดํ๋ฆฌ์ผ์ด์ B
Eureka Server ์ดํ๋ฆฌ์ผ์ด์ ์ ์๋์ ๊ฐ์ด ๋ง๋ค ์ ์์ต๋๋ค.
-
์์กด์ฑ ์ถ๊ฐ (build.gradle ํ์ผ)
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka- server' ... } -
์ ๋ ์นด ์๋ฒ ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication @EnableEurekaServer // ์ด ๋ถ๋ถ public class EurekaServerApplication { ... } -
๊ตฌ์ฑ ์ค์ (application.properties ํ์ผ)
server.port=8761 // Eureka Server๊ฐ listenํ ํฌํธ eureka.instance.hostname=eureka // Eureka Server์ ํธ์คํธ๋ช eureka.client.registerWithEureka=false // Eureka Server์ ์๊ธฐ ์์ ์ ๋ฑ๋กํ์ง ์๊ฒ ๋ค๋ ์๋ฏธ eureka.client.fetchRegistry=false // ๋ ์ง์คํธ๋ฆฌ ์ ๋ณด๋ฅผ ๋ก์ปฌ์ ์บ์ฑํ์ง ์๊ฒ ๋ค๋ ์๋ฏธ eureka.client.serviceUrl.defaultZone=http://${registry.host:localhost}:${server.port}/eureka/
์ฌ๊ธฐ๊น์ง ๊ตฌ์ฑ ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํ์์ผ localhost:8761 ๋ก ์ ์ํ๋ฉด ๊ฐ๋จํ Eureka Server ๋์๋ณด๋๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์ง๊ธ์ Eureka Server์ ๋ฑ๋ก๋ ์ธ์คํด์ค๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋น ๋ชฉ๋ก์ผ๋ก ๋ณด์ ๋๋ค.
์ธ์คํด์ค ๊ตฌ์ฑ
์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ๋ฑ๋กํ API Caller, Callee ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด๋ด ๋๋ค.
-
์์กด์ฑ ์ถ๊ฐ (build.gradle ํ์ผ)
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka- client' ... } -
์ธ์คํด์ค ๋ฑ๋ก ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication @EnableDiscoveryClient // ์ด ๋ถ๋ถ public class ApiCalleeApplication { ... } -
๊ตฌ์ฑ ์ค์ (application.properties ํ์ผ)
spring.application.name=apicallee // ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ๋ฑ๋กํ ์ธ์คํด์ค์ ๋ ผ๋ฆฌ์ ์ด๋ฆ eureka.instance.preferIpAddress=true // ์ธ์คํด์ค ์ด๋ฆ ๋์ IP์ฃผ์๋ฅผ ๋ฑ๋กํ๊ฒ ๋ค๋ ์๋ฏธ eureka.client.registerWithEureka=true // Eureka Server์ ์๊ธฐ ์์ ์ ๋ฑ๋กํ๊ฒ ๋ค๋ ์๋ฏธ eureka.client.serviceUrl.defaultZone=http://${registry.host:localhost}:${server.port}/eureka/
Eureka Server์ ๋ฑ๋กํ๋ ์ธ์คํด์ค ์๋ณ์๋ก๋ Application ID์ Instance ID๊ฐ ์์ต๋๋ค. Application ID๋ ์ธ์คํด์ค์ ๊ทธ๋ฃน์ ์๋ฏธํ๋ฉฐ, ์ ํ๋กํผํฐ ํ์ผ์์ ๋ช ์ํ spring.application.name ์ ๋๋ค. Instance ID๋ ๋์ผํ ์ธ์คํด์ค๊ฐ ์ฌ๋ฌ ๊ฐ ๋ ์์ ๋, ๊ฐ ์ธ์คํด์ค๋ฅผ ๊ตฌ๋ถํ๋ ์์์ ์ซ์์ ๋๋ค.
์ธ์คํด์ค์ ๋ ผ๋ฆฌ์ ์ด๋ฆ ๋์ IP์ฃผ์๋ฅผ ๋ฑ๋กํ๋ ์ด์ ๋ ์ปจํ ์ด๋ ๊ธฐ๋ฐ (ex. Docker) ๋ฐฐํฌ ์ ์ปจํ ์ด๋๊ฐ DNS ์ํธ๋ฆฌ๊ฐ ์๋ ์์๋ก ์์ฑ๋ ํธ์คํธ๋ช ์ ๋ถ์ฌ๋ฐ์ ์์ํ๊ธฐ ๋๋ฌธ์, API Caller๊ฐ Callee์ ์์น๋ฅผ ์ ์์ ์ผ๋ก ์ฐพ์ง ๋ชปํฉ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ํญ์ eureka.instance.preferIpAddress=true๋ก ์ค์ ํด๋๋ ํธ์ด ์ ์ ํ๋ค๊ณ ํฉ๋๋ค.
์ด๋ ๊ฒ ์ธ์คํด์ค๊ฐ Eureka Server์ ๋ฑ๋ก๋๋ฉด Eureka Server๋ ์ง์์ ์ธ health check๋ฅผ ํตํด ์ธ์คํด์ค์ ์ํ๋ฅผ ๊ฐ์ฉ ์ธ์คํด์ค ๋ชฉ๋ก์ ์ ๋ฐ์ดํธํ ๊ฒ์ ๋๋ค.
๋ณดํต Eureka Server์ ๋ฑ๋ก๋ ์ธ์คํด์ค๋ 30์ด๋ง๋ค ์์ ์ ์ํ๋ฅผ Eureka Server์ ์๋ฆฌ๋ฉฐ, ์ด ์ฃผ๊ธฐ๋ ๋ณ๋๋ก ์ค์ ํ ์ ์์ต๋๋ค
Ribbon as Client Side Load Balancing
์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ๋ง์ผ๋ก ์ถฉ๋ถํ์ง ์์ ์ด์
Eureka Server๋ง ์๋ค๊ณ ๊ฐ์ ํ๋ฉด, ๋ชจ๋ API ์์ฒญ์ Eureka Server๋ฅผ ํตํ๊ฒ ๋์ด Eureka Server๊ฐ ์๋ก์ด ๋ณ๋ชฉ ์ง์ ์ด ๋ ์ ์์ต๋๋ค.
์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ์์กด์ฑ์ ์ค์ด๊ธฐ ์ํด ํด๋ผ์ด์ธํธ ๋ถํ ๋ถ์ฐ์ด๋ผ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ฌ๊ธฐ์ Ribbon์ด ํ์ฉ๋ฉ๋๋ค.
ํด๋ผ์ด์ธํธ ๋ถํ ๋ถ์ฐ์ ์ญํ
- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ๊ฐ์ฉ ์ธ์คํด์ค ๋ชฉ๋ก์ ์บ์ฑํ์ฌ ๊ฐ ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค ๋ก์ปฌ์ ์ ์ฅํ๋ค
- ์ด๋ค ์ธ์คํด์ค๊ฐ API๋ฅผ ํธ์ถํ ๋ ๋จผ์ ๋ก์ปฌ์ ์บ์ฑ๋ ์ธ์คํด์ค ๋ชฉ๋ก์ ์ฐธ์กฐํ๋ค
- ์ผ๋ฐ์ ์ผ๋ก ํด๋ผ์ด์ธํธ ์ธก ์บ์ฑ์ RR(Round-Robbin) ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด API ํธ์ถ์ ์ฌ๋ฌ ์ธ์คํด์ค๋ก ๋ถ์ฐํ๋ค
- ์ฃผ๊ธฐ์ ์ผ๋ก ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ์ ์ํด ๋ก์ปฌ ์บ์๋ฅผ ์ ๋ฐ์ดํธํ๋ค
ํด๋ผ์ด์ธํธ ๋ก๋๋ฐธ๋ฐ์๋ฅผ ์ถ๊ฐํ ๊ทธ๋ฆผ์ ์๋์ ๊ฐ์ต๋๋ค.

RestTemplate์ ์ฌ์ฉํ Ribbon ๊ตฌ์ฑ
Spring Cloud ์ด๊ธฐ์๋ Ribbon์ด RestTemplate ํด๋์ค๋ฅผ ์ง์ํ์ง๋ง, ํ์ฌ๋ ๋์ด์ ์ง์๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ RestTemplate์์ Ribbon์ ์ฌ์ฉํ๋ ค๋ฉด '@LoadBalanced' ์ด๋ ธํ ์ด์ ์ ์ง์ ์ถ๊ฐํด์ค์ผ ํฉ๋๋ค. ๋ค๋ฅธ ๋์์ Netflix Feign ํด๋ผ์ด์ธํธ๋ก ์๋น์ค๋ฅผ ํธ์ถํ๋ ๊ฒ์ธ๋ฐ, ํ์ ์ถ๊ฐํ๋๋ก ํ๊ฒ ์ต๋๋ค.
-
์์กด์ฑ ์ถ๊ฐ (build.gradle ํ์ผ)
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-ribbon' ... } -
restTemplate ์ ์
@LoadBalanced @Bean RestTemplate restTemplate() { return new RestTemplate(); } -
ํด๋ผ์ด์ธํธ ๋ก๋๋ฐธ๋ฐ์ ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication @EnableDiscoveryClient @RibbonClient(name = "apicallee", configuration = RibbonConfiguration.class) public class ApiCallerApplication { ... @Autowired RestTemplate restTemplate; ... @RequestMapping("/call/api") public String blah() { ... // ์ RibbonClient ์ด๋ ธํ ์ด์ ์์ ๋ช ์ํ ๋ชฉ์ ์ง๋ฅผ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์์ ๊ฒ์ this.restTemplate.getForObject("http://apicallee/answer", String.class); } }
์์ ๊ฐ๋จํ ์์์์ ApiCaller ์ธ์คํด์ค๋ก "/call/api" ์์ฒญ์ด ๋ค์ด์ค๋ฉด ApiCallee ์ธ์คํด์ค์ "/answer"๋ฅผ ํธ์ถํ๋๋ก ๋์ด ์์ต๋๋ค.
'@RibbonClient' ์ด๋ ธํ ์ด์ ์์ ๋ช ์ํ name์ application.properties ํ์ผ์ spring.application.name๊ณผ ์ผ์นํฉ๋๋ค.
Zuul as API Gateway
API ๊ฒ์ดํธ์จ์ด์ ์ญํ
API ํธ์ถ์ ๋ํ ๋ณด์๊ณผ ๋ก๊น ๋ฑ์ ํธ๋ํนํ๊ธฐ ์ํด ๊ฐ ์์ฒญ์ ๋ํ ํํฐ์ ๋ผ์ฐํฐ ์ญํ ์ ํ๋ API ๊ฒ์ดํธ์จ์ด๊ฐ ํ์ํฉ๋๋ค.
๋ง์ฝ API ๊ฒ์ดํธ์จ์ด๊ฐ ์์ด ๋ณด์, ๋ก๊น , ์ฌ์ฉ์ ์ถ์ ๋ฑ์ ๊ฐ ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค์์ ์ ๊ฐ๊ฐ ๊ตฌํํ๊ฒ ๋๋ค๋ฉด ์ผ๊ด์ฑ์ด ๋จ์ด์ง๊ณ ์ธ์คํด์ค ๊ฐ์ ์์กด์ฑ์ด ๋ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ API ๊ฒ์ดํธ์จ์ด๋ ์๋์ ๊ฐ์ ์ญํ ์ ์ํํฉ๋๋ค.
- ํ๋์ entry point URL ๋ค์ ๋ชจ๋ ์๋น์ค๋ฅผ ๋ฐฐ์นํ๊ณ , ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ๋ฅผ ์ด์ฉํด ๋ชจ๋ ํธ์ถ์ ์ค์ ์ธ์คํด์ค๋ก ๋งคํํ๋ค
- API ๊ฒ์ดํธ์จ์ด๋ฅผ ๊ฒฝ์ ํ๋ ๋ชจ๋ ํธ์ถ์ TID (๊ณ ์ ํ ID)๋ฅผ ์ฝ์ ํ๋ค
- ํธ์ถ ์ ์์ฑ๋ TID๋ฅผ ์๋ต์ ์ฝ์ ํ๊ณ ํด๋ผ์ด์ธํธ(API Caller)์ ํ์ ํ๋ค
- ์ ์ /๋์ ๋ผ์ฐํ ์ ์ง์ํ๋ค
- ํธ์ถ์ ๋ํ ์ธ์ฆ(authentication)๊ณผ ์ธ๊ฐ(authorization)์ ์ฒ๋ฆฌํ๋ค
- ํธ์ถ ๋ก๊ทธ์ ์ด์ ๋ฐ๋ฅธ ์งํ๋ฅผ ์์งํ๋ค
์์ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ๋ถ๋ถ์์ ์ธ๊ธํ๋ ๊ฒ์ฒ๋ผ, API ๊ฒ์ดํธ์จ์ด๋ SPOF๊ฐ ๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. ๊ฐ๋ฅํ API ๊ฒ์ดํธ์จ์ด ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ณ statelessํ๊ฒ ์ ์งํ์ฌ ์ฝ๊ฒ ๋ค์คํํ ์ ์๋๋ก ํด์ผ ํฉ๋๋ค.
๋ผ์ฐํฐ ๊ตฌ์ฑ
-
์์กด์ฑ ์ถ๊ฐ (build.gradle ํ์ผ)
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul' ... } -
API ๊ฒ์ดํธ์จ์ด ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication @EnableDiscoveryClient @EnableZuulProxy // ์ด ๋ถ๋ถ public class ApiCallerApplication { ... } -
๊ตฌ์ฑ ์ค์ (application.properties ํ์ผ)
server.port=8762 spring.application.name=zuul eureka.client.registerWithEureka=true eureka.client.fetchRegistry=false eureka.client.serviceUrl.defaultZone=http://${registry.host:localhost}:${server.port}/eureka/
์ด์ Eureka Server, API Caller ์ดํ๋ฆฌ์ผ์ด์ , API Callee ์ดํ๋ฆฌ์ผ์ด์ , ๊ทธ๋ฆฌ๊ณ Zuul ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํํ ํ localhost:8762/actuator/routes ๋ก ์ ์ํด๋ณด๋ฉด ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ ์ํด Zuul์ด ๋ผ์ฐํ ํ ์ ์๋ API ๋ชฉ๋ก์ ํ์ธํ ์ ์์ต๋๋ค.
์ค์ต
์คํ
- Java 11
- Spring Boot 2.2.6
- Eureka
- Ribbon
- Swagger 2
- Sleuth
- Zipkin
๊ตฌ์ฑ๋

์์ค์ฝ๋
https://github.com/llb1026/spring_cloud_netflix_practice ๊ฐ์ธ repo์ ์ฐ์ ์ปค๋ฐ
๋ก์ปฌ์์ ์คํ
-
Build projects using gradle
$ cd PROJECT_DIRECTORY $ gradle bootjar -
Run jar file with specific port
// =========== Port Info =========== // eureka-server: 8761 // zuul-application: 8762 // zipkin-server: 9411 // ribbon-client: 8888 // ribbon-server: 9090, 9091, 9092 ... // ================================= $ java -jar -Dserver.port=XXXX build/libs/YYYY.jar -
Open the browser and go to http://localhost:8761 to check the Eureka server dashboard
-
Open the browser and go to http://localhost:8762/actuator/routes to check all the routes that Zuul can use according to the Eureka
-
Open the browser and go to http://localhost:8888/frontend to check how Ribbon works
-
Open the browser and go to http://localhost:8762/ribbonclient/frontend to check how Zuul routes request
-
Open the browser and go to http://localhost:8888/swagger-ui.html to check the swagger dashboard for ribbon-client
-
Open the browser and go to http://localhost:9411/zipkin to check the Zipkin server dashboard