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
Introduction to Resilience4j
Search
Masatoshi Tada
April 08, 2020
Technology
2
1k
Introduction to Resilience4j
2020年4月 #jsug 勉強会での資料です。Netflix Hystrixの代替となるサーキットブレイカーライブラリResilience4jおよびSpring Bootでの利用方法の解説です。
Masatoshi Tada
April 08, 2020
Tweet
Share
More Decks by Masatoshi Tada
See All by Masatoshi Tada
プロになるためのSpring上級知識 #jsug / advanced-spring-for-professionals
masatoshitada
3
1.9k
OpenID Connect 1.0 with Spring Security #jjug_ccc #jjug_ccc_b / oidc-with-spring-security
masatoshitada
1
1.3k
Flaskのセキュリティどうしてます?アクセス制御ライブラリCasbin入門! #pycharity / flask-authz-with-casbin
masatoshitada
0
830
今こそ知りたいSpring DI×AOP / spring-di-aop-for-every-developers
masatoshitada
4
1.9k
OAuth 2.0 with Spring Security #jjug_ccc #jjug_ccc_b / oauth2-with-spring-security
masatoshitada
4
1.8k
基礎から分かる!アプリケーション開発者のためのKubernetes入門 / kubernetes-basics-for-application-developers
masatoshitada
10
3.5k
2時間で分かる!Kubernetesとは何なのか / what-is-kubernetes
masatoshitada
0
900
SpringOne Platform 2019報告会 -概要、Resilience4j、LT- #jsug / springone-platform-2019
masatoshitada
0
1.1k
From Hystrix To Resilience4j
masatoshitada
1
1k
Other Decks in Technology
See All in Technology
Grafana x PagerDuty Better Together
jacopen
1
330
Zero Data Loss Autonomous Recovery Service サービス概要
oracle4engineer
PRO
0
1.9k
【NW X Security JAWS#3】L3-4:AWS環境のIPv6移行に向けて知っておきたいこと
shotashiratori
1
710
LayerXにおけるLLMプロダクト開発の今までとこれから
layerx
PRO
4
1.4k
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Musicを例に~
otanet
0
320
Babylon.js JAPAN活動紹介 (2024/4)
limes2018
1
120
2024春 注目のWeb系 OSS & SaaS 3選
makies
0
200
同じ様なUIをiOS/Android間で合わせるヒントNo.2
fumiyasac0921
1
110
Microsoft Intune 勉強会 第 2 回目
tamaiyutaro
2
510
IaCジェネレーターとBedrockで詳細設計書を生成してみた
tsukasa_ishimaru
4
940
生産性向上チームの紹介
cybozuinsideout
PRO
1
960
今さら聞けないDocker入門 〜 Dockerfileのベストプラクティス編
devops_vtj
21
6.2k
Featured
See All Featured
It's Worth the Effort
3n
180
27k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
80
44k
A Tale of Four Properties
chriscoyier
153
22k
A better future with KSS
kneath
231
16k
Adopting Sorbet at Scale
ufuk
69
8.6k
BBQ
matthewcrist
80
8.8k
The Cost Of JavaScript in 2023
addyosmani
21
3.9k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
22
1.6k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
How to train your dragon (web standard)
notwaldorf
75
5.2k
Building Effective Engineering Teams - LeadDev
addyosmani
32
1.9k
StorybookのUI Testing Handbookを読んだ
zakiyama
13
4.6k
Transcript
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH *OUSPEVDUJPOUP 3FTJMJFODFK ג ΧαϨΞϧଟాਅහ ݄ +46(ษڧձ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣗݾհ ▸ ଟాਅහʢ!TVLF@NBTBʣ ▸ ݚमτϨʔφʔ!ΧαϨΞϧ ▸
4QSJOH+BWB&&.JDSPTFSWJDFT $MPVE'PVOESZ,VCFSOFUFT ▸ 1JWPUBMೝఆߨࢣ ▸ ຊ4QSJOHϢʔβձελοϑ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 3FTJMJFODFKυΩϡϝϯτΛ༁͠·ͨ͠ʂ ▸ IUUQTHJUIVCDPNSFTJMJFODFKEPDTKB SFTJMJFODFKEPDTKB *TTVFใࠂɺϓϧϦΫͳͲ
͓͍ͪͯ͠·͢ʂ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ͜ͷηογϣϯͷత ▸ 3FTJMJFODFKυΩϡϝϯτΛಡΜͰࠔΒͳ͍Α͏ ʹɺഎܠΈΛཧղ͢Δʂ ▸ ࠓճ4QSJOH#PPUͰͷίʔυྫͳͲগͳΊ
ʢυΩϡϝϯτʹࢁ͋ΔͷͰʣ ▸ αϯϓϧίʔυ ▸ IUUQTHJUIVCDPN.BTBUPTIJ5BEBSFTJMJFODFK TQSJOHCPPUTBNQMF
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣍ ▸ 3FTJMJFODFKొͷഎܠ ▸ αʔΩοτϒϨΠΧʔͱঢ়ଶભҠ ▸
4QSJOH#PPUͰͷར༻ ▸ 4QSJOH$MPVE$JSDVJU#SFBLFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣍ ▸ 3FTJMJFODFKొͷഎܠ ▸ αʔΩοτϒϨΠΧʔͱঢ়ଶભҠ ▸
4QSJOH#PPUͰͷར༻ ▸ 4QSJOH$MPVE$JSDVJU#SFBLFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ϚΠΫϩαʔϏεߟ͑Δ͜ͱ͕͍ͬͺ͍ Circuit Breaker Design for
Failure Service Discovery Distributed Tracing API Gateway Observability Polyglot Persistence Containerization Orchestration
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVEͱ ▸ ϚΠΫϩαʔϏεʹඞཁͳػೳΛ·ͱΊͨ ϥΠϒϥϦ ▸ ϚΠΫϩαʔϏε։ൃΛ͋Δఔָʹͯ͘͠ΕΔ
▸ 4QSJOH#PPUϕʔε
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH <౾ࣝ>4QSJOH$MPVEͷόʔδϣϯ ▸ ӳࠃϩϯυϯࢢͷ֗ͷ໊લ͕͍͍ͯΔ Spring Cloud
ରԠ͢ΔSpring Bootͷόʔδϣϯ Angel ??? Brixton ??? Camden ??? Dalston ??? Edgware 1.5 Finchley 2.0 Greenwich 2.1 Hoxton 2.2 ←ࠓίί
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH /FUqJY044 ▸ /FUqJYࣾϚΠΫϩαʔϏεʹඞཁͳϥΠϒϥϦΛɺ ΦϦδφϧͷ044ͱͯ͠࡞͍ͬͯΔ ▸ )ZTUSJY
αʔΩοτϒϨΠΧʔ ▸ 3JCCPO ϩʔυόϥϯγϯά ▸ &VSFLB αʔϏεσΟεΧόϦʔ ▸ ;VVM "1*ήʔτΣΠ ▸ ɾɾɾ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVE/FUqJY ▸ 4QSJOHͱ/FUqJY044Λ࿈ܞͤ͞ΔϥΠϒϥϦ ▸ TQSJOHDMPVETUBSUFSOFUqJYIZTUSJY ▸
TQSJOHDMPVETUBSUFSOFUqJYSJCCPO ▸ TQSJOHDMPVETUBSUFSOFUqJYFVSFLBTFSWFS ▸ TQSJOHDMPVETUBSUFSOFUqJY[VVM ▸ ɾɾɾ ▸ લ4QSJOH$MPVEͷ໊ࢺతଘࡏͩͬͨ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH /FUqJY044ͷଟ͘อकϞʔυʹ ▸ อकϞʔυʹੵۃతʹ։ൃ͞Εͳ͍ ▸ )ZTUSJY3JCCPOอकϞʔυ ▸
&VSFLB;VVMͷ։ൃܧଓ͍ͯ͠ΔͬΆ͍ https://github.com/Netflix/Hystrix
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH0OF,FZOPUFΑΓ ▸ /FUqJYࣾ4QSJOHϓϩδΣΫτͱ ΑΓ࿈ܞ͍ͯ͘͜͠ͱΛൃද https://www.youtube.com/watch?v=mln3_o6qlBo
1:44ลΓ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVE/FUqJYେ͕อकϞʔυ ▸ TQSJOHDMPVEOFUqJYIZTUSJY ▸ TQSJOHDMPVEOFUqJYIZTUSJYDPOUSBDU ▸
TQSJOHDMPVEOFUqJYIZTUSJYEBTICPBSE ▸ TQSJOHDMPVEOFUqJYIZTUSJYTUSFBN ▸ TQSJOHDMPVEOFUqJYSJCCPO ▸ TQSJOHDMPVEOFUqJY[VVM ▸ TQSJOHDMPVEOFUqJYUVSCJOF ▸ TQSJOHDMPVEOFUqJYUVSCJOFTUSFBN ▸ TQSJOHDMPVEOFUqJYBSDIBJVT ˞FVSFLBର֎ https://spring.io/blog/2019/01/23/spring-cloud-greenwich-release-is-now-available ΑΓ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVE/FUqJYͷସ ͋͘·ͰҰྫ ▸ )ZTUSJYˠ3FTJMJFODFK ▸ &VSFLBˠ4QSJOH$MPVE$POTVM
▸ ;VVMˠ4QSJOH$MPVE(BUFXBZ ▸ 3JCCPOˠ4QSJOH$MPVE-PBE#BMBODFS ▸ "SDIJVTˠ4QSJOH$MPVE$POpH ▸ 5VSCJOFˠ.JDSPNFUFS 1SPNFUIFVT ※܁Γฦ͠ʹͳΓ·͕͢ɺZuulɾEureka͓Αͼspring-cloud-netflix-eurekaͷ։ൃܧଓ͍ͯ͠·͢
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 3FTJMJFODFKͱ ▸ )ZTUSJYʹΘΔαʔΩοτϒϨΠΧʔϥΠϒϥϦ ▸ ؔܕϓϩάϥϛϯάϞσϧ͕ಛ ▸
࡞ऀ3PCFSU8JOLMFSࢯ !SCSUXOLMS ▸ 4QSJOH/FUqJYͱಠཱͨ͠ϓϩδΣΫτ͕ͩ ▸ )ZTUSJYͷ3&"%.&ʹʮΘΓʹ3FTJMJFODFKΛΦεεϝ ͢ΔΑʂʯͱॻ͍ͯ͋Δ ▸ 4QSJOH#PPUͱͷ࿈ܞػೳΛఏڙ͍ͯ͠Δ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ίΞϞδϡʔϧ ▸ $JSDVJU#SFBLFSˡࠓίϨ ▸ #VMLIFBE ▸
3BUF-JNJUFS ▸ 3FUSZ ▸ $BDIF ▸ 5JNF-JNJUFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ΞυΦϯϞδϡʔϧ ▸ 4QSJOH#PPU4UBSUFS ▸ 3FUSPpUBEBQUFS ▸
'FJHOBEBQUFS ▸ $JSDVMBS#V⒎FS&WFOU DPOTVNFS ▸ ,PUMJODPSPVUJOFTTVQQPSU ▸ 3BUQBDL4UBSUFS ▸ 7FSUY'VUVSFEFDPSBUPS ▸ $VTUPN3Y+BWBPQFSBUPST ▸ $VTUPN4QSJOH3FBDUPSPQFSBUPST ▸ .JDSPNFUFS.FUSJDTFYQPSUFS ▸ %SPQXJ[BSE.FUSJDTFYQPSUFS ▸ 1SPNFUIFVT.FUSJDTFYQPSUFS ▸ $BNFM$JSDVJU#SFBLFS ▸ 4QSJOH$MPVE$JSDVJU#SFBLFS ▸ IUUQLSFTJMJFODFNPEVMF
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ͬ͘͟Γͱͨ͠ΞʔΩςΫνϟ CircuitBreakerConfig CircuitBreakerRegistry Circuit Breaker
Circuit Breaker Circuit Breaker ੜ ੜ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ͜Μͳίʔυ // ઃఆͷ࡞ CircuitBreakerConfig config
= CircuitBreakerConfig.ofDefaults(); // Registryͷ࡞ CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config); // αʔΩοτϒϨΠΧʔͷ࡞ CircuitBreaker cb = registry.circuitBreaker("backendB");
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ͜Μͳίʔυ // όοΫΤϯυݺͼग़͠ΛσίϨʔτ Supplier<String> ds
= cb.decorateSupplier( () -> backendBService.doSomething()); // ݺͼग़࣮͠ߦ Try<String> result = Try.ofSupplier(ds) // ྫ֎࣌ͷସॲཧ .recover(throwable -> "Recovery"); // ݁ՌΛऔಘ String resultValue = result.get();
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣍ ▸ 3FTJMJFODFKొͷഎܠ ▸ αʔΩοτϒϨΠΧʔͱঢ়ଶભҠ ▸
4QSJOH#PPUͰͷར༻ ▸ 4QSJOH$MPVE$JSDVJU#SFBLFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ϚΠΫϩαʔϏεͳ͍ͥ͠ʁ ▸ োͷൃੜ͕֬ɺϞϊϦεΑΓ֨ஈʹ্͕Δ͔Βʂ ᶃ ׂ͢ΔʹؒʹωοτϫʔΫ͕ೖΔʹো͕૿͑Δ ▸
ʮࢄίϯϐϡʔςΟϯάͷམͱ݀͠ʯͰݕࡧ ᶄ ՔಇࢦؔతʹԼ͢Δ ▸ ྫʣͷ㲈ɺͷ㲈 ᶅ සൟʹσϓϩΠɾεέʔϧ͢Δʹγϟοτμϯ͕සൟ ▸ λΠϛϯάѱ͘ɺγϟοτμϯதʹϦΫΤετ͕དྷΔ͔
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH %FTJHOGPS'BJMVSF ▸ ૬खͷোΛৗʹఆͯ͠ઃܭ͢͠ ▸ Ϩεϙϯε͕ฦͬͯ͜ͳ͔ͬͨΒͲ͏͠Α͏ʁ ▸
Ϩεϙϯε͕ͱ͔ͯͬͨΒͲ͏͠Α͏ʁ ▸ εςʔλείʔυσʔλߏ͕ఆ֎ͩͬͨΒ Ͳ͏͠Α͏ʁ ϚΠΫϩ αʔϏε " ϚΠΫϩ αʔϏε #
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH αʔΩοτϒϨΠΧʔͷׂ ▸ ૬खͷোΛݕͨ͠ΒϦΫΤετૹ৴ΛࢭΊɺ ▸ ແବͳॲཧΛ͠ͳ͍Α͏ʹ͢Δ ▸
૬खʹ͜ΕҎ্ͷෛՙΛ͔͚ͳ͍Α͏͢Δ ϚΠΫϩ αʔϏε " ϚΠΫϩ αʔϏε # ᶃϦΫΤετૹ৴ ᶄҟৗͳϨεϙϯε ᶅସॲཧ ɹΛ࣮ߦ ᶆҎ߱ϦΫΤετૹ৴ͤͣ ɹସॲཧͷΈ࣮ߦ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH αʔΩοτϒϨΠΧʔͷঢ়ଶ ঢ়ଶ ϦΫΤετ ૹ৴ ସॲཧ
CLOSED (ਖ਼ৗ) ͢Δ ҟৗͳϨεϙϯε࣌ ͷΈ࣮ߦ OPEN (ҟৗ) ͠ͳ͍ ৗʹ࣮ߦ ʢ૬खʹϦΫΤετ ૹ৴͠ͳ͍ʣ HALF_OPEN (CLOSEDʹΖ͏ͱ͢Δ) ͢Δ ʢࢦఆճͷΈʣ ҟৗͳϨεϙϯε࣌ ͷΈ࣮ߦ ˞͏ͭಛผͳঢ়ଶ͕ଘࡏ͠·͕͢ɺࠓճઆ໌ͷൣғ֎ͱ͠·͢
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH αʔΩοτϒϨΠΧʔͷঢ়ଶભҠ $-04&% 01&/ )"-'@01&/ ࣦഊ㱢ᮢPS
ݺग़Ԇ㱢ᮢ ͋Δ࣌ؒ ͕ܦա ࣦഊʻᮢBOE ݺग़Ԇʻᮢ ࣦഊ㱢ᮢPS ݺग़Ԇ㱢ᮢ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ʮࣦഊʯʮݺग़Ԇʯͱ ▸ ࣦഊʹྫ֎ͷൃੜ ▸ ରͷྫ֎ઃఆՄೳʢσϑΥϧτͰશྫ֎͕ରʣ ▸
ݺग़ԆʹΓ͕ฦΔ·Ͱͷ͕࣌ؒᮢΛ͑Δ ▸ ᮢઃఆՄೳʢσϑΥϧτඵʣ CircuitBreaker cb = ...; Supplier<String> ds = cb.decorateSupplier( () -> backendBService.doSomething()); ྫ֎ʹࣦഊɺ͍ʹݺग़Ԇ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ݺग़݁Ռͷอଘ ▸ ݺग़݁ՌʢޭɺࣦഊɺԆͳͲʣ εϥΠσΟϯάΟϯυʹอଘ͞ΕΔ ▸ ճϕʔεɿ/ݸͷݺग़݁Ռͷ॥ྻͰอ࣋
ɹɹɹɹɹɹʢσϑΥϧτʣ ▸ ࣌ؒϕʔεɿ֤ඵؒͷ෦ूΛ/ݸͷ॥ྻͰอ࣋
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ճϕʔεͷεϥΠσΟϯάΟϯυ public class FixedSizeSlidingWindowMetrics implements
Metrics { // ॥ྻͷ͞ private final int windowSize; // ॥ྻͷશཁૉΛूܭͨ݁͠ՌΛอ࣋ private final TotalAggregation totalAggregation; // ݸผͷݺग़݁ՌΛอ࣋͢Δ॥ྻ private final Measurement[] measurements; // ॥ྻͷΠϯσοΫε int headIndex; ▸ /ݸͷݺग़݁Ռͷ॥ྻͰอ࣋ ▸ / ݸҎ߱ͷݺग़݁Ռɺݹ͍݁ՌΛ্ॻ͖͢Δ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣌ؒϕʔεͷεϥΠσΟϯάΟϯυ public class SlidingTimeWindowMetrics implements
Metrics { // 1ඵຖͷݺग़݁ՌूܭΛอ࣋͢Δ॥ྻ final PartialAggregation[] partialAggregations; // ॥ྻͷ͞ private final int timeWindowSizeInSeconds; // ॥ྻͷશཁૉΛूܭͨ݁͠ՌΛอ࣋ private final TotalAggregation totalAggregation; // ॥ྻͷΠϯσοΫε int headIndex; ▸ ֤ඵؒͷ෦ूΛ/ݸͷ॥ྻͰอ࣋ ▸ ճճͷݺग़݁Ռอ࣋͠ͳ͍ ▸ / ඵҎ߱ͷݺग़݁Ռɺݹ͍݁ՌΛ্ॻ͖͢Δ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣦഊɺݺग़Ԇͷܭࢉํ๏ $-04&%ˠ01&/ ▸ ࣦഊʹ ࣦഊճ×૯ݺग़ճ º
▸ ݺग़Ԇʹ Ԇճ×૯ݺग़ճ º ▸ ݺग़ճ͕࠷খݺग़ճҎ্ʹͳͬͨΒܭࢉ͞ΕΔ ▸ ࠷খݺग़ճઃఆՄೳʢσϑΥϧτճʣ ▸ ٯʹݴ͏ͱɺ࠷খݺग़ճະຬͰɺશͯͷݺͼग़͕͠ ࣦഊͰ͋ͬͯ$-04&%͔Β01&/ʹભҠ͠ͳ͍
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣦഊɺݺग़Ԇͷܭࢉํ๏ )"-'@01&/ˠ01&/ ▸ ࠷େݺग़Մೳճͷઃఆ͕ඞཁ ▸ σϑΥϧτճɺ͜ΕΛ͑ͯݺͼग़͢ͱྫ֎
▸ ඞͣճϕʔεʹͳΔ ▸ ΟϯυαΠζʹ࠷େݺग़Մೳճ ▸ ࠷খݺग़ճʹ min(࠷େݺग़Մೳճ,$-04&%࣌ͷ࠷খݺग़ճ)
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ઃఆɿࣦഊɾݺग़Ԇ ˞4QSJOH#PPUར༻࣌BQQMJDBUJPOQSPQFSUJFTʹઃఆՄೳͳͷͰɺ্هͷίʔυඞཁແ͠ CircuitBreakerConfig config =
CircuitBreakerConfig.custom() .minimumNumberOfCalls(5) // ࠷খݺग़ճ .failureRateThreshold(50) // ࣦഊͷᮢ(%) .slowCallDurationThreshold( // ݺग़Ԇͷᮢ Duration.ofMillis(1000)) .recordExceptions( // ࣦഊͱݟͳ͢ྫ֎ͷϦετ AException.class, BException.class) .ignoreExceptions( // ࣦഊͱޭͱ͠ͳ͍ྫ֎ͷϦετ CException.class, DException.class) ... .build();
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ҙ ▸ ݺग़ԆͷᮢΛઃఆͯ͠ɺ λΠϜΞτ͞ΕΔ༁Ͱͳ͍ʂʂ ▸ ྫʣᮢΛඵʹઃఆͯ͠ɺϨεϙϯεʹඵ͔͔ͬ
ͨΒͦͷॲཧඵ͔͔ΔʢඵͰଧͪΒΕͳ͍ʣ ▸ λΠϜΞτ͢ΔʹɺRestTemplateͳͲʹ λΠϜΞτઃఆ͕ඞཁ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 01&/ˠ)"-'@01&/ͷͪ࣌ؒ 01&/ )"-'@01&/ ᶃඵܦա ᶄࣦഊͨ͠߹
ɹ01&/ʹΔ ᶅ࣍Կඵͭʁ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 01&/ˠ)"-'@01&/ͷͪ࣌ؒܭࢉํ๏ ▸ IntervalFunctionΠϯλϑΣʔε࣮Ϋϥεͷ apply()ϝιουͰࢦఆ͢Δ ▸ σϑΥϧτͰ༻ҙ͞Ε͍ͯΔ࣮
ᶃ Ұఆ͚࣌ؒͩͭʢ$POTUBOU#BDLP⒎ɺσϑΥϧτʣ ᶄ ϥϯμϜͳ࣌ؒͭʢ3BOEPNJ[FE#BDLP⒎ʣ ᶅ ͪ࣌ؒΛࢦؔతʹ૿͢ʢ&YQPOFOUJBM#BDLP⒎ʣ ᶆ ϥϯμϜʴࢦؔʢ&YQPOFOUJBM3BOEPN#BDLP⒎ʣ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ઃఆɿ01&/ˠ)"-'@01&/ͷͪ࣌ؒ ˞4QSJOH#PPUར༻࣌BQQMJDBUJPOQSPQFSUJFTʹઃఆՄೳͳͷͰɺ্هͷίʔυඞཁແ͠ // Randomized Backoff
CircuitBreakerConfig config = CircuitBreakerConfig.custom() .waitIntervalFunctionInOpenState( IntervalFunction.ofRandomized()) ... // Constant Backoff CircuitBreakerConfig config = CircuitBreakerConfig.custom() .waitDurationInOpenState(Duration.ofSeconds(3)) ...
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ઃఆɿ01&/ˠ)"-'@01&/ͷͪ࣌ؒ ˞4QSJOH#PPUར༻࣌BQQMJDBUJPOQSPQFSUJFTʹઃఆՄೳͳͷͰɺ্هͷίʔυඞཁແ͠ // Exponential Random
Backoff CircuitBreakerConfig config = CircuitBreakerConfig.custom() .waitIntervalFunctionInOpenState( IntervalFunction.ofExponentialRandomBackoff( Duration.ofSeconds(1), 2)) ... // Exponential Backoff CircuitBreakerConfig config = CircuitBreakerConfig.custom() .waitIntervalFunctionInOpenState( IntervalFunction.ofExponentialBackoff( Duration.ofSeconds(1), 2)) ...
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ओཁͳΫϥεͷΫϥεਤ 1PXFSFECZ1MBOU6.- ˞ਖ਼֬ͳΫϥεਤͷه๏ʹͳ͍ͬͯͳ͍͔͠Εͳ͍ͷͰɺ ɹงғؾͰಡΜͰ͍͍ͩ͘͞
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣍ ▸ 3FTJMJFODFKొͷഎܠ ▸ αʔΩοτϒϨΠΧʔͱঢ়ଶભҠ ▸
4QSJOH#PPUͰͷར༻ ▸ 4QSJOH$MPVE$JSDVJU#SFBLFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH#PPUͱͷ࿈ܞϥΠϒϥϦ ▸ SFTJMJFODFKTQSJOHCPPU ▸ 4QSJOH#PPU4UBSUFS ▸
ผ్TQSJOHCPPUTUBSUFSBDUVBUPSͱ TQSJOHCPPUTUBSUFSBPQඞཁ ▸ SFTJMJFODFKTQSJOHDMPVE ▸ SFTJMJFODFKTQSJOHCPPUʹ 4QSJOH$MPVE$POpHͱͷ࿈ܞػೳΛՃ͑ͨͷ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVEซ༻࣌ͷҙ ▸ TQSJOHDMPVEEFQFOEFODJFTΛؚΊ͍ͯͨ߹ɺ 3FTJMJFODFKͷόʔδϣϯ্ॻ͖͕ඞཁ ▸ TQSJOHDMPVEDJSDVJUCSFBLFS͕͍ͬͯΔ3FTJMJFODFKͷ
όʔδϣϯ͕ݹ͍ͨΊ ▸ ্ॻ͖͕ඞཁͳͷԼه ▸ SFTJMJFODFKDJSDVJUCSFBLFS ▸ SFTJMJFODFKUJNFMJNJUFS ▸ SFTJMJFODFKNJDSPNFUFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH BQQMJDBUJPOZNM resilience4j.circuitbreaker: instances: hello-api: failure-rate-threshold:
50 slow-call-rate-threshold: 100 slow-call-duration-threshold: 1s permitted-number-of-calls-in-half-open-state: 3 ... public HelloService(CircuitBreakerRegistry registry) { this.circuitBreaker = registry.circuitBreaker("hello-api"); } ໊લΛἧ͑Δ ໊લΛἧ͑Δ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH "VUP$POpHVSBUJPOରൣғ BQQMJDBUJPO QSPQFSUJFT CircuitBreakerConfig CircuitBreakerRegistry
Circuit Breaker Circuit Breaker Circuit Breaker ੜ ੜ Πϯϓοτ #FBOఆٛࡁΈͳͷͰ ࡞ෆཁ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ͍ํ @Service public class HelloService
{ private final CircuitBreaker circuitBreaker; // ίϯετϥΫλΠϯδΣΫγϣϯ public HelloService( CircuitBreakerRegistry registry) { this.circuitBreaker = registry.circuitBreaker("hello-api"); }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ΞϊςʔγϣϯελΠϧ @CircuitBreaker(name = "hello-api", fallbackMethod
= "helloFallback") public String hello() { return restTemplate.getForObject( helloApiUrl + "/hello", String.class); } // ସॲཧ public String helloFallback(Throwable t) { t.printStackTrace(); return "Recover"; } ˞͜ͷ߹CircuitBreakerΠϯελϯεΛੜ͢Δඞཁͳ͠
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH "DUVBUPSͰͷࢹ ▸ "DUVBUPSͰ$JSDVJU#SFBLFSͷঢ়ଶΛࢹͰ͖Δ ▸ BDUVBUPSNFUSJDTSFTJMJFODFKDJSDVJUCSFBLFS999 ▸
BDUVBUPSIFBMUI ▸ BDUVBUPSDJSDVJUCSFBLFST ▸ BDUVBUPSDJSDVJUCSFBLFSFWFOUT
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 1SPNFUIFVTར༻࣌ͷҙ ▸ SFTJMJFODFKQSPNFUIFVTͰͳ͘ɺ SFTJMJFODFKNJDSPNFUFS NJDSPNFUFSSFHJTUSZQSPNFUIFVTΛ͏
https://twitter.com/rbrtwnklr/status/1172792997026697216
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ࣍ ▸ 3FTJMJFODFKొͷഎܠ ▸ αʔΩοτϒϨΠΧʔͱঢ়ଶભҠ ▸
4QSJOH#PPUͰͷར༻ ▸ 4QSJOH$MPVE$JSDVJU#SFBLFS
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVE$JSDVJU#SFBLFS ▸ 4QSJOH͓ಘҙͷநԽϥΠϒϥϦ ▸ ԼهͷରԠαʔΩοτϒϨΠΧʔͳΒɺ ಉ͡Α͏ʹѻ͑Δ
▸ 3FTJMJFODFK ▸ /FUqJY)ZTUSJY ▸ "MJCBCB4FOUJOFM ▸ 4QSJOH3FUSZ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH TQSJOHDMPVETUBSUFSDJSDVJUCSFBLFSSFTJMJFODFK ▸ 4QSJOH$MPVE$JSDVJU#SFBLFSͷ 3FTJMJFODFK࣮ ▸ $JSDVJU#SFBLFSͱ5JNF-JNJUFSؚ͕·Ε͍ͯΔ
▸ SFTJMJFODFKNJDSPNFUFSΛՃ͢Εɺ "DUVBUPSΤϯυϙΠϯτΛ࡞Δ͜ͱՄೳ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ͜Μͳίʔυ import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
@Service public class HelloService { private final CircuitBreaker circuitBreaker; public HelloService(..., CircuitBreakerFactory circuitBreakerFactory) { this.circuitBreaker = circuitBreakerFactory.create("hello-api"); } public String hello() { String result = circuitBreaker.run( () -> restTemplate.getForObject(helloApiUrl + "/hello", String.class), throwable -> "Recovery"); return result; } ˞@CircuitBreakerͷΑ͏ͳΞϊςʔγϣϯఏڙ͞Ε͍ͯͳ͍
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH $JSDVJU#SFBLFSSVO ͷίʔυ public class Resilience4JCircuitBreaker
implements CircuitBreaker { @Override public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) { // TimeLimiterΛద༻ Callable restrictedCall = TimeLimiter.decorateFutureSupplier( timeLimiter, futureSupplier); // CircuitBreakerΛద༻ Callable<T> callable = io.github.resilience4j.circuitbreaker.CircuitBreaker .decorateCallable(defaultCircuitBreaker, restrictedCall); // ࣮ߦˍϑΥʔϧόοΫॲཧ return Try.of(callable::call).recover(fallback).get(); } } ▸ $JSDVJU#SFBLFS͚ͩͰͳ͘ɺ5JNF-JNJUFS ద༻͞ΕΔ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH $JSDVJU#SFBLFSɾ5JNF-JNJUFSͷઃఆ @Bean public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer()
{ TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom() // Կ͔ΧελϚΠζ͢ΔίʔυΛॻ͘ .build(); CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() // Կ͔ΧελϚΠζ͢ΔίʔυΛॻ͘ .build(); return factory -> factory.configureDefault( ɹɹɹɹɹɹɹɹɹɹɹid -> new Resilience4JConfigBuilder(id) .timeLimiterConfig(timeLimiterConfig) .circuitBreakerConfig(circuitBreakerConfig) .build()); } ▸ $VTUPNJ[FSΛར༻͢Δ ▸ BQQMJDBUJPOQSPQFSUJFTΛ͍͍ͨ߹ɺ ࣗͰ$POpHVSBUJPO1SPQFSUJFTͳͲΛ࡞Δඞཁ͋Γ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH 4QSJOH$MPVE$JSDVJU#SFBLFSΛ͏͔ʁ ▸ ҰൠʹɺϚΠΫϩαʔϏεؔ࿈ϥΠϒϥϦण໋͕͍ ˠͦΕΛݒ೦͢ΔͳΒ͏ ▸ நԽ͞Ε͍ͯΔͷͰɺ3FTJMJFODFKಛ༗ͷॲཧ
ॻ͖ͮΒ͘ͳΔ ˠͦΕ͕ݏͳΒΘͳ͍ ▸ ݺग़ʹ5JNF-JNJUFSඞͣద༻͞ΕΔ ˠͦΕ͕ݏͳΒΘͳ͍
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE ࣭5XJUUFSͰKTVH ·ͱΊ ▸ 3FTJMJFODFKɺ/FUqJY)ZTUSJYʹΘΔ ৽͍͠αʔΩοτϒϨΠΧʔϥΠϒϥϦ ▸ ঢ়ଶભҠͷΈΛཧղ͢Δ͜ͱ͕େ
▸ 4QSJOH#PPUͱͷ࿈ܞόονϦ ▸ 4QSJOH$MPVE$JSDVJU#SFBLFSͷར༻ ͓ΈͰ