هندسة الخدمات المصغرة

تقوم بنية الخدمات المصغرة ببناء التطبيق كمجموعة من الخدمات المترابطة بشكل غير محكم والقابلة للنشر بشكل مستقل. تمتلك كل خدمة قدرة تجارية محددة، ولها مخزن بيانات خاص بها، وتتواصل عبر الشبكة. على الرغم من أن الخدمات الصغيرة تقدم تعقيدًا تشغيليًا كبيرًا، إلا أنها تمكن المؤسسات من توسيع نطاق فرق التطوير، والنشر بشكل مستقل، وبناء أنظمة أكثر مرونة.
مقدمة
تقوم بنية الخدمات المصغرة ببناء التطبيق كمجموعة من الخدمات المترابطة بشكل غير محكم والقابلة للنشر بشكل مستقل. تمتلك كل خدمة قدرة تجارية محددة، ولها مخزن بيانات خاص بها، وتتواصل عبر الشبكة. على الرغم من أن الخدمات الصغيرة تقدم تعقيدًا تشغيليًا كبيرًا، إلا أنها تمكن المؤسسات من توسيع نطاق فرق التطوير، والنشر بشكل مستقل، وبناء أنظمة أكثر مرونة.
مونوليث مقابل الخدمات الصغيرة
متراصة
يحتوي التطبيق المتجانس على جميع الوظائف في قاعدة تعليمات برمجية واحدة ووحدة نشر واحدة:
┌─────────────────────────────────────────────┐
│ Monolith Application │
├──────────────┬──────────────┬───────────────┤
│ User Module │ Order Module│ Payment │
│ (controllers, services, repos, DB tables) │
└──────────────┴──────────────┴───────────────┘
مزايا متراصة:
- تطوير واختبار بسيط (عملية واحدة).
- تصحيح الأخطاء بسهولة (لا توجد مكالمات شبكة بين الوحدات).
- اتصال سريع (استدعاءات الطريقة في الذاكرة).
- لا يوجد تعقيد النظام الموزع.
- مثالية للفرق الصغيرة ومنتجات المرحلة المبكرة.
عيوب مونوليث:
- القياس يعني توسيع نطاق كل شيء، وليس فقط عنق الزجاجة.
- خطأ واحد يمكن أن يعطل التطبيق بأكمله.
- مكدس التكنولوجيا مقفل.
- يصبح من الصعب فهم قاعدة التعليمات البرمجية الكبيرة وصيانتها.
- يستغرق النشر وقتًا أطول مع نمو قاعدة التعليمات البرمجية.
- زيادة النفقات العامة لتنسيق الفريق.
بنية الخدمات المصغرة
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ User Service │ │ Order Service │ │ Payment Service │
│ (own DB, API) │ │ (own DB, API) │ │ (own DB, API) │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │
└──────────────────────┼──────────────────────┘
│
┌───────────▼───────────┐
│ API Gateway │
│ (auth, routing) │
└───────────────────────┘
المبادئ الأساسية
1. المسؤولية الفردية
تمتلك كل خدمة قدرة عمل واحدة بالضبط. إذا كان بإمكانك وصف غرض خدمة ما دون استخدام "و"، فمن المحتمل أن تكون ذات نطاق جيد.
جيد:
خدمة الدفع- تتولى معالجة الدفع واسترداد الأموال.خدمة الإخطار- يرسل رسائل البريد الإلكتروني والرسائل النصية القصيرة والإشعارات الفورية.خدمة المخزون- إدارة مستويات المخزون والحجوزات.
سيء:
خدمة المستخدم والطلب- تم دمج قدرتين متميزتين (ينتهك SRP).backend-service- كل شيء في خدمة واحدة (وليس الخدمات الصغيرة على الإطلاق).
2. إدارة البيانات اللامركزية
تمتلك كل خدمة قاعدة البيانات الخاصة بها. لا تشارك الخدمات قواعد البيانات مطلقًا، بل تتواصل عبر واجهات برمجة التطبيقات.
-- Service A has its own database
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE,
name VARCHAR(255)
);
-- Service B has its own database, stores only the user ID
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
total DECIMAL(10,2),
status VARCHAR(50)
);
لماذا لا نتشارك قواعد البيانات؟
- اقتران محكم — تغييرات المخطط في إحدى الخدمات تؤدي إلى انقطاع الخدمات الأخرى.
- الخدمات المختلفة لها احتياجات تخزين مختلفة (علائقية مقابل مستند مقابل رسم بياني).
- النشر المستقل يصبح مستحيلا.
- يتطلب القياس عمليات ترحيل مخطط منسقة.
3. المرونة وعزل الأخطاء
لا ينبغي أن ينتقل الفشل في إحدى الخدمات إلى الآخرين.
نمط قواطع دوائر:
// Using a circuit breaker to handle service failures gracefully
const breaker = new CircuitBreaker({
failureThreshold: 5,
resetTimeout: 30000, // 30 seconds
});
async function getPaymentStatus(orderId: string) {
try {
return await breaker.call(() => paymentService.getStatus(orderId));
} catch (error) {
// Fallback: return cached status or default
return { status: 'pending', note: 'Payment service unavailable' };
}
}
نمط الحاجز: تخصيص مجموعات سلاسل رسائل منفصلة لخدمات مختلفة بحيث لا تستنفد خدمة واحدة بطيئة جميع الموارد:
// Separate thread pools per service
const paymentPool = new ThreadPool({ maxThreads: 10 });
const inventoryPool = new ThreadPool({ maxThreads: 20 });
const notificationPool = new ThreadPool({ maxThreads: 5 });
4. قابلية النشر المستقلة
يمكن نشر كل خدمة بشكل مستقل. هذه هي الفائدة الأساسية للخدمات الصغيرة.
أتمتة النشر:
# GitHub Actions for a single microservice
name: Deploy Payment Service
on:
push:
paths:
- 'services/payment/**'
- '.github/workflows/payment.yml'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t payment-service .
- run: docker push registry.example.com/payment-service:${{ github.sha }}
- run: kubectl set image deployment/payment-service payment-service=registry.example.com/payment-service:${{ github.sha }}
أنماط الاتصال
الاتصال المتزامن (REST، gRPC)
الإيجابيات: سهل التنفيذ والسبب. دلالات الطلب والاستجابة مألوفة.
السلبيات: إنشاء اقتران وقت التشغيل — إذا كانت الخدمة النهائية معطلة، فسيتأثر المتصل.
// REST call using fetch
const order = await fetch(`http://order-service:8080/api/orders/${orderId}`);
// gRPC definition
service OrderService {
rpc GetOrder (GetOrderRequest) returns (Order);
}
message GetOrderRequest {
string order_id = 1;
}
الاتصال غير المتزامن (قوائم انتظار الرسائل)
الإيجابيات: اقتران فضفاض، مرونة أفضل، يدعم البنى القائمة على الأحداث.
السلبيات: يتطلب الاتساق النهائي، الذي يصعب تصحيحه، بنية تحتية للرسائل.
// Kafka producer
await producer.send({
topic: 'order.created',
messages: [{ value: JSON.stringify({ orderId, userId, total }) }]
});
// Kafka consumer in notification service
await consumer.run({
eachMessage: async ({ message }) => {
const { orderId, userId } = JSON.parse(message.value.toString());
await emailService.sendOrderConfirmation(userId, orderId);
}
});
الاختيار بين متزامن وغير متزامن
| معايير | متزامن | غير متزامن |
|---|---|---|
| هل يحتاج المتصل إلى استجابة فورية؟ | نعم | لا |
| هل يمكن تأجيل العملية؟ | لا | نعم |
| هل خدمة المصب متاحة دائمًا؟ | نعم | غير مطلوب |
| هل تحتاج إلى اتساق قوي؟ | نعم | في نهاية المطاف على ما يرام |
استراتيجيات التحلل
كيفية تقسيم متراصة
- تحديد السياقات المحددة — استخدم التصميم المستند إلى المجال (DDD) للعثور على الحدود الطبيعية.
- ابدأ بالخدمة ذات القيمة الأعلى — استخرج خدمة ذات قيمة مستقلة واضحة.
- استخرج خدمة واحدة في كل مرة — لا تحاول إجراء عملية ترحيل كبيرة.
- استخدم نمط Strangler Fig — قم بتوجيه حركة المرور تدريجيًا من الوحدة المتراصة إلى الخدمة الجديدة.
// Strangler Fig pattern
const gateway = express();
// Route to new service if available, fall back to monolith
gateway.use('/api/users', async (req, res, next) => {
try {
const response = await fetch('http://user-service/api/users' + req.path);
return res.json(await response.json());
} catch {
next(); // Fall through to monolith handler
}
});
إرشادات دقة الخدمة
| حجم الخدمة | حجم الفريق | تردد النشر | مثال |
|---|---|---|---|
| ⚡ صغير | 1-3 مطورين | عدة مرات / يوم | التحقق من المستخدم |
| 📐 متوسطة | 3-6 مطورين | يومي/أسبوعي | معالجة الطلب |
| 🏗️ كبيرة | 6-10 مطورين | أسبوعي | منصة الدفع |
القاعدة الأساسية: يجب أن تكون الخدمة صغيرة بما يكفي ليتمكن فريق واحد من امتلاكها بالكامل، وكبيرة بما يكفي لتوفير قيمة تجارية ذات معنى.
التحديات التشغيلية
إمكانية الملاحظة
تولد الخدمات الصغيرة كميات هائلة من القياس عن بعد. ثلاث ركائز:
1. التسجيل:
// Structured logging (JSON)
{
"timestamp": "2026-05-24T10:30:00.123Z",
"level": "error",
"service": "payment-service",
"trace_id": "abc123",
"message": "Payment processing failed",
"error": "stripe: insufficient funds",
"metadata": { "order_id": "ord_456", "amount": 2999 }
}
2. المقاييس (تنسيق بروميثيوس):
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="POST",path="/api/payments",status="500"} 42
3. التتبع الموزع (OpenTelemetry):
# OpenTelemetry auto-instrumentation
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4318"
OTEL_SERVICE_NAME: "payment-service"
OTEL_TRACES_SAMPLER: "parentbased_traceidratio"
OTEL_TRACES_SAMPLER_ARG: "0.1"
اكتشاف الخدمة
في البيئات الديناميكية (Kubernetes)، تتغير عناوين IP. تجد الخدمات بعضها البعض عبر DNS:
- Kubernetes DNS —
Payment-service.namespace.svc.cluster.local. - القنصل — تسجيل الخدمة مع فحوصات السلامة.
- Eureka — اكتشاف خدمة Netflix (سحابة الربيع).
بوابة API
نقطة دخول واحدة لجميع طلبات العملاء:
| وظيفة | مثال |
|---|---|
| التوجيه | /api/users → خدمة المستخدم، /api/orders → خدمة الطلب |
| المصادقة | التحقق من صحة رموز JWT قبل التوجيه |
| الحد من المعدل | 1000 طلب / دقيقة لكل عميل |
| طلب التحول | تحويل JSON إلى بروتوبوف |
| التخزين المؤقت للاستجابة | ذاكرة التخزين المؤقت الحصول على الاستجابات |
| كسر الدائرة | إيقاف التوجيه إلى الخدمات غير الصحية |
إدارة التكوين
إضفاء الطابع الخارجي على كافة التكوينات:
# ConfigMap in Kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
name: payment-service-config
data:
DATABASE_URL: "postgresql://..."
STRIPE_API_KEY: "${STRIPE_API_KEY}" # from Secret
MAX_RETRIES: "3"
FEATURE_FLAG_NEW_CHECKOUT: "true"
تنسيق الحاويات مع Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 3
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
containers:
- name: payment-service
image: registry.example.com/payment-service:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
عندما لا تستخدم الخدمات المصغرة
- فرق صغيرة (أقل من 10 مطورين) — يفوق العبء المعرفي للخدمات الصغيرة الفوائد.
- تطبيقات بسيطة — تطبيق CRUD مع القليل من الميزات. المونوليث أسرع في البناء.
- الشركات الناشئة في مراحلها المبكرة — سرعة التكرار مهمة أكثر من قابلية التوسع.
- حدود المجال غير واضحة — إذا لم تتمكن من تحديد حدود الخدمة، فسوف تقوم بإنشاء وحدة متراصة موزعة.
- تطبيقات ذات حركة مرور منخفضة — لا يوجد ما يبرر الحمل الزائد للخدمات الصغيرة (الشبكات والنشر والمراقبة).
قانون كونواي: تصمم المؤسسات أنظمة تعكس هيكل اتصالاتها. إذا لم يكن فريقك منظمًا حول حدود الخدمة، فستؤدي الخدمات الصغيرة إلى حدوث احتكاك.
استراتيجية الهجرة
المرحلة 1: التحضير
- أضف المراقبة والتسجيل المركزي إلى الوحدة المتراصة.
- تحديد السياقات المحددة باستخدام ورش عمل DDD.
- استخراج المكتبات المشتركة (المصادقة، والتسجيل، والمرافق).
- قم بإعداد CI/CD والحاويات.
المرحلة الثانية: الاستخراج
- استخراج الخدمة الأولى (الأقل خطورة، والأعلى قيمة).
- تنفيذ نمط التين الخانق.
- تشغيل متراصة + خدمة جديدة بالتوازي.
- أضف قواطع الدائرة والاحتياطيات.
المرحلة 3: النطاق
- استخراج خدمات إضافية بشكل متكرر.
- تنفيذ الاتصالات المستندة إلى الأحداث حيثما كان ذلك مناسبًا.
- إضافة شبكة خدمة (Istio، Linkerd) للشبكات المتقدمة.
- الاستثمار في هندسة المنصات (خلف الكواليس، بوابات المطورين).
توصيات مكدس التكنولوجيا
| فئة | خيارات | ملحوظات |
|---|---|---|
| نطاق | Spring Boot، NestJS، FastAPI، Go kit | اختر بناءً على خبرة الفريق |
| واجهة برمجة التطبيقات | ريست، جي آر بي سي، غراف كيو إل | gRPC للداخلية، REST للخارجية |
| المراسلة | كافكا، رابيت إم كيو، ناتس | كافكا لإنتاجية عالية |
| قاعدة البيانات | بوستجريس كيو ال، دينامو دي بي، مونغو دي بي | مطابقة قاعدة البيانات لاحتياجات الخدمة |
| حاوية | عامل ميناء | عالمي |
| التنسيق | كوبيرنيتيس | EKS أو AKS أو GKE أو مُدار ذاتيًا |
| بوابة API | كونغ، مبعوث، بوابة AWS API | مبعوث لتكامل شبكة الخدمة |
| إمكانية الملاحظة | القياس عن بعد المفتوح، بروميثيوس، جايجر | القياس عن بعد المفتوح هو المعيار |
| سي آي/سي دي | إجراءات GitHub، GitLab CI، ArgoCD | ArgoCD لـ GitOps |
| شبكة الخدمة | إستيو، لينكيرد، هدب | رابط للبساطة |
| الإدارة السرية | HashiCorp Vault، مدير أسرار AWS | قبو للسحابة المتعددة |
خاتمة
تعد الخدمات الصغيرة نموذجًا معماريًا قويًا يتيح النشر المستقل واستقلالية الفريق والأنظمة القابلة للتطوير. ومع ذلك، فإنها تأتي مع تعقيد تشغيلي كبير. أنجح عمليات تبني الخدمات المصغرة:
- ابدأ بوحدة متراصة — افهم نطاقك قبل التقسيم.
- استخراج الخدمات بشكل تدريجي — خدمة واحدة في كل مرة.
- استثمر بكثافة في التشغيل الآلي — CI/CD، والمراقبة، والبنية التحتية كتعليمات برمجية.
- تنظيم الفرق حول الخدمات — مواءمة هيكل الفريق مع التصميم المعماري.
- تبنّي الاتساق النهائي — لا يجب أن يكون كل شيء متسقًا بقوة.
الخدمات الصغيرة ليست هي البنية الافتراضية — فهي تمثل حلاً لمشاكل تنظيمية وقياسية محددة. اخترهم عمدا، وليس بشكل افتراضي.
مقالات مختارة

50 مهارة من Claude تستحق البناء في 2026

ابن مساعد ملاحظات خاص بالذكاء الاصطناعي
حوّل مجلد ملاحظات Markdown إلى مساعد بحث دون كشف المسودات الخاصة.

أتمتة استخراج بيانات الفواتير باستخدام OCR
ابن خط معالجة يقرأ الفواتير ويستخرج الحقول ويعلّم القيم غير المؤكدة للمراجعة.
التعليقات
0 تعليقاتلا توجد تعليقات معتمدة بعد. قد تنتظر الردود الجديدة المراجعة.