log

[MSA] MSA๋ž€? ์ด ์ •๋ฆฌ ๋ณธ๋ฌธ

๐Ÿ“‹ Project

[MSA] MSA๋ž€? ์ด ์ •๋ฆฌ

sun_young 2024. 6. 30. 21:38

๐Ÿ”Ž MSA(MicroService Architecture)๋ž€?

์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์€ ์„œ๋น„์Šค๋กœ ๊ตฌ์„ฑ๋˜์–ด ๊ฐ ์„œ๋น„์Šค๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐœ๋ฐœ๋˜๊ณ  ๋ฐฐํฌ๋˜๋Š” ๊ตฌ์กฐ

→ ์ „์ฒด ์‹œ์Šคํ…œ์ด ๋ถ„์‚ฐ๋˜์–ด ์žˆ์–ด ๊ฐœ๋ฐœ, ๋ฐฐํฌ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐ€๋Šฅํ•˜๋ฉฐ ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ์šฉ์ดํ•˜๋‹ค

๋”๋ณด๊ธฐ

 

์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ํšŒ์›, ๊ฐ์ • ๋ถ„์„ - ์ฃผ๋ฅ˜ ์ถ”์ฒœ, ์ฃผ๋ฅ˜ ๋ฆฌ๋ทฐ ๊ด€๋ฆฌ ์ด๋ ‡๊ฒŒ ์ด 3๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•˜์˜€๋‹ค

+ ๊ฐ ์„œ๋น„์Šค๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ DB!

 

 

 


 

๐Ÿ”Ž Netflix OSS Eureka Server

โœ… Spring Cloud Netflix

์Šคํ”„๋ง ๋ถ€ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ํ†ตํ•ฉ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ์ง€์›ํ•˜๋Š” Netflix์˜ OSS ์„œ๋น„์Šค

 

โœ… Eureka

Netflix OSS ์„œ๋น„์Šค ์ค‘ ํ•˜๋‚˜๋กœ ๊ฐ๊ฐ์˜ ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๋“ค์ด ๋™์ ์œผ๋กœ ํ™•์žฅ, ์ถ•์†Œ ๋˜๋”๋ผ๋„ ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ๋ฅผ ํ•˜๋‚˜์˜ ์„œ๋น„์Šค๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค

 

์ตœ์ดˆ์—๋Š” ๋ชจ๋“  ์„œ๋น„์Šค๊ฐ€ Spring Cloud์— ์˜ํ•ด์„œ ๊ด€๋ฆฌ๋˜์—ˆ์ง€๋งŒ ํ˜„์žฌ๋Š” ๋ช‡๋ช‡ ๊ธฐ์ˆ ๋“ค์„ ์žฌ๊ตฌ์„ฑ ํ˜น์€ ๋ฐœ์ „์‹œํ‚ค๊ฑฐ๋‚˜ ๋…๋ฆฝ์ ์ธ ์„œ๋น„์Šค๋กœ ์ง„ํ™”์‹œ์ผœ ๊ธฐ์กด์˜ ์„œ๋น„์Šค๋“ค์€ Maintenance ๋ชจ๋“œ๋กœ ๋“ค์–ด๊ฐ„ ๊ฒƒ๋“ค์ด ์กด์žฌํ•œ๋‹ค

* Maintenance : ๋ชจ๋“ˆ์„ ์œ ์ง€ ๋ณด์ˆ˜ ๋ชจ๋“œ๋กœ ์ „ํ™˜ํ•˜๋ฉด Spring-Cloud ํŒ€์ด ๋” ์ด์ƒ ๋ชจ๋“ˆ์— ์ƒˆ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค

 

<๊ตฌ์„ฑ>

Eureka๋Š” Eureka Server์™€ Eureka Client๋กœ ๊ตฌ์„ฑ๋œ๋‹ค

 

  • Eureka Server : Eureka Client์— ํ•ด๋‹นํ•˜๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋“ค์˜ ์ƒํƒœ ์ •๋ณด๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๊ฐ–๋Š”๋‹ค 
  • Eureka Client : ์„œ๋น„์Šค๊ฐ€ ์‹œ์ž‘๋  ๋•Œ Eureka Server์— ์ž์‹ ์˜ ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•œ๋‹ค. ๋“ฑ๋ก๋œ ํ›„์—๋Š” 30์ดˆ๋งˆ๋‹ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ping์„ ์ „์†กํ•˜์—ฌ ์ž์‹ ์ด ๊ฐ€์šฉ ์ƒํƒœ์ž„์„ ์•Œ๋ฆฌ๋Š”๋ฐ ์ผ์ • ํšŸ์ˆ˜ ์ด์ƒ ping์ด ํ™•์ธ๋˜์ง€ ์•Š์œผ๋ฉด Eureka Server์—์„œ ํ•ด๋‹น ์„œ๋น„์Šค๋ฅผ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ์ œ์™ธ์‹œํ‚จ๋‹ค
๋”๋ณด๊ธฐ

 

<ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๊ธฐ>

1. Service Discovery Sever ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

์ด๋•Œ, ์•„๋ž˜์™€ ๊ฐ™์ด dependency ์ฐฝ์—์„œ Eureka Server๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค

 

2. eureka ์„œ๋ฒ„์˜ application.yml ํŒŒ์ผ ์ถ”๊ฐ€

spring:
  application:
    name: eureka

server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

- register-with-eureka : ์œ ๋ ˆ์นด ์„œ๋น„์Šค ๋“ฑ๋ก ์—ฌ๋ถ€

- fetch-registry : ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ •๋ณด ์บ์‹ฑ ์—ฌ๋ถ€

 

3. @EnableEurekaServer ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaApplication.class, args);
	}

}

 

4. ๊ฒŒ์ดํŠธ์›จ์ด ์„œ๋น„์Šค ์ƒ์„ฑ

์ด๋•Œ, ์•„๋ž˜์™€ ๊ฐ™์ด dependency ์ฐฝ์—์„œ Gateway๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค + Eureka Discovery Client๋„ ์ถ”๊ฐ€

 

5. ๊ฒŒ์ดํŠธ์›จ์ด ์„œ๋น„์Šค ํ”„๋กœ์ ํŠธ์˜ application.yml ์ž‘์„ฑ

eureka:
  instance:
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

- prefer-ip-address : ์œ ๋ ˆ์นด ์„œ๋น„์Šค ๋“ฑ๋ก ์—ฌ๋ถ€

- register-with-eureka : ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ž์‹ ์„ ๋“ฑ๋กํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์—ฌ๋ถ€

- fetch-registry : ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์žˆ๋Š” ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์—ฌ๋ถ€

 

6. ๊ฒŒ์ดํŠธ์›จ์ด  ์„œ๋น„์Šค ํ”„๋กœ์ ํŠธ์—๋„ ๋™์ผํ•˜๊ฒŒ @EnableEurekaServer ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค

 

7. Eureka Server์— Service ๋“ฑ๋ก

Service ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ํ›„ Eureka Discovery Client ์ถ”๊ฐ€

(Spring Web๋„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค)

 

8. ์„œ๋น„์Šค ํ”„๋กœ์ ํŠธ์˜ application.yml ํŒŒ์ผ ์ž‘์„ฑ

eureka:
  instance:
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 30
  client:
    registry-fetch-interval-seconds: 30
    disable-delta: true
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

- registry-fetch-interval-seconds : ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ •๋ณด ์บ์‹ฑ ์—ฌ๋ถ€

- disable-delta : ์œ ๋ ˆ์นด ์„œ๋ฒ„์—๊ฒŒ ์„œ๋น„์Šค ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ๋งŒ ๊ฐ€์ง€๊ณ  ์˜ค๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์—ฌ๋ถ€

 

9. ์„œ๋น„์Šค ํ”„๋กœ์ ํŠธ์—๋„ ๋™์ผํ•˜๊ฒŒ @EnableEurekaServer ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค

 

 

๐Ÿ“ข ์š”์ฒญ ๋ณด๋‚ด๊ธฐ

 

http://localhost:9000/auth/login์œผ๋กœ ์š”์ฒญํ•˜๋ฉด ๊ฒŒ์ดํŠธ์›จ์ด ์„œ๋น„์Šค๊ฐ€ ์ด๋ฅผ auth ์„œ๋น„์Šค์˜ /login ๊ฒฝ๋กœ๋กœ ๋ผ์šฐํŒ…ํ•œ๋‹ค

auth ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ ๊ฒŒ์ดํŠธ์›จ์ด์—์„œ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ธ์ฆ์ฒ˜๋ฆฌ๋Š” ์ง„ํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค 

 


๐Ÿ”Ž ํ•„ํ„ฐ ์ถ”๊ฐ€ํ•˜๊ธฐ

API Gateway๋Š” API ์„œ๋ฒ„ ์•ž๋‹จ์—์„œ ๋ชจ๋“  API ์„œ๋ฒ„๋“ค์˜ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋‹จ์ผํ™” ํ•ด์ฃผ๋Š” ๋˜ ๋‹ค๋ฅธ ์„œ๋ฒ„์ด๋‹ค

API์— ๋Œ€ํ•œ ์ธ์ฆ๊ณผ ์ธ๊ฐ€ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๋ฉ”์‹œ์ง€์˜ ๋‚ด์šฉ์— ๋”ฐ๋ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด๋ถ€์— ์žˆ๋Š” ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค๋กœ ๋ผ์šฐํŒ…ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค

→ ์ด๋•Œ Filter ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์กฐ๊ฑด์„ ๋ถ„๊ธฐํ•œ๋‹ค

 

gateway:
      routes:
        - id: auth
          uri: http://localhost:8090/
          predicates:
                - Path=/auth/**
        - id: analyze
          uri: http://localhost:8091/
          predicates:
            - Path=/analyze/**
          filters:
            - name: AuthorizationHeaderFilter

 

๋ผ์šฐํŒ… ์„ค์ • ์•„๋ž˜์— filters๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ผ๋ฐ˜ ์ปค์Šคํ…€ ํ•„ํ„ฐ(AuthorizationHeaderFilter)๋ฅผ ์ ์šฉํ•˜์˜€๋‹ค

auth ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ์—๋Š” ์ธ์ฆ ์š”์ฒญ์„ ์ง„ํ–‰ํ•˜์ง€ ์•Š์œผ๋ฉฐ analyze ์„œ๋น„์Šค์— ๋Œ€ํ•ด ์ธ์ฆ์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค

 

@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {

    public AuthorizationHeaderFilter() {
        super(Config.class);
    }

    public static class Config {
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
           
        };
    }
}

 

 

AuthorizationHeaderFilter์—๋Š” jwt ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๋‹ค

 

 


๐Ÿ”Ž ์„œ๋น„์Šค ๊ฐ„ ํ†ต์‹ ์€ ์–ด๋–ป๊ฒŒ?

์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ํšŒ์›์ด ์ฃผ๋ฅ˜ ๋ฆฌ๋ทฐ๋ฅผ ๋‚จ๊ธธ ๋•Œ ํ•ด๋‹น ํšŒ์›์˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ๋ฐ ์ฃผ๋ฅ˜ ๋ฆฌ๋ทฐ ์„œ๋น„์Šค์™€ ํšŒ์› ์„œ๋น„์Šค๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— MSA๊ฐ„์˜ ํ†ต์‹ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ–ˆ๋‹ค

 

1๏ธโƒฃ RestTemplate 

HTTP ํ†ต์‹ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค๋ฅธ MSA์— ์š”์ฒญ์„ ๋‚ ๋ฆฌ๊ณ  ์–ป์–ด์˜จ ์‘๋‹ต์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค

 

 

2๏ธโƒฃ FeignClient

Feign์€ ์„œ๋น„์Šค ๊ฐ„ ํ†ต์‹ ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค

๋‚ด๋ถ€์ ์œผ๋กœ HTTP ํ†ต์‹  ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ค€๋‹ค

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ณ  ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ RESTful ์„œ๋น„์Šค ๊ฐ„์˜ ํ†ต์‹ ์„ ์ง์ ‘ ์ •์˜ํ•˜์ง€ ์•Š๊ณ  ์ธํ„ฐํŽ˜์ด์Šค ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค

(์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” FeginClient๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค)

 

@FeignClient(name = "auth-service", url = "http://sunjoo-server-auth-spring-1:8090")
public interface UserClient {

    @GetMapping("/auth/userinfo")
    UserInfoResponse getUserInfo(@RequestHeader("Authorization") String token);
}

๋”ฐ๋กœ UserClinet ํด๋ž˜์Šค ์ƒ์„ฑ ํ›„ ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค

 

name์—๋Š” ๋‹ค๋ฅธ MSA์˜ ์ด๋ฆ„์„ ์ ์–ด์ฃผ๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ GET์œผ๋กœ auth-service์˜ /auth/userinfo๋กœ ์š”์ฒญ์„ ์ •์˜ํ•˜๊ณ  ์š”์ฒญ ํ—ค๋”์— ํ† ํฐ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค