फिर से नमस्कार!
पिछली बार, हमने एक ही समय पर किसी को भी डाले बिना, बाहरी सेवाओं के लिए बड़ी संख्या में अनुरोधों को हल करने की समस्या को हल करने के लिए
ओस्ट्रोवोक में एक उपकरण चुनने की बात की थी। यह लेख
हाप्रोसी के चयन के साथ समाप्त हुआ। आज मैं इस समाधान का उपयोग करते समय उन बारीकियों को साझा करूंगा जिनका मुझे सामना करना पड़ा था।

Haproxy कॉन्फ़िगरेशन
पहली मुश्किल यह थी कि संदर्भ के आधार पर
maxconn
विकल्प अलग है:
आदत से बाहर, मैंने केवल पहला विकल्प (
performance tuning
) लिया। इस विकल्प के बारे में दस्तावेज़ीकरण क्या कहता है:
समवर्ती कनेक्शन की अधिकतम प्रति-प्रक्रिया संख्या को <संख्या> पर सेट करता है। यह
कमांड-लाइन तर्क "-n" के बराबर है। प्रॉक्सी स्वीकार करना बंद कर देगा
कनेक्शन जब इस सीमा तक पहुँच जाता है।
ऐसा लगता है कि क्या जरूरत है। हालाँकि, जब मुझे इस तथ्य के बारे में पता चला कि प्रॉक्सी के नए कनेक्शन अभी नहीं चले हैं, तो मैंने प्रलेखन को और अधिक ध्यान से पढ़ना शुरू किया, और वहाँ मुझे पहले से ही दूसरा पैरामीटर (
bind options
) मिल गया:
समवर्ती कनेक्शनों की इस संख्या तक सॉकेट्स को सीमित करता है। बाहरी
कनेक्शन सिस्टम के बैकलॉग में रहेगा जब तक कि कनेक्शन नहीं है
का विमोचन किया। यदि अनिर्दिष्ट है, तो सीमा सीमांत की अधिकतम सीमा के समान होगी।
तो,
frontends maxconn
हैं, तो
frontends maxconn
लाभ के लिए
frontends maxconn
:
एक सीमा पर समवर्ती कनेक्शन की अधिकतम संख्या को ठीक करें
...
डिफ़ॉल्ट रूप से, यह मान 2000 पर सेट है।
महान, आपको क्या चाहिए। कॉन्फ़िगरेशन में जोड़ें:
global daemon maxconn 524288 ... defaults mode http maxconn 524288
अगला गग यह था कि हाप्रोसी सिंगल-थ्रेडेड है। मुझे नग्नेक्स में मॉडल की बहुत आदत है, इसलिए इस बारीकियों ने मुझे हमेशा उदास किया है। लेकिन निराशा न करें -
विली तरारेयू (
हैप्रोक्सी डेवलपर ) समझ गया कि वह क्या कर रहा है, इसलिए उसने विकल्प जोड़ा -
nbproc
।
हालाँकि, सीधे दस्तावेज़ में यह कहता है:
विविध प्रक्रियाओं का उपयोग करना
डेबग के लिए हार्डर है और वास्तव में अस्वीकृत है।
यदि आप की जरूरत है तो यह विकल्प वास्तव में उन मामलों में सिरदर्द ला सकता है:
- सर्वरों के लिए अनुरोधों / कनेक्शनों की संख्या को सीमित करें (क्योंकि आपके पास पहले से ही एक काउंटर के साथ एक प्रक्रिया नहीं होगी, लेकिन कई प्रक्रियाएं हैं, और प्रत्येक के पास अपना काउंटर है);
- Haproxy प्रबंधन सॉकेट से आंकड़े ले लीजिए
- नियंत्रण सॉकेट के माध्यम से बैकएंड को सक्षम / अक्षम करना;
- ... शायद कुछ और हो। ¯ \ _ (ツ) _ / ツ
फिर भी, देवताओं ने हमें मल्टी-कोर प्रोसेसर दिए, इसलिए मैं उन्हें अधिकतम उपयोग करना चाहूंगा। मेरे मामले में, दो शारीरिक कोर में चार कोर थे। हाप्रोसी के लिए, मैंने पहला कोर चुना, और यह इस तरह दिखता था:
nbproc 4 cpu-map 1 0 cpu-map 2 1 cpu-map 3 2 cpu-map 4 3
सीपीयू-मैप का उपयोग करते हुए
, हम हाप्रोसी प्रक्रियाओं को एक विशिष्ट कोर से बांधते हैं। ओएस अनुसूचक को अब यह सोचने की ज़रूरत नहीं है कि हाप्रोसी की योजना कहाँ है, जिससे
content switch
शांत हो, और सीपीयू कैश गर्म हो।
कई बफ़र हैं, लेकिन हमारे मामले में नहीं
- tune.bufsize - हमारे मामले में इसे चलाने के लिए आवश्यक नहीं था, लेकिन यदि आपके पास कोड
400 (Bad Request)
साथ त्रुटियां हैं, तो संभवतः यह आपका मामला है। - tune.http.cookielen - यदि आप उपयोगकर्ताओं को बड़ी कुकीज़ वितरित करते हैं, तो, नेटवर्क पर प्रसारण के दौरान नुकसान से बचने के लिए, इस बफर को भी बढ़ाने के लिए समझ में आ सकता है।
- यदि आपके पास बहुत अधिक हेडर हैं, तो ट्यून .http.maxhdr 400 प्रतिक्रिया कोड का एक और संभावित स्रोत है।
अब निचले स्तर के सामान पर विचार करें
tune.rcvbuf.client /
tune.rcvbuf.server ,
tune.sndbuf.client /
tune.sndbuf.server - दस्तावेज़ीकरण निम्नलिखित कहता है:
यह आम तौर पर सेट नहीं होना चाहिए, और डिफ़ॉल्ट आकार (0) कर्नेल ऑटोट्यून को उपलब्ध स्मृति की मात्रा के आधार पर इस मूल्य को देता है।
लेकिन मेरे लिए, स्पष्ट निहितार्थ से बेहतर है, इसलिए मैंने इन विकल्पों के मूल्यों को कल सुनिश्चित करने के लिए मजबूर किया।
और एक अन्य पैरामीटर जो बफ़र्स से संबंधित नहीं है, लेकिन काफी महत्वपूर्ण है।
निरंतर कनेक्शन की अधिकतम संख्या को सेट करता है जिसे एक प्रक्रिया स्वीकार कर सकती है
अन्य काम पर जाने से पहले पंक्ति। एकल प्रक्रिया मोड में, उच्च संख्या
उच्च कनेक्शन दरों पर बेहतर प्रदर्शन दें। हालाँकि बहु-प्रक्रिया में
मोड, आमतौर पर प्रक्रियाओं के बीच थोड़ी सी निष्पक्षता रखना बेहतर होता है
प्रदर्शन बढ़ाएँ।
हमारे मामले में, बहुत सारे प्रॉक्सी अनुरोध उत्पन्न होते हैं, इसलिए मैंने एक बार में अधिक अनुरोध स्वीकार करने के लिए यह मान बढ़ाया। फिर भी, जैसा कि प्रलेखन कहता है, यह परीक्षण के लायक है कि बहु-थ्रेडेड मोड में लोड को प्रक्रियाओं के बीच समान रूप से वितरित किया जाता है।
सभी पैरामीटर एक साथ:
tune.bufsize 16384 tune.http.cookielen 63 tune.http.maxhdr 101 tune.maxaccept 256 tune.rcvbuf.client 33554432 tune.rcvbuf.server 33554432 tune.sndbuf.client 33554432 tune.sndbuf.server 33554432
क्या कभी नहीं होता है टाइमआउट। हम उनके बिना क्या करेंगे?
- टाइमआउट कनेक्ट - बैकएंड के साथ कनेक्शन स्थापित करने का समय। यदि बैकएंड के साथ कनेक्शन बहुत अच्छा नहीं है, तो नेटवर्क को सामान्य होने तक इस टाइमआउट द्वारा इसे अक्षम करना बेहतर है।
- टाइमआउट क्लाइंट - डेटा के पहले बाइट्स के प्रसारण के लिए टाइमआउट। यह "रिजर्व में" अनुरोध करने वालों को डिस्कनेक्ट करने में मदद करता है।
गो में HTTP क्लाइंट के बारे में कुलस्टोरीगो में एक नियमित एचटीटीपी क्लाइंट है जो सर्वरों से कनेक्शन का पूल रखने की क्षमता रखता है। तो एक दिलचस्प कहानी हुई, जिसमें HTTP क्लाइंट में ऊपर वर्णित टाइमआउट और कनेक्शन पूल ने भाग लिया। एक बार एक डेवलपर ने शिकायत की कि वह समय-समय पर एक प्रॉक्सी से 408 त्रुटियां करता है। हमने ग्राहक कोड में देखा और निम्नलिखित तर्क देखे:
- हम पूल से एक मुफ्त स्थापित कनेक्शन लेने की कोशिश कर रहे हैं;
- यदि यह काम नहीं करता है, तो गोरोइन में एक नए कनेक्शन की स्थापना शुरू करें;
- पूल को फिर से जांचें;
- अगर पूल में मुफ्त है - हम इसे लेते हैं, और नए को पूल में डालते हैं, यदि नहीं - नए का उपयोग करें।
पहले से ही समझ में आ गया कि नमक क्या है?
यदि क्लाइंट ने एक नया कनेक्शन स्थापित किया है, लेकिन इसका उपयोग नहीं किया है, तो पांच सेकंड के बाद सर्वर इसे बंद कर देता है, और मामला खत्म हो गया है। क्लाइंट इसे तभी पकड़ता है जब उसे पहले से ही पूल से कनेक्शन मिल जाता है और वह इसका इस्तेमाल करने की कोशिश करता है। यह ध्यान में रखने योग्य है।
- टाइमआउट सर्वर - सर्वर से प्रतिक्रिया के लिए प्रतीक्षा करने का अधिकतम समय।
- टाइमआउट क्लाइंट-फिन / टाइमआउट सर्वर-फिन - यहां हम खुद को आधे-बंद कनेक्शनों से बचाते हैं ताकि ऑपरेटिंग सिस्टम टेबल में उन्हें जमा न करें।
- टाइमआउट http-request सबसे उपयुक्त टाइमआउट में से एक है। आपको धीमे ग्राहकों को काटने की अनुमति देता है जो उनके लिए आवंटित समय में HTTP अनुरोध नहीं कर सकते हैं।
- समयबाह्य http-Keep-ज़िंदा - विशेष रूप से हमारे मामले में, यदि 50-सेकंड से अधिक समय तक अनुरोध के बिना एक
keep-alive
कनेक्शन लटका रहता है, तो सबसे अधिक संभावना है कि कुछ गलत हो गया है और कनेक्शन बंद हो सकता है, जिससे कुछ नया करने के लिए मेमोरी खाली हो जाएगी प्रकाश।
सभी टाइमआउट एक साथ:
defaults mode http maxconn 524288 timeout connect 5s timeout client 10s timeout server 120s timeout client-fin 1s timeout server-fin 1s timeout http-request 10s timeout http-keep-alive 50s
लॉगिंग। यह इतना कठिन क्यों है?
जैसा कि मैंने पहले लिखा था, मेरे निर्णयों में सबसे अधिक बार मैं Nginx का उपयोग करता हूं, इसलिए मैं इसके सिंटैक्स और लॉग प्रारूपों को संशोधित करने की सादगी से खराब हो गया हूं। मुझे विशेष रूप से हत्यारे की सुविधा पसंद आई - प्रारूप लॉग ऑन जसन के रूप में, फिर उन्हें किसी भी मानक पुस्तकालय के साथ पार्स करने के लिए।
हाप्रोक्सी में हमारे पास क्या है? ऐसा एक अवसर है, केवल आप विशेष रूप से syslog में लिख सकते हैं, और कॉन्फ़िगरेशन सिंटैक्स थोड़ा अधिक लपेटा जाता है।
मैं आपको टिप्पणियों के साथ एक उदाहरण विन्यास दूंगा:
विशेष रूप से दर्द ऐसे क्षणों के कारण होता है:
- छोटे चर नाम, और विशेष रूप से उनके संयोजन जैसे एचएयू या% एफपी
- प्रारूप को कई लाइनों में विभाजित नहीं किया जा सकता है, इसलिए आपको एक पंक्ति में फुटक्लॉथ लिखना होगा। नई / अनावश्यक वस्तुओं को जोड़ना / हटाना मुश्किल है
- काम करने के लिए कुछ चर के लिए, उन्हें स्पष्ट रूप से कैप्चर अनुरोध हेडर के माध्यम से घोषित किया जाना चाहिए
नतीजतन, कुछ दिलचस्प पाने के लिए, आपके पास बस इस तरह का पदचिह्न होना चाहिए:
log-format '{"status":"%ST","bytes_read":"%B","bytes_uploaded":"%U","hostname":"%H","method":"%HM","request_uri":"%HU","handshake_time":"%Th","request_idle_time":"%Ti","request_time":"%TR","response_time":"%Tr","timestamp":"%Ts","client_ip":"%ci","client_port":"%cp","frontend_port":"%fp","http_request":"%r","ssl_ciphers":"%sslc","ssl_version":"%sslv","date_time":"%t","http_host":"%[capture.req.hdr(0)]","http_referer":"%[capture.req.hdr(1)]","http_user_agent":"%[capture.req.hdr(2)]"}'
खैर, यह प्रतीत होता है, छोटी चीजें, लेकिन अच्छा है
मैंने ऊपर दिए गए लॉग के प्रारूप का वर्णन किया है, लेकिन इतना सरल नहीं है। इसमें कुछ तत्व जमा करने के लिए, जैसे:
- HTTP_HOST,
- http_referer,
- http_user_agent,
पहले आपको अनुरोध (
कैप्चर ) से इस डेटा को कैप्चर करने और कैप्चर किए गए मानों की एक सरणी में रखने की आवश्यकता है।
यहाँ एक उदाहरण है:
capture request header Host len 32 capture request header Referer len 128 capture request header User-Agent len 128
परिणामस्वरूप, अब हम उन तत्वों तक पहुँच सकते हैं जिनकी हमें इस प्रकार आवश्यकता है:
%[capture.req.hdr(N)]
, जहां एन कैप्चर ग्रुप डेफिनेशन की अनुक्रम संख्या है।
उपरोक्त उदाहरण में, होस्ट हेडर 0 नंबर पर होगा, और यूजर-एजेंट नंबर 2 पर होगा।
हाप्रोसी की एक ख़ासियत है: यह स्टार्टअप पर बैकएंड के DNS पते को हल करता है और, यदि यह किसी भी पते को हल नहीं कर सकता है, तो बहादुर की मृत्यु हो जाती है।
हमारे मामले में, यह बहुत सुविधाजनक नहीं है, क्योंकि बहुत सारे बैकएंड हैं, हम उन्हें प्रबंधित नहीं करते हैं, और हाप्रोक्सी से 503 प्राप्त करना बेहतर है क्योंकि पूरे प्रॉक्सी सर्वर एक प्रदाता के कारण शुरू करने से इनकार कर देंगे। निम्नलिखित विकल्प हमें इसमें मदद करता है:
init-addr ।
दस्तावेज़ीकरण से सीधे ली गई एक पंक्ति हमें एक पते को हल करने के लिए सभी उपलब्ध तरीकों से गुजरने की अनुमति देती है, और एक फ़ाइल के मामले में, बस इस मामले को बाद तक स्थगित करें और आगे बढ़ें:
default-server init-addr last,libc,none
और अंत में, मेरा पसंदीदा: बैकएंड चयन।
Haproxy बैकेंड चयन विन्यास के लिए वाक्यविन्यास सभी के लिए परिचित है:
use_backend <backend1_name> if <condition1> use_backend <backend2_name> if <condition2> default-backend <backend3>
लेकिन, सही शब्द है, यह किसी भी तरह बहुत नहीं है। मैंने पहले से ही सभी बैकेंड को एक स्वचालित तरीके से वर्णित किया है (
पिछले लेख देखें ), यहां
use_backend
उत्पन्न करना संभव होगा, बुरा व्यवसाय मुश्किल नहीं है, लेकिन मैं नहीं करना चाहता था। नतीजतन, एक और रास्ता मिल गया था:
capture request header Host len 32 capture request header Referer len 128 capture request header User-Agent len 128 # host_present Host acl host_present hdr(host) -m len gt 0 # , use_backend %[req.hdr(host),lower,field(1,'.')] if host_present # , default_backend default backend default mode http server no_server 127.0.0.1:65535
इस प्रकार, हमने बैकएंड और यूआरएल के नामों को मानकीकृत किया है जिसके द्वारा आप उनके पास जा सकते हैं।
खैर, अब उपरोक्त उदाहरणों को एक फ़ाइल में संकलित करना:
कॉन्फ़िगरेशन का पूर्ण संस्करण global daemon maxconn 524288 nbproc 4 cpu-map 1 0 cpu-map 2 1 cpu-map 3 2 cpu-map 4 3 tune.bufsize 16384 tune.comp.maxlevel 1 tune.http.cookielen 63 tune.http.maxhdr 101 tune.maxaccept 256 tune.rcvbuf.client 33554432 tune.rcvbuf.server 33554432 tune.sndbuf.client 33554432 tune.sndbuf.server 33554432 stats socket /run/haproxy.sock mode 600 level admin log /dev/stdout local0 debug defaults mode http maxconn 524288 timeout connect 5s timeout client 10s timeout server 120s timeout client-fin 1s timeout server-fin 1s timeout http-request 10s timeout http-keep-alive 50s default-server init-addr last,libc,none log 127.0.0.1:2514 len 8192 local1 notice emerg log 127.0.0.1:2514 len 8192 local7 info log-format '{"status":"%ST","bytes_read":"%B","bytes_uploaded":"%U","hostname":"%H","method":"%HM","request_uri":"%HU","handshake_time":"%Th","request_idle_time":"%Ti","request_time":"%TR","response_time":"%Tr","timestamp":"%Ts","client_ip":"%ci","client_port":"%cp","frontend_port":"%fp","http_request":"%r","ssl_ciphers":"%sslc","ssl_version":"%sslv","date_time":"%t","http_host":"%[capture.req.hdr(0)]","http_referer":"%[capture.req.hdr(1)]","http_user_agent":"%[capture.req.hdr(2)]"}' frontend http bind *:80 http-request del-header X-Forwarded-For http-request del-header X-Forwarded-Port http-request del-header X-Forwarded-Proto capture request header Host len 32 capture request header Referer len 128 capture request header User-Agent len 128 acl host_present hdr(host) -m len gt 0 use_backend %[req.hdr(host),lower,field(1,'.')] if host_present default_backend default backend default mode http server no_server 127.0.0.1:65535 resolvers dns hold valid 1s timeout retry 100ms nameserver dns1 127.0.0.1:53
अंत तक पढ़ने वालों को धन्यवाद। हालाँकि, यह सब नहीं है।
अगली बार, हम सिस्टम को अनुकूलित करने से संबंधित निम्न-स्तरीय चीज़ों को देखेंगे, जिसमें Haproxy काम करता है, ताकि वह और हमारा ऑपरेटिंग सिस्टम एक साथ सहज हों, और सभी के लिए पर्याप्त लोहा हो।
जल्द मिलते हैं!