تتطلب بوابات VPN عالية السعة التي تنهي آلاف الأنفاق المشفرة المتزامنة نطاقاً ترددياً متماثلاً فائق الكفاءة في اتجاهي الاستقبال والإرسال. وبينما تعمل تقنيات تسريع الاستقبال مثل RSS وRPS على توزيع الحزم الواردة بسلاسة عبر أنوية المعالجات، فإن مسار الإرسال الخارجي (egress) غالباً ما يتعرض لتراجع غير متوقع في الأداء عند زيادة كثافة التدفق.

على الخوادم متعددة الأنوية المزودة ببطاقات واجهة شبكة (NIC) بسرعات 10GbE أو 25GbE أو 100GbE تدعم طوابير عتادية متعددة (Multi-Queue)، تكون معالجة الحزم الصادرة عرضة لتنازع الأقفال (lock contention) داخل النواة. فعندما تحاول أنوية معالجة متعددة في الوقت ذاته إدراج حزم الإرسال في طابور عتادي واحد، تفرض أقفال الدوران (spinlocks) معالجة تسلسلية بطيئة. يؤدي هذا التسلسل إلى إهدار دورات المعالج في حلقات انتظار عقيمة، وتشتيت خطوط الذاكرة المخبأة L1/L2/L3 عبر مقابس المعالجات، وحدوث قفزات مفاجئة في أزمنة التأخير القصوى (p99).

توفر تقنية Linux Transmit Packet Steering (XPS) المدمجة في مكدس الشبكات حلاً جذرياً لهذا الاختناق. فمن خلال إنشاء تعيين محدد وذكي بين أنوية المعالجة المرسلة (أو طوابير الاستقبال) وطوابير الإرسال العتادية، تقضي XPS على عبء تنازع الأقفال وترفع كفاءة الذاكرة في خوادم الحافة.


Tx Lock Contention: اختناق الإرسال عبر الأنظمة متعددة الأنوية

لفهم أسباب نشوء اختناقات الإرسال، نستعرض المسار الذي تسلكه الحزم الصادرة عبر عتاد الشبكات متعدد الطوابير في لينكس:

  1. توليد الحزم أو إعادة توجيهها: تبني التطبيقات، أو واجهات الأنفاق (مثل wg0 في WireGuard)، أو طبقات التوجيه ذاكرة وسيطة للمقبس (sk_buff).
  2. اختيار طابور الإرسال: يستدعي مكدس الشبكة الدالة dev_pick_tx() في ملف net/core/dev.c لتحديد طابور الإرسال العتادي المستهدف (struct netdev_queue).
  3. حيازة قفل الطابور: قبل إيداع الحزمة في الذاكرة الدائرية للمشغل عبر ndo_start_xmit()، يتعين على النواة حيازة القفل الحصري المخصص لذلك الطابور: __netif_tx_lock().
تنازع الطوابير في غياب تقنية XPS (عدة أنوية تتنافس على طابور واحد):

النواة 0 ──► [ dev_queue_xmit() ] ──┐
                                    ├──► [ قفل الدوران __netif_tx_lock() ] ──► [ طابور الإرسال 0 ]
النواة 1 ──► [ dev_queue_xmit() ] ──┤    (انتظار مستمر وتوقف المعالجة)
                                    │
النواة 2 ──► [ dev_queue_xmit() ] ──┘

في الحالة الافتراضية دون إعداد التعيين، يعتمد اختيار الطابور على تجزئة التدفق القياسية (skb_tx_hash()). وفي بيئات أنفاق VPN المتماثلة حيث تتشارك آلاف الاتصالات سمات تغليف UDP متشابهة، تتطابق مخرجات التجزئة من أنوية مختلفة لتوجه الحزم إلى نفس طابور الإرسال في اللحظة ذاتها.

عند تصادم الأنوية المتعددة على القفل __netif_tx_lock()، تدخل الخيوط البرمجية في حلقات انتظار مغلقة (busy-wait). ومع ارتفاع عدد الأنوية إلى 32 أو 64 أو 128، يتضاعف وقت ضياع المعالجة بصورة هائلة. تكشف أدوات التحليل مثل perf top استهلاك نسبة ضخمة من وقت المعالج في الروتين queued_spin_lock_slowpath بدلاً من استثمارها في عمليات التشفير ونقل البيانات.


Architectural Mechanics: آلية عمل تقنية Linux XPS

تؤسس ميزة Transmit Packet Steering طبقة توجيه مرنة بين سياقات تنفيذ المعالجة وطوابير الإرسال العتادية لبطاقة الشبكة. تعمل XPS من خلال نمطين أساسيين: التوجيه المعتمد على الأنوية والتوجيه المعتمد على طوابير الاستقبال.

1. التوجيه المعتمد على أنوية المعالجة (xps_cpus)

يربط هذا النمط أنوية محددة بطوابير إرسال حصرية. يعرض كل طابور إرسال في نظام sysfs قناعاً ثنائياً يسمى xps_cpus. وبمجرد تفعيله:

  • ترسل كل نواة بياناتها حصرياً عبر طابور الإرسال المخصص لها (أو مجموعة محددة مستقلة).
  • إذا تساوى عدد طوابير الإرسال العتادية مع عدد الأنوية النشطة أو فاقها، تحصل كل نواة على مسار إرسال خاص دون أي تنازع.
  • نظراً لأن نواة معالجة واحدة فقط هي التي تتعامل مع بنية netdev_queue المحددة في أي لحظة، تصبح حيازة __netif_tx_lock() عملية فورية تنجز دون انتظار.
إرسال خالي من الأقفال عبر نمط xps_cpus (تعيين 1:1 بين النواة والطابور):

النواة 0  ──► [ xps_cpus = 0x1 ] ──► [ طابور إرسال مخصص 0 ] ──► [ كابل الشبكة ]
النواة 1  ──► [ xps_cpus = 0x2 ] ──► [ طابور إرسال مخصص 1 ] ──► [ كابل الشبكة ]
النواة 2  ──► [ xps_cpus = 0x4 ] ──► [ طابور إرسال مخصص 2 ] ──► [ كابل الشبكة ]
النواة 3  ──► [ xps_cpus = 0x8 ] ──► [ طابور إرسال مخصص 3 ] ──► [ كابل الشبكة ]

2. التوجيه المعتمد على طوابير الاستقبال (xps_rxqs)

تعالج محولات الشبكة الحديثة وبوابات VPN تدفقات ثنائية الاتجاه متناظرة. فعندما تستقبل البوابة حزمة واردة على طابور الاستقبال Rx رقم $N$، تحتفظ النواة التي تولت المقاطعة ببيانات الترويسة وجداول التوجيه دافئة في ذاكرتها المخبأة L1/L2.

يربط المعامل xps_rxqs اختيار طابور الإرسال مباشرة بطابور الاستقبال الذي استقبل الحزمة:

  • تولد الحزمة المستلمة عبر طابور Rx رقم 0 ردود الإرسال الصادرة (مثل إشعارات استلام TCP ACK أو ردود المصافحة) عبر طابور Tx رقم 0 تحديداً.
  • يضمن هذا التناظر تنفيذ الإرسال على نفس النواة التي استقبلت الحزمة، مما يلغي تماماً الحاجة لإلغاء صلاحية الذاكرة المخبأة بين الأنوية.

NUMA Topology and Cache Locality: استقرار الذاكرة في خوادم الحافة

في الخوادم الكبيرة متعددة المقابس (مثل منصات المعالجات المزدوجة AMD EPYC أو Intel Xeon)، تؤثر بنية الذاكرة غير الموحدة (NUMA) تأثيراً مباشراً على سرعة الشبكة.

تشتت الذاكرة المخبأة والضغط على مسارات الربط

ترتبط بطاقات الشبكة PCIe فيزيائياً بمجمع المقبس التابع لنود NUMA محدد. فإذا قامت نواة في النود 1 بإرسال حزمة عبر بطاقة شبكة تابعة للنود 0 دون تهيئة تراعي توزيع NUMA:

  1. إجهاد مسارات الربط: تضطر النواة لإرسال مؤشرات الواصفات وعناوين DMA عبر مسار الربط بين المعالجات (مثل AMD Infinity Fabric أو Intel UPI).
  2. تذبذب خطوط الذاكرة المخبأة L3: يتنقل قفل __netif_tx_lock() ومؤشرات الذاكرة الدائرية ذهاباً وإياباً بين كاش L3 لكلا المعالجين.
  3. ارتفاع تباين زمن الانتقال: تستغرق عمليات الوصول إلى الذاكرة البعيدة دورات أطول بكثير مقارنة بالذاكرة المحلية، مما يؤدي إلى عدم استقرار التأخير (jitter).

يضمن ضبط أقنعة XPS وفقاً لحدود NUMA المحلية أن ترسل الأنوية حزمها فقط عبر طوابير بطاقات الشبكة المتصلة بنفس المعالج، محافظاً على سعة مسارات النظام.


ضبط إعدادات النواة: تفعيل وتحسين XPS في لينكس

يتطلب تطبيق XPS بصورة مثالية فحص إمكانيات واجهة الشبكة، وحساب الأقنعة الثنائية المناسبة للأنوية، والتكامل مع آليات إدارة طوابير المشغل.

1. إعداد الأقنعة الثنائية لربط الأنوية بالطوابير

مثال لضبط تعيين بنسبة 1:1 لبطاقة شبكة تضم 4 أنوية و4 طوابير إرسال على الواجهة eth0:

# استعراض طوابير الإرسال المتاحة على الواجهة eth0
ls -d /sys/class/net/eth0/queues/tx-*

# تخصيص النواة 0 (القناع 0x1) لطابور الإرسال Tx-0
echo "1" | sudo tee /sys/class/net/eth0/queues/tx-0/xps_cpus

# تخصيص النواة 1 (القناع 0x2) لطابور الإرسال Tx-1
echo "2" | sudo tee /sys/class/net/eth0/queues/tx-1/xps_cpus

# تخصيص النواة 2 (القناع 0x4) لطابور الإرسال Tx-2
echo "4" | sudo tee /sys/class/net/eth0/queues/tx-2/xps_cpus

# تخصيص النواة 3 (القناع 0x8) لطابور الإرسال Tx-3
echo "8" | sudo tee /sys/class/net/eth0/queues/tx-3/xps_cpus

إذا تجاوز عدد الأنوية عدد طوابير الإرسال المتاحة، تجمع الأنوية المشتركة في نفس كتلة الذاكرة المخبأة L3 ضمن قناع ثنائي لطابور موحد.

2. التنسيق بين XPS وحدود طوابير البايتات (BQL)

بينما تقضي XPS على تنازع الأقفال البرمجية، تحتاج الطوابير العتادية لضبط تراكم البيانات لتفادي ظاهرة تضخم الذاكرة الوسيطة (bufferbloat). تعمل خاصية Byte Queue Limits (BQL) تلقائياً داخل كل طابور مشغل:

# الاطلاع على الحد الديناميكي الحالي المحسوب بواسطة BQL للطابور Tx رقم 0
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/limit

# مراقبة حجم البايتات الموجودة حالياً قيد المعالجة العتادية
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/inflight

يحقق التعاون بين XPS وBQL توازناً مثالياً: تتيح XPS إيداعاً فورياً دون أقفال، بينما تحد BQL من عمق الطابور العتادي للإبقاء على زمن استجابة متدنٍ للغاية.


المقارنة الهندسية: الإرسال الافتراضي مقابل تهيئة XPS

يوضح الجدول التالي قياسات الأداء المسجلة على موجه حافة VPN بسرعة 40GbE تحت تدفق حزم يتراوح حجمها بين 64 بايت و1420 بايت:

معيار القياس اختيار الطوابير الافتراضي التعيين المتماثل عبر XPS المكسب الهندسي المحقق
تنازع الأقفال (__netif_tx_lock) 18% إلى 32% من وقت المعالج أقل من 0.2% من وقت المعالج استعادة ~30% من طاقة المعالجة
معدل الإخفاق في كاش L3 14.8 إخفاقاً / ألف حزمة 2.1 إخفاقاً / ألف حزمة تحسن بمقدار 7 أضعاف في كفاءة الكاش
حركة المرور عبر مسار UPI/IF مرتفعة (تنقل دائم للبيانات) محصورة في نود NUMA المحلي تخفيف الضغط عن ممرات الربط
زمن التأخير عند المئين 99 (p99) 4.8 مللي ثانية عند الذروة 0.65 مللي ثانية عند الذروة انخفاض تشتت التأخير بنسبة 86%
سعة توجيه الحزم (Mpps) 8.2 مليون حزمة / ثانية 14.1 مليون حزمة / ثانية زيادة بنسبة 72% في الإنتاجية الفعلية
اضطراب ترتيب الحزم الصادرة يحدث أحياناً بسبب التنازع تسلسل صارم ومحكم لكل نواة تفادي إعادة الإرسال الزائفة لـ TCP

بنية RiceGuard: إرسال متسارع خالٍ من الأقفال

في البنية التحتية لـ VPNRice، تشغل عقد RiceGuard الطرفية وحدات معالجة متعددة الخيوط مصممة للاستفادة الكاملة من خطوط الاتصال متعددة الجيجابت. ويتم تثبيت كل خيط لمعالجة التشفير بصورة دائمة على نواة معالجة محددة (CPU Pinning).

تدمج طبقة الإرسال في RiceGuard هذا التوزيع مع جداول XPS الخاصة بالنواة:

/* تهيئة ربط الأنوية بمسارات الإرسال في RiceGuard */
int configure_worker_egress_affinity(int worker_id, int core_id) {
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core_id, &cpuset);

    /* تثبيت خيط العمل بدقة على النواة المستهدفة */
    if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) {
        perror("pthread_setaffinity_np");
        return -1;
    }

    /* يوجه المقبس الحزم مباشرة إلى طابور XPS المتوافق */
    return 0;
}

بفضل إرسال حزم WireGuard المشفرة مباشرة من النواة المربوطة بطابور XPS المخصص لها، تنتقل الحزم إلى مصفوفة المشغل دون انتظار أي أقفال تنافسية.

وبالاقتران مع تقنية الذاكرة الحلقية دون نسخ (zero-copy)، تضمن هذه التوليفة بقاء زمن تأخير الحزم في أنفاق VPNRice مستقراً دون عتبة 1 مللي ثانية حتى أثناء أوقات الذروة الشديدة.