كيفية الحد من تكرار الطلبات في HAProxy: تعليمات خطوة بخطوة


يشرح المؤلف كيفية التنفيذ في حدود سرعة استعلام HAProxy ( تحديد المعدل) مع عناوين IP معينة. قام فريق Mail.ru Cloud Solutions بترجمة مقاله - نأمل أنه لن تضطر معه لقضاء الكثير من الوقت والجهد عليه كما كان عليك أن تقضيه.

والحقيقة هي أن هذه إحدى الطرق الأكثر شيوعًا لحماية الخادم من هجمات DoS ، ولكن من الصعب العثور على تعليمات واضحة على الإنترنت حول كيفية تكوينه تحديدًا. عن طريق التجربة والخطأ ، أجبر المؤلف HAProxy على الحد من تكرار الطلبات على قائمة عناوين IP ، والتي يتم تحديثها في الوقت الفعلي.

لا يلزم معرفة مسبقة لتكوين HAProxy ، حيث تم توضيح جميع الخطوات اللازمة أدناه.

HAProxy مفتوح المصدر ومجاني هو موازن تحميل وخادم وكيل يمكن الوصول إليهما بشكل كبير. في السنوات الأخيرة ، أصبحت شائعة جدًا لأنها توفر أداءً عاليًا بحد أدنى من الموارد. على عكس البرامج البديلة ، يقدم الإصدار غير الربحي من HAProxy Community Edition ميزات كافية لتحقيق التوازن الموثوق في التحميل.

من الصعب جدًا معرفة هذا البرنامج. ومع ذلك ، لديها وثائق فنية دقيقة للغاية ومفصلة . يقول المؤلف أن هذا هو أكثر الوثائق التفصيلية بين جميع البرامج مفتوحة المصدر التي استخدمها على الإطلاق.
لذا ، إليك دليل خطوة بخطوة.

تكوين موازن التحميل


لتوفير الوقت وعدم تشتيت الانتباه من خلال إعداد البنية التحتية ، التقط صور Docker و Docker Compose وقم بتشغيل المكونات الرئيسية بسرعة.

المهمة الأولى هي رفع مثيل العمل من موازن التحميل HAProxy مع العديد من خوادم Apache الخلفية.

استنساخ المستودع


$ git clone git@github.com:stargazer/haproxy-ratelimiter.git
$ cd haproxy-ratelimiter

يمكنك أن تبحث في Dockerfileو docker-compose.ymlمع معلمات التثبيت. نقاشهم يتجاوز نطاق هذه المقالة ، لذلك دعونا نتحدث عن حقيقة أنهم أنشأوا مثيل HAProxy عامل يسمى loadbalancerمع خادمين خلفية api01و api02. لتكوين HAProxy ، سنستخدم الملف أولاً haproxy-basic.cfg، ثم ننتقل إلى haproxy-ratelimiting.cfg.

من أجل البساطة ، تم haproxy-basic.cfgتقليل ملف التكوين إلى الحد الأدنى وتم مسحه من الفائض. لنلق نظرة عليها:

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend proxy
bind *:80

use_backend api

backend api
balance roundrobin

server api01 api01:80
server api02 api02:80

يقوم القسم frontend proxyبتعيين HAProxy للاستماع على المنفذ 80 وإعادة توجيه جميع الطلبات إلى تجمع الخادم apiعلى الواجهة الخلفية.

الفئة backend apiيحدد الواجهة الخلفية تجمع apiمع اثنين من خوادم الواجهة الخلفية api01و api02وعناوين المقابلة. يتم تحديد الخادم لخدمة كل طلب وارد بواسطة خوارزمية موازنة التحميل roundrobin، أي في الواقع ، يتم استخدام الخادمين المتوفرين بدوره.

دعونا نطلق جميع حاوياتنا الثلاث


$ sudo docker-compose up

الآن لدينا وعاء loadbalancerالتي تعيد توجيه الطلبات إلى اثنين الخلفية api01و الخوادم api02. سنحصل على رد من أحدهم إذا دخلنا في شريط العنوان http://localhost/.

من المثير للاهتمام تحديث الصفحة عدة مرات والاطلاع على السجلات docker-compose.

api01_1 | 192.168.192.3 - - [08 / يناير / 2019: 11: 38: 09 +0000] "GET / HTTP / 1.1" 200 45
api02_1 | 192.168.192.3 - - [08 / يناير / 2019: 11: 38: 10 +0000] "GET / HTTP / 1.1" 304 -
api01_1 | 192.168.192.3 - - [08 / يناير / 2019: 11: 38: 10 +0000] "GET / HTTP / 1.1" 304 -
api02_1 | 192.168.192.3 - - [08 / يناير / 2019: 11: 38: 11 +0000] "GET / HTTP / 1.1" 304 -
api01_1 | 192.168.192.3 - - [08 / يناير / 2019: 11: 38: 11 +0000] "GET / HTTP / 1.1" 304 -
api02_1 | 192.168.192.3 - - [08 / يناير / 2019: 11: 38: 11 +0000] "GET / HTTP / 1.1" 304 -

كما ترون ، apiيعالج خادمان الطلبات في المقابل.

لدينا الآن مثيل HAProxy مع تكوين موازنة تحميل بسيط للغاية ، ولدينا فكرة عن كيفية عمله.

أضف حدًا لعدد الطلبات


لتعيين حد لعدد الطلبات إلى موازن التحميل ، تحتاج إلى تعديل ملف التكوين في مثيل HAProxy. تأكد من أن الحاوية loadbalancerتستخدم ملف التكوين haproxy-ratelimiter.cfg.

ما عليك سوى تعديل ملف Dockerfile لاستبدال ملف التكوين.

FROM haproxy:1.7
COPY haproxy-ratelimiter.cfg /usr/local/etc/haproxy/haproxy.cfg

وضع الحدود


يتم تسجيل جميع الإعدادات في ملف التكوين haproxy-ratelimiter.cfg. دعونا ندرسه بعناية.

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend proxy
bind *:80

# ACL function declarations
acl is_abuse src_http_req_rate(Abuse) ge 10
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
acl abuse_cnt src_get_gpc0(Abuse) gt 0

# Rules
tcp-request connection track-sc0 src table Abuse
tcp-request connection reject if abuse_cnt
http-request deny if abuse_cnt
http-request deny if is_abuse inc_abuse_cnt

use_backend api
backend api
balance roundrobin

server api01 api01:80
server api02 api02:80

backend Abuse
stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)

تقدم HAProxy مجموعة من المواد الأولية ذات المستوى المنخفض التي توفر المزيد من المرونة ومناسبة لمجموعة متنوعة من حالات الاستخدام. غالبًا ما تذكرني عداداتها بالسجل التراكمي (adder) في وحدة المعالجة المركزية. يخزنون نتائج وسيطة ، ويأخذون دلالات مختلفة كمدخلات ، ولكن في النهاية هم مجرد أرقام. لفهم كل شيء بشكل جيد ، من المنطقي أن تبدأ من نهاية ملف التكوين.

الطاولة Abuse


backend Abuse
stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)


قمنا هنا بإعداد خلفية وهمية تسمى Abuse("إساءة"). وهمية ، لأنها تستخدم فقط لطاولة العصا ، والتي يمكن أن تشير إليها بقية التكوين بالاسم Abuse. الطاولة الثابتة هي طاولة مخزنة في ذاكرة العملية ، حيث يمكنك تحديد العمر لكل سجل.

يتميز جدولنا بالخصائص التالية:

  • type ip: يتم حفظ الطلبات في الجدول بعنوان IP كمفتاح. وبالتالي ، ستشير الطلبات من نفس عنوان IP إلى نفس السجل. وهذا يعني في الأساس أننا نتتبع عناوين IP والبيانات ذات الصلة.
  • size 100K: يحتوي الجدول على 100 ألف سجل كحد أقصى.
  • expire 30m: فترة الاحتفاظ بالسجلات هي 30 دقيقة من عدم النشاط.
  • store gpc0,http_req_rate(10s): gpc0يتم تخزين العداد وعدد طلبات عنوان IP لآخر 10 ثوانٍ مع إدخالات . وبمساعدة المساعدة ، gpc0سنتتبع عدد مرات ملاحظة عنوان IP في الانتهاكات. في الواقع ، تعني القيمة المضادة الإيجابية أن عنوان IP تم وضع علامة عليه بالفعل على أنه مريب. دعنا نسمي هذا العداد abuse indicator.

بشكل عام ، Abuseيتيح لك الجدول تتبع ما إذا تم وضع علامة على عنوان IP على أنه مشبوه ، بالإضافة إلى التكرار الحالي للطلبات الواردة من هذا العنوان. لذلك ، لدينا تاريخ من السجلات ، بالإضافة إلى معلومات في الوقت الحقيقي.

الآن دعنا ننتقل إلى القسم frontend proxyونرى الجديد هناك.

وظائف وقواعد ACL


frontend proxy
bind *:80

# ACL function declarations
acl is_abuse src_http_req_rate(Abuse) ge 10
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
acl abuse_cnt src_get_gpc0(Abuse) gt 0

# Rules
tcp-request connection track-sc0 src table Abuse
tcp-request connection reject if abuse_cnt
http-request deny if abuse_cnt
http-request deny if is_abuse inc_abuse_cnt

use_backend api

قوائم التحكم في الوصول (ACLs) هي إعلانات وظائف يتم استدعاؤها فقط عند تعيين القاعدة.

دعونا نلقي نظرة فاحصة على جميع إدخالات ACL الثلاثة. ضع في اعتبارك أن جميعها تشير بشكل صريح إلى جدول Abuseيستخدم عناوين IP كمفتاح ، لذلك تنطبق كل وظيفة على عنوان IP للطلب:

  • acl is_abuse src_http_req_rate(Abuse) ge 10: is_abuseترجع الدالة Trueإذا كان تكرار الطلب الحالي أكبر من أو يساوي عشرة.
  • acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0: inc_abuse_cntترجع الدالة Trueإذا كانت قيمة الزيادة gpc0أكبر من الصفر. نظرًا لأن القيمة الأولية gpc0هي صفر ، فإن هذه الدالة ترجع دائمًا True. وبعبارة أخرى ، فإنه يزيد القيمة abuse indicator، مما يشير بشكل أساسي إلى إساءة الاستخدام من عنوان IP هذا.
  • acl abuse_cnt src_get_gpc0(Abuse) gt 0: abuse_cntترجع الدالة Trueإذا كانت القيمة gpc0أكبر من الصفر. وبعبارة أخرى ، يقول إذا كان عنوان IP هذا قد تم رصده بالفعل في الانتهاكات.

كما ذكرنا سابقًا ، فإن قوائم ACL هي مجرد إعلانات ، أي إعلانات وظائف. لا تنطبق على الطلبات الواردة حتى يتم تشغيل بعض القواعد.

من المنطقي أن ننظر إلى القواعد المحددة في نفس القسم frontend. يتم تطبيق القواعد على كل طلب وارد واحدًا تلو الآخر - وتشغيل الوظائف من قائمة التحكم بالوصول التي حددناها للتو.

دعونا نرى ما تفعله كل قاعدة:

  • tcp-request connection track-sc0 src table Abuse: يضيف استعلامًا إلى الجدول Abuse. نظرًا لأن المفتاح هو عنوان IP في الجدول ، تضيف هذه القاعدة إلى قائمة عناوين IP.
  • tcp-request connection reject if abuse_cnt: TCP-, IP- , abuse. , TCP- IP-.
  • http-request deny if abuse_cnt: , IP- . IP-, abuse.
  • http-request deny if is_abuse inc_abuse_cnt: , is_abuse inc_abuse_cnt True. , , IP- , IP- .

في الجوهر ، نقدم نوعين من عمليات التحقق: في الوقت الفعلي وفي القائمة السوداء من سجل طلبات البحث. ترفض القاعدة الثانية جميع اتصالات TCP الجديدة إذا تم ملاحظة عنوان IP في الانتهاكات. تحظر القاعدة الثالثة خدمة طلبات HTTP لعنوان IP من القائمة السوداء ، بغض النظر عن التكرار الحالي للطلبات الواردة من هذا العنوان. تضمن القاعدة الرابعة رفض طلبات HTTP من عنوان IP في نفس اللحظة بمجرد تجاوز عتبة تكرار الطلب. وبالتالي ، تعمل القاعدة الثانية بشكل أساسي على اتصالات TCP الجديدة ، والثالثة والرابعة - على الاتصالات التي تم إنشاؤها بالفعل ، الأول هو فحص تاريخي ، والثاني فحص في الوقت الفعلي.

لنجرب المرشح في العمل!


يمكننا الآن تجميع وتشغيل حاوياتنا مرة أخرى.

$ sudo docker-compose down
$ sudo docker-compose build
$ sudo docker-compose up

يجب أن يبدأ موازن التحميل قبل خادمي الواجهة الخلفية.

دعونا نوجه متصفحنا إلى http://localhost/. إذا قمنا بتحديث الصفحة بسرعة عشرات المرات ، فسوف نتجاوز عتبة عشرة طلبات في فاصل زمني مدته عشر ثوان - وسيتم رفض طلباتنا. إذا واصلنا تحديث الصفحة ، فسيتم رفض الطلبات الجديدة على الفور - حتى قبل إنشاء اتصال TCP.

الأسئلة


لماذا هو حد عشرة طلبات لكل عشر ثوان؟


Abuseيحدد الجدول http_req_rate(10s)، أي أن تكرار الطلبات يقاس في نافذة من عشر ثوان. is_abuseترجع دالة من ACL Trueبمعدل طلب ≥10 خلال الفاصل الزمني المحدد. وبالتالي ، يعتبر إساءة الاستخدام تكرار طلبات عشرة أو أكثر في عشر ثوان.

في هذه المقالة ، على سبيل المثال ، قررنا تعيين حد منخفض لتسهيل التحقق من تشغيل المحدد.

ما الفرق بين قواعد اتصال http-request و tcp-request؟


من التوثيق :

http- طلب: تحدد عبارة http-request مجموعة من القواعد التي تنطبق على طبقة الشبكة 7 [نموذج OSI]

من التوثيق :
tcp-request connection: تنفيذ إجراء على اتصال وارد بناءً على حالة في طبقة الشبكة 4

HTTP-, TCP-?


تخيل أن طلبات HTTP إلى الخادم ترسل اتصالات TCP متعددة من نفس عنوان IP. سيتجاوز تكرار طلبات HTTP العتبات بسرعة. عندها تدخل القاعدة الرابعة حيز التنفيذ ، والتي تتجاهل الطلبات وتدرج عنوان IP في القائمة السوداء.

أصبح من الممكن تمامًا أن تظل اتصالات HTTP من نفس عنوان IP مفتوحة (راجع اتصال HTTP المستمر ) ، وانخفض تكرار طلبات HTTP إلى ما دون قيمة العتبة. تضمن القاعدة الثالثة استمرار حظر طلبات HTTP ، حيث يتم abuse indicatorتشغيلها على عنوان IP هذا.

افترض الآن أنه بعد بضع دقائق ، يحاول نفس IP إنشاء اتصالات TCP. يتم إسقاطها على الفور ، لأن القاعدة الثانية تنطبق: فهي ترى عنوان IP المسمى وتقطع الاتصال على الفور.

استنتاج


في البداية ، قد يكون من الصعب فهم حدود سرعة معالجة الطلبات باستخدام HAProxy. للقيام بكل شيء بشكل صحيح ، تحتاج إلى تفكير "منخفض المستوى" إلى حد ما وعدد من الإجراءات غير البديهية. ربما يكون التوثيق في هذا الجزء تقنيًا للغاية ويعاني من عدم وجود أي أمثلة أساسية. نأمل أن يعوض هذا الدليل عن العيب ويظهر الاتجاه لكل من يريد أن يسلك هذا المسار.

ماذا تقرأ :

  1. كيف يتم تنفيذ البنية المتسامحة في النظام الأساسي Mail.ru Cloud Solutions .
  2. أفضل 10 حيل ونصائح Kubernetes .
  3. قناة Telegram حول التحول الرقمي .

All Articles