ProHoster > Օրագիր > Վարչակազմը > Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում
Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում
Տիպիկ պայման Kubernetes-ում CI/CD-ի ներդրման ժամանակ. հավելվածը պետք է կարողանա չընդունել նոր հաճախորդի հարցումները, նախքան ամբողջությամբ դադարեցնելը, և ամենակարևորը, հաջողությամբ լրացնել գոյություն ունեցողները:
Այս պայմանին համապատասխանելը թույլ է տալիս հասնել զրոյական պարապուրդի տեղակայման ընթացքում: Այնուամենայնիվ, նույնիսկ շատ հայտնի փաթեթներ օգտագործելիս (ինչպես NGINX և PHP-FPM), դուք կարող եք հանդիպել դժվարությունների, որոնք կհանգեցնեն սխալների մեծացման յուրաքանչյուր տեղակայման ժամանակ...
Տեսություն. Ինչպես է ապրում պարանոցը
Մենք արդեն մանրամասն հրապարակել ենք պատիճի կյանքի ցիկլի մասին Այս հոդվածը. Քննարկվող թեմայի համատեքստում մեզ հետաքրքրում է հետեւյալը՝ այն պահին, երբ պատիճը մտնում է վիճակ Դադարեցում, նոր հարցումները դադարում են նրան ուղարկել (pod ջնջված է ծառայության վերջնակետերի ցանկից): Այսպիսով, տեղակայման ժամանակ խափանումներից խուսափելու համար բավական է, որ մենք ճիշտ լուծենք հավելվածը դադարեցնելու խնդիրը։
Պետք է նաև հիշել, որ լռելյայն արտոնյալ ժամկետն է 30 վայրկյանՍրանից հետո պատիճը կդադարեցվի, և հայտը պետք է ժամանակ ունենա մշակելու բոլոր հարցումները մինչև այս ժամկետը: ՆշումԹեև ցանկացած խնդրանք, որը տևում է ավելի քան 5-10 վայրկյան, արդեն իսկ խնդրահարույց է, և նրբագեղ անջատումն այլևս չի օգնի դրան…
Ավելի լավ հասկանալու համար, թե ինչ է տեղի ունենում, երբ պատիճն ավարտվում է, պարզապես նայեք հետևյալ գծապատկերին.
A1, B1 - Օջախի վիճակի վերաբերյալ փոփոխությունների ընդունում
A2 - Մեկնում SIGTERM
B2 - վերջնակետերից պատի հեռացում
B3 - Փոփոխությունների ընդունում (վերջնական կետերի ցանկը փոխվել է)
B4 - Թարմացրեք iptables-ի կանոնները
Խնդրում ենք նկատի ունենալ. վերջնակետի պատիջը ջնջելը և SIGTERM ուղարկելը ոչ թե հաջորդաբար, այլ զուգահեռ է կատարվում: Եվ քանի որ Ingress-ը անմիջապես չի ստանում Endpoints-ի թարմացված ցանկը, հաճախորդներից նոր հարցումներ կուղարկվեն pod, ինչը կհանգեցնի 500-ի սխալի առաջացմանը pod դադարեցման ժամանակ: (Այս հարցի վերաբերյալ ավելի մանրամասն նյութերի համար մենք թարգմանված). Այս խնդիրը պետք է լուծվի հետևյալ եղանակներով.
Ուղարկել կապ. փակել պատասխան վերնագրերում (եթե դա վերաբերում է HTTP հավելվածին):
Եթե հնարավոր չէ փոփոխություններ կատարել կոդը, ապա հաջորդ հոդվածը նկարագրում է լուծում, որը թույլ կտա Ձեզ մշակել հարցումները մինչև շնորհալի շրջանի ավարտը:
Տեսություն. Ինչպես են NGINX-ը և PHP-FPM-ն ավարտում իրենց գործընթացները
NGINX- ը
Սկսենք NGINX-ից, քանի որ դրա հետ ամեն ինչ քիչ թե շատ ակնհայտ է։ Սուզվելով տեսության մեջ՝ մենք իմանում ենք, որ NGINX-ն ունի մեկ հիմնական պրոցես և մի քանի «աշխատողներ». դրանք մանկական գործընթացներ են, որոնք մշակում են հաճախորդի հարցումները: Տրվում է հարմար տարբերակ՝ օգտագործելով հրամանը nginx -s <SIGNAL> դադարեցնել գործընթացները կամ արագ անջատման կամ նրբագեղ անջատման ռեժիմում: Ակնհայտ է, որ հենց վերջին տարբերակն է մեզ հետաքրքրում։
Այնուհետև ամեն ինչ պարզ է. պետք է ավելացնել preStop-կեռիկ հրաման, որը կուղարկի նրբագեղ անջատման ազդանշան: Դա կարելի է անել Deployment-ում, կոնտեյների բլոկում.
Այժմ, երբ պատիճն անջատվի, մենք կտեսնենք հետևյալը NGINX կոնտեյների տեղեկամատյաններում.
2018/01/25 13:58:31 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down
2018/01/25 13:58:31 [notice] 11#11: gracefully shutting down
Եվ սա կնշանակի այն, ինչ մեզ անհրաժեշտ է. NGINX-ը սպասում է հարցումների ավարտին, այնուհետև սպանում է գործընթացը: Այնուամենայնիվ, ստորև մենք կքննարկենք նաև ընդհանուր խնդիր, որի պատճառով նույնիսկ հրամանով nginx -s quit գործընթացը սխալ է ավարտվում.
Եվ այս փուլում մենք ավարտեցինք NGINX-ը. գոնե տեղեկամատյաններից կարելի է հասկանալ, որ ամեն ինչ աշխատում է այնպես, ինչպես պետք է:
Ի՞նչ գործ ունի PHP-FPM-ի հետ: Ինչպե՞ս է այն վարվում նրբագեղ անջատման հետ: Եկեք պարզենք այն:
PHP-FPM
PHP-FPM-ի դեպքում մի քիչ քիչ ինֆորմացիա կա։ Եթե կենտրոնանաք պաշտոնական ձեռնարկ ըստ PHP-FPM-ի, այն կասի, որ ընդունված են հետևյալ POSIX ազդանշանները.
SIGINT, SIGTERM - արագ անջատում;
SIGQUIT - նրբագեղ անջատում (այն, ինչ մեզ անհրաժեշտ է):
Մնացած ազդանշանները չեն պահանջվում այս առաջադրանքում, ուստի մենք բաց կթողնենք դրանց վերլուծությունը: Գործընթացը ճիշտ ավարտելու համար ձեզ հարկավոր է գրել հետևյալ preStop կեռը.
Առաջին հայացքից սա այն ամենն է, ինչ պահանջվում է երկու տարաներում էլ նրբագեղ անջատում կատարելու համար: Սակայն խնդիրն ավելի բարդ է, քան թվում է։ Ստորև բերված են երկու դեպքեր, որոնց դեպքում նրբագեղ անջատումը չի աշխատել և առաջացրել է նախագծի կարճաժամկետ անհասանելիություն տեղակայման ընթացքում:
Պրակտիկա. Նրբագեղ անջատման հետ կապված հնարավոր խնդիրներ
NGINX- ը
Նախևառաջ օգտակար է հիշել՝ հրամանը կատարելուց բացի nginx -s quit Կա ևս մեկ փուլ, որին արժե ուշադրություն դարձնել. Մենք հանդիպեցինք խնդրի, երբ NGINX-ը դեռ SIGQUIT ազդանշանի փոխարեն կուղարկեր SIGTERM՝ պատճառ դառնալով, որ հարցումները ճիշտ չլրացվեն: Նմանատիպ դեպքեր կարելի է գտնել, օրինակ. այստեղ. Ցավոք, մենք չկարողացանք պարզել այս պահվածքի կոնկրետ պատճառը. NGINX տարբերակի վերաբերյալ կասկած կար, բայց այն չհաստատվեց: Ախտանիշն այն էր, որ հաղորդագրություններ են նկատվել NGINX կոնտեյների տեղեկամատյաններում. «բաց վարդակ #10 մնացել է միացման 5-ում», որից հետո պատիճը կանգ առավ։
Նման խնդիր մենք կարող ենք դիտարկել, օրինակ, Ingress-ի պատասխաններից, որոնք մեզ անհրաժեշտ են.
Տեղակայման պահին կարգավիճակի կոդերի ցուցիչները
Այս դեպքում մենք ստանում ենք ընդամենը 503 սխալի կոդը հենց Ինգրեսից. այն չի կարող մուտք գործել NGINX կոնտեյներ, քանի որ այն այլևս հասանելի չէ: Եթե նայեք կոնտեյների տեղեկամատյաններին NGINX-ով, ապա դրանք պարունակում են հետևյալը.
[alert] 13939#0: *154 open socket #3 left in connection 16
[alert] 13939#0: *168 open socket #6 left in connection 13
Stop ազդանշանը փոխելուց հետո բեռնարկղը սկսում է ճիշտ կանգ առնել. դա հաստատվում է նրանով, որ 503 սխալն այլևս չի նկատվում:
Եթե դուք բախվում եք նմանատիպ խնդրի, ապա իմաստ ունի պարզել, թե ինչ կանգառի ազդանշան է օգտագործվում կոնտեյների մեջ և կոնկրետ ինչ տեսք ունի preStop կեռիկը: Միանգամայն հնարավոր է, որ պատճառը հենց դրանում է։
PHP-FPM... և ավելին
PHP-FPM-ի հետ կապված խնդիրը նկարագրված է տրիվիալ կերպով. այն չի սպասում երեխայի գործընթացների ավարտին, այն դադարեցնում է դրանք, ինչի պատճառով տեղակայման և այլ գործողությունների ժամանակ տեղի է ունենում 502 սխալ: 2005 թվականից ի վեր bugs.php.net-ում կան մի քանի սխալի մասին հաղորդումներ (օրինակ այստեղ и այստեղ), որը նկարագրում է այս խնդիրը: Բայց դուք, ամենայն հավանականությամբ, ոչինչ չեք տեսնի տեղեկամատյաններում. PHP-FPM-ը կհայտարարի իր գործընթացի ավարտի մասին՝ առանց որևէ սխալի կամ երրորդ կողմի ծանուցումների:
Արժե պարզաբանել, որ խնդիրն ինքնին կարող է փոքր-ինչ կամ մեծ չափով կախված լինել հենց հավելվածից և չի կարող դրսևորվել, օրինակ, մոնիտորինգում: Եթե հանդիպեք դրան, առաջին հերթին ձեր մտքին է գալիս մի պարզ լուծում sleep(30). Այն թույլ կտա լրացնել նախկինում եղած բոլոր հարցումները (և մենք չենք ընդունում նորերը, քանի որ pod արդեն ունակ Դադարեցում), և 30 վայրկյան հետո պատիճն ինքնին կավարտվի ազդանշանով SIGTERM.
Ստացվում է, որ lifecycle քանի որ կոնտեյները կունենա հետևյալ տեսքը.
Սակայն պայմանավորված 30 վրկ sleep մենք ուժեղ մենք կավելացնենք տեղակայման ժամանակը, քանի որ յուրաքանչյուր պատիճ կդադարեցվի նվազագույն 30 վայրկյան, ինչը վատ է: Ի՞նչ կարելի է անել այս մասին:
Դիմենք դիմումի անմիջական կատարման համար պատասխանատու կողմին. Մեր դեպքում դա այդպես է PHP-FPMՈրը լռելյայնորեն չի վերահսկում իր երեխայի գործընթացների կատարումըՀիմնական գործընթացը անմիջապես դադարեցվում է: Դուք կարող եք փոխել այս վարքագիծը՝ օգտագործելով հրահանգը process_control_timeout, որը սահմանում է մանկական պրոցեսների համար վարպետի ազդանշաններին սպասելու ժամկետները: Եթե արժեքը սահմանեք 20 վայրկյան, դա կընդգրկի կոնտեյներով աշխատող հարցումների մեծ մասը և կդադարեցնի հիմնական գործընթացը, երբ դրանք ավարտվեն:
Այս իմացությամբ վերադառնանք մեր վերջին խնդրին։ Ինչպես նշվեց, Kubernetes-ը մոնոլիտ հարթակ չէ. նրա տարբեր բաղադրիչների միջև հաղորդակցությունը որոշակի ժամանակ է պահանջում: Սա հատկապես ճիշտ է, երբ հաշվի ենք առնում Ingresses-ի և հարակից այլ բաղադրիչների աշխատանքը, քանի որ տեղակայման պահին նման ուշացման պատճառով հեշտ է ստանալ 500 սխալի մեծացում: Օրինակ, սխալ կարող է առաջանալ վերին հոսանքին հայտ ուղարկելու փուլում, բայց բաղադրիչների միջև փոխազդեցության «ժամանակային ուշացումը» բավականին կարճ է՝ մեկ վայրկյանից պակաս:
Հետեւաբար, Ընդհանուր առմամբ արդեն նշված հրահանգով process_control_timeout համար կարող եք օգտագործել հետևյալ շինարարությունը lifecycle:
Այս դեպքում ուշացումը կփոխհատուցենք հրամանով sleep և մեծապես մի մեծացրեք տեղակայման ժամանակը. կա՞ նկատելի տարբերություն 30 վայրկյանի և մեկ վայրկյանի միջև: Իրականում դա է process_control_timeoutԻսկ lifecycle օգտագործվում է միայն որպես «անվտանգության ցանց» ուշացման դեպքում:
Ընդհանուր առմամբ նկարագրված վարքագիծը և համապատասխան լուծումը վերաբերում են ոչ միայն PHP-FPM-ին. Նմանատիպ իրավիճակ կարող է այս կամ այն կերպ առաջանալ այլ լեզուների/շրջանակների օգտագործման ժամանակ: Եթե դուք չեք կարող շտկել նրբագեղ անջատումը այլ եղանակներով, օրինակ՝ վերաշարադրելով կոդը, որպեսզի հավելվածը ճիշտ մշակի դադարեցման ազդանշանները, կարող եք օգտագործել նկարագրված մեթոդը: Գուցե այն ամենագեղեցիկը չէ, բայց աշխատում է:
Պրակտիկա. Բեռնման թեստավորում՝ պատիճի աշխատանքը ստուգելու համար
Բեռնվածության փորձարկումը բեռնարկղը ստուգելու եղանակներից մեկն է, քանի որ այս ընթացակարգը այն ավելի է մոտեցնում իրական մարտական պայմաններին, երբ օգտվողները այցելում են կայք: Վերոնշյալ առաջարկությունները ստուգելու համար կարող եք օգտագործել Yandex.Tankom: Այն հիանալի կերպով ծածկում է մեր բոլոր կարիքները: Ստորև բերված են խորհուրդներ և առաջարկություններ թեստավորում անցկացնելու համար մեր փորձից պարզ օրինակով Grafana-ի և Yandex.Tank-ի գծապատկերների շնորհիվ:
Այստեղ ամենակարեւորն այն է քայլ առ քայլ ստուգեք փոփոխությունները. Նոր ուղղում ավելացնելուց հետո կատարեք թեստը և տեսեք, թե արդյոք արդյունքները փոխվել են վերջին փորձարկման համեմատ: Հակառակ դեպքում, դժվար կլինի բացահայտել անարդյունավետ լուծումները, իսկ երկարաժամկետ հեռանկարում դա կարող է միայն վնաս հասցնել (օրինակ՝ մեծացնել տեղակայման ժամանակը):
Մեկ այլ նրբերանգ է դիտել բեռնարկղերի տեղեկամատյանները դրա դադարեցման ժամանակ: Արդյո՞ք այնտեղ արձանագրված է նրբագեղ անջատման մասին տեղեկություն։ Այլ ռեսուրսներ մուտք գործելու ժամանակ (օրինակ, հարևան PHP-FPM կոնտեյներ) գրանցամատյաններում որևէ սխալ կա՞: Սխալներ բուն հավելվածում (ինչպես վերը նկարագրված NGINX-ի դեպքում): Հուսով եմ, որ այս հոդվածի ներածական տեղեկատվությունը կօգնի ձեզ ավելի լավ հասկանալ, թե ինչ է տեղի ունենում կոնտեյների հետ դրա դադարեցման ժամանակ:
Այսպիսով, առաջին փորձնական վազքը տեղի ունեցավ առանց lifecycle և առանց հավելվածի սերվերի համար լրացուցիչ հրահանգների (process_control_timeout PHP-FPM-ում): Այս թեստի նպատակն էր բացահայտել սխալների մոտավոր թիվը (և կան արդյոք այդպիսիք): Բացի այդ, լրացուցիչ տեղեկություններից դուք պետք է իմանաք, որ յուրաքանչյուր պատի տեղակայման միջին ժամանակը մոտ 5-10 վայրկյան էր, մինչև այն լիովին պատրաստ լինի: Արդյունքներն են.
Yandex.Tank տեղեկատվական վահանակը ցույց է տալիս 502 սխալների աճ, որոնք տեղի են ունեցել տեղակայման պահին և տևել են միջինը մինչև 5 վայրկյան: Ենթադրաբար դա պայմանավորված էր նրանով, որ հին պատի վերաբերյալ առկա հարցումները դադարեցվում էին, երբ այն դադարեցվում էր: Սրանից հետո հայտնվեցին 503 սխալներ, ինչը NGINX-ի դադարեցված կոնտեյների արդյունք էր, որը նույնպես անջատեց կապերը հետնամասի պատճառով (ինչը խանգարեց Ingress-ին միանալ դրան):
Տեսնենք, թե ինչպես process_control_timeout PHP-FPM-ում մեզ կօգնի սպասել երեխայի գործընթացների ավարտին, այսինքն. ուղղել նման սխալները. Կրկին տեղակայել՝ օգտագործելով այս հրահանգը.
500-րդ տեղակայման ժամանակ այլևս սխալներ չկան: Տեղակայումը հաջող է, նրբագեղ անջատման աշխատանքներ:
Այնուամենայնիվ, արժե հիշել Ingress բեռնարկղերի հետ կապված խնդիրը, սխալների փոքր տոկոսը, որը մենք կարող ենք ստանալ ժամանակի հետաձգման պատճառով: Նրանցից խուսափելու համար մնում է միայն կառույց ավելացնել sleep և կրկնել տեղակայումը: Սակայն կոնկրետ մեր դեպքում փոփոխություններ չեն նկատվել (կրկին սխալներ):
Ամփոփում
Գործընթացը նրբորեն դադարեցնելու համար մենք դիմումից ակնկալում ենք հետևյալ վարքագիծը.
Սպասեք մի քանի վայրկյան, ապա դադարեցրեք նոր կապեր ընդունելը:
Սպասեք, մինչև բոլոր հարցումները ավարտվեն և փակեք բոլոր պահպանման կապերը, որոնք չեն կատարում հարցումները:
Ավարտեք ձեր գործընթացը:
Այնուամենայնիվ, ոչ բոլոր հավելվածները կարող են աշխատել այս կերպ: Kubernetes-ի իրողություններում խնդրի լուծումներից մեկը հետևյալն է.
նախապես կանգառի ավելացում, որը կսպասի մի քանի վայրկյան;
ուսումնասիրելով մեր backend-ի կազմաձևման ֆայլը համապատասխան պարամետրերի համար:
NGINX-ի օրինակը պարզ է դարձնում, որ նույնիսկ այն հավելվածը, որն ի սկզբանե պետք է ճիշտ մշակի դադարեցման ազդանշանները, կարող է դա չանել, ուստի կարևոր է ստուգել 500 սխալի առկայությունը հավելվածի տեղակայման ժամանակ: Սա նաև թույլ է տալիս խնդրին ավելի լայն նայել և չկենտրոնանալ մեկ պատիճ կամ կոնտեյների վրա, այլ նայել ամբողջ ենթակառուցվածքին որպես ամբողջություն:
Որպես փորձարկման գործիք, դուք կարող եք օգտագործել Yandex.Tank-ը ցանկացած մոնիտորինգի համակարգի հետ համատեղ (մեր դեպքում տվյալները վերցվել են Grafana-ից Prometheus backend-ով թեստի համար): Նրբագեղ անջատման հետ կապված խնդիրները հստակ տեսանելի են ծանր բեռների տակ, որոնք կարող է առաջացնել հենանիշը, և մոնիտորինգն օգնում է ավելի մանրամասն վերլուծել իրավիճակը թեստի ընթացքում կամ դրանից հետո:
Ի պատասխան հոդվածի վերաբերյալ արձագանքների. հարկ է նշել, որ խնդիրները և լուծումները նկարագրված են այստեղ՝ կապված NGINX Ingress-ի հետ: Մյուս դեպքերի համար կան այլ լուծումներ, որոնք կարող ենք դիտարկել շարքի հաջորդ նյութերում։