ميكروسيرفيسات PHP: من النظرية إلى الإنتاج
الانتقال من البنية المتجانسة إلى بنية الميكروسيرفيسات في PHP ليس مجرد ترقية تقنية، بل تغيير جذري في طريقة تفكير المطور. على المستوى المتقدم، نواجه تحديات حقيقية: المعاملات الموزعة، تناسق البيانات، زمن استجابة الشبكة، وصعوبة التصحيح. في هذه المقالة، سنستعرض الأنماط الرئيسية والتقنيات العملية التي تساعد في بناء نظام موثوق وقابل للتوسع باستخدام PHP.
1. التواصل بين الخدمات: متزامن مقابل غير متزامن
اختيار بروتوكول الاتصال هو أول ما يواجهه المصمم. في نظام PHP البيئي، هناك طريقتان رئيسيتان.
الاتصال المتزامن عبر REST/gRPC
مثالي للعمليات التي تتطلب استجابة فورية (مثل التحقق من رصيد المستخدم). ومع ذلك، فإنه يخلق تبعيات صارمة: إذا تعطلت الخدمة B، ستتعطل الخدمة A أيضًا. يُوصى باستخدام نمط Circuit Breaker.
// مثال على Circuit Breaker في PHP باستخدام مكتبة Guzzleuse GuzzleHttp\\Client;use GuzzleHttp\\Exception\\ConnectException;
class CircuitBreaker { private int $failureCount = 0; private int $threshold = 3; private int $timeout = 30; // ثوانٍ private bool $open = false; private int $lastFailureTime = 0;
public function call(string $url): ?array { if ($this->isOpen()) { return null; // إغلاق سريع }
try { $client = new Client(['timeout' => 2.0]); $response = $client->get($url); $this->reset(); return json_decode($response->getBody(), true); } catch (ConnectException $e) { $this->recordFailure(); return null; } }
private function isOpen(): bool { if (!$this->open) return false; if (time() - $this->lastFailureTime > $this->timeout) { $this->open = false; // حالة نصف مفتوحة return false; } return true; }
private function recordFailure(): void { $this->failureCount++; $this->lastFailureTime = time(); if ($this->failureCount >= $this->threshold) { $this->open = true; } }
private function reset(): void { $this->failureCount = 0; $this->open = false; }}الاتصال غير المتزامن عبر قوائم الانتظار (RabbitMQ, Kafka)
للعمليات التي لا تتطلب استجابة فورية (إرسال البريد الإلكتروني، إنشاء التقارير). استخدم مكتبة php-amqplib.
// نشر حدث في RabbitMQuse PhpAmqpLib\\Connection\\AMQPStreamConnection;use PhpAmqpLib\\Message\\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');$channel = $connection->channel();
$channel->queue_declare('order_created', false, true, false, false);
$data = json_encode([ 'order_id' => 12345, 'user_id' => 678, 'total' => 1500.00]);$msg = new AMQPMessage($data, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);$channel->basic_publish($msg, '', 'order_created');
$channel->close();$connection->close();2. إدارة البيانات: CQRS و Event Sourcing
في الميكروسيرفيسات، يجب أن تمتلك كل خدمة بياناتها الخاصة. ولكن ماذا تفعل إذا كنت بحاجة إلى دمج بيانات من خدمات مختلفة لإعداد تقرير؟ هنا يأتي دور نمط CQRS (فصل مسؤولية الاستعلام عن الأمر).
تنفيذ CQRS بسيط في PHP
نفصل الأوامر (الكتابة) عن الاستعلامات (القراءة). للكتابة، نستخدم Doctrine ORM، وللقراءة، نستخدم استعلامات SQL مباشرة لنموذج القراءة.
// الأمر: إنشاء طلبclass CreateOrderCommand { public function __construct( public readonly int $userId, public readonly array $items, public readonly float $total ) {}}
// معا