๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

25-03-19

๐Ÿ“Œ Daily Reportโ€‹

https://github.com/ssginc-be/DOKI/issues/126


๐Ÿ“Œ ํ”„๋กœ์ ํŠธ ์ƒํ™ฉโ€‹

์•ˆํƒ€๊น๊ฒŒ๋„ ๋‚ด ์ฒด๋ ฅ์ด ์˜์ง€์— ์•ˆ ๋”ฐ๋ผ์ฃผ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๋ชจ๋‹ˆํ„ฐ๋ฅผ ๋ชป ์ณ๋‹ค๋ณด๊ฒ ์„ ์ •๋„๋กœ ํŽธ๋‘ํ†ต์— ์•ˆ๊ตฌ๊ฑด์กฐ์ฆ์— ๋ฌต์งํ•œ ํ”ผ๋กœ์— ๋ญ”์ง€ ๋ชจ๋ฅผ ๋ถ• ๋œฌ ๋Š๋‚Œ๊นŒ์ง€ ๋“ค์–ด์„œ ๊ฑฐ์˜ ๋ˆˆ ๊ฐ์€์ฑ„๋กœ ๋ณ‘์›์— ๊ฐ”๋‹ค.

ํ…์ŠคํŠธ๋งŒ ๋ณด๋ฉด ๋ญ”๊ฐ€ ์ƒ์ƒ‰๋‚ด๋Š”๊ฑฐ ๊ฐ™์€๋ฐ ์ €๊ฒŒ ๋‹ค ์ข…ํ•ฉ์„ธํŠธ๋กœ ์˜ค๋‹ˆ๊นŒ ์–ต์ง€๋กœ ๋ชจ๋‹ˆํ„ฐ ๋ณด๋ฉด์„œ ์ž‘์—…ํ•ด๋„ ํ•œ 70%๋Š” ๋ฉ๋•Œ๋ฆด ๊ฒƒ ๊ฐ™์„ ์ •๋„๋กœ ํž˜๋“ค์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ˆ˜์•ก 2์ข…๋ฅ˜ ์„ž์–ด ๋งž๊ณ  ์ง„ํ†ต์ œ๋„ ์ฒ˜๋ฐฉ๋ฐ›์•˜๋Š”๋ฐ, ์ข€ ๋น„์‹ผ๊ฒŒ ํ ์ด์ง€๋งŒ ๊ธฐ์ ๊ฐ™์ด ์ง€์˜ฅ์—์„œ ์‚ด์•„๋‚˜์™”๋‹ค; ์†”์งํžˆ ๊ธฐ๋Œ€ ์•ˆํ–ˆ๋Š”๋ฐ ๋ฌด์Šจ ๋ฏธ๋ž˜ ์ˆ˜๋ช… ๋•ก๊ฒจ์˜จ์ค„ ใ…‹ใ…‹ใ…‹

์ƒํƒœ๊ฐ€ ํ˜ธ์ „๋ผ์„œ ๋‹คํ–‰์ด์ง€๋งŒ ๋‚ด์‹ฌ ์งœ์ฆ์ด ๋‚œ๋‹ค.

์•„๋‹ˆ ์™œ ์ฒด๋ ฅ์ด ํ˜‘์กฐ๋ฅผ ์•ˆํ•ด์ฃผ์ง€?

๋‚ด๊ฐ€ ์–ผ๋งˆ๋‚˜ ์•„์นจ์—๋„ ๋‚ฎ์—๋„ ์ €๋…์—๋„ ์ƒˆ๋ฒฝ์—๋„ ๊ฐœ๋ฐœํ•˜๊ณ  ์‹ถ์€๋ฐ? ์ง€๊ธˆ ํ• ๊ฒŒ ์–ผ๋งˆ๋‚˜ ๋งŽ์€๋ฐ?


๐Ÿ“Œ ๋ฌด์˜๋ฏธํ•œ synchronizedโ€‹

์˜ˆ์•ฝ ๋™์‹œ์„ฑ TDD๊ฐ€ ๋“œ๋””์–ด ๋งˆ๋ฌด๋ฆฌ ๋˜์—ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋Š” 10000๋ช…์˜ ์ •์›์„ ๊ฐ€์ง„ ์—”ํŠธ๋ฆฌ์— ๋Œ€ํ•˜์—ฌ 50000๊ฐœ์˜ ๋™์‹œ ์˜ˆ์•ฝ ์‹œ๋„๋ฅผ ๊ฑธ์—ˆ๋Š”๋ฐ, ๊ฐ’์ด ํฌ๋‹ค๋ณด๋‹ˆ ํ™˜๊ฒฝ ์„ธํŒ…๋„ ๋“ค์–ด๊ฐ€์„œ ์ƒ๊ฐ๋ณด๋‹ค ๊นŒ๋‹ค๋กญ๋”๋ผ. ์ผ๋‹จ ๋‹ค์Œ์˜ ์„ค์ •๋“ค์ด ํ•„์š”ํ–ˆ๋‹ค.


  1. MySQL์˜ max-connections ๋Š˜๋ฆฌ๊ธฐ (-> ํด๋ผ์ด์–ธํŠธ ์ ‘์†ํ•ด์„œ ์„ค์ •)
  2. JVM heap memory ๋Š˜๋ฆฌ๊ธฐ (-> gradle ํŒŒ์ผ์—์„œ ์„ค์ • [๋ ˆํผ๋Ÿฐ์Šค])
  3. hikari max-pool ๋ฐ timeout ๋Š˜๋ฆฌ๊ธฐ (-> yml์—์„œ ์„ค์ •)

ํ•˜๋‹จ์€ ๋ณ„๋‹ค๋ฅธ ์ฒ˜๋ฆฌ ์—†์ด ์„œ๋น„์Šค์— @Transactional๋งŒ ๋ถ™์ธ ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ๊ณผ์ด๋‹ค.

test_result_none


๊ทธ๋ฆฌ๊ณ  ์ด๊ฑด ์„œ๋น„์Šค์— synchronized ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ๊ณผ์ด๋‹ค.

test_result_synchronized

๊ฒฐ๊ณผ๊ฐ€ ๋” ์•ˆ์ข‹์Œ ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹

synchronized์— ๋Œ€ํ•œ ๋ณด์™„์ฑ…๊ณผ ๊ทธ ๋ณด์™„์ฑ…์˜ ํ•œ๊ณ„์ ์€ ์—ฌ๊ธฐ์„œ ์ž˜ ์„ค๋ช…ํ•ด์ฃผ์—ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ, ํ˜„์žฌ ์ƒํ™ฉ์— ํ•„์š”ํ•œ ์กฐ๊ฑด์„ ๋‹จ๊ธฐ๊ฐ„์˜ ๊ฐœ๋ฐœ ์ผ์ •์— ๋งŒ์กฑํ•˜๋ ค๋ฉด Pessimistic Lock์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.


๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด๊ฑด Pessimistic Lock์„ ์ ์šฉํ•œ ๊ฒฐ๊ณผ์ด๋‹ค.

test_result_pm_lock


๐Ÿ“Œ API Gateway์˜ ํŽธ๋ฆฌํ•œ uri ์„ค์ •โ€‹

ํ˜„์žฌ API Gateway์˜ ๋ผ์šฐํŒ…์€ ์ด๋Ÿฐ์‹์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค.

application.yml
spring:
gateway:
routes:
############## RESERVE-SERVICE ##############
######## [reserve-service] REST APIs ########
- id: reserve-service
uri: http://localhost:9091 # 2) localhost:9000 ๋ง๊ณ  ์—ฌ๊ธฐ๋กœ ๋ณด๋‚ด์คŒ
predicates: # 1) ์—ฌ๊ธฐ๋กœ ์ ‘์† ์‹œ๋„ํ•˜๋ฉด
- Path=/v2/reserve/**

############## COMMON-SERVICE ###############
##### [common-service] Public Endpoints #####
- id: common-service
uri: http://localhost:9093
predicates:
- Path=/, /auth/**, /search, /store, /noti/**, /v1/auth/**, /v1/auth/**, /v1/store/**
filters:
- PublicFilter
###### [common-service] Member Endpoints #####
- id: common-service
uri: http://localhost:9093
predicates:
- Path=/member/**, /reserve/**, /v1/member/**, /v1/reserve/**
filters:
- MemberAuthFilter
###### [common-service] Manager Endpoints #####
- id: common-service
uri: http://localhost:9093
predicates:
- Path=/store/reserve/**
filters:
- ManagerAuthFilter
###### [common-service] Admin Endpoints #####
- id: common-service
uri: http://localhost:9093
predicates:
- Path=/store/registration
filters:
- AdminAuthFilter
########### static files ##############
- id: common-service
uri: http://localhost:9093
predicates:
- Path=/css/**, /js/**, /icon/**, /img/**

์ด๋Ÿฌํ•œ ์„ค์ •์˜ ๋ฌธ์ œ๋ผ๋ฉด, ์ถ”ํ›„ ํฌํŠธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๊ฑธ๋ฆด ํ™•๋ฅ ์ด ๋†’๋‹ค๋Š” ์ ์ด๋‹ค.

๋ฌผ๋ก  ํ…Œ์ŠคํŠธ ๊ณผ์ •์—์„œ ๋‹ค ๊ฑธ๋ฆฌ๊ฒ ์ง€๋งŒ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ๋ณดํ†ต ๊ท€์ฐฎ์€๊ฒŒ ์•„๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•˜๋Š๋ƒ? ์‚ฌ์‹ค API Gateway๋Š” Service Discovery์— ๋“ฑ๋ก๋œ ์„œ๋น„์Šค๋ช…์œผ๋กœ uri๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ์ง€์›ํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ด๋Ÿฐ์‹์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

application.yml
spring:
gateway:
routes:
############## RESERVE-SERVICE ##############
######## [reserve-service] REST APIs ########
- id: reserve-service
uri: lb://RESERVE-SERVICE # 2) localhost:9000 ๋ง๊ณ  ์—ฌ๊ธฐ๋กœ ๋ณด๋‚ด์คŒ
predicates: # 1) ์—ฌ๊ธฐ๋กœ ์ ‘์† ์‹œ๋„ํ•˜๋ฉด
- Path=/v2/reserve/**

############## COMMON-SERVICE ###############
##### [common-service] Public Endpoints #####
- id: common-service
uri: lb://COMMON-SERVICE
predicates:
- Path=/, /auth/**, /search, /store, /noti/**, /v1/auth/**, /v1/auth/**, /v1/store/**

๊ทธ๋ž˜์„œ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ Nginx ์•ˆ์“ฐ๋ƒ๊ณ  ๋งˆ๋ฅด๊ณ  ๋‹ณ๋„๋ก ๋“ค์—ˆ๋Š”๋ฐ, ์“ธ ํ•„์š”๋ฅผ ๋ชป๋Š๋ผ๊ฒ ๋‹ค.


๐Ÿ“Œ latest ํ•˜์ง€ ์•Š์€ latestโ€‹

1.0.0-beta.6์„ ๋ฆด๋ฆฌ์ฆˆํ•œ ํ›„, https ์„ค์ • ๋•Œ๋ฌธ์— ๋จผ์ € http ์ชฝ์— ์ด์ƒ์ด ์—†๋Š”์ง€ ํ™•์ธํ•˜๋ ค ํ–ˆ๋‹ค.

๊ทผ๋ฐ 404๊ฐ€ ๋–ด๋‹ค. ใ…‡ใ„ด

404_page

์ฒ˜์Œ์—๋Š” docker network ํ™˜๊ฒฝ์„ ์˜์‹ฌํ–ˆ๋‹ค. ๋ผ์šฐํŒ… uri๋ฅผ ๊ทธ๋ƒฅ localhost๋ผ๊ณ  ์จ๋†จ์œผ๋‹ˆ...

์•„๋งˆ compose ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์กฐ์ •ํ•ด์ฃผ๋ฉด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ € ๋งŽ์€ route๋ฅผ ๋‹ค ์–ด๋–ป๊ฒŒ? ๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค์—ˆ๋‹ค.

์ด๋ฅผ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ์ด๊ณณ์ €๊ณณ ๋ ˆํผ๋ฅผ ์ฐพ์•„๋ดค๋Š”๋ฐ, ๊ฒฐ๊ตญ์—” ๊ทธ๋ƒฅ ๋ˆ„๊ฐ€ ๊นƒํ—ˆ๋ธŒ์— ์˜ฌ๋ ค๋†“์€ ์ฝ”๋“œ์—์„œ ํ•ด๋‹ต์„ ์–ป์—ˆ๋‹ค.

๋ฌธ๋ฒ•์ด ์ข€ ํŠน์ดํ•˜๋”๋ผ.


๐Ÿ˜‰ ์‘ ์ „๋ถ€ ๋‹ค ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์จโ€‹

Image

๊ทผ๋ฐ ๊ทธ๋Œ€๋กœ ์ ์šฉํ•˜๊ณ  ๋ฐฐํฌํ–ˆ์„๋•Œ ๊ฒŒ์ดํŠธ์›จ์ด๊ฐ€ ํ„ฐ์ ธ์žˆ๊ธธ๋ž˜ ๋กœ์ปฌ์—์„œ compose up์œผ๋กœ ๋กœ๊ทธ๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค.

Image

predicates๊ฐ€... ์™œ ๋‚ ๋ผ๊ฐ„๊ฑฐ์ง€;?

Image

(์ฐธ๊ณ ๋กœ ์ €๊ฒŒ locale์„ ๋”ฐ๋ผ๊ฐ€์„œ IDEA์—์„  ํ•œ๊ตญ์–ด ๋กœ๊ทธ๋ฅผ ๋„์›Œ์คŒ. ๊ท€์—ฝ๋‹ค ใ…‹ใ…‹)


๊ฒฐ๊ตญ ์ด๋Ÿฐ์‹์œผ๋กœ ๋…ธ๊ฐ€๋‹คํ•ด์ฃผ๋‹ˆ๊นŒ ํ„ฐ์ง€์ง„ ์•Š์•˜๋‹ค.

ํ•˜์ง€๋งŒ ์ด ๋…ธ๊ฐ€๋‹ค๋ฅผ ์“ฐ๋Š๋‹ˆ ๊ทธ๋ƒฅ ๋กœ์ปฌ์—์„œ๋„ lb://~ ๊ฐ€ ๋‚˜์€๋ฐ ๋กœ์ปฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ต์ฒดํ•˜๋Š”๊ฒŒ ๋‚ซ๊ฒ ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์–˜๋„ ํ…Œ์ŠคํŠธํ•˜๋‹ˆ๊นŒ ์—ฌ์ „ํžˆ 404์˜€๋‹ค.

compose.yml
services:
api-gateway:
environment:
eureka.client.serviceUrl.defaultZone: http://service-discovery:8761/eureka
SPRING_CLOUD_GATEWAY_ROUTES[0]_URI: lb://RESERVE-SERVICE
SPRING_CLOUD_GATEWAY_ROUTES[0]_PREDICATES[0]: Path=/v2/reserve/**
SPRING_CLOUD_GATEWAY_ROUTES[1]_URI: lb://COMMON-SERVICE
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[0]: Path=/
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[1]: Path=/auth/**
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[2]: Path=/search
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[3]: Path=/store
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[4]: Path=/noti/**
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[5]: Path=/v1/auth/**
SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[6]: Path=/v1/store/**
SPRING_CLOUD_GATEWAY_ROUTES[2]_URI: lb://COMMON-SERVICE
SPRING_CLOUD_GATEWAY_ROUTES[2]_PREDICATES[0]: Path=/member/**
SPRING_CLOUD_GATEWAY_ROUTES[2]_PREDICATES[1]: Path=/reserve/**
SPRING_CLOUD_GATEWAY_ROUTES[2]_PREDICATES[2]: Path=/v1/member/**
SPRING_CLOUD_GATEWAY_ROUTES[2]_PREDICATES[3]: Path=/v1/reserve/**
SPRING_CLOUD_GATEWAY_ROUTES[3]_URI: lb://COMMON-SERVICE
SPRING_CLOUD_GATEWAY_ROUTES[3]_PREDICATES[0]: Path=/store/reserve/**
SPRING_CLOUD_GATEWAY_ROUTES[4]_URI: lb://COMMON-SERVICE
SPRING_CLOUD_GATEWAY_ROUTES[4]_PREDICATES[0]: Path=/store/registration
SPRING_CLOUD_GATEWAY_ROUTES[5]_URI: lb://COMMON-SERVICE
SPRING_CLOUD_GATEWAY_ROUTES[5]_PREDICATES[0]: Path=/css/**
SPRING_CLOUD_GATEWAY_ROUTES[5]_PREDICATES[1]: Path=/js/**
SPRING_CLOUD_GATEWAY_ROUTES[5]_PREDICATES[2]: Path=/icon/**
SPRING_CLOUD_GATEWAY_ROUTES[5]_PREDICATES[3]: Path=/img/**

๐Ÿ™„ ๋Œ€์ฒด ๋ญ๊ฐ€ ๋ฌธ์ œ์•ผโ€‹

๊ฒฐ๊ตญ 9093๋ฒˆ ํฌํŠธ ์ธ๋ฐ”์šด๋“œ๋ฅผ ์—ด์–ด์„œ ๊นŒ๋ดค๋Š”๋ฐ, common-service ์ž์ฒด๊ฐ€ 404์˜€๋‹ค.

...๋ผ์šฐํŒ…์€ ๋จนํ˜”๋˜ ๊ฒƒ์ด๋‹ค.

404๊ฐ€ ๋œฌ๋‹ค๋Š” ๊ฒƒ์€ ํƒ€์ž„๋ฆฌํ”„ ํ…œํ”Œ๋ฆฟ์ด ์—†๋‹ค๋Š”๊ฑด๋ฐ ์ด๊ฒŒ CORS๋กœ ํ„ฐ์กŒ์„๋ฆฌ๋„ ์—†๊ณ  ์ง„์งœ ํŒŒ์ผ์ด ์ปจํ…Œ์ด๋„ˆ ๋ณผ๋ฅจ์— ์—†์„๋ฆฌ๋„ ์—†๊ณ 

๊ณฐ๊ณฐํžˆ ์ƒ๊ฐํ•˜๋‹ค๊ฐ€ ํ˜„์žฌ ๋ฐฐํฌ๋œ ์ด๋ฏธ์ง€๊ฐ€ ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ๋ฒ„์ „์—์„œ ์—…๋Žƒ์ด ์•ˆ๋œ๊ฑธ์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค๋Š” ์˜์‹ฌ์ด ๋นก ๋“ค์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด ๋ ˆํผ๋Ÿฐ์Šค์—์„œ ๋˜‘๊ฐ™์€ ๋ง์„ ํ•˜๊ณ  ์žˆ๋‹ค.

Best practice is generally to be explicit in your docker run and similar commands: use a unique tag for every image build (like a date stamp, source control commit ID, or build number), use that specific version/build number when youโ€™re deploying, and donโ€™t rely on things like the latest tag.

The trick here is that if you docker run someimage:latest, Docker first starts by looking at its local list of images. If it already has something with that exact name and tag, it just runs it; if not, it will implicitly docker pull first. This extends to higher-level orchestration systems too (you have to go fairly far out of your way to get Kubernetes to force it to reload an image, for example).

์•„. ๋ญ”๊ฐ€ ์˜ˆ์ „๋ถ€ํ„ฐ ์ปจํ…Œ์ด๋„ˆ ๋ฒ„์ „ ๋‚˜๋ˆ ์•ผ ํ•˜์ง€ ์•Š๋‚˜ ํ•˜๊ณ  ์‹ ๊ฒฝ์“ฐ์˜€๋˜๊ฒŒ ์‹œ๊ฐ„ ์—†์–ด์„œ ๋„˜์–ด๊ฐ”๋Š”๋ฐ ์Šค๋…ธ์šฐ๋ณผ์ด ๋˜์–ด์„œ ๋Œ์•„์˜ด

์ˆ˜๋™ ๋ฐฐํฌํ•ด๋ณด๋‹ˆ๊นŒ ์„œ๋น„์Šค ์ž˜ ๋œจ๋”๋ผ.

ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹

๊ทธ๋ž˜์„œ ์ˆ˜๋™ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ธ‰ํ•˜๊ฒŒ ๋งŒ๋“ค๊นŒ ๋ง๊นŒ ํ•˜๋‹ค๊ฐ€, ๊ทธ๋ƒฅ CI๋ฅผ 1์ฐจ์ ์œผ๋กœ ๊ณ ์น˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

์ด์ƒ์ ์ธ๊ฑด ๋‚ด๊ฐ€ ์š”์ฆ˜ ์ž๊พธ gradle์—์„œ ํ”„๋กœ์ ํŠธ ๋ฒ„์ „์—…์„ ๊นŒ๋จน์œผ๋‹ˆ๊นŒ ์ด๊ฑธ ํ‹€์–ด๋ง‰๋Š”๊ฑฐ๋ž‘

์˜ฅํ† ํ‚ท์œผ๋กœ ์ปค๋ฐ‹ ํŒŒ์‹ฑํ•ด์„œ ์ž๋™์œผ๋กœ CI์— ๋ณ€๊ฒฝ๋œ ๋ฒ„์ „ ๋ฐ˜์˜ํ•˜๋Š”๊ฑด๋ฐ...

์‹œ๊ฐ„์ด ์—†์œผ๋‹ˆ ๋ฆด๋ฆฌ์ฆˆ๋งˆ๋‹ค CI๋ฅผ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ฃผ๊ธฐ๋กœ ํ•˜๊ณ , ๋ฒ„์ „ ๋“ค์–ด๊ฐ€๋Š” ๋ถ€๋ถ„์„ ๋”ฐ๋กœ ๋ณ€์ˆ˜ํ™”ํ•ด์„œ 1์ฐจ๋ผ๊ณ  ์นญํ•˜๊ฒ ๋‹ค.

๊ทธ๋‚˜์ €๋‚˜ ์ด๊ฑฐ๋•Œ๋ฌธ์— ์˜ค๋Š˜ ELB ์„ธํŒ… ๋ชปํ•จ. ์‹คํ™”๋ƒ?