53๋ถ์ง๋ฆฌ ํฌ๋ก ํ๋์์ ์์ํ ๋ฐฐํฌ ์ข ๋ฃ ์ค๊ณ
๐ Overview
ํ๋์ ๋ฐฐํฌํ ๋ ์ฌ๋์ด ๊ธฐ๋ค๋ฆฌ๋ ์๊ฐ์ด ์์๋ค. (ํ.. ์ค์ 09:00 ~ 10:00 ์ฌ์ด์ฏค?)
์ด๋ฉ์ผ์ ๋ณด๋ด๋ ํฌ๋ก ํ๋๊ฐ ํ ํ์ฐจ์ 53๋ถ ๊ฑธ๋ ธ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๊ฒ ๋๋ ์ค์ ๋ฐฐํฌํ๋ฉด ๋ฐ์ก์ด ์ค๊ฐ์์ ๋๊ธธ ๊ฒ ๊ฐ์, ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ ธ๋ค๊ฐ ๋ฐฐํฌํ ์ ์ด ์๋ค.
์๋น์ค๋ Kubernetes ์์์ ๋๊ณ ArgoCD ๊ฐ ๋กค๋ง ์ ๋ฐ์ดํธ๋ก ๋ฐฐํฌํ๋ค. ์ ํ๋๊ฐ ์ค๋น๋๋ฉด ๊ตฌ ํ๋๋ ์ ํด์ง ์ ์ ์๊ฐ ์์ ์ฌ๋ผ์ง๋ค. 53๋ถ์ง๋ฆฌ ์์ ์ด ๊ทธ ์์ ๋๋ ์๋ ์์ผ๋, ๊ธฐ๋ค๋ฆฌ๋ ์ชฝ์ ์ฌ๋์ด ๋งก๊ณ ์์๋ ์ ์ด๋ค.
์ฒ์์ ์ด๊ฑธ ์ฑ๋ฅ ๋ฌธ์ ๋ก ๋ดค๋ค. ํฌ๋ก ์ด ๋๋ฆฌ๋ ๋น ๋ฅด๊ฒ ๋ง๋ค๋ฉด ๋๋ ์ผ์ด๋ผ๊ณ .
๊ทธ๋ฐ๋ฐ ์คํ ์๊ฐ์ ๋ถํดํด๋ณด๋ ๋๋ถ๋ถ์ด ์๋์ ์ผ๋ก ๋ฃ์ ๋๊ธฐ ์๋ค. ๋ฉ์ผ ์๋ฒ์ rate limit ์ ๊ฑธ๋ ค ๋ฐ์ก์ด ๊ฑฐ๋ถ๋๋ ๊ฒ์ ๋ง๊ธฐ ์ํด ํ ๊ฑด๊ณผ ๋ค์ ๊ฑด ์ฌ์ด์ ๊ฐ๊ฒฉ์ ๋๊ณ ์์๋ค. ์ฑ๋ฅ์ ์ํด ์ค์ฌ๋ ๋๋ ๊ฐ์ด ์๋๋ผ, ๋ฐ์ก์ด ์ฑ๋ฆฝํ๊ธฐ ์ํ ์กฐ๊ฑด์ด์๋ค.
์ด ํฌ๋ก ์ v1 ์๋น์ค์์ v2 ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ ์ฝ๋์๋ค. ๋ง์ด๊ทธ๋ ์ด์ ์ ์์ ์ฅ์น๋ก v1 ์ ๋์์ ๋จผ์ ํ ์คํธ๋ก ๊ณ ์ ํ๊ณ ๊ทธ ํ ์คํธ๋ฅผ ํต๊ณผ์ํค๋ ๋ฐฉ์์ ํํ๋๋ฐ, ๋๋ถ์ ๊ธฐ๋ฅ์ด ์ด๊ธ๋๋ ์ผ์ ์์์ง๋ง v1 ์ด ๊ฐ๊ณ ์๋ ๊ตฌ์กฐ์ ๋ถํฉ๋ฆฌํจ๊น์ง ๊ณ์ฝ์ผ๋ก ํจ๊ป ๊ตณ์ด์ก๋ค. ํ ํ๋ก์ธ์ค๊ฐ ์์ฐจ๋ก ๋ฐ์กํ๋ฉฐ ๊ทธ ์ฌ์ด๋ฅผ ๋๊ธฐ๋ก ๋ฉ์ด๋ค๋ ํํ๊ฐ ์ ํํ ๊ทธ๋ฐ ํญ๋ชฉ์ด์๋ค.
๊ทธ๋์ ๋ชฉํ๋ฅผ ๋ค์ ์ก์๋ค. ํฌ๋ก ์ ๋น ๋ฅด๊ฒ ๋ง๋๋ ๊ฒ์ด ์๋๋ผ, ํฌ๋ก ํ ํ์ฐจ๋ฅผ ์งง๊ฒ ์ ์งํ๋ ๊ฒ ๊ณผ ๋ฐฐํฌ๊ฐ ์งํ ์ค์ธ ์ผ์ ์ค์ค๋ก ๊ธฐ๋ค๋ฆฌ๊ฒ ๋ง๋๋ ๊ฒ ์ด๋ค. ์ด ๋์ด ๋ง๋ฌผ๋ ค์ผ ์ฌ๋์ด ๋ฐฐํฌ ์์์ ๊ธฐ๋ค๋ฆด ํ์๊ฐ ์์ด์ง๋ค.
๊ทธ๋ฐ๋ฐ ํ์๋ ์๋ฌด ์ฅ์น๊ฐ ์์๋ค. ์ข ๋ฃ ์ ํธ๋ฅผ ๋ฐ์ผ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ณง๋ฐ๋ก ํ๋ก์ธ์ค๋ฅผ ๋๋ด๊ณ ์์ด์, ์งํ ์ค์ธ ์์ฒญ์ด๋ ๋๊ณ ์๋ ํฌ๋ก ์ ๊ธฐ๋ค๋ฆฌ๋ ์ ์ฐจ ์์ฒด๊ฐ ์์๋ค. ๋ฐฐํฌ ์์ ์ฑ์ด ์ ์ ์๊ฐ๊ณผ ์ด์ ๋งก๊ฒจ์ ธ ์๋ ๊ฒ์ด๋ค.
ํ ์ผ์ ๋ ๊ฐ์๋ค.
- ๋ฐ์ก์ ํฌ๋ก ๋ฐ์ผ๋ก ๋ด๋ณด๋ด ํ ํ์ฐจ๋ฅผ ์งง๊ฒ ๋ง๋ ๋ค.
- graceful shutdown ์ ๋ฃ์ด ๋จ์ ์ผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ธฐ๋ค๋ฆฌ๊ฒ ํ๋ค.
์ด๋ฒ ํฌ์คํ ์ ์ด ๋ ๊ฐ์ง๋ฅผ ์์๋๋ก ํด๊ฒฐํ ๊ธฐ๋ก์ด๋ค.
1. ๊ธฐ๋ค๋ฆด ์ ์๋ ํฌ๊ธฐ๋ก ๋ง๋ค๊ธฐ โ ๋ฐ์ก์ ํฌ๋ก ๋ฐ์ผ๋ก
๋จผ์ 53๋ถ์ ๋ถํดํ๋ค. ํ ํ์ฐจ 945์ด ๊ฐ์ด๋ฐ 540์ด(57%)๊ฐ ์๋์ ์ธ ๋๊ธฐ ์๋ค. ๋ฐ์ก์ ์ฑ๊ณตํ ๋๋ง๋ค 5์ด๋ฅผ ์ฌ์๊ณ , ๊ทธ ํ์ฐจ์ ๋์์ด 108๊ฑด์ด์๋ค.
์ด ๋๊ธฐ๋ ์ค์ผ ์ ์๋ค. ๋ฉ์ผ ์๋ฒ๊ฐ ๋ฐ์์ฃผ๋ ์๋์ ๋ง์ถ ๊ฐ์ด๋ผ, ์ค์ด๋ฉด ๋ฐ์ก์ด ๊ฑฐ๋ถ๋๊ธฐ ์์ํ๋ค. ๊ทธ๋ ๋ค๋ฉด ๋ฐ๊ฟ ์ ์๋ ๊ฑด ํ๋๋ฟ์ด์๋ค. ํ ํ๋ก์ธ์ค๊ฐ 108๊ฑด์ ๋๊ธฐ๋ฅผ ์ ๋ถ ํผ์ ์ง์ด์ง๋ ๊ตฌ์กฐ ๋ค.
๊ทธ๋์ ํฌ๋ก ์ ๋ณด๋ผ ๋ฉ์์ง๋ฅผ outbox ํ ์ด๋ธ์ ์ ์ฌํ๊ธฐ๋ง ํ๊ณ , ๋ฆด๋ ์ด๊ฐ ๊ทธ ํ์ Kafka ๋ก ๋ฐํํ๊ณ , ์ปจ์๋จธ๊ฐ ์ค์ ๋ฐ์ก์ ๋งก๋๋ก ๋๋ด๋ค. 5์ด ๋๊ธฐ๋ ์ปจ์๋จธ ์ชฝ์ผ๋ก ์ฎ๊ฒจ๊ฐ๋ค.
์ค๋ณต์ UPDATE ํ ์ค๋ก ๋ง๋๋ค
outbox ๋ฆด๋ ์ด๋ ๋ฐํ์ ๋์น์ง ์๋ ๋์ ์ค๋ณต์ ๋ ์๋๋ค. ์ฌ๊ธฐ์๋ ๋ฐํํ๊ธฐ ์ ์ ์๋ ํ์๋ถํฐ ์ฌ๋ฆฌ๋ ๋ฐฉ์ ์ผ๋ก ๊ทธ ์ค๋ณต์ ์ํ์ ๋๋ค.
const affected = await this.outboxRepository.nativeUpdate(
{
outboxUuid,
status: OutboxStatus.Pending,
// ๋ด๊ฐ ์ฝ์ ๋ค๋ก ์๋ฌด๋ ๊ฑด๋๋ฆฌ์ง ์์๊ณ ($eq), ์๋ ํ์๊ฐ ์ํ ์๋์ผ ๋($lt)๋ง ๊ฐฑ์ ๋๋ค.
attempts: { $eq: attempts, $lt: Outbox.MaxAttempts },
},
{
attempts: raw('attempts + 1'),
nextAttemptAt,
},
);
// ํ ๊ฑด์ด ๊ฐฑ์ ๋์ ๋์๋ง ์ด ์คํ์ด ๋ฐํํ ๊ถ๋ฆฌ๋ฅผ ๊ฐ์ง๋ค.
return affected === 1;$eq ๋ ์ฌ๋ฌ ํ๋๊ฐ ๊ฐ์ ํ์ ๋์์ ์ง๋ ๊ฒฝ์์, $lt ๋ ๋์์ด ์คํจํ๋ ํ์ ๋ง๋๋ค.
๋ค๋ง ๋ชจ๋ ์คํจ๋ฅผ ์ํ๊น์ง ์ฌ์๋ํ์ง๋ ์๋๋ค. ์์ ๋ถ๊ฐ ์ฃผ์์ฒ๋ผ ๋ค์ ๋ณด๋ด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ ์ค๋ฅ๋ ์ฌ์๋ ์์ด ๋ฐ๋ก ์ข ๊ฒฐํ๋๋ก ํ๋ค.
ํ์๋ฅผ ๋ฐํ ๋ค์ ์ฌ๋ฆฌ๋ฉด ๋ฌธ์ ๊ฐ ์๊ธด๋ค. ๋ฐํ์ ์ฑ๊ณตํ๋๋ฐ ์ํ ๊ธฐ๋ก์ด ์คํจํ ํ์ ์๋ ํ์๊ฐ ๊ทธ๋๋ก์ธ ์ฑ pending ์ผ๋ก ๋จ๊ณ , ๋ค์ ์ฃผ๊ธฐ๊ฐ ๊ทธ ํ์ ๊ณ์ ๋ค์ ์ง๋๋ค. ๊ฐ์ ๋ฉ์์ง๊ฐ ๋์์ด ๋ฐํ๋๋ ๊ฒ์ด๋ค. ๋จผ์ ์ฌ๋ ค ๋๋ ๊ฒ๋ง์ผ๋ก ์ด ๋ฐ๋ณต์ ๋์ด ์๊ธด๋ค.
๋๊ธฐ๋ ์ปจ์๋จธ๋ก ์ฎ๊ฒจ๊ฐ๋ค
์ปจ์๋จธ๋ ๋ฉ์์ง๋ฅผ ๋ฐ์ ๋ฉ์ผ์ ๋ณด๋ธ๋ค. ๋ฌธ์ ์ ์ถ๋ฐ์ ์ด์๋ 5์ด ๋๊ธฐ๊ฐ ์ฌ๊ธฐ๋ก ์จ๋ค.
@EventPattern(OutboxTopic.EmailDispatch)
async handleEmailDispatch(@Payload() message: EmailDispatchMessage): Promise<void> {
// ๋๊ธฐ๋ ์ฌ๋ผ์ง ๊ฒ์ด ์๋๋ผ ์ฌ๊ธฐ๋ก ์ฎ๊ฒจ์๋ค. ๋ค๋ง ์ด ๋๊ธฐ๋ฅผ ์ง์ด์ง๋ ๊ฒ์
// ๋ฐฐํฌ๊ฐ ์์ฃผ๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํ๋ ํฌ๋ก ์ด ์๋๋ผ, ์ฃฝ์ด๋ ๋ค์ ์งํ๋ ์ปจ์๋จธ๋ค.
await this.emailRateLimiter.acquire();
await this.emailSender.send(message);
}๊ฐ์ 5์ด๋ฅผ ์ฌ์ ํ ๊ธฐ๋ค๋ฆฌ์ง๋ง ์ฑ์ง์ด ๋ฌ๋ผ์ก๋ค. ์ด์ ์๋ ํฌ๋ก ํ ํ์ฐจ๊ฐ 108๊ฑด์ ๋๊ธฐ๋ฅผ ํผ์ ์ง์ด์ก๊ณ , ๋ฐฐํฌ๋ ๊ทธ ํ์ฐจ๊ฐ ๋๋๊ธธ ๊ธฐ๋ค๋ ค์ผ ํ๋ค. ์ง๊ธ์ ์ฌ๋ฌ ์ปจ์๋จธ๊ฐ ๋๋ ๊ฐ์ ธ๊ฐ๊ณ , ํ๋๊ฐ ๋์ค์ ์ฃฝ์ด๋ ์ฒ๋ฆฌ๋์ง ์์ ๋ฉ์์ง๋ ๋ค๋ฅธ ์ปจ์๋จธ๊ฐ ๋ค์ ๋ฐ๋๋ค.
์ด ๋ณํ๊ฐ ์ข ๋ฃ ์ค๊ณ์ ์ค ๊ฒ์ ๋ ๊ฐ์ง๋ค.
- ํฌ๋ก ์ด ์งง์์ก๋ค. ๋ฉ์์ง๋ฅผ ์ ์ฌํ๋ ์๊ฐ๋ง ์ฐ๋ ์คํ ์๊ฐ์ด ์ด ๋จ์๋ก ๋ด๋ ค์๊ณ , ๋น๋ก์ โํฌ๋ก ์ ๋ช ์ด๊น์ง ๊ธฐ๋ค๋ฆด ๊ฒ์ธ๊ฐโ ๋ฅผ ๋ฌผ์ ์ ์๊ฒ ๋์๋ค.
- ๋ฆด๋ ์ด์ ์ปจ์๋จธ๋ ๊ธฐ๋ค๋ ค์ค ํ์๊ฐ ์๋ค. ๋์ค์ ์ฃฝ์ด๋ ๋ค๋ฅธ ์ชฝ์ด ์ด์ด๋ฐ์ผ๋, ์ ๋ฌ์ด ๋๊น์ง ๋๋์ง๊ฐ ํ๋ก์ธ์ค ์์กด๊ณผ ๋ฌด๊ดํ๋ค.
์ด ์์๋ฅผ ๋ค์ง์ด ์ข ๋ฃ ๋๊ธฐ๋ฅผ ๋จผ์ ๋ฃ์๋ค๋ฉด, ์ํ์ ๋ช ์ด๋ก ์ก๋ ๋งค ๋ฐฐํฌ๊ฐ ๊ฐ์ ์ข ๋ฃ๋ก ๋๋ฌ์ ๊ฒ์ด๋ค. 53๋ถ์ ๊ธฐ๋ค๋ ค์ฃผ๋ ์ํ์ ์กด์ฌํ ์ ์๋ค.
2. ๊ธฐ๋ค๋ฆฌ๋ ์ ์ฐจ๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์์ ํ๊ฒ ๋ง๋ค๊ธฐ
Nest ์๋ ์ข
๋ฃ ํ
์ด ์๊ณ app.enableShutdownHooks() ํ ์ค๋ก ์ผค ์ ์๋ค. ์ฒ์์ ์ด๊ฑธ๋ก ๋๋ ์ผ์ด๋ผ๊ณ ์๊ฐํ๋ค.
๋ฃ์ด๋ดค์ง๋ง ์๋ฌด๊ฒ๋ ๋ฌ๋ผ์ง์ง ์์๋ค. ์์ธ์ ์ด๋ฏธ SIGTERM ๋ฆฌ์ค๋๊ฐ ํ๋ ๋ฑ๋ก๋์ด ์์๋ค๋ ๊ฒ ์ด์๋ค.
// ์ฌ๋ด ํ
๋ ๋ฉํธ๋ฆฌ ํจํค์ง๊ฐ ์ฌ์ด ๋ ๋ฆฌ์ค๋ โ ํธ๋ ์ด์ค๋ฅผ ๋น์ด ๋ค ํ๋ก์ธ์ค๋ฅผ ๋๋ธ๋ค
process.on('SIGTERM', () => {
sdk.shutdown().finally(() => process.exit(0));
});์ข
๋ฃ ํ
์ ์ถ๊ฐํ๋ฉด ๊ฐ์ ์ ํธ๋ฅผ ๋ ๋ฆฌ์ค๋๊ฐ ๋์์ ๋ฐ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํธ๋ ์ด์ค๋ฅผ ๋น์ฐ๋ ์ชฝ์ด ์ ๋ฐ๋ฆฌ์ด ์์ process.exit(0) ์ ํธ์ถํ๋ฏ๋ก, Nest ๊ฐ ๋ง ์์ํ app.close() ๋ ๋๊น์ง ๊ฐ์ง ๋ชปํ๊ณ ์๋ฆฐ๋ค.
์ฆ ๋ฌธ์ ๋ ์ข ๋ฃ ์ ์ฐจ๊ฐ ์๋ค ๋ ๊ฒ์ด ์๋๋ผ ์ข ๋ฃ ์์๋ฅผ ๋๊ฐ ์์ ํ๋๊ฐ ์๋ค.
๊ทธ๋์ ์ด๋ฏธ ๋ฑ๋ก๋ ๋ฆฌ์ค๋๋ฅผ ๊ฑท์ด๋ด ๋ณด๊ดํ๊ณ , ์ฐ๋ฆฌ ์ ์ฐจ๊ฐ ๋๋ ๋ง์ง๋ง์ ๋ค์ ๋ถ๋ฌ์ฃผ๊ธฐ๋ก ํ๋ค.
const handlers: SignalHandler[] = [];
for (const signal of params.signals) {
handlers.push(...(emitter.listeners(signal) as SignalHandler[]));
emitter.removeAllListeners(signal);
}
return {
count: handlers.length,
invoke(signal: NodeJS.Signals): void {
for (const handler of handlers) {
// ํ ๊ฑด์ด throw ํ๋ฉด ๋ค ๋ฆฌ์ค๋์ ์ ์ ์ข
๋ฃ ๊ฒฝ๋ก๊ฐ ํต์งธ๋ก ์ฌ๋ผ์ง๋ฏ๋ก ๊ฑด๋ณ๋ก ๊ฒฉ๋ฆฌํ๋ค.
try {
handler.call(emitter, signal);
} catch (error) {
params.logger.error('gracefulShutdown phase=flush failed', error);
}
}
},
};ํจํค์ง๊ฐ SDK ์ธ์คํด์ค๋ฅผ ๋
ธ์ถํ์ง ์์ sdk.shutdown() ์ ์ง์ ๋ถ๋ฅผ ์๋ ์์๋ค. ๋ฆฌ์ค๋ ์์ฒด๋ฅผ ํจ์๋ก ๋ค๊ณ ์๋ค๊ฐ ๋๋ถ๋ฅด๋ ๋ฐฉ์์ด ์ ์ผํ ์ ํ์ด์๋ค.
ํธ์ถ ์๋ฆฌ๋ NestFactory.create ์ด์ , ๋ชจ๋ ๋ก๋ ์งํ๋ค. ๋ถํ
๋์ค์ ์ค๋ ์ ํธ๊น์ง ๋ฎ์ด์ผ ํ๋ฏ๋ก ์ฑ ์ฐธ์กฐ๋ ๊ฐ์ด ์๋๋ผ ์ง์ฐ ํจ์๋ก ๋๊ฒผ๋ค.
์ผ๋ง๋ ๊ธฐ๋ค๋ฆด ๊ฒ์ธ๊ฐ โ ๋ค ๊ฐ์ ๊ฐ์ด ํ ๋ฌถ์์ธ ์ด์
์์๋ฅผ ์์ ํ๊ฒ ๋์ ๋๊ธฐ ์ํ์ ์ ํ ์ฐจ๋ก์๋ค. ์ฒ์์ ํญ๋ชฉ๋ณ๋ก ๋ฐ๋ก ์ ํ๋ฉด ๋๋ ๊ฐ์ด๋ผ๊ณ ์๊ฐํ๋๋ฐ, ์ค์ ๋ก๋ ๋ค ๊ฐ๊ฐ ์๋ก๋ฅผ ์ ์ฝํ๋ ํ๋์ ์์ฐ ์ด์๋ค.
export const ShutdownTimeout = {
// ์ ์ ์๋ต ์ค ๊ฐ์ฅ ๊ธด ์ธ๋ถ ์๋ฒ ํธ์ถ ์ํ 20์ด + ์ฌ์ 5์ด. ์ด ์๋๋ก ๋ด๋ฆฌ๋ฉด ์ฑ๊ณต ์๋ต์ ๋๋๋ค.
HttpDrainMs: 25_000,
ConnectionPollMs: 250,
// ๊ฐ์ฅ ๊ธด ํฌ๋ก ์ ์คํ ์๊ฐ์ ์ด ๊ฐ์ ๋์ง๋ง ํ๋ฃจ 1ํ๋ผ ๊ทธ ์๊ฐ๋ ๋ฐฐํฌ๋ฅผ ํผํ๋ค. ๊ทธ ์ธ ํฌ๋ก ์ ์ด ๊ฐ ์์ ๋๋์ผ ํ๋ค.
CronDrainMs: 90_000,
// ํฌ๋ก ๋๊ธฐ 90์ด(์์ฒญ ๋๊ธฐ 25์ด์ ๋์ ์งํ) + app.close ์ ํ
๋ ๋ฉํธ๋ฆฌ flush ์์ฐ 20์ด.
// k8s ์ ์ 130์ด์์ preStop 10์ด๋ฅผ ๋บ 120์ด ์์ ๋ค์ด๊ฐ๋ค.
HardDeadlineMs: 110_000,
} as const;๊ฐ์ ๊ทผ๊ฑฐ๋ ์ค์ธก์์ ๊ฐ์ ธ์๋ค. HTTP 25์ด๋ ์ ์ ์๋ต ์ค ๊ฐ์ฅ ๋๋ฆฐ ๊ฒฝ๋ก๊ฐ ์ธ๋ถ ํธ์ถ 20์ด ์ํ์ ๊ฑธ๋ฆฌ๋ API ์๊ธฐ ๋๋ฌธ์ด๊ณ , ํฌ๋ก 90์ด๋ APM ์์ ํฌ๋ก ๋ณ ์คํ ์๊ฐ ์ต๋๊ฐ์ ๋ฝ์ ์ ํ๋ค.
์ด ๊ณผ์ ์์ ํ๋๋ฅผ ๋ฐฐ์ ๋ค. ์กฐํ ์ฐฝ์ ๊ธธ์ด๊ฐ ๊ฒฐ๋ก ์ ๋ฐ๊พผ๋ค. 24์๊ฐ ์ฐฝ์์๋ ๊ฐ์ฅ ๊ธด ํฌ๋ก ์ ์คํ ์๊ฐ์ด 80์ด ์ ๋๋ผ 90์ด๊ฐ ๋๋ํด ๋ณด์๋๋ฐ, 7์ผ ์ฐฝ์ผ๋ก ๋๋ฆฌ์ ๊ฐ์ ํฌ๋ก ์ด 121์ด๊น์ง ํ๋ ๋ ์ด ์์๋ค.
๊ทธ ํฌ๋ก ์ ์์ ์ ํ๋ฃจ ํ ๋ฒ๋ง ๋๋ ์ข
๋ฅ์๋ค. ์ํ์ ์ฌ๋ ค ๋ชจ๋ ๋ฐฐํฌ๋ฅผ ๋๋ฆฌ๊ฒ ๋ง๋๋ ๋์ , ๊ทธ ์๊ฐ๋๋ฅผ ๋ฐฐํฌ ๊ธ์ง ๊ตฌ๊ฐ์ผ๋ก ์ ํ๊ณ ์ ์ฅ์์ PR ๊ท์น ๋ฌธ์์ ๋ฃ์๋ค. main ๋ธ๋์น๋ก ๋ฐฐํฌ PR ์ ๋ง๋ค ๋ ํ์ธํ๋ ํญ๋ชฉ์ด ๋๋๋ก ํด์, ์ฌ๋์ด ๊ธฐ์ตํ์ง ์์๋ ๋ฐฐํฌ ํ๋ฆ์ด ๊ฑธ๋ฌ์ฃผ๊ฒ ํ๋ค.
๋ง์ง๋ง ์ค์ 110์ด๋ ์ฐ๋ฆฌ๊ฐ ๊ณ ๋ฅธ ๊ฐ์ด ์๋๋ผ ์ฃผ์ด์ง ์๊ฐ์์ ๊ฑฐ๊พธ๋ก ๊ณ์ฐํ ๊ฐ ์ด๋ค.
Kubernetes ๋ ํ๋์ ์ข
๋ฃ ์ ํธ๋ฅผ ๋ณด๋ธ ๋ค 130์ด๋ฅผ ๊ธฐ๋ค๋ ค์ฃผ๊ณ , ๊ทธ๋๋ ๋๋์ง ์์ผ๋ฉด ๊ฐ์ ๋ก ์ฃฝ์ธ๋ค. ๊ทธ์ค ์ฒ์ 10์ด๋ ์ ์์ฒญ์ด ๋ ๋ค์ด์ค์ง ์๊ฒ ์ ์ ๋ฉ์ถฐ ์๋ ์๊ฐ(preStop)์ด๋ผ, ์ ํ๋ฆฌ์ผ์ด์
์ด ์ค์ ๋ก ์ธ ์ ์๋ ๊ฑด 120์ด๋ค. ๊ทธ ์์์ ํ์คํ ๋๋ด๊ธฐ ์ํด 110์ด๊ฐ ๋๋ฉด ์ค์ค๋ก ๋ฉ์ถ๋๋ก ํ๋ค.
์ด 130์ด๋ ๋ฐฐํฌํ ๋๋ฟ ์๋๋ผ ํธ๋ํฝ์ด ์ค์ด ํ๋ ์๋ฅผ ์ค์ผ ๋๋ ๋๊ฐ์ด ์ฐ์ธ๋ค. ๊ทธ๋์ ๋๋ํ๊ฒ ๋๋ฆฌ๋ฉด ๊ทธ๋งํผ ๋ชจ๋ ์ถ์๊ฐ ๋๋ ค์ง๋ค.
๋จ๋ ์ฌ์ ๊ฐ 10์ด๋ฟ์ด๋, HTTP ์์ฒญ๊ณผ ํฌ๋ก ์ ์ฐจ๋ก๋ก ๊ธฐ๋ค๋ฆด ์๋ ์์๋ค. ๋์ ๋์์ ๊ธฐ๋ค๋ ค์ผ ํ๋ค.
// ์งํ ์ค ํฌ๋ก ์ด ์์ ๋ ๋ฐฐํฌ ์๊ฐ์ด ๋์ง ์๋๋ก ์์ฒญ๊ณผ ํฌ๋ก ์ ๋์์ ๊ธฐ๋ค๋ฆฐ๋ค.
const [drain, cron] = await Promise.all([
this.drainHttp().catch(/* ... */),
ShutdownState.waitForCronsIdle(ShutdownTimeout.CronDrainMs).catch(/* ... */),
]);์ด Promise.all ์ ์ฑ๋ฅ ์ต์ ํ๊ฐ ์๋๋ผ ์์ฐ์ด ์ฑ๋ฆฝํ๊ธฐ ์ํ ํ์์กฐ๊ฑด ์ด๋ค. ์ง๋ ฌ๋ก ๋๋๋ฆฌ๋ฉด 25 + 90 = 115์ด๊ฐ ๋์ด ๋ฐ๋๋ผ์ธ 110์ด๋ฅผ ๋๊ธฐ๊ณ , ์ ์์ ์ผ๋ก ์ข
๋ฃ๋๋ ๊ฒฝ์ฐ์๋ ๊ฐ์ ์ข
๋ฃ๋ก ๋ฐ๋๋ค.
์ฝ๋๋ง ๋ณด๋ฉด โ๋์์ ๊ธฐ๋ค๋ฆฌ๋ ์กฐ๊ธ ๋น ๋ฅด๊ฒ ๋คโ ๋ก ์ฝํ๋ค. ๊ทธ๋์ ์ฃผ์์ ์ต์ ํ๊ฐ ์๋๋ผ๋ ์ฌ์ค์ ๋จ๊ฒผ๋ค. ๋๊ตฐ๊ฐ ๊ฐ๋ ์ฑ์ ์ด์ ๋ก ์ง๋ ฌ๋ก ํด๋ ์๊ฐ ๋ชจ๋ ๋ฐฐํฌ๊ฐ ๊ฐ์ ์ข ๋ฃ๋๋๋ฐ, ๊ทธ ์ ํธ๋ ๋ก๊ทธ ํ ์ค๋ฟ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
๐ค Understanding
์ด๋ฒ ์์ ์์ ๊ฐ์ฅ ํฌ๊ฒ ๋จ์ ๊ฒ์, ๋ฌด์ค๋จ ๋ฐฐํฌ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ค์ ์ด ์๋๋ผ ์ฑ๊ณผ ์ธํ๋ผ๊ฐ ๊ณต์ ํ๋ ํ๋์ ์์ฐ ์ด๋ผ๋ ์ ์ด๋ค.
์ ํ๋ฆฌ์ผ์ด์
์ด 110์ด๋ฅผ ์ฐ๊ฒ ๋ค๊ณ ์ ํ๋ ๊ฒ๋ง์ผ๋ก๋ ์๋ฏธ๊ฐ ์๋ค. ํ๋ ์ข
๋ฃ ์ ์๊ฐ ๊ธฐ๋ณธ๊ฐ 30์ด๋ก ๋จ์ ์์ผ๋ฉด ์์ฒญ๊ณผ ํฌ๋ก ์ ๊ธฐ๋ค๋ฆฌ๋ ์ ์ฐจ๊ฐ 30์ด์ ์๋ฆฐ๋ค. ๊ทธ๋์ ๋ฐฐํฌ ์์๊ฐ ๊ณง ์์ ์กฐ๊ฑด์ด ๋์๋ค. ์ฐจํธ์ ์ ์ ์๊ฐ๊ณผ preStop ์ด ๋จผ์ ๋ฐ์๋ ๋ค์์ผ ์ ํ๋ฆฌ์ผ์ด์
๋ณ๊ฒฝ์ด ๋๊ฐ ์ ์๋ค.
๊ฐ์ ์ฑ๊ฒฉ์ ์์กด์ด ๊ทธ๋ณด๋ค ์์ ํ๋ ๋ ์์๋ค. 53๋ถ์ง๋ฆฌ ์์ ์ outbox ์ ๋ธ๋ก์ปค ๋ค๋ก ์ฎ๊ธฐ๋ ์ผ์ด ์ข ๋ฃ ์ ์ฐจ๋ณด๋ค ๋จผ์ ์์ผ ํ๋ค. ๋์ด์ผ๋ณด๋ฉด ์ข ๋ฃ๋ฅผ ์ค๊ณํ๋ ์ผ์ ์ ๋ฐ์ ๊ธฐ๋ค๋ฆด ์ ์๋ ํฌ๊ธฐ์ ์ผ๋ก ๋ง๋ค์ด ๋๋ ๊ฒ ์ด์๋ค.
๋๊ธฐ๊ฐ ์ฌ๋ผ์ง ๊ฒ์ด ์๋๋ผ๋ ์ ๋ ์ ์ด ๋๋ค. rate limit ์ ๋ง์ถ 5์ด๋ ์ปจ์๋จธ์ ๊ทธ๋๋ก ๋จ์ ์๋ค. ๋ฌ๋ผ์ง ๊ฒ์ ๊ทธ ์๊ฐ์ ๋๊ฐ ์ง์ด์ง๋๊ฐ ์๊ณ , ์ข ๋ฃ๊ฐ ๊ธฐ๋ค๋ ค์ผ ํ๋ ์ชฝ์์ ๊ธฐ๋ค๋ ค์ฃผ์ง ์์๋ ๋๋ ์ชฝ์ผ๋ก ์ฎ๊ธด ๊ฒ์ด ์ด๋ฒ ๋ณ๊ฒฝ์ ์ค์ฒด์๋ค.
๊ฒ์ฆ๋ ๋ก์ปฌ์ด ์๋๋ผ ๋กค์์ ๋ก๊ทธ๋ก ํ๋ค. ์ค์ ๋กค์์์์ ๊ตฌ ํ๋ ์ ๋ถ๊ฐ ์ ํธ ์์ โ ์์ฒญยทํฌ๋ก ๋๊ธฐ โ ์์ ์ ๋ฆฌ โ ํธ๋ ์ด์ค ๋น์ฐ๊ธฐ ๋ฅผ ์์ญ ๋ฐ๋ฆฌ์ด ์์ ์์ฃผํ๊ณ , ๋ฐ๋๋ผ์ธ์ผ๋ก ๋๊ธด ๊ฒฝ์ฐ๋ ์์๋ค.
๋ค๋ง ์ง๊ธ์ ์์น๊ฐ ๋์ ์๋๋ค. 25์ดยท90์ดยท110์ด๋ ๋ชจ๋ ํ์ฌ์ ํธ๋ํฝ๊ณผ ํฌ๋ก ์คํ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ ํ ๊ฐ์ด๋ผ, ์๋น์ค๊ฐ ๋ฌ๋ผ์ง๋ฉด ํจ๊ป ๋ฌ๋ผ์ ธ์ผ ํ๋ค. ๊พธ์คํ ๊ด์ธกํ๋ฉด์ ์กฐ์ ํด ๋๊ฐ ์๊ฐ์ด๋ค.
๋ฐฐํฌ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ 53๋ถ์์ ์์ํด ๊ฒฐ๊ตญ ์ ํธ์ ์์ ๊ถ๊ณผ ์๊ฐ ์์ฐ์ ๋ค์ ์ค๊ณํ๋ ์ผ์ด ๋์๋ค. ์ข ๋ฃ๋ฅผ ์ ๋ฆฌ ์์ ์ด ์๋๋ผ ์ ํ ์๊ฐ์ด ๊ฑธ๋ฆฐ ์ ์ฐจ ๋ก ๋ณด๊ฒ ๋ ๊ฒ์ด ์ด๋ฒ์ ์ป์ ๊ฐ์ฅ ํฐ ๊ด์ ์ ๋ณํ์๋ค.
์ฐธ๊ณ ์๋ฃ