
تقوم بنية الخدمات المصغرة ببناء التطبيق كمجموعة من الخدمات المترابطة بشكل غير محكم والقابلة للنشر بشكل مستقل. تمتلك كل خدمة قدرة تجارية محددة، ولها مخزن بيانات خاص بها، وتتواصل عبر الشبكة. على الرغم من أن الخدمات الصغيرة تقدم تعقيدًا تشغيليًا كبيرًا، إلا أنها تمكن المؤسسات من توسيع نطاق فرق التطوير، والنشر بشكل مستقل، وبناء أنظمة أكثر مرونة.
تقوم بنية الخدمات المصغرة ببناء التطبيق كمجموعة من الخدمات المترابطة بشكل غير محكم والقابلة للنشر بشكل مستقل. تمتلك كل خدمة قدرة تجارية محددة، ولها مخزن بيانات خاص بها، وتتواصل عبر الشبكة. على الرغم من أن الخدمات الصغيرة تقدم تعقيدًا تشغيليًا كبيرًا، إلا أنها تمكن المؤسسات من توسيع نطاق فرق التطوير، والنشر بشكل مستقل، وبناء أنظمة أكثر مرونة.
يحتوي التطبيق المتجانس على جميع الوظائف في قاعدة تعليمات برمجية واحدة ووحدة نشر واحدة:
┌─────────────────────────────────────────────┐
│ 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) │
└───────────────────────┘
تمتلك كل خدمة قدرة عمل واحدة بالضبط. إذا كان بإمكانك وصف غرض خدمة ما دون استخدام "و"، فمن المحتمل أن تكون ذات نطاق جيد.
جيد:
خدمة الدفع - تتولى معالجة الدفع واسترداد الأموال.خدمة الإخطار - يرسل رسائل البريد الإلكتروني والرسائل النصية القصيرة والإشعارات الفورية.خدمة المخزون - إدارة مستويات المخزون والحجوزات.سيء:
خدمة المستخدم والطلب - تم دمج قدرتين متميزتين (ينتهك SRP).backend-service - كل شيء في خدمة واحدة (وليس الخدمات الصغيرة على الإطلاق).تمتلك كل خدمة قاعدة البيانات الخاصة بها. لا تشارك الخدمات قواعد البيانات مطلقًا، بل تتواصل عبر واجهات برمجة التطبيقات.
-- 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)
);
لماذا لا نتشارك قواعد البيانات؟
لا ينبغي أن ينتقل الفشل في إحدى الخدمات إلى الآخرين.
نمط قواطع دوائر:
// 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 });
يمكن نشر كل خدمة بشكل مستقل. هذه هي الفائدة الأساسية للخدمات الصغيرة.
أتمتة النشر:
# 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 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);
}
});
| معايير | متزامن | غير متزامن |
|---|---|---|
| هل يحتاج المتصل إلى استجابة فورية؟ | نعم | لا |
| هل يمكن تأجيل العملية؟ | لا | نعم |
| هل خدمة المصب متاحة دائمًا؟ | نعم | غير مطلوب |
| هل تحتاج إلى اتساق قوي؟ | نعم | في نهاية المطاف على ما يرام |
// 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:
Payment-service.namespace.svc.cluster.local.نقطة دخول واحدة لجميع طلبات العملاء:
| وظيفة | مثال |
|---|---|
| التوجيه | /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"
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
قانون كونواي: تصمم المؤسسات أنظمة تعكس هيكل اتصالاتها. إذا لم يكن فريقك منظمًا حول حدود الخدمة، فستؤدي الخدمات الصغيرة إلى حدوث احتكاك.
| فئة | خيارات | ملحوظات |
|---|---|---|
| نطاق | Spring Boot، NestJS، FastAPI، Go kit | اختر بناءً على خبرة الفريق |
| واجهة برمجة التطبيقات | ريست، جي آر بي سي، غراف كيو إل | gRPC للداخلية، REST للخارجية |
| المراسلة | كافكا، رابيت إم كيو، ناتس | كافكا لإنتاجية عالية |
| قاعدة البيانات | بوستجريس كيو ال، دينامو دي بي، مونغو دي بي | مطابقة قاعدة البيانات لاحتياجات الخدمة |
| حاوية | عامل ميناء | عالمي |
| التنسيق | كوبيرنيتيس | EKS أو AKS أو GKE أو مُدار ذاتيًا |
| بوابة API | كونغ، مبعوث، بوابة AWS API | مبعوث لتكامل شبكة الخدمة |
| إمكانية الملاحظة | القياس عن بعد المفتوح، بروميثيوس، جايجر | القياس عن بعد المفتوح هو المعيار |
| سي آي/سي دي | إجراءات GitHub، GitLab CI، ArgoCD | ArgoCD لـ GitOps |
| شبكة الخدمة | إستيو، لينكيرد، هدب | رابط للبساطة |
| الإدارة السرية | HashiCorp Vault، مدير أسرار AWS | قبو للسحابة المتعددة |
تعد الخدمات الصغيرة نموذجًا معماريًا قويًا يتيح النشر المستقل واستقلالية الفريق والأنظمة القابلة للتطوير. ومع ذلك، فإنها تأتي مع تعقيد تشغيلي كبير. أنجح عمليات تبني الخدمات المصغرة:
الخدمات الصغيرة ليست هي البنية الافتراضية — فهي تمثل حلاً لمشاكل تنظيمية وقياسية محددة. اخترهم عمدا، وليس بشكل افتراضي.
لا توجد تعليقات معتمدة بعد. قد تنتظر الردود الجديدة المراجعة.