नगनेक्स में स्लेशडॉट प्रभाव का पता लगाना


10

क्या कोई तरीका है कि मैं मुझे सूचित करने के लिए नगीनेक्स बना सकता हूं अगर एक रेफरल से हिट एक सीमा से परे जाती है?

उदाहरण के लिए, यदि मेरी वेबसाइट Slashdot में चित्रित की गई है और अचानक मेरे पास एक घंटे में आने वाले 2K हिट हैं, तो मैं चाहता हूं कि जब 1K एक घंटे से अधिक हो जाए तो मुझे सूचित किया जाए।

क्या नगीनक्स में ऐसा करना संभव होगा? संभवतः लू के बिना? (चूँकि मेरे प्रोडक्ट्स में लुआ संकलित नहीं है)


4
"स्लैशडॉट" क्या है ??
ewwhite

मैं कुछ इस तरह से किया था ddos ​​ngix पर पता लगाने के लिए। मैंने इसे एक्सेस लॉग पार्स करके हासिल किया। मैंने प्रवेश लॉग को पार्स करने और प्रति घंटे अद्वितीय आईपी कनेक्शन की गणना करने के लिए एक क्रॉन जॉब किया।
हेक्स

8
आपका मतलब है कि आप चाहते हैं कि यदि आप पासा द्वारा खरीदे गए हैं, तो नगनेक्स का पता लगाने में सक्षम हों?
एमडीएमरा

1
@ हेक्स (और शायद आपकी स्क्रिप्ट से कुछ स्निपेट्स) इस सवाल का एक शानदार जवाब
देंगे

3
शायद अब स्लैशडॉट होने के बारे में चिंता करने की कोई आवश्यकता नहीं है। आपका वेबसर्वर एक घंटे में अतिरिक्त 4 कनेक्शन को संभालने में सक्षम होना चाहिए। हालांकि, Redditted होने के बारे में चिंता करना चाहते हो सकता है ...
HopelessN00b

जवाबों:


3

सबसे कुशल समाधान एक डेमॉन होता है कि लिखने के लिए हो सकता है , और का ट्रैक रखने के क्षेत्र।tail -faccess.log$http_referer

हालाँकि, एक त्वरित और गंदा समाधान एक अतिरिक्त access_logफ़ाइल जोड़ना होगा , केवल एक $http_refererचर के साथ चर को लॉग इन करने के लिए log_format, और स्वचालित रूप से लॉग को हर दस मिनट में घुमाएगी।

  • इसे मानक लॉगोट स्क्रिप्ट्स की मदद से पूरा किया जा सकता है, जिसके लिए फाइलों को फिर से खोलने के लिए (जैसे मानक प्रक्रिया, एक साधारण समय के लिए / a / 15183322 / एसओ पर एक नज़र रखना चाहिए) नगनेक्स के सुशोभित पुनरारंभ करने की आवश्यकता हो सकती है- आधारित स्क्रिप्ट) ...

  • या, भीतर चर का उपयोग करके access_log, संभवत: मिनट विनिर्देशन $time_iso8601को mapएक ifनिर्देश की सहायता से या एक निर्देश के आधार पर प्राप्त करके (यह निर्भर करता है कि आप कहां रखना चाहते हैं access_log)।

तो, उपरोक्त के साथ, आपके पास 6 लॉग फाइलें हो सकती हैं, जिनमें से प्रत्येक 10 मिनट की अवधि को कवर करती है http_referer.Txx{0,1,2,3,4,5}x.log, उदाहरण के लिए, प्रत्येक फ़ाइल को अलग करने के लिए मिनट का पहला अंक प्राप्त करके।

अब, आपको बस एक सरल शेल स्क्रिप्ट देनी है, जो हर 10 मिनट पर चल सकती है, catउपरोक्त सभी फाइलें एक साथ, इसे पाइप करें sort, इसे पाइप करें uniq -c, टू sort -rn, टू head -16, और आपके पास 16 सबसे आम Refererविविधताओं की एक सूची है। यह तय करने के लिए स्वतंत्र है कि क्या संख्या और क्षेत्र का कोई संयोजन आपके मानदंड से अधिक है, और एक अधिसूचना करें।

इसके बाद, एक एकल सफल अधिसूचना के बाद, आप इन 6 फ़ाइलों में से सभी को निकाल सकते हैं, और बाद के रनों में, किसी भी अधिसूचना को जारी नहीं करते हैं, सभी छह फाइलें मौजूद हैं (और / या एक निश्चित अन्य संख्या, जैसा कि आप फिट देखते हैं)।


यह सुपर उपयोगी लगता है। मैं बहुत अधिक के लिए पूछ रहा हो सकता है, लेकिन पहले के जवाब की तरह, क्या आप एक स्क्रिप्ट के साथ मदद करना चाहेंगे?
क्विंटन Par

@QuintinPar अतिरिक्त पाठ्यचर्या करता है! ;-) यदि आप चाहें, तो मैं किराया और परामर्श के लिए उपलब्ध हूं; मेरा ईमेल cnst++@FreeBSD.org है, कांस्टेंटाइन
SU

पूरी तरह से समझते हैं। अब तक की सभी मदद के लिए बहुत बहुत धन्यवाद। आशा है कि मैं आपको किसी दिन खर्च कर सकता हूं :-)
क्विंटन Par

1
@QuintinPar आपका स्वागत है! कोई चिंता नहीं, यह उपरोक्त युक्ति के साथ एक बहुत ही सरल स्क्रिप्ट होनी चाहिए; मूल रूप से परीक्षण, विन्यास और पैकेजिंग का सिर्फ एक मामला है। :)
cnst

1
आप एक सुपर हीरो हैं!
क्विंटन Par

13

मुझे लगता है कि यह लॉगलेट और grep के साथ कहीं बेहतर होगा। यहां तक ​​कि अगर यह लुआ इनलाइन के साथ करना संभव है, तो आप हर अनुरोध के लिए उस ओवरहेड को नहीं चाहते हैं और जब आप स्लैशडॉट किए गए हैं तो आप इसे विशेष रूप से नहीं चाहते हैं।

यहाँ एक 5-सेकंड संस्करण है। इसे एक स्क्रिप्ट में चिपकाएँ और इसके चारों ओर कुछ और पठनीय पाठ डालें और आप सुनहरे हों।

5 * * * * logtail -f /var/log/nginx/access_log -o /tmp/nginx-logtail.offset | grep -c "http://[^ ]slashdot.org"

बेशक, यह पूरी तरह से reddit.com और facebook.com और लाखों अन्य साइटों को अनदेखा करता है जो आपको बहुत सारे ट्रैफ़िक भेज सकते हैं। 100 अलग-अलग साइटों का उल्लेख नहीं करने के लिए आपको प्रत्येक 20 आगंतुकों को भेज रहा है। आपके पास संभवतः एक सादा पुराना ट्रैफ़िक थ्रेशोल्ड होना चाहिए, जो आपके लिए एक ईमेल भेजने का कारण बनता है, चाहे वह किसी भी तरह का हो।


1
समस्या का सक्रिय होना है। मुझे किसी भी साइट से जानने की आवश्यकता है। एक और सवाल यह है कि मैं थ्रेसहोल्ड कहां रखूं? क्या आपके पास कुछ अतिरिक्त लॉग पार्सिंग का मतलब है? इसके अलावा, मुझे फोरमिल्ला
पार से

दहलीज इस बात पर निर्भर करेगी कि आपका सर्वर कितना ट्रैफ़िक संभाल सकता है। केवल आप ही इसे सेट कर सकते हैं। यदि आप तेज अधिसूचना चाहते हैं, तो इसे हर घंटे के बजाय हर पांच मिनट में चलाएं और थ्रेसहोल्ड को 12 से विभाजित करें। -o विकल्प एक ऑफसेट फ़ाइल के लिए है, इसलिए यह जानता है कि अगली बार पढ़ना कहां शुरू करना है।
लदादादा

@ लाडदादा, मैं असहमत हूं कि ओवरहेड पर्याप्त होगा, मेरा समाधान देखें - serverfault.com/a/870537/110020 - मेरा मानना ​​है कि ओवरहेड काफी न्यूनतम होगा यदि इसे ठीक से लागू किया जाता है, खासकर (1), यदि आपका बैकएंड है वास्तव में धीमा है, तो यह ओवरहेड नगण्य होगा, या, (2), यदि आपका बैकएंड पहले से ही काफी स्निपी और / या ठीक से कैश्ड है, तो आपके पास पहले से ट्रैफिक से निपटने के लिए कम मुद्दे होने चाहिए, और थोड़ा अतिरिक्त लोड होना चाहिए। ' टी एक सेंध लगाओ। कुल मिलाकर, ऐसा लगता है कि इस प्रश्न के दो उपयोग मामले हैं, (1), बस सूचित किया जा रहा है, और (2), स्वचालित स्केलिंग।
cnst

4

Nginx limit_req_zone निर्देश, किसी भी चर पर अपने क्षेत्रों का आधार कर सकते हैं $ http_referrer भी शामिल है।

http {
    limit_req_zone  $http_referrer  zone=one:10m   rate=1r/s;

    ...

    server {

        ...

        location /search/ {
            limit_req   zone=one  burst=5;
        }

आप वेब सर्वर पर आवश्यक राज्य की मात्रा को सीमित करने के लिए भी कुछ करना चाहेंगे, हालांकि, रेफ़र हेडर काफी लंबे और विविध हो सकते हैं और आप एक इनफिनिटी संस्करण देख सकते हैं। आप सभी अनुरोधों के लिए वैरिएबल हैडर के हैश पर आधारित एक चर सेट करने के लिए nginx विभाजित_क्लियर सुविधा का उपयोग कर सकते हैं । नीचे दिए गए उदाहरण में केवल 10 रुपये का उपयोग किया गया है, लेकिन आप इसे 1000 के साथ आसानी से कर सकते हैं। इसलिए यदि आप स्लैशडॉट हो गए हैं, तो जिन लोगों का रेफ़र उसी बाल्टी में हैश करने के लिए हुआ है क्योंकि स्लैशडॉट URL भी ब्लॉक हो जाएगा, लेकिन आप विभाजित करने वाले ग्राहकों में 1000 बाल्टियों का उपयोग करके 0.1% तक सीमित कर सकते हैं।

यह कुछ इस तरह दिखेगा (पूरी तरह से अप्रयुक्त, लेकिन प्रत्यक्ष रूप से सही):

http {

split_clients $http_referrer $refhash {
               10%               x01;
               10%               x02;
               10%               x03;
               10%               x04;
               10%               x05;
               10%               x06;
               10%               x07;
               10%               x08;
               10%               x09;
               *                 x10;
               }

limit_req_zone  $refhash  zone=one:10m   rate=1r/s;

...

server {

    ...

    location /search/ {
        limit_req   zone=one  burst=5;
    }

यह एक दिलचस्प दृष्टिकोण है; हालाँकि, मेरा मानना ​​है कि यह सवाल एक स्वचालित अलर्ट के बारे में है जब स्लैशडॉट प्रभाव हो रहा है; आपका समाधान लगभग 10% उपयोगकर्ताओं को बेतरतीब ढंग से अवरुद्ध करने के लिए हल करता है। इसके अलावा, मेरा मानना ​​है कि उपयोग करने के लिए आपका तर्क split_clientsगलत हो सकता है - limit_reqएक "टपका हुआ बाल्टी" पर आधारित है, जिसका अर्थ है कि समग्र राज्य को निर्दिष्ट क्षेत्र के आकार से अधिक नहीं होना चाहिए।
cnst

2

हाँ, बेशक यह NGINX में संभव है!

आप निम्नलिखित डीएफए को लागू कर सकते हैं :

  1. मूल्यों को सामान्य करने के लिए $http_refererसंभवतः कुछ रेगेक्स का उपयोग करके , के आधार पर , दर सीमित करना लागू करें map। जब सीमा पार हो जाती है, तो एक आंतरिक त्रुटि पृष्ठ उठाया जाता है, जिसे आप संबंधित प्रश्न के अनुसारerror_page हैंडलर के माध्यम से पकड़ सकते हैं , एक आंतरिक रीडायरेक्ट (क्लाइंट के लिए दृश्यमान नहीं) के रूप में एक नए आंतरिक स्थान पर जा सकते हैं।

  2. अधिक सीमाओं के लिए उपरोक्त स्थान में, आप एक चेतावनी अनुरोध करते हैं, जिससे बाहरी तर्क सूचना को निष्पादित कर सकते हैं; इस अनुरोध को बाद में कैश किया जाता है, यह सुनिश्चित करते हुए कि आपको दिए गए समय विंडो के अनुसार केवल 1 अद्वितीय अनुरोध प्राप्त होगा।

  3. पूर्व अनुरोध के HTTP स्थिति कोड को पकड़ो (एक स्थिति कोड using 300 लौटाकर और proxy_intercept_errors on, या, वैकल्पिक रूप से, नहीं-निर्मित-बाय-डिफ़ॉल्ट का उपयोग करें auth_requestया add_after_body"निशुल्क" सबरेक्वेस्ट) का उपयोग करें, और मूल अनुरोध को पूरा करें पहले चरण में शामिल नहीं था। ध्यान दें कि हमें काम करने के लिए पुनरावर्ती error_pageसंचालन को सक्षम करने की आवश्यकता है ।

यहाँ मेरा PoC और एक MVP है, वो भी https://github.com/cnst/StackOverflow.cnst.nginx.conf/blob/master/sf.432636.detecting-slashdot-effect-in-nginx.conf पर :

limit_req_zone $http_referer zone=slash:10m rate=1r/m;  # XXX: how many req/minute?
server {
    listen 2636;
    location / {
        limit_req zone=slash nodelay;
        #limit_req_status 429;  #nginx 1.3.15
        #error_page 429 = @dot;
        error_page 503 = @dot;
        proxy_pass http://localhost:2635;
        # an outright `return 200` has a higher precedence over the limit
    }
    recursive_error_pages on;
    location @dot {
        proxy_pass http://127.0.0.1:2637/?ref=$http_referer;
        # if you don't have `resolver`, no URI modification is allowed:
        #proxy_pass http://localhost:2637;
        proxy_intercept_errors on;
        error_page 429 = @slash;
    }
    location @slash {
        # XXX: placeholder for your content:
        return 200 "$uri: we're too fast!\n";
    }
}
server {
    listen 2635;
    # XXX: placeholder for your content:
    return 200 "$uri: going steady\n";
}
proxy_cache_path /tmp/nginx/slashdotted inactive=1h
        max_size=64m keys_zone=slashdotted:10m;
server {
    # we need to flip the 200 status into the one >=300, so that
    # we can then catch it through proxy_intercept_errors above
    listen 2637;
    error_page 429 @/.;
    return 429;
    location @/. {
        proxy_cache slashdotted;
        proxy_cache_valid 200 60s;  # XXX: how often to get notifications?
        proxy_pass http://localhost:2638;
    }
}
server {
    # IRL this would be an actual script, or
    # a proxy_pass redirect to an HTTP to SMS or SMTP gateway
    listen 2638;
    return 200 authorities_alerted\n;
}

ध्यान दें कि यह उम्मीद के मुताबिक काम करता है:

% sh -c 'rm /tmp/slashdotted.nginx/*; mkdir /tmp/slashdotted.nginx; nginx -s reload; for i in 1 2 3; do curl -H "Referer: test" localhost:2636; sleep 2; done; tail /var/log/nginx/access.log'
/: going steady
/: we're too fast!
/: we're too fast!

127.0.0.1 - - [26/Aug/2017:02:05:49 +0200] "GET / HTTP/1.1" 200 16 "test" "curl/7.26.0"
127.0.0.1 - - [26/Aug/2017:02:05:49 +0200] "GET / HTTP/1.0" 200 16 "test" "curl/7.26.0"

127.0.0.1 - - [26/Aug/2017:02:05:51 +0200] "GET / HTTP/1.1" 200 19 "test" "curl/7.26.0"
127.0.0.1 - - [26/Aug/2017:02:05:51 +0200] "GET /?ref=test HTTP/1.0" 200 20 "test" "curl/7.26.0"
127.0.0.1 - - [26/Aug/2017:02:05:51 +0200] "GET /?ref=test HTTP/1.0" 429 20 "test" "curl/7.26.0"

127.0.0.1 - - [26/Aug/2017:02:05:53 +0200] "GET / HTTP/1.1" 200 19 "test" "curl/7.26.0"
127.0.0.1 - - [26/Aug/2017:02:05:53 +0200] "GET /?ref=test HTTP/1.0" 429 20 "test" "curl/7.26.0"
%

आप देख सकते हैं कि पहला अनुरोध एक फ्रंट-एंड और एक बैकएंड हिट के परिणामस्वरूप होता है, जैसा कि अपेक्षित था (मुझे उस स्थान पर एक डमी बैकएंड जोड़ना होगा limit_req, क्योंकि return 200सीमा से अधिक पूर्वता होगी, एक वास्तविक बैकेंड आवश्यक नहीं है बाकी हैंडलिंग के लिए)।

दूसरा अनुरोध सीमा से ऊपर है, इसलिए, हम अलर्ट भेजते हैं (प्राप्त करते हैं 200), और इसे कैश करते हैं, लौटाते हैं 429(यह उपरोक्त सीमा के कारण आवश्यक है कि 300 से नीचे के अनुरोधों को पकड़ा नहीं जा सकता), जिसे बाद में फ्रंट-एंड द्वारा पकड़ा गया है , जो अब स्वतंत्र है जो चाहे वह करने के लिए स्वतंत्र है।

तीसरा अनुरोध अभी भी सीमा से अधिक है, लेकिन हमने पहले ही अलर्ट भेज दिया है, इसलिए, कोई नया अलर्ट नहीं भेजा जाता है।

किया हुआ! यह GitHub पर कांटा करने के लिए मत भूलना!


क्या दो दर सीमित करने की स्थिति एक साथ काम कर सकती है? : मैं अब इस अधिकार का उपयोग कर रहा serverfault.com/a/869793/26763
Quintin सममूल्य

@QuintinPar :-) मुझे लगता है कि यह इस बात पर निर्भर करेगा कि आप इसका उपयोग कैसे करते हैं - स्पष्ट समस्या यह होगी कि किसी भी स्थान पर किसी भी स्थान पर इस शर्त को अलग किया जाए; लेकिन अगर यह एक है limit_req, और दूसरा एक है limit_conn, तो बस limit_req_status 429ऊपर का उपयोग करें (बहुत नए nginx की आवश्यकता है), और मुझे लगता है कि आपको सुनहरा होना चाहिए; अन्य विकल्प हो सकते हैं (यह सुनिश्चित करने के लिए एक काम करने के लिए nginx w / का पीछा कर रहा है set_real_ip_from, लेकिन, वास्तव में आप क्या करना चाहते हैं, इसके आधार पर अधिक कुशल विकल्प हो सकते हैं)।
cnst

@QuintinPar अगर ऐसा कुछ है जो मेरे उत्तर से गायब है, तो मुझे बताएं। BTW, ध्यान दें कि एक बार सीमा समाप्त हो गई है, और आपकी स्क्रिप्ट को कॉल किया जाना है, जब तक कि इस तरह की स्क्रिप्ट को nginx द्वारा ठीक से कैश नहीं किया जाता है, तब तक आपकी सामग्री में देरी हो सकती है; उदाहरण के लिए, आप स्क्रिप्ट को अतुल्यकालिक रूप से कुछ के साथ लागू करना चाहते हैं golang, या अपस्ट्रीम के टाइमआउट विकल्पों में देख सकते हैं; भी, के proxy_cache_lock onरूप में अच्छी तरह से उपयोग करने के लिए चाहते हो सकता है , और यदि स्क्रिप्ट विफल रहता है (उदाहरण के लिए, error_pageसाथ ही proxy_intercept_errorsफिर से उपयोग कर ) क्या करने के लिए संभवतः कुछ त्रुटि हैंडलिंग जोड़ सकते हैं । मुझे भरोसा है कि मेरी POC अच्छी शुरुआत है। :)
cnst

इस प्रयास के लिए धन्यवाद। मेरे लिए एक प्रमुख मुद्दा अभी भी है, मैं पहले से ही http स्तर पर limit_req और limit_conn का उपयोग कर रहा हूं और यह मेरे पास मौजूद सभी वेबसाइटों पर लागू होता है। मैं इसे ओवरराइड नहीं कर सकता। तो यह समाधान कुछ और के लिए एक कार्यक्षमता का उपयोग कर रहा है। इस समाधान के लिए कुछ और दृष्टिकोण?
क्विंटन पर

@QuintinPar नेस्टेड नेक्सक्स उदाहरणों के बारे में क्या है, जहां हर एक limit_req/ के एक सेट का उपयोग करेगा limit_conn? उदाहरण के लिए, बस अपने मौजूदा फ्रंट-एंड सर्वर के सामने उपरोक्त कॉन्‍फ़िगरेशन डालें। आप set_real_ip_fromअपस्ट्रीम nginx में उपयोग कर सकते हैं यह सुनिश्चित करने के लिए कि आईपी को लाइन के नीचे सही तरीके से रखा गया है। इसके अलावा, अगर यह अभी भी फिट नहीं है, तो मुझे लगता है कि आपको अपनी सटीक बाधाओं और कल्पना को और अधिक स्पष्ट रूप से व्यक्त करना होगा - हम किस यातायात स्तर की बात कर रहे हैं? स्टेटम को चलाने के लिए कितनी बार (1min / 5min / 1h) चलाने की आवश्यकता होती है? पुराने logtailसमाधान में क्या गलत है ?
cnst
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.