الفصل 1: مقدمة في الخدمات المصغرة
🎯 أهداف الفصل
- فهم الفرق بين النظام الأحادي والخدمات المصغرة
- تحديد مزايا وعيوب كل نهج
- اكتشاف الأنماط الأساسية للخدمات المصغرة
- إتقان مبادئ تطبيق 12-Factor
- معرفة متى تختار أي بنية
1. البنية الأحادية
1.1 التعريف
النظام الأحادي هو تطبيق حيث يتم نشر جميع الوظائف معًا في عملية واحدة.
1.2 مثال: التجارة الإلكترونية الأحادية
// هيكل نموذجي لنظام أحادي
src/main/java/com/ecommerce/
├── EcommerceApplication.java
├── config/
│ └── SecurityConfig.java
├── controller/
│ ├── UserController.java
│ ├── ProductController.java
│ ├── OrderController.java
│ ├── PaymentController.java
│ └── InventoryController.java
├── service/
│ ├── UserService.java
│ ├── ProductService.java
│ ├── OrderService.java
│ ├── PaymentService.java
│ └── InventoryService.java
├── repository/
│ ├── UserRepository.java
│ ├── ProductRepository.java
│ ├── OrderRepository.java
│ └── ...
└── model/
├── User.java
├── Product.java
├── Order.java
└── ...
1.3 مزايا النظام الأحادي
| الميزة | التفسير |
|---|---|
| سهولة التطوير | مشروع واحد، بيئة تطوير واحدة |
| نشر بسيط | ملف JAR/WAR واحد للنشر |
| اختبارات سهلة | اختبارات تكامل بسيطة |
| المعاملات ACID | قاعدة بيانات واحدة = معاملات سهلة |
| تصحيح أخطاء بسيط | تتبع كامل للأخطاء |
| أداء محلي | لا يوجد تأخير شبكي بين الوحدات |
| إعادة هيكلة سهلة | بيئة التطوير يمكنها إعادة التسمية في كل مكان |
1.4 عيوب النظام الأحادي
| العيب | التفسير |
|---|---|
| توسيع الكل أو لا شيء | من المستحيل توسيع وحدة واحدة فقط |
| نشر محفوف بالمخاطر | خطأ واحد = تعطل التطبيق بالكامل |
| تكديس فريد | كل شيء في Java (أو غيرها) |
| وقت بناء طويل | إعادة تجميع كل شيء في كل مرة |
| صراعات الفريق | دمج صعب في مشروع كبير |
| ديون تقنية | صعوبة في التحديث |
| تدريب طويل | يجب على المطور الجديد فهم كل شيء |
1.5 متى يصبح النظام الأحادي مشكلة
السنة 1: شركة ناشئة
- 3 مطورين
- 50 ألف سطر من الكود
- نشر: 5 دقائق
→ نظام أحادي مثالي ✅
السنة 3: نمو
- 30 مطور
- 500 ألف سطر من الكود
- نشر: 45 دقيقة
- صراعات Git يومية
→ النظام الأحادي يصبح عائقًا ⚠️
السنة 5: توسع
- 100 مطور
- 2 مليون سطر من الكود
- نشر: ساعتان
- الجمعة السوداء: كل شيء يتعطل
→ النظام الأحادي = "كرة طين كبيرة" ❌
2. بنية الخدمات المصغرة
2.1 التعريف
الخدمات المصغرة هي نهج حيث يتم تقسيم التطبيق إلى خدمات صغيرة مستقلة، كل منها:
- قابلة للنشر بشكل مستقل
- لها قاعدة بيانات خاصة بها
- تتواصل عبر API (HTTP/REST أو الرسائل)
- تُدار بواسطة فريق صغير
2.2 الخصائص الرئيسية
1. مسؤولية واحدة
كل خدمة تقوم بشيء واحد جيدًا:
- user-service: إدارة المستخدمين فقط
- order-service: إدارة الطلبات فقط
- inventory-service: إدارة المخزون فقط
2. الاستقلالية
كل خدمة:
- لها مستودع Git خاص بها
- لها قاعدة بيانات خاصة بها (قاعدة بيانات لكل خدمة)
- لها خط أنابيب CI/CD خاص بها
- يمكن نشرها بمفردها
- يمكنها استخدام تقنية مختلفة
3. الاتصال
متزامن (HTTP/REST):
- العميل ينتظر الرد
- بسيط ولكنه يربط
غير متزامن (الرسائل):
- أرسل وانسى
- غير مرتبط ولكنه معقد
2.3 مزايا الخدمات المصغرة
| الميزة | التفسير |
|---|---|
| توسيع مستهدف | توسيع الخدمة التي تحتاج إلى ذلك فقط |
| عزل الأعطال | تعطل خدمة واحدة ≠ تعطل الكل |
| نشر مستقل | نشر 10 مرات في اليوم لكل خدمة |
| تعدد اللغات | Java، Node، Python، Go... حسب الحاجة |
| فرق مستقلة | "أنت تبنيها، أنت تديرها" |
| قابلية التوسع | إضافة خدمة دون التأثير على الأخرى |
| التحديث | إعادة كتابة خدمة واحدة في كل مرة |
2.4 عيوب الخدمات المصغرة
| العيب | التفسير |
|---|---|
| تعقيد موزع | تصحيح الأخطاء صعب |
| تأخير الشبكة | مكالمات HTTP بين الخدمات |
| المعاملات الموزعة | ACID مستحيل، تحتاج إلى Sagas |
| اتساق محتمل | البيانات ليست متزامنة فورًا |
| عمليات معقدة | مراقبة، تسجيل، تتبع |
| تكلفة البنية التحتية | المزيد من الخوادم، المزيد من قواعد البيانات |
| تكلفة إضافية | كل خدمة = تكلفة ذاكرة إضافية |
3. مقارنة مفصلة
3.1 جدول مقارنة
| المعيار | النظام الأحادي | الخدمات المصغرة |
|---|---|---|
| التعقيد الأولي | منخفض | مرتفع |
| التعقيد على المدى الطويل | مرتفع | مُدار |
| النشر | الكل أو لا شيء | مستقل |
| التوسيع | عمودي | أفقي |
| التكنولوجيا | فريدة | متعددة اللغات |
| الفريق | فريق واحد | فرق لكل خدمة |
| قاعدة البيانات | مشتركة | لكل خدمة |
| المعاملات | ACID بسيطة | Sagas (معقدة) |
| تصحيح الأخطاء | بسيط | موزع (معقد) |
| التأخير | منخفض | أعلى |
| التكلفة الأولية | منخفضة | مرتفعة |
| الوقت للسوق | سريع في البداية | أبطأ في البداية |
3.2 معايير القرار
4. أنماط الخدمات المصغرة الأساسية
4.1 نمط بوابة API
المسؤوليات:
- توجيه الطلبات
- المصادقة/التفويض
- تحديد المعدل
- موازنة التحميل
- إنهاء SSL
- التخزين المؤقت
- تحويل الطلب/الرد
4.2 نمط اكتشاف الخدمة
كيف يعمل:
- تبدأ الخدمة → تسجل نفسها في Eureka
- يريد العميل الاتصال بخدمة A
- يطلب العميل من Eureka: "أين خدمة A؟"
- يعيد Eureka قائمة الأمثلة
- يختار العميل مثالًا (موازنة التحميل من جانب العميل)
- يتصل العميل مباشرة بالمثال
4.3 نمط قاطع الدائرة
الحالات:
- مغلق: عادي، تمر المكالمات
- مفتوح: الكثير من الفشل، المكالمات محظورة → تراجع
- نصف مفتوح: اختبار إذا عادت الخدمة
// مثال مع Resilience4j
@CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
public User getUser(Long id) {
return userServiceClient.getUser(id); // اتصال بعيد
}
public User getUserFallback(Long id, Exception ex) {
return new User(id, "غير معروف", "الخدمة غير متاحة مؤقتًا");
}
4.4 نمط Saga (المعاملات الموزعة)
في نظام أحادي:
@Transactional
public void createOrder(Order order) {
orderRepository.save(order); // ✅
inventoryService.reserve(order); // ✅
paymentService.charge(order); // ❌ فشل → إلغاء الكل
}
مع الخدمات المصغرة (Saga Choreography):
4.5 Event Sourcing & CQRS
الأحداث بدلاً من الحالات:
// بدلاً من: UPDATE orders SET status = 'SHIPPED'
// نخزن الأحداث:
OrderCreated { orderId: 1, items: [...], timestamp: ... }
PaymentReceived { orderId: 1, amount: 100, timestamp: ... }
OrderShipped { orderId: 1, trackingNumber: "ABC123", timestamp: ... }
5. تطبيق 12-Factor
مبادئ 12 عامل هي مبادئ لبناء تطبيقات سحابية:
العوامل الـ12
| # | العامل | الوصف | تطبيق Spring Boot |
|---|---|---|---|
| 1 | قاعدة الكود | مستودع واحد = تطبيق واحد | مستودع Git لكل خدمة |
| 2 | التبعيات | التصريح بوضوح | pom.xml / build.gradle |
| 3 | التكوين | التكوين في البيئة | application.yml + متغيرات البيئة |
| 4 | الخدمات الداعمة | التعامل معها كموارد مرفقة | مصدر بيانات قابل للتكوين |
| 5 | البناء، الإصدار، التشغيل | فصل المراحل | خط أنابيب CI/CD |
| 6 | العمليات | بدون حالة | الجلسة في Redis |
| 7 | ربط المنافذ | التصدير عبر المنفذ | Tomcat مدمج |
| 8 | التزامن | التوسع عبر العمليات | أمثلة متعددة |
| 9 | التخلص | بدء/إيقاف سريع | إيقاف سلس |
| 10 | التكافؤ بين التطوير والإنتاج | بيئات متشابهة | Docker |
| 11 | السجلات | التعامل معها كتيار | stdout → جامع |
| 12 | العمليات الإدارية | مهام إدارية لمرة واحدة | Spring Batch |
مثال: العامل 3 - التكوين
# ❌ سيء: تكوين مدمج
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret123
# ✅ جيد: تكوين خارجي
spring:
datasource:
url: ${DATABASE_URL}
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
مثال: العامل 6 - العمليات بدون حالة
// ❌ سيء: حالة في الذاكرة
@RestController
public class CartController {
private Map<Long, Cart> carts = new HashMap<>(); // حالة محلية!
@PostMapping("/cart/{userId}/add")
public void addItem(@PathVariable Long userId, @RequestBody Item item) {
carts.computeIfAbsent(userId, Cart::new).add(item);
}
}
// ✅ جيد: حالة خارجية (Redis)
@RestController
public class CartController {
private final RedisTemplate<String, Cart> redis;
@PostMapping("/cart/{userId}/add")
public void addItem(@PathVariable Long userId, @RequestBody Item item) {
String key = "cart:" + userId;
Cart cart = redis.opsForValue().get(key);
if (cart == null) cart = new Cart();
cart.add(item);
redis.opsForValue().set(key, cart);
}
}
6. التصميم الموجه بالمجال (DDD) والخدمات المصغرة
6.1 السياق المحدود
يحدد السياق المحدود حدود الخدمة المصغرة:
6.2 نفس المفهوم، سياقات مختلفة
// في سياق المبيعات
public class Customer {
private Long id;
private String name;
private String email;
private List<Order> orders;
private LoyaltyLevel loyaltyLevel;
}
// في سياق الشحن
public class Customer {
private Long id;
private String name;
private Address shippingAddress;
private String phoneNumber;
}
// في سياق الفوترة
public class Customer {
private Long id;
private String name;
private PaymentMethod defaultPaymentMethod;
private BillingAddress billingAddress;
}
7. الأنماط المضادة لتجنبها
7.1 النظام الأحادي الموزع
❌ نمط مضاد: النظام الأحادي الموزع
- 10 خدمات يجب نشرها معًا
- مخطط قاعدة بيانات مشترك
- ارتباط قوي بين الخدمات
- أسوأ من العالمين!
7.2 الخدمات النانوية
❌ نمط مضاد: خدمات صغيرة جدًا
- خدمة لكل كيان
- UserService، UserAddressService، UserPreferenceService
- تكلفة إضافية هائلة
- معاملات مستحيلة
7.3 قاعدة بيانات مشتركة
❌ نمط مضاد: قاعدة بيانات مشتركة
خدمة A ──┬──> PostgreSQL <──┬── خدمة B
│ │
└──> جدول الطلبات <┘
المشكلة:
- ارتباط قوي عبر المخطط
- من المستحيل تعديل جدول
- معاملات متقاطعة مغرية
7.4 كل شيء متزامن
❌ نمط مضاد: كل شيء متزامن
خدمة الطلب
↓ HTTP متزامن
خدمة المخزون
↓ HTTP متزامن
خدمة الدفع
↓ HTTP متزامن
خدمة الإشعار
المشكلة:
- تأخير متراكم
- خدمة بطيئة = كل شيء بطيء
- فشل متسلسل
8. الانتقال من النظام الأحادي إلى الخدمات المصغرة
8.1 استراتيجية: نمط شجرة التين الخانقة
8.2 خطوات الانتقال
- تحديد السياقات المحدودة في النظام الأحادي
- ابدأ بالأقل خطورة (مثل: الإشعارات)
- استخراج إلى خدمة جديدة
- التوجيه عبر بوابة API
- إزالة الكود القديم من النظام الأحادي
- التكرار للسياق التالي
9. ملخص
النقاط الرئيسية
✅ النظام الأحادي = بسيط ولكنه لا يتوسع
✅ الخدمات المصغرة = معقدة ولكنها مرنة
✅ ابدأ بالنظام الأحادي إذا كان ممكنًا
✅ انتقل عندما يصبح النظام الأحادي عائقًا
✅ تطبيق 12-Factor = ممارسات جيدة للسحابة
✅ DDD = يساعد في تحديد الحدود
✅ الأنماط = قاطع الدائرة، Saga، Event Sourcing
قائمة التحقق قبل الخدمات المصغرة
- فريق ذو خبرة في DevOps؟
- بنية تحتية Kubernetes/Docker؟
- مراقبة وتسجيل مركزي؟
- CI/CD ناضج؟
- سياقات محدودة جيدًا؟
- مشاكل حقيقية في التوسع؟
10. اختبار التحقق
السؤال 1
أي نمط يسمح بتجنب سلسلة من الأعطال بين الخدمات؟
عرض الإجابة
قاطع الدائرة - يكتشف الأعطال و"يفتح" الدائرة لإرجاع تراجع فورًا بدلاً من انتظار انتهاء المهلة.
السؤال 2
لماذا "قاعدة بيانات لكل خدمة" مهم؟
عرض الإجابة
- فك الارتباط: يمكن لكل خدمة تطوير مخططها بشكل مستقل
- الاستقلالية: لا توجد تبعية على مسؤول قاعدة بيانات مركزي
- التكنولوجيا: PostgreSQL لخدمة، MongoDB لأخرى
- تجنب الارتباط المخفي عبر المخطط المشترك
السؤال 3
ما هو "النظام الأحادي الموزع"؟
عرض الإجابة
نمط مضاد حيث لدينا عدة خدمات ولكن:
- يجب نشرها معًا
- تشارك قاعدة بيانات
- مرتبطة بقوة
لدينا تعقيد الخدمات المصغرة بدون الفوائد.