מדריך לחוסן 4j

1. סקירה כללית

במדריך זה נדבר על ספריית Resilience4j.

הספרייה מסייעת ביישום מערכות גמישות על ידי ניהול סובלנות תקלות בתקשורת מרחוק.

הספרייה היא בהשראת Hystrix אך מציעה ממשק API הרבה יותר נוח ומספר תכונות אחרות כמו Rate Limiter (חסום בקשות תכופות מדי), Bulkhead (הימנע מיותר מדי בקשות במקביל) וכו '.

2. הגדרת Maven

כדי להתחיל, עלינו להוסיף את מודולי היעד שלנו pom.xml (למשל, כאן אנו מוסיפים את המפסק):

 io.github.resilience4j resilience4j-circuitbreaker 0.12.1 

הנה, אנו משתמשים ב- מפסק מעגל מודול. ניתן למצוא את כל המודולים והגרסאות העדכניות שלהם ב- Maven Central.

בחלקים הבאים נעבור על המודולים הנפוצים ביותר בספריה.

3. מפסק

שים לב כי עבור מודול זה אנו זקוקים ל- מפסק מעגל 4j תלות המוצגת לעיל.

דפוס המפסק מסייע לנו במניעת מפל של כשלים כאשר שירות מרחוק אינו פעיל.

לאחר מספר ניסיונות כושלים, אנו יכולים לשקול כי השירות אינו זמין / עומס יתר ולדחות בשקיקה את כל הבקשות הבאות לזה. בדרך זו אנו יכולים לחסוך משאבי מערכת לשיחות העלולות להיכשל.

בואו נראה איך נוכל להשיג זאת באמצעות Resilience4j.

ראשית, עלינו להגדיר את ההגדרות לשימוש. הדרך הפשוטה ביותר היא להשתמש בהגדרות ברירת המחדל:

CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults ();

אפשר גם להשתמש בפרמטרים מותאמים אישית:

CircuitBreakerConfig config = CircuitBreakerConfig.custom () .failureRateThreshold (20) .ringBufferSizeInClosedState (5) .build ();

כאן קבענו את רף התעריף ל -20% ומספר מינימלי של 5 ניסיונות שיחה.

לאחר מכן, אנו יוצרים a CircuitBreaker התנגד והתקשר באמצעותו לשירות המרוחק:

ממשק RemoteService {int תהליך (int i); } הרישום CircuitBreakerRegistry = CircuitBreakerRegistry.of (config); CircuitBreaker circuitBreaker = registry.circuitBreaker ("שלי"); פונקציה מעוטרת = CircuitBreaker .decorateFunction (circuitBreaker, service :: process);

לבסוף, בואו נראה איך זה עובד באמצעות מבחן JUnit.

ננסה להתקשר לשירות 10 פעמים. אנו אמורים להיות מסוגלים לוודא שהשיחה ניסתה לפחות 5 פעמים, ואז להפסיק אותה ברגע ש -20% מהשיחות נכשלו:

מתי (service.process (כל (Integer.class))). ואז לזרוק (RuntimeException חדש ()); עבור (int i = 0; i <10; i ++) {נסה {decor.apply (i); } לתפוס (התעלמות מחריג) {}} אמת (שירות, זמנים (5)). תהליך (כל (Integer.class));

3.1. מפסקי פחת מדינות והגדרות

א CircuitBreaker יכול להיות באחת משלוש המדינות:

  • סָגוּר - הכל בסדר, לא מעורב קצר
  • לִפְתוֹחַ - השרת המרוחק מושבת, כל הבקשות אליו קצרות מעגל
  • חצי פתוח - פרק זמן מוגדר מאז הכניסה למצב OPEN עבר CircuitBreaker מאפשר לבקשות לבדוק אם השירות המרוחק חזר למצב מקוון

אנו יכולים להגדיר את ההגדרות הבאות:

  • סף שיעורי הכישלון שמעליו CircuitBreaker נפתח ומתחיל שיחות בקצר
  • משך ההמתנה המגדיר כמה זמן CircuitBreaker צריך להישאר פתוח לפני שהוא עובר לחצי פתוח
  • גודל חיץ הטבעת כאשר ה- CircuitBreaker הוא חצי פתוח או סגור
  • תחפושת CircuitBreakerEventListener שמטפל CircuitBreaker אירועים
  • תחפושת לְבַסֵס אשר מעריך אם חריג צריך להיחשב ככישלון ובכך להגדיל את שיעור הכישלון

4. מגביל תעריפים

בדומה לסעיף הקודם, תכונות אלה מחייבות את חוסן 4j-ratelimiter תלות.

כשמו כן הוא, פונקציונליות זו מאפשרת הגבלת גישה לשירות כלשהו. ה- API שלו דומה מאוד ל- מפסקי פחת - יש רישום, תצורה ו מַגְבִּיל שיעורים.

הנה דוגמה לאיך זה נראה:

RateLimiterConfig config = RateLimiterConfig.custom (). LimitForPeriod (2) .build (); RateLimiterRegistry registry = RateLimiterRegistry.of (config); RateLimiter rateLimiter = registry.rateLimiter ("שלי"); פונקציה מעוטרת = RateLimiter.decorateFunction (rateLimiter, שירות :: תהליך);

כעת כל השיחות נעשות בגוש השירות המעוטר במידת הצורך כדי להתאים לתצורה של מגביל התעריפים.

אנו יכולים להגדיר פרמטרים כמו:

  • תקופת רענון המגבלה
  • מגבלת ההרשאות לתקופת הרענון
  • המתנה המוגדרת כברירת מחדל למשך ההרשאה

5. סיבוב

כאן נצטרך תחילה את ה- resilience4j- מחסה תלות.

זה אפשרי להגבלת מספר השיחות במקביל לשירות מסוים.

בואו נראה דוגמה לשימוש ב- Bulkhead API להגדרת מספר מקסימלי של שיחות אחד במקביל:

BulkheadConfig config = BulkheadConfig.custom (). MaxConcurrentCalls (1) .build (); רישום BulkheadRegistry = BulkheadRegistry.of (config); מחסן של קורה = registry.bulkhead ("שלי"); פונקציה מעוטרת = Bulkhead.decorateFunction (מחיצה, שירות :: תהליך);

כדי לבדוק תצורה זו, אנו נקרא לשיטת שירות מדומה.

ואז, אנו מבטיחים זאת תותח אינו מאפשר שיחות אחרות:

תפס CountDownLatch = CountDownLatch חדש (1); כאשר (service.process (anyInt ())). thenAnswer (הפעלה -> {latch.countDown (); Thread.currentThread (). להצטרף (); להחזיר null;}); משימת ForkJoinTask = ForkJoinPool.commonPool (). הגש (() -> {נסה {dekorated.apply (1);} לבסוף {bulkhead.onComplete ();}}); latch.await (); assertThat (bulkhead.isCallPermitted ()). isFalse ();

אנו יכולים להגדיר את ההגדרות הבאות:

  • הכמות המקסימלית של ביצועים מקבילים המותרים על ידי המחיצה
  • משך הזמן המקסימלי שיחכה שרשור כשמנסים להזין מחיצה רוויה

6. נסה שוב

עבור תכונה זו, נצטרך להוסיף את ה- resilience4j-retry ספרייה לפרויקט.

אנחנו יכולים נסה שוב שיחה נכשלה באופן אוטומטי באמצעות API לנסות שוב:

RetryConfig config = RetryConfig.custom (). MaxAttempts (2) .build (); Registry Registry = RetryRegistry.of (config); נסה שוב שוב = registry.retry ("שלי"); פונקציה מעוטרת = נסה שוב.decorateFunction (נסה שוב, (מספרים שלמים) -> {service.process (s); החזר null;});

עכשיו בואו לחקות מצב שבו יוצא מן הכלל חריג במהלך שיחת שירות מרחוק ונוודא שהספריה מנסה אוטומטית את השיחה שנכשלה:

מתי (service.process (anyInt ())). ואז לזרוק (RuntimeException חדש ()); נסה {dekorated.apply (1); להיכשל ("צפוי שייזרק חריג אם כל הניסיונות מחדש נכשלו"); } לתפוס (חריג e) {אמת (שירות, זמנים (2)). תהליך (כל (Integer.class)); }

אנו יכולים גם להגדיר את הדברים הבאים:

  • מספר הניסיונות המקסימלי
  • משך ההמתנה לפני ניסיון חוזר
  • פונקציה מותאמת אישית לשינוי מרווח ההמתנה לאחר כשל
  • תחפושת לְבַסֵס אשר מעריך אם חריג אמור לגרום לניסיון נוסף לשיחה

7. מטמון

מודול המטמון מחייב את resilience4j-cache תלות.

האתחול נראה מעט שונה משאר המודולים:

מטמון javax.cache.Cache = ...; // השתמש כאן במטמון מתאים Cache cacheContext = Cache.of (cache); פונקציה מעוטרת = Cache.decorateSupplier (cacheContext, () -> service.process (1));

כאן המטמון נעשה על ידי יישום המטמון JSR-107 בו נעשה שימוש ו- Resilience4j מספק דרך ליישם אותו.

שים לב כי אין ממשק API לקישוט פונקציות (כמו Cache.decorateFunction (פונקציה)), ה- API תומך רק ספק ו ניתן להתקשר סוגים.

8. TimeLimiter

עבור מודול זה, עלינו להוסיף את ה- resilience4j-timelimiter תלות.

זה אפשרי להגביל את משך הזמן הקריאה לשירות מרוחק באמצעות ה- TimeLimiter.

כדי להדגים, בואו נקים א TimeLimiter עם פסק זמן מוגדר של אלפית השנייה:

ארוך ttl = 1; TimeLimiterConfig config = TimeLimiterConfig.custom (). TimeoutDuration (Duration.ofMillis (ttl)). Build (); TimeLimiter timeLimiter = TimeLimiter.of (config);

לאחר מכן, בואו נוודא ש- Resilience4j מתקשר Future.get () עם פסק הזמן הצפוי:

Future futureMock = דמה (Future.class); ניתן להתקשר מוגבלתCall = TimeLimiter.decorateFutureSupplier (timeLimiter, () -> futureMock); restrictedCall.call (); אמת (futureMock) .get (ttl, TimeUnit.MILLISECONDS);

אנחנו יכולים גם לשלב את זה עם CircuitBreaker:

Callable chainedCallable = CircuitBreaker.decorateCallable (circuitBreaker, restrictedCall);

9. מודולי תוספות

Resilience4j מציעה גם מספר מודולי תוספות המאפשרים את שילובם עם מסגרות וספריות פופולריות.

חלק מהשילובים הידועים יותר הם:

  • מגף אביב - resilience4j-spring-boot מודול
  • חבורת הבוגדים - resilience4j-ratpack מודול
  • התאמה מחודשת - resilience4j-retrofit מודול
  • Vertx - resilience4j-vertx מודול
  • אשף דרופ - resilience4j- מדדים מודול
  • פרומתאוס - חוסן 4j-פרומתיאוס מודול

10. מסקנה

במאמר זה עברנו היבטים שונים בספריית Resilience4j ולמדנו כיצד להשתמש בה לטיפול בבעיות שונות של סובלנות תקלות בתקשורת בין שרתים.

כמו תמיד, ניתן למצוא את קוד המקור של הדוגמאות לעיל ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found