์ ์
Client-side Service Discovery
- Eureka๋ ์ฃผ์๊ฐ ๋์ ์ผ๋ก ๋ณํ๋ AWS์ ๊ฐ์ Cloud ์์คํ
ํ๊ฒฝ์์ ํด๋ผ์ด์ธํธ๊ฐ ์๋น์ค ์ธ์คํด์ค๋ฅผ ํธ์ถํ ์ ์๋๋ก ๊ฐ ์๋น์ค๋ค์
IP / Port / Instance ID
๋ฅผ ๊ฐ์ง๊ณ ์๋ REST ๊ธฐ๋ฐ์ ๋ฏธ๋ค์จ์ด ์๋ฒ์ ๋๋ค. - ์ฆ, Service Registry๋ฅผ ์ ๊ณตํ๊ณ ๊ด๋ฆฌํด์ฃผ๋ ์๋น์ค์ ๋๋ค.
Eureka ํ๋ ๊ด๋ จ
-
Service Registration
- ์๋น์ค๊ฐ ์๊ธฐ ์์ ์ ์ ๋ณด๋ฅผ Eureka ์๋ฒ์ ๋ฑ๋กํ๋ ํ๋
-
Service Registry
- ๋ฑ๋ก๋ ์๋น์ค๋ค์ ์ ๋ณด ๋ชฉ๋ก
-
Service Discovery
- ์๋น์ค ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด๊ณ ์ ํ๋ ๋์์ ์ ๋ณด๋ฅผ Service Registry๋ฅผ ํตํด ๋ฐ๊ฒฌํ๋ ๊ณผ์
Eureka ๊ตฌ์ฑ ์์ ๊ด๋ จ
-
Eureka Client
- ์๋น์ค๋ค์ ์์น ์ ๋ณด๋ฅผ ์์๋ด๊ธฐ ์ํด Eureka์ ์ ๋ณด๋ฅผ ์์ฒญํ๋ ์๋น์ค
-
Eureka Service
- Eureka Client์ ์ํด ๋ฐ๊ฒฌ์ ๋์์ด ๋๋๋ก Eureka์ ๋ฑ๋ก์ ์์ฒญํ ์๋น์ค
-
Eureka Server
- Eureka Service๊ฐ ์๊ธฐ ์์ ์ ๋ฑ๋ก(Service Registration)ํ๋ ์๋ฒ์ด์, Eureka Client๊ฐ ๋ฑ๋ก๋ ์๋น์ค ๋ชฉ๋ก(Service Registry)๋ฅผ ์์ฒญํ๋ ์๋ฒ
์๋น์ค ์ธ์คํด์ค์ ๋คํธ์ํฌ ์์น๋ฅผ ์ฐพ๊ณ ๋ก๋๋ฐธ๋ฐ์ฑํ๋ ์ญํ ์ ํด๋ผ์ด์ธํธ๊ฐ ๋ด๋นํฉ๋๋ค.
์๋น์ค ์ธ์คํด์ค๋ ์์๋ ๋ ์์ ์ ๋คํธ์ํฌ ์ฃผ์๋ฅผ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ(Service Registry) ์ ๋ฑ๋กํ๊ณ , ์๋น์ค ๋ ์ง์คํธ๋ฆฌ๋ ๊ฐ ์๋น์ค ์ธ์คํด์ค์ ์ํ๋ฅผ ๊ณ์ํด์ ์ฒดํฌํฉ๋๋ค.
ํด๋ผ์ด์ธํธ๋ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ์ ๋ฑ๋ก๋ ์ธ์คํด์ค ์ค ํ๋๋ฅผ ๊ณจ๋ผ์ ์์ฒญ์ ๋ณด๋ด๋ ๋ฐฉ์์ผ๋ก ๋ก๋ ๋ฐธ๋ฐ์ฑ(Load Balancing) ์ด ์ด๋ฃจ์ด์ง๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ธ์คํด์ค๊ฐ ์ข ๋ฃ๋๋ฉด ์๋น์ค ๋ ์ง์คํธ๋ฆฌ์ ๋ฑ๋ก๋ ์ ๋ณด๋ ์ญ์ ๋ฉ๋๋ค.
Netflix OSS๊ฐ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋์ค์ปค๋ฒ๋ฆฌ ํจํด์ ์ข์ ์์ ๋๋ค. Netflix Eureka๋ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ๋ก ์๋น์ค ์ธ์คํด์ค์ ๋ฑ๋ก๊ณผ ๊ฐ์ฉํ ์ธ์คํด์ค๋ฅผ ์ฐพ๋ REST API๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ Netflix Ribbon์ Eureka์ ๊ฐ์ด ๋์ํ๋ IPC ํด๋ผ์ด์ธํธ๋ก ๊ฐ๋ฅํ ์๋น์ค ์ธ์คํด์ค ๊ฐ ๋ก๋ ๋ฐธ๋ฐ์ฑ์ ํด์ค๋๋ค.
ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋์ค์ปค๋ฒ๋ฆฌ๋ Service Client๊ฐ Service Registry์์ ์ง์ ์๋น์ค์ ์์น๋ฅผ ์ฐพ์์ ํธ์ถํ๋ ๋ฐฉ์์ธ ๋ฐ๋ฉด์ ์๋ฒ ์ฌ์ด๋ ๋์ค์ปค๋ฒ๋ฆฌ๋ ์ผ์ข ์ Proxy ์๋ฒ์ธ ๋ก๋ ๋ฐธ๋ฐ์๋ก ์์ฒญ์ ๋จผ์ ๋ณด๋ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ก๋ ๋ฐธ๋ฐ์๋ Service Registry๋ฅผ ์กฐํํด์ ๊ฐ์ฉํ ์ธ์คํด์ค๋ฅผ ์ฐพ๊ณ ๊ทธ ์ค ์ ํํด์ ์์ฒญ์ ๋ผ์ฐํ ํ๋ ๋ฐฉ์์ ๋๋ค. Service Registry์ ๋ฑ๋ก๋๋ ๋ฐฉ์์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋์ค์ปค๋ฒ๋ฆฌ์ ๋์ผํฉ๋๋ค.
AWS Elastic Load Balancer(ELB) ๊ฐ ์๋ฒ ์ฌ์ด๋ ๋์ค์ปค๋ฒ๋ฆฌ ํจํด์ ์ข์ ์์ ๋๋ค. ELB๋ ์ผ๋ฐ์ ์ผ๋ก ์ธํฐ๋ท์์ ๋ค์ด์ค๋ ์ธ๋ถ ํธ๋ํฝ์ ๋ก๋ ๋ฐธ๋ฐ์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๊ณ , VPC(Virtual Private Cloud) ์์ ๋ด๋ถ ํธ๋ํฝ์ ์ฒ๋ฆฌํ ๋ ์ฌ์ฉ๋๊ธฐ๋ ํฉ๋๋ค. ํด๋ผ์ด์ธํธ์์ DNS ์ด๋ฆ์ ์ด์ฉํด ELB๋ก ์์ฒญ์ ๋ณด๋ด๋ฉด ELB๋ ๋ฑ๋ก๋ EC2(Elastic Compute Cloud) ์ธ์คํด์ค๋ ECS(EC2 Container Service) ์ปจํ ์ด๋ ์ฌ์ด์์ ๋ถํ๋ฅผ ๋ถ์ฐํฉ๋๋ค.
์๋น์ค ๋ ์ง์คํธ๋ฆฌ๋ ๊ฐ ์๋น์ค ์ธ์คํด์ค์ ๋คํธ์ํฌ ์์น ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ํญ์ ์ต์ ์ ๋ณด๋ฅผ ์ ์งํด์ผ ํ๋ฉฐ ๊ณ ๊ฐ์ฉ์ฑ์ด ํ์ํฉ๋๋ค.
๋ํ์ ์ธ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ์ธ Netflix Eureka๋ ์๋น์ค ์ธ์คํด์ค๋ฅผ ๋ฑ๋กํ๊ณ ์กฐํํ๋ REST ๊ธฐ๋ฐ API๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ฐ ์๋น์ค ์ธ์คํด์ค๋ POST
์์ฒญ์ผ๋ก ์์ ์ ๋คํธ์ํฌ ์์น๋ฅผ ๋ฑ๋กํ๊ณ 30์ด๋ง๋ค PUT
์์ฒญ์ผ๋ก ์์ ์ ์ ๋ณด๋ฅผ ๊ฐฑ์ ํฉ๋๋ค. ๋ฑ๋ก๋ ์๋น์ค ์ ๋ณด๋ DELETE
์์ฒญ์ด๋ ํ์ ์์์ผ๋ก ์ญ์ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฑ๋ก๋ ์๋น์ค ์ ๋ณด๋ GET
์์ฒญ์ผ๋ก ์กฐํํ ์ ์์ต๋๋ค.
๊ฐ ์๋น์ค๋ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ์ ๊ฐ์์ ์ ๋ณด๋ฅผ ๋ฑ๋กํ๊ณ ํด์ ํด์ผ ํ๋๋ฐ ์ฌ๊ธฐ์๋ ๋ ๊ฐ์ง ๋ฐฉ์์ด ์กด์ฌํฉ๋๋ค.
- ์ ํ ๋ฑ๋ก ํจํด (Self Registration Pattern): ์๋น์ค ์ค์ค๋ก ๋ฑ๋ก์ ๊ด๋ฆฌ
- ์จ๋ ํํฐ ๋ฑ๋ก ํจํด (3rd Party Registration Pattern): ์ 3์ ์์คํ ์์ ๋ฑ๋ก์ ๊ด๋ฆฌ
1) ์ ํ ๋ฑ๋ก ํจํด
๋ฑ๋ก๊ณผ ๊ด๋ฆฌ๋ฅผ ํ๋ ์ฃผ์ฒด๊ฐ ์๋น์ค์ธ ๋ฐฉ์์ ๋๋ค. ๊ฐ ์๋น์ค๋ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ์ ์์ ์ ์ ๋ณด๋ฅผ ๋ฑ๋กํ๊ณ , ํ์ํ๋ค๋ฉด ์ฃผ๊ธฐ์ ์ผ๋ก ์์ ์ด ์ด์ ์๋ค๋ ์ ํธ(Heartbeat)๋ฅผ ๊ณ์ ์ ์กํฉ๋๋ค. ๋ง์ฝ ์ด ์ ๋ณด๊ฐ ์ผ์ ์๊ฐ์ด ์ง๋๋ ์ค์ง ์๋๋ค๋ฉด ์๋น์ค์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒ์ผ๋ก ๋ณด๊ณ ๋ฑ๋ก์ด ํด์ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋น์ค๊ฐ ์ข ๋ฃ๋ ๋๋ ๋ฑ๋ก์ ํด์ ํฉ๋๋ค.
์์ ์ดํด๋ณธ Eureka Client๊ฐ ์ด์ ํด๋นํฉ๋๋ค. Spring์์๋ @EnableEurekaClient
์ด๋
ธํ
์ด์
์ ์ด์ฉํด ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
2) ์จ๋ ํํฐ ๋ฑ๋ก ํจํด
์ธ๋ถ์์ ์๋น์ค ๋ฑ๋ก์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค. ์๋น์ค ๋ฑ๋ก์ ๊ด๋ฆฌํ๋ ์๋น์ค ๋ ์ง์คํธ๋ผ(Service Registrar) ๋ฅผ ๋ฐ๋ก ๋๋ ๊ฒ์ ๋๋ค. ์๋น์ค ๋ ์ง์คํธ๋ผ๋ ๊ฐ ์๋น์ค ์ธ์คํด์ค์ ๋ณํ๋ฅผ ํด๋ง(Polling)์ด๋ ์ด๋ฒคํธ ๊ตฌ๋ ์ผ๋ก ๊ฐ์งํด์ ์๋น์ค ๋ ์ง์คํธ๋ฆฌ์ ๊ณ์ ์ ๋ฐ์ดํธํฉ๋๋ค.
1) ์์กด์ฑ ์ค์
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2) @EnableEurekaServer ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
3) ํ๋กํผํฐ ์ค์ (Config Server ๋ด์ eureka-server.yml)
registerWithEureka: false
-> Eureka Service์ ์์ ์ ๋ฑ๋กํ์ง ์๋๋คfetchRegistry: false
-> Registry ์ ๋ณด๋ฅผ ๋ก์ปฌ์ ์บ์ฑํ์ง ์๋๋ค
eureka:
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:8010/eureka/
1) ์์กด์ฑ ์ค์
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2) @EnableEurekaClient ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication
@EnableEurekaClient
public class LicenseServiceApplication {
public static void main(String[] args) {
SpringApplication.run(LicenseServiceApplication.class, args);
}
}
3) ํ๋กํผํฐ ์ค์ (Config Server ๋ด์ license-service.yml)
preferIpAddress: true
-> ์๋น์ค์ ํธ์คํธ ์ด๋ฆ์ด ์๋ IP ์ฃผ์๋ฅผ Eureka์ ๋ฑ๋กํ๋๋ก ์ง์
โ IP ์ฃผ์๋ฅผ ์ ํธํ๋ ์ด์
๊ธฐ๋ณธ์ ์ผ๋ก Eureka๋ ํธ์คํธ ์ด๋ฆ์ผ๋ก ์ ์ํ๋ ์๋น์ค๋ฅผ ๋ฑ๋กํฉ๋๋ค. ์ด๊ฒ์ DNS๊ฐ ์ง์๋ ํธ์คํธ ์ด๋ฆ์ ํ ๋นํ๋ ์๋ฒ ๊ธฐ๋ฐ ํ๊ฒฝ์์ ์ ๋์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ปจํ ์ด๋ ๊ธฐ๋ฐ์ ํ๊ฒฝ์์๋ DNS ์ํธ๋ฆฌ๊ฐ ์๋ ์์๋ก ์์ฑ๋ ํธ์คํธ ์ด๋ฆ์ ๋ถ์ฌ๋ฐ์ ์์ํฉ๋๋ค. ๋ฐ๋ผ์ ํด๋น ๊ฐ์ true๋ก ์ค์ ํ์ง ์๋๋ค๋ฉด ํด๋น ์ปจํ ์ด๋์ ๋ํ DNS ์ํธ๋ฆฌ๊ฐ ์์ผ๋ฏ๋ก ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํธ์คํธ ์ด๋ฆ์ ์์น๋ฅผ ์ ์์ ์ผ๋ก ์ป์ง ๋ชปํ๊ฒ ๋ฉ๋๋ค.
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8010/eureka/
Spring Cloud Config Server๋ ์คํ๋ง ๋ถํธ๋ก ๋ง๋ REST ๊ธฐ๋ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ถ์ฐ ์์คํ ์์ ํ๊ฒฝ์ค์ ์ ์ธ๋ถ๋ก ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํด์ค๋๋ค. Config Server๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ ํ๊ฒฝ(๊ฐ๋ฐ, ํ ์คํธ, ํ๋ก๋์ ๋ฑ)์ ๋ํ ์ดํ๋ฆฌ์ผ์ด์ ๋ค์ ์์ฑ์ ํ ๊ณณ์์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ์ค์ ๊ด๋ฆฌ์ ์ฉ์ด์ฑ
- ์ด์์ค์ ์๋ฒ ๋น๋ ๋ฐ ๋ฐฐํฌ๋ฅผ ๋ค์ ํ ํ์ ์์ด ํ๊ฒฝ์ค์ ๋ณ๊ฒฝ ๊ฐ๋ฅ
Spring Cloud Config Server
- ํ๊ฒฝ์ค์ (name-value pair, YAML ํ์ผ)์ ์ํ HTTP, ๋ฆฌ์์ค ๊ธฐ๋ฐ API
- ์์ฑ ๊ฐ ์ํธํ ๋ฐ ์ํธ ํด๋ (๋์นญ ๋๋ ๋น๋์นญ)
- @EnableConfigServer ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ Spring Boot ์ดํ์ผ์ด์ ์ ์ ์ฉ
Config Client(for Spring Boot ์ดํ๋ฆฌ์ผ์ด์ )
- Config Server์ ๋ถ์ด ์๊ฒฉ ์์ฑ ์์ค๋ก Spring ํ๊ฒฝ ์ด๊ธฐํ
- ์์ฑ ๊ฐ ์ํธํ ๋ฐ ์ํธ ํด๋ (๋์นญ ๋๋ ๋น๋์นญ)
์์กด์ฑ ์ค์
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
์ ํ๋ฆฌ์ผ์ด์ ํ๋กํผํฐ ์ค์ (application.yml)
spring:
application:
name: {application.name}
profiles:
active: git
cloud:
config:
server:
git:
uri: {remote.property.source.uri}
username: {username}
password: {password}
@EnableConfigServer ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication
@EnableConfigServer
public class PhotoAppApiConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(PhotoAppApiConfigServerApplication.class, args);
}
}
์์กด์ฑ ์ค์
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Remote Git Repository์ ํ๋กํผํฐ ํ์ผ ์์ฑ
- ์ฐ์ ์์: {application.name}-{profile}.yml > {application.name}.yml > application.yml
๋ถํธ์คํธ๋ํ ์ค์ (bootstrap.yml)
spring:
application:
name: {application.name}
profiles:
active: {profile}
cloud:
config:
uri: {config.server.uri}
- ์ด๋,
spring.application.name
์ ์๊ฒฉ ์ ์ฅ์์ ์๋ ํ์ผ๋ช ์ด๋ ๋์ผํด์ผ ํฉ๋๋ค. - ์๊ฒฉ ์ ์ฅ์์ ๋๋ ํฐ๋ฆฌ๋ณ๋ก ๊ด๋ฆฌ์ค์ด๋ผ๋ฉด
spring.cloud.config.server.git.searchPaths
๋ฅผ ์ถ๊ฐํด์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
- ๋ชจ๋๋ฆฌ์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋จ์ํ๊ฒ ๋ค๋ฅธ ๋ฉ์๋๋ ํจ์๋ฅผ ํธ์ถํ๋ฉด ๋ฉ๋๋ค.
- ํ์ง๋ง ๋ง์ดํฌ๋ก์๋น์ค์์๋ ์๋น์ค ๋จ์๋ก ๋๋์ด์ ธ ์๋ ๋ถ์ฐ ์์คํ ์ด๊ธฐ ๋๋ฌธ์ ์๋น์ค ๊ฐ์ ํต์ ์ด ํ์ํฉ๋๋ค.
- ์ด๋ฌํ ํต์ ์ **ํ๋ก์ธ์ค ๊ฐ ํต์ (Inter-Process Communication)**์ด๋ผ๊ณ ํฉ๋๋ค.
-
ํต์ ๋ฐฉ์์ ๋จผ์ ํธ์ถํ๋ ์ชฝ๊ณผ ํธ์ถ๋นํ๋ ์ชฝ์ ์๋ก ๊ตฌ๋ถํด๋ณผ ์ ์์ต๋๋ค.
-
ํ๋์ ์์ฒญ์ด ํ๋์ ์๋น์ค๋ฅผ ์คํํ๋ฉด ์ผ๋์ผ(One-to-One)
-
ํ๋์ ์์ฒญ์ด ์ฌ๋ฌ ์๋น์ค๋ฅผ ์คํํ๋ฉด ์ผ๋๋ค(One-to-Many)
-
๊ทธ๋ฆฌ๊ณ ๋๊ธฐ(Synchronous)์ ๋น๋๊ธฐ(Asynchronous)๋ก๋ ๊ตฌ๋ถํ ์ ์์ต๋๋ค.
-
๋๊ธฐ ๋ฐฉ์์ ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ด ์ฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๋ฐฉ์์ผ๋ก ์ดํ ๋์์ ๋ฉ์ถ ์ํ๊ฐ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ต์ ๋ฐ์ ํ์ ์ฒ๋ฆฌํฉ๋๋ค.
-
๋ฐ๋๋ก ๋น๋๊ธฐ ๋ฐฉ์์ ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ด ์ฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ค์์ ์คํํฉ๋๋ค.
-
1) ์์ฒญ / ์๋ต: ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ด ์ฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
-
2) ์๋ฆผ: ์์ฒญ์ ๋ณด๋ด๊ธฐ๋ง ํฉ๋๋ค. ๋ชจ๋ฐ์ผ์ ํธ์ ์๋ฆผ์ ์๊ฐํ์๋ฉด ๋ฉ๋๋ค.
-
3) ์์ฒญ / ๋น๋๊ธฐ ์๋ต: ์์ฒญ์ ๋ณด๋ด๋ฉด ๋น๋๊ธฐ๋ก ์๋ต์ด ์ต๋๋ค.
-
4) ํผ๋ธ๋ฆฌ์ / ๊ตฌ๋ : ๋ฑ๋ก๋ ์๋น์ค๋ค์ ์์ฒญ์ ๋ณด๋ ๋๋ค. ์์ฒญ์ ๋ฐ์ ์๋น์ค๋ค์ ๊ฐ์ ๋ก์ง์ ์ฒ๋ฆฌํฉ๋๋ค.
-
5) ํผ๋ธ๋ฆฌ์ / ๋น๋๊ธฐ ์๋ต: ์์ ๊ฐ์ง๋ง ๋น๋๊ธฐ ํํ๋ก ์๋ต์ ๋ณด๋ ๋๋ค.
-
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ๋ผ์ ํ๋์ ๋ฐฉ์๋ง์ผ๋ก๋ ์ถฉ๋ถํ๊ธฐ๋ ํ๊ณ , ์ฌ๋ฌ ๋ฐฉ์์ ํจ๊ป ์ฌ์ฉํ๊ธฐ๋ ํฉ๋๋ค. ๋ค์ ํ์ ํธ์ถ ์๋น์ค๋ฅผ ์๋ก ๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
-
- ์น๊ฐ์ด ๋ชจ๋ฐ์ผ๋ก ํฝ์ ์ ์์ฒญํฉ๋๋ค. ์ด ์์ฒญ์ ์ฌํ ๊ด๋ฆฌ ์๋น์ค๋ฅผ ํธ์ถํฉ๋๋ค (์๋ฆผ)
-
- ์ฌํ ๊ด๋ฆฌ ์๋น์ค๋ ์น๊ฐ ๊ด๋ฆฌ ์๋น์ค์์ ์น๊ฐ ์ ๋ณด๋ฅผ ํ์ธํฉ๋๋ค (์์ฒญ/์๋ต)
-
- ์ฌํ ๊ด๋ฆฌ ์๋น์ค๋ ํด๋น ์ฌํ์ ๋์คํจ์ฒ์ ๊ฐ๊น์ด ํ์๊ธฐ์ฌ์๊ฒ ๋ณด๋ ๋๋ค (ํผ๋ธ๋ฆฌ์/๊ตฌ๋ )
-
ํ์ ํธ์ถ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ก ๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
-
์น๊ฐ์ด ํ์๋ฅผ ๋ถ๋ฅผ ๋ REST API๋ฅผ ํธ์ถํ๊ฒ ๋ฉ๋๋ค. ์ด๋, POST ๋ฐฉ์์ผ๋ก
/trips
๋ฅผ ํธ์ถํ๊ฒ ๋ฉ๋๋ค. -
์ฌํ ๊ด๋ฆฌ ์๋น์ค์์ ์น๊ฐ์ ๋ํ ์ ๋ณด๋ฅผ ์กฐํํ๊ธฐ ์ํด, ์น๊ฐ ๊ด๋ฆฌ ์๋น์ค๊ฐ ์ ๊ณตํ๋ REST API๋ฅผ ์ฌ์ฉํด์ GET ๋ฐฉ์์ผ๋ก
/passengers/{passengerId}
๋ก ์์ฒญ์ ๋ณด๋ ๋๋ค. -
๊ทธ๋ผ ์น๊ฐ ID๋ก ์น๊ฐ ์ ๋ณด๋ฅผ ์กฐํํด์ ํด๋น ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์ฌํ ์ ๋ณด๋ฅผ ์ต์ข ์ ์ผ๋ก ์์ฑํ๊ฒ ๋ฉ๋๋ค.
-
REST๋ ๋๊ธฐ ๋ฐฉ์์ด๋ฏ๋ก ์์ฒญํ ๋ง์ดํฌ๋ก์๋น์ค๋ ์๋ต์ ๋ฐ์ ๋ง์ดํฌ๋ก์๋น์ค๊ฐ ์์ฒญ์ ์ฒ๋ฆฌํ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ฒ ๋ฉ๋๋ค.
-
๊ทธ๋ฆฌ๊ณ ํญ์ ์ผ๋์ผ ํต์ ๋ฐฉ์์ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
- ๋น๋๊ธฐ ๋ฐฉ์์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋๊ณ ์๋ต์ ๊ธฐ๋ค๋ฆฌ์ง ์์ต๋๋ค.
- ์ด ๋ฉ์์ง๋ Header์ Body๋ก ๊ตฌ์ฑ๋์ด ์๊ณ Channel์ ํตํด ์ ์ก๋ฉ๋๋ค.
- ๋ฉ์์ง๋ ํ ๊ณณ์์๋ง ๋ณด๋ผ ์ ์๊ณ (์ผ๋์ผ), ํผ๋ธ๋ฆฌ์/๊ตฌ๋ ๋ชจ๋ธ์ ๋ฐ๋ผ ์ฌ๋ฌ ๊ณณ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ์ ์์ต๋๋ค(์ผ๋๋ค).
- ์ฆ, ๊ทธ ๋ฉ์์ง๋ฅผ ๋ฐ๊ฒ ๋ค๊ณ ๊ตฌ๋ ํด๋์ ์๋น์ค์๊ฒ ๋ชจ๋ ๋ฉ์์ง๊ฐ ์ ์ก๋๋ ๊ฒ์ ๋๋ค.
- ์ด๋ฌํ ๋ฉ์์ง ๋ฐฉ์์ ํด๋ผ์ด์ธํธ์ ์๋น์ค ์ฌ์ด์ ์์กด๋๋ฅผ ์ค์ฌ์ค๋๋ค.
- ๋๊ธฐ ๋ฐฉ์์ ํด๋ผ์ด์ธํธ์ ์๋น์ค๊ฐ ์๋ก๋ฅผ ์์์ผ ํ๊ณ ์ง์ ํต์ ํ๋ ๊ตฌ์กฐ์ด์ง๋ง,
- ๋ฉ์์ง ๋ฐฉ์์ ๊ทธ ์ฌ์ด์ ๋ฉ์์ง ์์คํ ์ด ๋ค์ด๊ฐ์ ๊ฐ์ ์ ์ผ๋ก ํต์ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
- ์ผ๋์ผ ํต์ ๋ฟ๋ง ์๋๋ผ ์ผ๋๋ค ํต์ ์ ์ง์ํ๋ ๊ฒ๋ ์ฅ์ ์ ๋๋ค.
- ๋ฉ์์ง๋ฅผ ์ ์กํ๋ ํ์ค ํ๋กํ ์ฝ์ AMQP์ ๋๋ค.
- ๊ทธ๋ฆฌ๊ณ ์คํ์์ค ๋ฉ์์ง ์์คํ ์ ๋ํ์ ์ผ๋ก RabbitMQ์ Apache Kafka๊ฐ ์์ต๋๋ค.
- ์ฌํ ๊ด๋ฆฌ ์๋น์ค๋ ์ด๋ป๊ฒ ์น๊ฐ ๊ด๋ฆฌ ์๋น์ค๋ฅผ ์๊ณ ์์ฒญ์ ๋ณด๋ผ๊น์?
- ์ด๋ ์ฌ์ฉํ ์ ์๋ ๊ธฐ์ ์ Eureka Discovery Service์ ๋๋ค.
- ํด๋น ์ธ์คํด์ค๊ฐ ์คํ์ด ๋ ๋ Eureka Discovery Service๋ก ๋ฑ๋ก์ ํ๊ฒ ๋ฉ๋๋ค.
- ๊ทธ๋์ Eureka๋ ํ์ฌ ์คํ๋๊ณ ์๋ ๋ชจ๋ ์ธ์คํด์ค๋ค์ ์ฃผ์์ ํฌํธ ๋ฒํธ๋ฅผ ์๊ฒ ๋ฉ๋๋ค.
- ๊ทธ๋ฌ๋ฏ๋ก ์ฌํ ๊ด๋ฆฌ ์๋น์ค๋ Eureka๋ฅผ ํตํด์ ์์ฒญ์ ๋ณด๋ด์ผํ ์ฌ๋ฐ๋ฅธ ์ฃผ์์ ํฌํธ๋ฒํธ๋ฅผ ์๊ฒ ๋์ ์์ฒญ์ ๋ณด๋ผ ์ ์๊ฒ ๋ฉ๋๋ค.
RestTemplate ๋น ๋ฑ๋ก
@LoadBalanced
: ์คํ๋ง ํด๋ผ์ฐ๋๊ฐ Ribbon์ ์ง์ํ๋ RestTemplate ํด๋์ค๋ฅผ ์์ฑํ๋๋ก ์ง์
@SpringBootApplication
@EnableEurekaClient
public class PhotoAppApiUsersApplication {
public static void main(String[] args) {
SpringApplication.run(PhotoAppApiUsersApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
RestTemplate Client ์์ฑ
-
restTemplate.exchange({url}, {HTTP Method}, {HTTP Entity(Header/Body)}, {response type}, {parameter})
-
RestTemplate ํธ์ถ์์ ์๋น์ค์ ๋ฌผ๋ฆฌ์ ์์น๋ฅผ ์ฌ์ฉํ๋ ๋์ ํธ์ถํ๋ ค๋ ์๋น์ค์ ์ ๋ ์นด ์๋น์ค ID๋ฅผ ์ฌ์ฉํฉ๋๋ค(spring.application.name).
-
RestTemplate์ด Eurekaํํ
organization-service
์ ๋ํ ๋ชจ๋ ์ฃผ์๋ค์ ๋จผ์ ๋ฌผ์ด๋ณด๊ณ , ๋ฐ์ ์ฃผ์๋ค์ ๊ฐ์ง๊ณ ๋ก๋ ๋ฐธ๋ฐ์ฑ(๋ผ์ด๋ ๋ก๋น ๋ฐฉ์)์ ํตํด์ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋ฉ๋๋ค.
@Component
public class OrganizationRestTemplateClient {
@Autowired
private RestTemplate restTemplate;
public Organization getOrganization(String organizationId) {
ResponseEntity<Organization> restExchange =
restTemplate.exchange(
"http://organization-service/v1/organizations/{organizationId}",
HttpMethod.GET,
null,
Organization.class,
organizationId
);
return restExchange.getBody();
}
}
- REST ๊ธฐ๋ฐ ์๋น์ค ํธ์ถ์ ์ถ์ํํ Spring Cloud Netflix ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ์ ์ธ์ ๋ฐฉ์(Declarative REST Client)
- ์ธํฐํ์ด์ค๋ฅผ ํตํด ํด๋ผ์ด์ธํธ ์ธก ํ๋ก๊ทธ๋จ ์์ฑ
- Spring์ด ๋ฐํ์์ ๊ตฌํ์ฒด๋ฅผ ์ ๊ณต
์์กด์ฑ ์ค์
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients ์ด๋ ธํ ์ด์ ์ถ๊ฐ
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class PhotoAppApiUsersApplication {
public static void main(String[] args) {
SpringApplication.run(PhotoAppApiUsersApplication.class, args);
}
}
Feign Client ์ธํฐํ์ด์ค ์์ฑ
@FeignClient(name = "{service.name}")
-> ์ธํฐํ์ด์ค๋ฅผ ๋ํํ ์๋น์ค ์ ํ๋ฆฌ์ผ์ด์ ์ง์
@FeignClient(name = "organization-service", path = "v1/organizations/")
public interface OrganizationFeignClient {
@GetMapping(path = "{organizationId}", produces = MediaType.APPLICATION_JSON_VALUE)
Organization getOrganization(@PathVariable("organizationId") String organizationId);
}
Feign Client์ ๋ํ ๋ก๊น ์ค์
- ํจํค์ง ์ ์ฒด ํ์ฑํ
logging:
level:
com:
alexcode:
photoapp:
api:
users:
PhotoAppApiUsers:
feign: DEBUG
- ํน์ ํด๋ผ์ด์ธํธ๋ง ํ์ฑํ
logging:
level:
com:
alexcode:
photoapp:
api:
users:
PhotoAppApiUsers:
feign:
AlbumServiceClient: DEBUG
- ๋ก๊น ๋ ๋ฒจ์ ๋ํ ๋น ์์ฑ
@Configuration
public class FeignClientConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
- NONE: ๋ก๊น ์์, ๋ํดํธ๊ฐ
- BASIC: ์์ฒญ ํจ์, URL, ์๋ต ์ํ์ฝ๋๋ง์ ๋ก๊น
- HEADERS: BASIC์๋ค๊ฐ ์์ฒญ๊ณผ ์๋ต์ Header๊น์ง ๋ก๊น
- FULL: ์์ฒญ๊ณผ ์๋ต์ Body, Header ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ธ์ ๋ฉํ๋ฐ์ดํฐ๊น์ง ๋ก๊น