Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Spring BootのGraceful shutdownって内部でどうやって実現されているの?
Search
kawakawaryuryu
July 30, 2020
Programming
0
1k
Spring BootのGraceful shutdownって内部でどうやって実現されているの?
JSUG勉強会 2020年その6 LT大会!の発表資料です
kawakawaryuryu
July 30, 2020
Tweet
Share
More Decks by kawakawaryuryu
See All by kawakawaryuryu
Spring Boot 1.5→2.1バージョンアップを経験して分かったハマりどころ
kawakawaryuryu
1
3.2k
第6章ICMP 第7章Ping
kawakawaryuryu
0
60
第14章DNS
kawakawaryuryu
0
43
逆求人イベント
kawakawaryuryu
0
82
Other Decks in Programming
See All in Programming
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
.NET のための通信フレームワーク MagicOnion 入門 / Introduction to MagicOnion
mayuki
1
1.6k
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
1.3k
Enabling DevOps and Team Topologies Through Architecture: Architecting for Fast Flow
cer
PRO
0
330
CSC509 Lecture 09
javiergs
PRO
0
140
型付き API リクエストを実現するいくつかの手法とその選択 / Typed API Request
euxn23
8
2.2k
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
junk0612
5
2.2k
ふかぼれ!CSSセレクターモジュール / Fukabore! CSS Selectors Module
petamoriken
0
150
Contemporary Test Cases
maaretp
0
140
Flutterを言い訳にしない!アプリの使い心地改善テクニック5選🔥
kno3a87
1
190
Kaigi on Rails 2024 〜運営の裏側〜
krpk1900
1
230
Make Impossible States Impossibleを 意識してReactのPropsを設計しよう
ikumatadokoro
0
170
Featured
See All Featured
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Typedesign – Prime Four
hannesfritz
40
2.4k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
65k
Visualization
eitanlees
145
15k
Art, The Web, and Tiny UX
lynnandtonic
297
20k
A Modern Web Designer's Workflow
chriscoyier
693
190k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
KATA
mclloyd
29
14k
RailsConf 2023
tenderlove
29
900
Transcript
Spring BootͷGraceful shutdownͬͯ෦ͰͲ͏ͬ ࣮ͯݱ͞Ε͍ͯΔͷʁ 2020/07/30 JSUGษڧձ 2020 ͦͷ6 LTେձ ޱɹཽଠʢ@kawakawaryuryuʣ
Who am I • ޱཽଠʢ@kawakawaryuryuʣ • ϠϑʔגࣜձࣾɹใγεςϜຊ෦ • ࣾձܭγεςϜͷ։ൃ •
࠷ۙ • ϑϩϯτΤϯυͷਓʹͳΓͭͭ͋Δ • Spring৮Εͯͳ͍ 2
Spring Boot 2.3͔ΒGraceful shutdown͕؆୯ʹ • Spring Boot 2.3͔Β؆୯ʹ࣮ݱͰ͖ΔΑ͏ʹͳͬͨ • Jetty,
Reactor Netty, Tomcat, UndertowͰαϙʔτ • ڍಈ • ఀࢭࢦࣔޙɺ৽نϦΫΤετड͚͚ͳ͍ • ॲཧதͷϦΫΤετ͕͔ྃͯ͠ΒαʔόΛఀࢭ͢Δ 3
Graceful shutdown࣮ݱํ๏ • application.ymlʹ2ͭͷϓϩύςΟΛՃ͢Δ͚ͩ • ඇৗʹ؆୯ʂ 4 server: shutdown: graceful
spring: lifecycle: timeout-per-shutdown-phase: 20s #αʔόͷ࠷େγϟοτμϯ࣌ؒ
͜͜Ͱٙ • ෦ͰͲ͏࣮ͬͯݱ͍ͯ͠Δͷʁ • ϒϥοΫϘοΫε͗͢Δɾɾ • ؾʹͳͬͯΕͳ͍ 5
ιʔείʔυͬͯΈ·ͨ͠ • ΰʔϧ • Graceful shutdownͷ࣮ॲཧՕॴΛ֬ೝ͢Δ • Graceful shutdownॲཧ͕ͲͷΑ͏ʹݺΕΔ͔֬ೝ͢Δ •
લఏ • Spring Boot 2.3.1Ͱ֬ೝ • Web ServerJettyͰ֬ೝ 6
·ͣSpring Bootىಈ % ./mvnw spring-boot:run ... . ____ _ __
_ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE) ... 2020-07-30 02:35:10.626 INFO 15060 --- [ main] o.e.jetty.server.AbstractConnector : Started ServerConnector@552ed807{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} 2020-07-30 02:35:10.628 INFO 15060 --- [ main] o.s.b.web.embedded.jetty.JettyWebServer : Jetty started on port(s) 8080 (http/1.1) with context path '/' 2020-07-30 02:35:10.640 INFO 15060 --- [ main] c.k.s.SampleGracefulShutdownApplication : Started SampleGracefulShutdownApplication in 1.517 seconds (JVM running for 1.795) 7
ΞϓϦΛఀࢭ 2020-07-30 02:35:14.253 INFO 15060 --- [ Thread-223] o.s.b.web.embedded.jetty.JettyWebServer :
Commencing graceful shutdown. Waiting for active requests to complete 2020-07-30 02:35:14.258 INFO 15060 --- [ jetty-shutdown] o.s.b.web.embedded.jetty.JettyWebServer : Graceful shutdown complete 2020-07-30 02:35:14.264 INFO 15060 --- [ Thread-223] o.e.jetty.server.AbstractConnector : Stopped ServerConnector@552ed807{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} 2020-07-30 02:35:14.265 INFO 15060 --- [ Thread-223] org.eclipse.jetty.server.session : node0 Stopped scavenging 2020-07-30 02:35:14.267 INFO 15060 --- [ Thread-223] o.e.j.s.h.ContextHandler.application : Destroying Spring FrameworkServlet 'dispatcherServlet' 2020-07-30 02:35:14.268 INFO 15060 --- [ Thread-223] o.e.jetty.server.handler.ContextHandler : Stopped o.s.b.w.e.j.JettyEmbeddedWebAppContext@38ed139b{application,/,[file:///private/var/folders/ds/ ky2m710d41ldw12zs6jhg4jh0000gn/T/jetty-docbase.10343674703387388779.8080/],UNAVAILABLE} 2020-07-30 02:35:14.270 INFO 15060 --- [ Thread-223] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' 8
ΞϓϦΛఀࢭ 2020-07-30 02:35:14.253 INFO 15060 --- [ Thread-223] o.s.b.web.embedded.jetty.JettyWebServer :
Commencing graceful shutdown. Waiting for active requests to complete 2020-07-30 02:35:14.258 INFO 15060 --- [ jetty-shutdown] o.s.b.web.embedded.jetty.JettyWebServer : Graceful shutdown complete 2020-07-30 02:35:14.264 INFO 15060 --- [ Thread-223] o.e.jetty.server.AbstractConnector : Stopped ServerConnector@552ed807{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} 2020-07-30 02:35:14.265 INFO 15060 --- [ Thread-223] org.eclipse.jetty.server.session : node0 Stopped scavenging 2020-07-30 02:35:14.267 INFO 15060 --- [ Thread-223] o.e.j.s.h.ContextHandler.application : Destroying Spring FrameworkServlet 'dispatcherServlet' 2020-07-30 02:35:14.268 INFO 15060 --- [ Thread-223] o.e.jetty.server.handler.ContextHandler : Stopped o.s.b.w.e.j.JettyEmbeddedWebAppContext@38ed139b{application,/,[file:///private/var/folders/ds/ ky2m710d41ldw12zs6jhg4jh0000gn/T/jetty-docbase.10343674703387388779.8080/],UNAVAILABLE} 2020-07-30 02:35:14.270 INFO 15060 --- [ Thread-223] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' 9 ͜ͷΫϥε͕(SBDFGVMTIVUEPXOʹؔΘͬͯͦ͏
JettyWebServerΫϥε • ͜ͷ෦ͰGraceful ShutdownΛߦͬͯͦ͏ 10 public class JettyWebServer implements WebServer
{ @Override public void shutDownGracefully(GracefulShutdownCallback callback) { if (this.gracefulShutdown == null) { callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE); return; } this.gracefulShutdown.shutDownGracefully(callback); } } UIJTHSBDFGVM4IVUEPXOΠϯελϯε͕OVMMͰͳ͍ ߹ʹ(SBDFGVMTIVUEPXOΛߦ͏
GracefulShutdownΫϥε 11 void shutDownGracefully(GracefulShutdownCallback callback) { logger.info("Commencing graceful shutdown. Waiting
for active requests to complete"); for (Connector connector : this.server.getConnectors()) { shutdown(connector); // (1) } this.shuttingDown = true; new Thread(() -> awaitShutdown(callback), "jetty-shutdown").start(); // (2) } ΞϓϦΛఀࢭͨ࣌͠ʹग़ྗ͞Εͨϩάͱಉ͡ Γ͜ͷ෦Ͱ(SBDFGVMTIVUEPXOͷॲཧΛͯͦ͠͏ ͔͜͜ΒઌͷॲཧεϥΠυͷ࠷ޙʹࡌ͚ͬͯ͋Γ·͢
JettyWebServerΫϥεʢ࠶ܝʣ • ͜ͷ෦ͰGraceful shutdownΛߦ͍ͬͯͦ͏ͳ͜ͱ͔ͬͨ • ͍ͭࣗ͜ମͲ͔͜ΒݺΕ͍ͯΔʁ 12 public class JettyWebServer
implements WebServer { @Override public void shutDownGracefully(GracefulShutdownCallback callback) { if (this.gracefulShutdown == null) { callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE); return; } this.gracefulShutdown.shutDownGracefully(callback); } }
WebServerGracefulShutdownLifecycle • ্هΫϥεͷstopϝιουͰݺΕΔ • SmartLifecycleͷstopϝιουΛΦʔόʔϥΠυ͍ͯ͠Δ 13 class WebServerGracefulShutdownLifecycle implements SmartLifecycle
{ @Override public void stop(Runnable callback) { this.running = false; this.webServer.shutDownGracefully((result) -> callback.run()); } }
SmartLifecycleʁ 14 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/SmartLifecycle.html
SmartLifecycle • Graceful shutdownͷॲཧΛݺͼग़͍ͯ͠Δਖ਼ମ͜Ε • SmartLifecycleΛ࣮ͨ͠ΫϥεApplicationContextͷىಈ࣌ ఀࢭ࣌ʹҙͷॲཧ͕ݺΕΔ 15
SmartLifecycleͷ࣮ 16 public class SampleSmartLifecycle implements SmartLifecycle { @Override public
void start() { // ىಈ࣌ͷҙॲཧΛ࣮ } @Override public void stop() { // ఀࢭ࣌ͷҙॲཧΛ࣮ } @Override public void stop(Runnable callback) { // ఀࢭ࣌ͷҙॲཧΛ࣮ // callbackΛड͚औͬͯ͞Εͨॲཧͷݺͼग़͕͠Մೳ } @Override public boolean isRunning() { // ίϯϙʔωϯτ͕Քಇதͷ߹ʹtrueΛฦ͢Α͏ʹ࣮ } } (SBDFGVMTIVUEPXOͰ͜ͷϝιουΛ ΦʔόʔϥΠυ͍ͯͨ͠
17 "QQMJDBUJPO$POUFYUΫϩʔζ࣌ʹ #FBOొ͞Ε͍ͯΔ4NBSU-JGFDZDMFͷ TUPQϝιουΛॱ൪ʹݺΜͰ͍͘
·ͱΊ • Spring BootͷGraceful shutdownSmartLifecycleͱ͍͏ΈΛ ͬͯApplicationContextͷఀࢭ࣌ʹݺͼग़͞ΕΔ • IDEΛۦ͢ΕSpring BootͷιʔείʔυׂͱಡΊΔͷͰ ͔Βͳ͍ͱ͖ಡΜͰΈΔͷ͕͓͢͢Ί
18
ઌQiitaʹهࣄΛॻ͖·ͨ͠ 19 https://qiita.com/kawakawaryuryu/items/d0cfd1bb1ec0402fd6c8
͝ਗ਼ௌ͋Γ͕ͱ͏ ͍͟͝·ͨ͠
͓·͚ JettyͷGraceful shutdown ࣮ॲཧՕॴͷ֬ೝ
GracefulShutdownΫϥε 22 void shutDownGracefully(GracefulShutdownCallback callback) { logger.info("Commencing graceful shutdown. Waiting
for active requests to complete"); for (Connector connector : this.server.getConnectors()) { shutdown(connector); // (1) } this.shuttingDown = true; new Thread(() -> awaitShutdown(callback), "jetty-shutdown").start(); // (2) } ΞϓϦΛఀࢭͨ࣌͠ʹग़ྗ͞Εͨϩάͱಉ͡
(1) ৽نϦΫΤετडΛఀࢭ͢Δॲཧ 23 void shutDownGracefully(GracefulShutdownCallback callback) { for (Connector connector
: this.server.getConnectors()) { shutdown(connector); // (1) } } private void shutdown(Connector connector) { try { connector.shutdown().get(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } catch (ExecutionException ex) { // Continue } } αʔό͕࣋ͭશίωΫλΛॱ൪ʹ ఀࢭ͍ͯ͘͠ ˠ৽نίωΫγϣϯͷडΛఀࢭ
(2) ॲཧதͷϦΫΤετͷྃޙ αʔόΛఀࢭ͢Δॲཧ 24 private void awaitShutdown(GracefulShutdownCallback callback) { while
(this.shuttingDown && this.activeRequests.get() > 0) { sleep(100); } this.shuttingDown = false; long activeRequests = this.activeRequests.get(); if (activeRequests == 0) { logger.info("Graceful shutdown complete"); callback.shutdownComplete(GracefulShutdownResult.IDLE); } else { logger.info(LogMessage.format("Graceful shutdown aborted with %d request(s) still active", activeRequests)); callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE); } } ΞΫςΟϒͳϦΫΤετ͕ͳ͘ͳΔ ·ͰTMFFQͭͭ͠ϧʔϓΛճ͢
(2) ॲཧதͷϦΫΤετͷྃޙ αʔόΛఀࢭ͢Δॲཧ 25 private void awaitShutdown(GracefulShutdownCallback callback) { while
(this.shuttingDown && this.activeRequests.get() > 0) { sleep(100); } this.shuttingDown = false; long activeRequests = this.activeRequests.get(); if (activeRequests == 0) { logger.info("Graceful shutdown complete"); callback.shutdownComplete(GracefulShutdownResult.IDLE); } else { logger.info(LogMessage.format("Graceful shutdown aborted with %d request(s) still active", activeRequests)); callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE); } } ΞΫςΟϒͳϦΫΤετ͕ʹͳͬͨΒ γϟοτμϯ ˠॲཧதͷϦΫΤετΛ͔ྃͯ͠Β ҆શʹఀࢭ