25-03-19
๐ Daily Reportโ
๐ ํ๋ก์ ํธ ์ํฉโ
์ํ๊น๊ฒ๋ ๋ด ์ฒด๋ ฅ์ด ์์ง์ ์ ๋ฐ๋ผ์ฃผ๋ ๊ฒ ๊ฐ๋ค.
๋ชจ๋ํฐ๋ฅผ ๋ชป ์ณ๋ค๋ณด๊ฒ ์ ์ ๋๋ก ํธ๋ํต์ ์๊ตฌ๊ฑด์กฐ์ฆ์ ๋ฌต์งํ ํผ๋ก์ ๋ญ์ง ๋ชจ๋ฅผ ๋ถ ๋ฌ ๋๋๊น์ง ๋ค์ด์ ๊ฑฐ์ ๋ ๊ฐ์์ฑ๋ก ๋ณ์์ ๊ฐ๋ค.
ํ ์คํธ๋ง ๋ณด๋ฉด ๋ญ๊ฐ ์์๋ด๋๊ฑฐ ๊ฐ์๋ฐ ์ ๊ฒ ๋ค ์ข ํฉ์ธํธ๋ก ์ค๋๊น ์ต์ง๋ก ๋ชจ๋ํฐ ๋ณด๋ฉด์ ์์ ํด๋ ํ 70%๋ ๋ฉ๋๋ฆด ๊ฒ ๊ฐ์ ์ ๋๋ก ํ๋ค์๋ค.
๊ทธ๋์ ์์ก 2์ข ๋ฅ ์์ด ๋ง๊ณ ์งํต์ ๋ ์ฒ๋ฐฉ๋ฐ์๋๋ฐ, ์ข ๋น์ผ๊ฒ ํ ์ด์ง๋ง ๊ธฐ์ ๊ฐ์ด ์ง์ฅ์์ ์ด์๋์๋ค; ์์งํ ๊ธฐ๋ ์ํ๋๋ฐ ๋ฌด์จ ๋ฏธ๋ ์๋ช ๋ก๊ฒจ์จ์ค ใ ใ ใ
์ํ๊ฐ ํธ์ ๋ผ์ ๋คํ์ด์ง๋ง ๋ด์ฌ ์ง์ฆ์ด ๋๋ค.
์๋ ์ ์ฒด๋ ฅ์ด ํ์กฐ๋ฅผ ์ํด์ฃผ์ง?
๋ด๊ฐ ์ผ๋ง๋ ์์นจ์๋ ๋ฎ์๋ ์ ๋ ์๋ ์๋ฒฝ์๋ ๊ฐ๋ฐํ๊ณ ์ถ์๋ฐ? ์ง๊ธ ํ ๊ฒ ์ผ๋ง๋ ๋ง์๋ฐ?
๐ ๋ฌด์๋ฏธํ synchronized
โ
์์ฝ ๋์์ฑ TDD๊ฐ ๋๋์ด ๋ง๋ฌด๋ฆฌ ๋์๋ค. ํ ์คํธ๋ 10000๋ช ์ ์ ์์ ๊ฐ์ง ์ํธ๋ฆฌ์ ๋ํ์ฌ 50000๊ฐ์ ๋์ ์์ฝ ์๋๋ฅผ ๊ฑธ์๋๋ฐ, ๊ฐ์ด ํฌ๋ค๋ณด๋ ํ๊ฒฝ ์ธํ ๋ ๋ค์ด๊ฐ์ ์๊ฐ๋ณด๋ค ๊น๋ค๋กญ๋๋ผ. ์ผ๋จ ๋ค์์ ์ค์ ๋ค์ด ํ์ํ๋ค.
- MySQL์ max-connections ๋๋ฆฌ๊ธฐ (-> ํด๋ผ์ด์ธํธ ์ ์ํด์ ์ค์ )
- JVM heap memory ๋๋ฆฌ๊ธฐ (-> gradle ํ์ผ์์ ์ค์ [๋ ํผ๋ฐ์ค])
- hikari max-pool ๋ฐ timeout ๋๋ฆฌ๊ธฐ (-> yml์์ ์ค์ )
ํ๋จ์ ๋ณ๋ค๋ฅธ ์ฒ๋ฆฌ ์์ด ์๋น์ค์ @Transactional๋ง ๋ถ์ธ ํ ์คํธ์ ๊ฒฐ๊ณผ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๊ฑด ์๋น์ค์ synchronized
ํค์๋๋ฅผ ์ถ๊ฐํ ํ
์คํธ์ ๊ฒฐ๊ณผ์ด๋ค.
๊ฒฐ๊ณผ๊ฐ ๋ ์์ข์ ใ ใ ใ ใ ใ ใ
synchronized์ ๋ํ ๋ณด์์ฑ ๊ณผ ๊ทธ ๋ณด์์ฑ ์ ํ๊ณ์ ์ ์ฌ๊ธฐ์ ์ ์ค๋ช ํด์ฃผ์๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก, ํ์ฌ ์ํฉ์ ํ์ํ ์กฐ๊ฑด์ ๋จ๊ธฐ๊ฐ์ ๊ฐ๋ฐ ์ผ์ ์ ๋ง์กฑํ๋ ค๋ฉด Pessimistic Lock์ด ์ข์ ๊ฒ ๊ฐ๋ค.
๋ง์ง๋ง์ผ๋ก, ์ด๊ฑด Pessimistic Lock์ ์ ์ฉํ ๊ฒฐ๊ณผ์ด๋ค.
๐ API Gateway์ ํธ๋ฆฌํ uri ์ค์ โ
ํ์ฌ API Gateway์ ๋ผ์ฐํ ์ ์ด๋ฐ์์ผ๋ก ์ค์ ๋์ด ์๋ค.
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๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ง์ํ๋ค.
์๋ฅผ ๋ค์ด, ์ด๋ฐ์์ผ๋ก ์์ ํ ์ ์๋ค.
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๊ฐ ๋ด๋ค. ใ ใด
์ฒ์์๋ docker network ํ๊ฒฝ์ ์์ฌํ๋ค. ๋ผ์ฐํ uri๋ฅผ ๊ทธ๋ฅ localhost๋ผ๊ณ ์จ๋จ์ผ๋...
์๋ง compose ์คํฌ๋ฆฝํธ๋ฅผ ์กฐ์ ํด์ฃผ๋ฉด ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ค. ํ์ง๋ง ์ ๋ง์ route๋ฅผ ๋ค ์ด๋ป๊ฒ? ๋ผ๋ ์๋ฌธ์ด ๋ค์๋ค.
์ด๋ฅผ ์์๋ณด๊ธฐ ์ํด ์ด๊ณณ์ ๊ณณ ๋ ํผ๋ฅผ ์ฐพ์๋ดค๋๋ฐ, ๊ฒฐ๊ตญ์ ๊ทธ๋ฅ ๋๊ฐ ๊นํ๋ธ์ ์ฌ๋ ค๋์ ์ฝ๋์์ ํด๋ต์ ์ป์๋ค.
๋ฌธ๋ฒ์ด ์ข ํน์ดํ๋๋ผ.
๐ ์ ์ ๋ถ ๋ค ์ฒ์๋ถํฐ ๋ค์ ์จโ
๊ทผ๋ฐ ๊ทธ๋๋ก ์ ์ฉํ๊ณ ๋ฐฐํฌํ์๋ ๊ฒ์ดํธ์จ์ด๊ฐ ํฐ์ ธ์๊ธธ๋ ๋ก์ปฌ์์ compose up์ผ๋ก ๋ก๊ทธ๋ฅผ ์ดํด๋ณด์๋ค.
predicates๊ฐ... ์ ๋ ๋ผ๊ฐ๊ฑฐ์ง;?
(์ฐธ๊ณ ๋ก ์ ๊ฒ locale์ ๋ฐ๋ผ๊ฐ์ IDEA์์ ํ๊ตญ์ด ๋ก๊ทธ๋ฅผ ๋์์ค. ๊ท์ฝ๋ค ใ ใ )
๊ฒฐ๊ตญ ์ด๋ฐ์์ผ๋ก ๋ ธ๊ฐ๋คํด์ฃผ๋๊น ํฐ์ง์ง ์์๋ค.
ํ์ง๋ง ์ด ๋ ธ๊ฐ๋ค๋ฅผ ์ฐ๋๋ ๊ทธ๋ฅ ๋ก์ปฌ์์๋ lb://~ ๊ฐ ๋์๋ฐ ๋ก์ปฌ ์คํฌ๋ฆฝํธ๋ฅผ ๊ต์ฒดํ๋๊ฒ ๋ซ๊ฒ ๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ ํ ์คํธํ๋๊น ์ฌ์ ํ 404์๋ค.
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 thelatest
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 implicitlydocker 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 ์ธํ ๋ชปํจ. ์คํ๋?