DevOps and Infrastructure

بناء خدمات مصغرة مرنة باستخدام Resilience4j وأنماط قاطع الدائرة

في مشهد الأنظمة الموزعة الحديثة، الفشل ليس مسألة "إذا"، بل "متى". كمطورين يصممون خدمات مصغرة، يجب أن نقبل أن انقسامات الشبكة، وانتهاء مهلة الخدمة، وفشل واجهات برمجة التطبيقات الخارجية أمر لا مفر منه. إذا فشل أحد المكونات في سلسلتك، فقد يتسبب ذلك في عطل منهجي، مما يؤدي إلى إسقاط تطبيقك بالكامل. هنا تأتي أنماط المرونة للعب دورها. من بين المكتبات المختلفة المتاحة في بيئة جافا، برز Resilience4j كمعيار ذهبي، حيث يقدم نهجاً خفيفاً ووظيفياً للتعامل مع الأعطال.

لماذا تعتبر المرونة أمراً بالغ الأهمية في الخدمات المصغرة

تتميز التطبيقات أحادية البنية بنقطة فشل واحدة، لكنها أسهل في الإدارة محلياً. وعلى العكس من ذلك، تقدم الخدمات المصغرة تعقيداً وزمن انتقال للشبكة. عندما تستدعي الخدمة A الخدمة B، وكانت الخدمة B بطيئة أو غير مستجيبة، قد تصبح خيوط الخدمة A محجوبة، مما يستنفد مجموعة الخيوط الخاصة بها ويؤدي في النهاية إلى تعطل المستدعي. يُعرف هذا بـ "العطل المتسلسل".

تهدف هندسة المرونة إلى منع هذه التسلسلات من خلال عزل الأعطال، وإعادة محاولة الأخطاء العابرة، والسقوط بشكل لائق. يوفر Resilience4j عدة وحدات لتحقيق ذلك، حيث يُعد قاطع الدائرة (Circuit Breaker) الأكثر أهمية لحماية الأعطال المتسلسلة.

فهم نمط قاطع الدائرة

يعمل نمط قاطع الدائرة بشكل مشابه لقاطع الدائرة الكهربائية في منزلك. إذا حدثت العديد من الأعطال، فإن القاطع "ينفجر" ويفتح الدائرة، مما يوقف جميع الطلبات الموجهة إلى الخدمة المعطلة. بعد فترة استرداد محددة، يسمح لعدد محدود من طلبات "الاختبار" بالمرور. إذا نجحت هذه الطلبات، يُغلق القاطع؛ وإذا فشلت، يفتح مرة أخرى.

يطبق Resilience4j هذا النمط بمرونة عالية في التكوين، مما يتيح لك تعريف عتبات معدل الفشل، والحد الأدنى لعدد المكالمات، وأحجام النافذة المنزلقة.

تنفيذ Resilience4j في Spring Boot

للبدء، تحتاج إلى إضافة تبعية قاطع الدائرة الخاص بـ Resilience4j إلى مشروعك. إذا كنت تستخدم Maven، أضف التالي إلى ملف pom.xml:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.7.1</version>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-circuitbreaker</artifactId>
    <version>1.7.1</version>
</dependency>

بمجرد الإضافة، يمكنك تكوين قاطع الدائرة عبر ملف application.yml. يقوم هذا بإخراج التكوين، مما يسهل ضبط السلوك في بيئة الإنتاج دون إعادة نشر الكود.

resilience4j:
  circuitbreaker:
    instances:
      backendA:
        sliding-window-size: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s
        permitted-number-of-calls-in-half-open-state: 3

في طبقة الخدمات الخاصة بك، تقوم ببساطة بتضمين التسميات (annotations) على الأساليب التي ترغب في حمايتها. يتكامل Resilience4j بسلاسة مع برمجة الجوانب (AOP) في Spring وواجهات الجافا الوظيفية.

مثال عملي للكود: آلية إعادة المحاولة والسقوط

بالإضافة إلى كسر الدائرة، غالباً ما تريد إعادة محاولة الطلبات الفاشلة (بسبب مشاكل الشبكة العابرة) وتقديم استجابة احتياطية عندما تكون الدائرة مفتوحة. إليك كيفية تنفيذ ذلك باستخدام تسميات Resilience4j في خدمة Spring Boot:

@Service
public class PaymentService {

    private final PaymentClient paymentClient;

    // حقن عبر المنشئ
    public PaymentService(PaymentClient paymentClient) {
        this.paymentClient = paymentClient;
    }

    @CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback")
    @Retry(name = "paymentService")
    public String processPayment(String orderId) {
        // استدعاء بوابة الدفع الخارجية
        return paymentClient.charge(orderId);
    }

    // يجب أن تتطابق توقيعات طريقة السقوط مع الأسلوب الأصلي
    public String paymentFallback(String orderId, Exception e) {
        log.error("فشل الدفع للطلب: {} بسبب {}", orderId, e.getMessage());
        return "خدمة الدفع غير متاحة حالياً. يرجى المحاولة مرة أخرى لاحقاً.";
    }
}

في هذا المثال، تتعامل التسمية @Retry مع الأعطال العابرة عن طريق محاولة الاتصال مرة أخرى وفقاً لسياسة التكوين المحددة. إذا استمرت الأعطال، ينشط @CircuitBreaker، ويتم استدعاء طريقة paymentFallback، مما يضمن حصول المستخدم على استجابة لائقة بدلاً من خطأ غامض أو انتهاء مهلة الوقت.

الملاحظة والرصد

لا فائدة من قاطع الدائرة إذا لم تتمكن من رؤية حالته. يكشف Resilience4j عن المقاييس عبر Micrometer، والذي يتكامل مع أدوات مثل Prometheus وGrafana. يمكنك مراقبة مقاييس مثل resilience4j.circuitbreaker.call.fails أو resilience4j.circuitbreaker.state. يتيح لك هذا الرؤية إعداد تنبيهات عندما تبدأ خدماتك في الفشل بشكل متكرر، مما يمنح فريقك الوقت للتحقيق قبل أن ينكسر القاطع تماماً.

الخاتمة

لا يتعلق بناء خدمات مصغرة مرنة بمنع جميع الأعطال، بل بإدارتها بفعالية. من خلال الاستفادة من Resilience4j، يمكن لمطوري جافا تنفيذ أنماط المرونة القياسية في الصناعة مثل قواطع الدائرة وإعادة المحاولة بأقل قدر من الشفرة النمطية. تحمي هذه الأنماط نظامك من الأعطال المتسلسلة، وتحسن تجربة المستخدم من خلال التدهور اللائق، وتوفر الملاحظة اللازمة للحفاظ على صحة النظام في بيئة الإنتاج. مع توسع بنية الخدمات المصغرة الخاصة بك، يجب أن يكون دمج استراتيجيات المرونة هذه من أولوياتك القصوى.

Share: