[Linux] Graceful Shutdown
Graceful Shutdown์ ๋ฒ์ญํ์๋ฉด "์ฐ์ํ ์ค๋จ"์ผ๋ก, ์์ ์ ์ธ ์์คํ ์ ๋ง๋ค๋ ์ค์ํ ํต์ฌ ์์น ์ค ํ๋๋ค.
Graceful Shutdown์ ๊ธฐ๋ณธ ์๋ฆฌ๋ ๋๋ต 2๊ฐ์ง ์ ๋๊ฐ ์๋ค.
-
shutdown์ด ์์๋๋ฉด ๋ ์ด์์ ์์ฒญ์ ๋ฐ์ง ์๋๋ค.
-
shutdown์ด ์์๋์๋๋ผ๋, ์ด๋ฏธ ๋ฐ์ ์์ฒญ์ ๋ค ์ฒ๋ฆฌํ๊ณ ์ข ๋ฃํ๋ค.
์ด๋ฅผ ํตํด์ ๋ญ๊ฐ ์ด๋ ์ ๋ ์๋ ์ํ๋ก ์์
์ด ๋๊ธฐ๋ ํ์์ ๋ฐฉ์งํ๋ ๊ฒ์ ์ฃผ์์ ์ผ๋ก ์ผ๋๋ค.
์ด์ ๋ํ ๊ณ ๋ ค ์์ด ์์คํ
์ ๋ง๋ ๋ค๋ฉด, ์จ์ ํ์ง ์์ ์ํ๋ก ๋ฐ์ดํฐ๊ฐ ์์๋๊ธฐ ์ฝ๋ค. ์๋ฅผ ๋ค์ด ๋งค ํ์คํฌ๋ง๋ค A->B->C 3๊ฐ์ ์์
์ ํด์ผํ๋๋ฐ, B๊น์ง๋ง ์ฒ๋ฆฌํ๊ณ ์ค๋จ๋์ด๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค.
Graceful Shutdown์ ์ด๋ฌํ ์ฌํ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด, ํ๋ก์ธ์ค ์ข ๋ฃ ์ ํธ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์งํด์ ์ ์ ํ ์คํ ์์ ๋ฉ์ถ๋๋ก ์ ๋ํ๋ ๋ฐฉ๋ฒ๋ก ์ด๋ค.
์๋ฆฌ์ ์ ํ์ฌํญ
Graceful Shutdown์ ์๋ฆฌ์ ์ ํ์ ์๋ ค๋ฉด Linux์์ ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์ด๋ ์ ๋ ์๊ณ ์์ด์ผ ํ๋ค.
์ผ๋จ ์ ์ ํ๊ฒ Graceful Shutdown ํ๊ฒฝ์ ๊ตฌ์ฑํ๋๋ผ๋, ๋ชจ๋ ์ํฉ์์ ๋์ํ๊ฒ ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค.
Linux์์ ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํ๋ ์ ํธ์๋ ๋ํ์ ์ผ๋ก ํฌ๊ฒ 3๊ฐ์ง๊ฐ ์๋ค.
-
SIGTERM: ์ ์ ์ข ๋ฃ. ํ๋ก์ธ์ค์๊ฒ ์ข ๋ฃ ์์ฒญ ์ ํธ๋ฅผ ๋ณด๋ธ๋ค. ๋ช ์ด ์ ๋์ ์ ์์๊ฐ์ ์ฃผ๊ณ , ์์์ ์ ๋ฆฌํ์ง ์๋๋ค๋ฉด OS๊ฐ ๊ฐ์ ๋ก ์ค๋จ์ํจ๋ค.
-
SIGINT: ์ ์ ์ข ๋ฃ. Ctrl+C๋ฅผ ํธ์ถํ์๋ ์ฃผ๋ก ๋ ๋ผ๊ฐ๋ค. ์ด๊ฒ๋ SIGTERM๊ณผ ๋์ ์๋ฆฌ๋ ๋น์ทํ๋ค.
-
SIGKILL: ๋น์ ์ ์ข ๋ฃ. ๋ฐ๋ก ์ค๋จ์ํจ๋ค.
์ฌ๊ธฐ์ SIGTERM์ด๋ SIGINT๋ ์ ์์๊ฐ์ด ์๊ธฐ์ ๋ฆฌ์์ค ์ ๋ฆฌ์์ ์ ์ด๋ ์ ๋ ์ฒ๋ฆฌํ ์ ์์ง๋ง, SIGKILL์ ๊ฒฝ์ฐ์๋ ๊ทธ๊ฒ์ด ๋ถ๊ฐ๋ฅํ๋ค.
๊ฐ๋ ํ๋ก์ธ์ค ์ข
๋ฃํ ๋ kill -9๋ก ์ค๋จ ๋ช
๋ น์ ๋ ๋ฆฐ ๊ธฐ์ต์ด ์์ ๊ฒ์ด๋ค. ์ด๊ฒ SIGKILL์ด๋ค.
๋น์ ์ ๋ญ๊ฐ ์ ๋ฆฌํ ์๊ฐ๋ ์ฃผ์ง ์๊ณ ์ฃฝ์ฌ๋ฒผ๋ฆฐ ๊ฒ์ด๋ค.
SIGTERM์ kill -15๋ฅผ ์จ์ผ ํ๋ค.
https://linuxhandbook.com/sigterm-vs-sigkill/
์์ผ๋ก๋ ๋ช์ด ์ ๋ ๊ธฐ๋ค๋ ค์ฃผ๋ ์ฌ์ ๋ฅผ ๊ฐ์ ธ๋ณด์
SIGINT, SIGTERM ํธ๋ค๋งํด๋ณด๊ธฐ (with Rust)
๊ฐ๋จํ ์์ ์ฝ๋๋ฅผ ํตํด์ Graceful Shutdown์ ๊ตฌํํ๋ ๋ฐฉ์์ ๋ณด์ฌ๋ณด๊ฒ ๋ค.
์๋์ ๊ฐ์ ์คํ
์ ๋ฐ๋ณตํ๋ ์ฝ๋๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ณด์.
์ฌ๊ธฐ์ A-B-C๋ ํ๋์ ์์ ํ ์์
์ด๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ
์ ๋งคํ ์ง์ ์์ ์ข
๋ฃ ์ ํธ๋ฅผ ๋ณด๋ด๋ฉด ์ด๋์ ๋ ์๋ ์ํ์์ ์ค๋จ๋ ์ ์๋ค.
์ด๊ฑธ ํธ๋ค๋งํ๋ ค๋ฉด SIGINT์ SIGTERM ์ ํธ๋ฅผ catchํด์ ๋ฌด์ํ ์ ์๋๋ก ํด์ผ ํ๋ค.
์ฌ๊ธฐ์๋ signal-hook๋ผ๋ ์ ์ฉ crate๋ฅผ ํตํด์ ๊ฐ๋จํ ์ ์ด ๋ก์ง์ ๊ตฌํํด๋ณด๊ฒ ๋ค.

use std::{
process::exit,
sync::{atomic::AtomicBool, Arc},
thread::sleep,
time::Duration,
};
fn main() {
let sigterm = Arc::new(AtomicBool::new(false));
let sigint = Arc::new(AtomicBool::new(false));
signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&sigterm)).unwrap();
signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&sigint)).unwrap();
let mut count = 0;
loop {
if sigterm.load(std::sync::atomic::Ordering::Relaxed) {
println!("SIGTERM received");
exit(0);
}
if sigint.load(std::sync::atomic::Ordering::Relaxed) {
println!("SIGINT received");
exit(0);
}
println!("A: {count}");
sleep(Duration::from_secs(1));
println!("B: {count}");
sleep(Duration::from_secs(1));
println!("C: {count}");
sleep(Duration::from_secs(1));
count += 1;
}
}
๊ฐ๊ฐ์ ํ๋๊ทธ์ฉ atomic ๋ณ์๋ฅผ ๋๊ณ , SIG๊ฐ ๋ฐ์ํ๋ฉด ๊ทธ๊ฑธ catchํด์ ์ ์ฅํ๋๋ก ํ๋ค.
์ด๋ฌ๋ฉด ๋ด๋ถ์์ ํธ๋ค๋ฌ๋ฅผ ์ปค์คํ
ํ๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ์ค๋จ๋์ง ์๊ณ , ํ๋ก๊ทธ๋จ ์์ค์์ ์ข
๋ฃ ์์ ์ ํต์ ํ ์ ์๋ค.
ํ ๊ฑฐ ๋คํ๊ณ exit ๋ ๋ ค์ ์ข
๋ฃํ๋ฉด ๋๋ ๊ฒ์ด๋ค.
๊ทธ๋ผ ์ด์
๋ฐ๋ก ์ข
๋ฃ๋์ง ์๊ณ ํ ์คํ
๋ค ๊ธฐ๋ค๋ฆฐ ๋ค์์ ์ข
๋ฃ๋ ๊ฒ์ด๋ค.
Java SpringBoot์ ๊ฒฝ์ฐ
Spring์ฒ๋ผ ์ด๋์ ๋ ์์ฑ๋ ํํ์ ์๋ฒ ํ๋ ์์ํฌ๋ค์ ์์ฒด์ ์ผ๋ก Graceful Shutdown์ ๋ํ ์ต์ ์ ์ ๊ณตํ๋ค. ๊ทธ๋ฅ ์์์ ์ค๋ช ํ๊ฑธ ํ๋๊ทธ๋ง ์ถ๊ฐํ๋ฉด ์ ์ฉ๋๋๋ก ํด๋ ๊ฒ์ด๋ค.
application properties์ ์ด๊ฒ๋ง ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
server:
shutdown: graceful
SpringBoot 2.3๋ถํฐ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.