Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Ի՞նչը կարող է ստիպել այնպիսի խոշոր ընկերությանը, ինչպիսին Lamoda-ն է, պարզեցված գործընթացով և տասնյակ փոխկապակցված ծառայություններով, էապես փոխել իր մոտեցումը: Մոտիվացիան կարող է բոլորովին տարբեր լինել՝ օրենսդրականից մինչև փորձեր անելու ցանկություն, որը բնորոշ է բոլոր ծրագրավորողներին:

Բայց դա չի նշանակում, որ դուք չեք կարող հույս դնել լրացուցիչ առավելությունների վրա: Սերգեյ Զաիկան ձեզ կասի, թե կոնկրետ ինչ կարող եք հաղթել, եթե կիրառեք իրադարձությունների վրա հիմնված API-ն Kafka-ում (մի քանիսը) Անպայման կխոսվի նաև մեծ կադրերի և հետաքրքիր բացահայտումների մասին՝ առանց դրանց փորձը չի կարող։

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Հրաժարում պատասխանատվությունից. Այս հոդվածը հիմնված է հանդիպման նյութերի վրա, որը Սերգեյը անցկացրել է 2018 թվականի նոյեմբերին HighLoad++-ում: Կաֆկայի հետ աշխատելու Լամոդայի կենդանի փորձը գրավեց ունկնդիրներին ոչ պակաս, քան ժամանակացույցի մյուս զեկույցները: Կարծում ենք՝ սա հիանալի օրինակ է այն բանի, որ դուք միշտ կարող եք և պետք է համախոհներ գտնեք, և HighLoad++-ի կազմակերպիչները կշարունակեն փորձել ստեղծել դրան նպաստող մթնոլորտ։

Գործընթացի մասին

Lamoda-ն էլեկտրոնային առևտրի մեծ հարթակ է, որն ունի իր կոնտակտային կենտրոնը, առաքման ծառայությունը (և բազմաթիվ մասնաճյուղեր), լուսանկարչական ստուդիա, հսկայական պահեստ, և այս ամենն աշխատում է իր սեփական ծրագրաշարով: Կան վճարման տասնյակ եղանակներ, b2b գործընկերներ, որոնք կարող են օգտվել այս ծառայություններից մի քանիսը կամ բոլորը և ցանկանում են իմանալ իրենց արտադրանքի վերաբերյալ արդի տեղեկատվություն: Բացի այդ, Lamoda-ն Ռուսաստանի Դաշնությունից բացի գործում է երեք երկրներում և այնտեղ ամեն ինչ մի փոքր այլ է։ Ընդհանուր առմամբ, հավանաբար, կան ավելի քան հարյուր եղանակներ նոր պատվերի կազմաձևման համար, որոնք պետք է մշակվեն յուրովի: Այս ամենը գործում է տասնյակ ծառայությունների օգնությամբ, որոնք երբեմն հաղորդակցվում են ոչ ակնհայտ ձևերով։ Գոյություն ունի նաև կենտրոնական համակարգ, որի հիմնական պատասխանատվությունը պատվերի կարգավիճակներն են։ Մենք նրան անվանում ենք ԲՈԲ, ես աշխատում եմ նրա հետ:

Փոխհատուցման գործիք՝ իրադարձությունների վրա հիմնված API-ով

Իրադարձությունների վրա հիմնված բառը միանգամայն շեղված է, մի փոքր ավելի մանրամասն կպարզենք, թե ինչ է դա նշանակում: Ես կսկսեմ այն ​​համատեքստից, որում մենք որոշեցինք փորձել Կաֆկայում իրադարձությունների վրա հիմնված API մոտեցումը:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Ցանկացած խանութում, բացի պատվերներից, որոնց դիմաց հաճախորդները վճարում են, լինում են դեպքեր, երբ խանութից պահանջվում է գումար վերադարձնել, քանի որ ապրանքը չի համապատասխանում հաճախորդին: Սա համեմատաբար կարճ գործընթաց է՝ անհրաժեշտության դեպքում մենք ճշտում ենք տեղեկատվությունը և փոխանցում գումարը։

Բայց օրենսդրության փոփոխությունների պատճառով վերադարձն ավելի բարդացավ, և մենք ստիպված եղանք դրա համար առանձին միկրոծառայություն իրականացնել։

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Մեր մոտիվացիան.

  1. Օրենք FZ-54 - մի խոսքով, օրենքը պահանջում է հարկայինին հաշվետվություն ներկայացնել յուրաքանչյուր դրամական գործարքի մասին, լինի դա վերադարձ, թե անդորրագիր, մի քանի րոպեի բավականին կարճ SLA-ի ընթացքում: Մենք՝ որպես էլեկտրոնային առևտրի ընկերություն, բավականին շատ գործողություններ ենք իրականացնում։ Տեխնիկապես սա նշանակում է նոր պատասխանատվություն (և հետևաբար՝ նոր ծառայություն) և բոլոր ներգրավված համակարգերի բարելավումներ:
  2. BOB պառակտում Ընկերության ներքին նախագիծն է՝ BOB-ին ազատելու մեծ թվով ոչ հիմնական պարտականություններից և նվազեցնելու դրա ընդհանուր բարդությունը:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Այս դիագրամը ցույց է տալիս հիմնական Lamoda համակարգերը: Հիմա դրանց մեծ մասն ավելի շատ է փոքրացող մոնոլիտի շուրջ 5-10 միկրոծառայությունների համաստեղություն. Նրանք կամաց-կամաց աճում են, բայց մենք փորձում ենք դրանք փոքրացնել, քանի որ մեջտեղում ընտրված բեկորը տեղակայելը սարսափելի է. մենք չենք կարող թույլ տալ, որ այն ընկնի: Մենք ստիպված ենք վերապահել բոլոր փոխանակումները (սլաքները) և հաշվի առնել այն փաստը, որ դրանցից որևէ մեկը կարող է անհասանելի դառնալ:

BOB-ն ունի նաև բավականին շատ փոխանակումներ՝ վճարային համակարգեր, առաքման համակարգեր, ծանուցման համակարգեր և այլն։

Տեխնիկապես BOB-ը հետևյալն է.

  • ~150k կոդ + ~100k տող թեստեր;
  • php7.2 + Zend 1 & Symfony Components 3;
  • >100 API և ~50 ելքային ինտեգրում;
  • 4 երկիր՝ սեփական բիզնես տրամաբանությամբ.

BOB-ի տեղակայումը թանկ և ցավոտ է, կոդերի և խնդիրների քանակն այն է, որ ոչ ոք չի կարող այդ ամենը դնել իր գլխում: Ընդհանրապես, այն պարզեցնելու շատ պատճառներ կան։

Վերադարձի գործընթաց

Սկզբում գործընթացում ներգրավված են երկու համակարգեր՝ BOB և Payment: Այժմ հայտնվում են ևս երկուսը.

  • Ֆիսկալիզացիայի ծառայություն, որը հոգ կտանի ֆիսկալիզացիայի և արտաքին ծառայությունների հետ կապի հետ կապված խնդիրների մասին։
  • Փոխհատուցման գործիք, որը պարզապես պարունակում է նոր փոխանակումներ՝ BOB-ը չուռացնելու համար:

Այժմ գործընթացը այսպիսի տեսք ունի.

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

  1. BOB-ը ստանում է գումարի վերադարձի հարցում:
  2. BOB-ը խոսում է այս փոխհատուցման գործիքի մասին:
  3. Փոխհատուցման գործիքը վճարում է ասում. «Վերադարձրեք գումարը»:
  4. Վճարումը վերադարձնում է գումարը:
  5. Refund Tool-ը և BOB-ը համաժամացնում են կարգավիճակները միմյանց հետ, քանի որ առայժմ երկուսն էլ դրա կարիքն ունեն: Մենք դեռ պատրաստ չենք ամբողջությամբ անցնել Փոխհատուցման գործիքին, քանի որ BOB-ն ունի UI, հաշվետվություններ հաշվապահական հաշվառման համար և ընդհանրապես շատ տվյալներ, որոնք այդքան հեշտությամբ չեն կարող փոխանցվել: Դուք պետք է նստեք երկու աթոռների վրա:
  6. Ֆիսկալիզացիայի խնդրանքը հեռանում է:

Արդյունքում Կաֆկայի վրա մի տեսակ միջոցառումների ավտոբուս պատրաստեցինք՝ միջոցառում-ավտոբուս, որով ամեն ինչ սկսվեց։ Ուռեյ, հիմա մենք ունենք ձախողման մեկ կետ (սարկազմ):

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Դրական և բացասական կողմերը բավականին ակնհայտ են: Մենք ավտոբուս ենք սարքել, ինչը նշանակում է, որ հիմա բոլոր ծառայությունները կախված են դրանից։ Սա հեշտացնում է դիզայնը, բայց համակարգում ներդնում է ձախողման մեկ կետ: Կաֆկան կկործանվի, գործընթացը կդադարի.

Ինչ է իրադարձությունների վրա հիմնված API-ն

Այս հարցի լավ պատասխանը Մարտին Ֆաուլերի զեկույցում է (GOTO 2017) «Իրադարձությունների վրա հիմնված ճարտարապետության բազմաթիվ իմաստներ».

Հակիրճ ինչ արեցինք.

  1. Փաթեթավորեք բոլոր ասինխրոն փոխանակումները միջոցով իրադարձությունների պահեստավորում. Ցանցում կարգավիճակի փոփոխության մասին յուրաքանչյուր շահագրգիռ սպառողին տեղեկացնելու փոխարեն՝ մենք իրադարձություն ենք գրում կարգավիճակի փոփոխության մասին կենտրոնացված պահեստի, և թեմայով հետաքրքրված սպառողները կարդում են այն ամենը, ինչ հայտնվում է այնտեղից:
  2. Իրադարձությունն այս դեպքում ծանուցում է (տեղեկացումներ) որ ինչ-որ բան փոխվել է։ Օրինակ՝ պատվերի կարգավիճակը փոխվել է։ Սպառողը, ով հետաքրքրված է կարգավիճակի փոփոխությանը ուղեկցող որոշ տվյալներով, որոնք ներառված չեն ծանուցման մեջ, կարող է անձամբ իմանալ դրա կարգավիճակը:
  3. Առավելագույն տարբերակը իրադարձությունների ամբողջական աղբյուրն է, պետական ​​փոխանցում, որի իրադարձությունը պարունակում է մշակման համար անհրաժեշտ ողջ տեղեկատվությունը. որտեղից է այն եկել և ինչ կարգավիճակի է հասել, կոնկրետ ինչպես են փոխվել տվյալները և այլն: Հարցը միայն իրագործելիությունն է և տեղեկատվության քանակությունը, որը դուք կարող եք թույլ տալ պահել:

Որպես Refund Tool-ի գործարկման մաս, մենք օգտագործեցինք երրորդ տարբերակը: Իրադարձությունների այս պարզեցված մշակումը, քանի որ կարիք չկար հանել մանրամասն տեղեկատվություն, գումարած այն վերացրել է այն սցենարը, երբ յուրաքանչյուր նոր իրադարձություն առաջացնում է սպառողների կողմից ստացվող հարցումների պարզաբանման պոռթկում:

Փոխհատուցման գործիքի ծառայություն բեռնված չէ, ուրեմն Կաֆկան ավելի շատ գրչի համն է, քան անհրաժեշտությունը։ Չեմ կարծում, որ եթե փոխհատուցման ծառայությունը դառնա բարձր բեռնված նախագիծ, բիզնեսը երջանիկ կլիներ:

Async փոխանակում ԻՆՉՊԵՍ ԿԱ

Ասինխրոն փոխանակումների համար PHP բաժինը սովորաբար օգտագործում է RabbitMQ: Հարցման տվյալները հավաքել ենք, հերթագրել, նույն ծառայության սպառողը կարդացել ու ուղարկել է (կամ չի ուղարկել)։ Ինքն API-ի համար Lamoda-ն ակտիվորեն օգտագործում է Swagger-ը: Մենք նախագծում ենք API, նկարագրում ենք այն Swagger-ում և ստեղծում հաճախորդի և սերվերի կոդ: Մենք նաև օգտագործում ենք մի փոքր ուժեղացված JSON RPC 2.0:

Որոշ տեղերում օգտագործվում են ESB ավտոբուսներ, որոշներն ապրում են activeMQ-ով, բայց, ընդհանուր առմամբ, RabbitMQ - ստանդարտ.

Async փոխանակում TO BE

Իրադարձություններ-ավտոբուսի միջոցով փոխանակում նախագծելիս կարելի է անալոգիա գտնել: Մենք նմանապես նկարագրում ենք ապագա տվյալների փոխանակումը իրադարձությունների կառուցվածքի նկարագրությունների միջոցով: Յամլ ձևաչափը, մենք պետք է ինքներս անեինք կոդերի գեներացումը, գեներատորը ստեղծում է DTO-ներ ըստ սպեցիֆիկացիայի և սովորեցնում է հաճախորդներին և սերվերներին աշխատել նրանց հետ: Սերունդը գնում է երկու լեզուների. golang և php. Սա օգնում է պահպանել գրադարանները հետևողական: Գեներատորը գրված է գոլանգով, ինչի պատճառով էլ ստացել է gogi անվանումը։

Կաֆկայում իրադարձությունների աղբյուրը բնորոշ բան է: Կա լուծում Kafka Confluent-ի հիմնական ձեռնարկատիրական տարբերակից, կա նակադի, լուծում մեր տիրույթի եղբայր Զալանդոյից։ Մեր վանիլային Կաֆկայով սկսելու մոտիվացիա - Սա նշանակում է լուծումը թողնել ազատ, մինչև մենք վերջնականապես որոշենք, թե արդյոք այն կօգտագործենք ամենուր, ինչպես նաև մեզ մանևրելու և կատարելագործվելու տեղ թողնել. մենք աջակցություն ենք ուզում մեր համար: JSON RPC 2.0, գեներատորներ երկու լեզվի համար և տեսնենք էլ ինչ։

Զավեշտալի է, որ նույնիսկ նման ուրախալի դեպքում, երբ կա մոտավորապես նմանատիպ բիզնես՝ Զալանդոն, որը մոտավորապես նմանատիպ լուծում է արել, մենք չենք կարող արդյունավետ օգտագործել այն։

Գործարկման ժամանակ ճարտարապետական ​​օրինաչափությունը հետևյալն է. մենք կարդում ենք անմիջապես Կաֆկայից, բայց գրում ենք միայն միջոցառումներ-ավտոբուսի միջոցով: Կաֆկայում կարդալու համար շատ բան կա՝ բրոքերներ, հավասարակշռողներ, և այն քիչ թե շատ պատրաստ է հորիզոնական մասշտաբի, ես ուզում էի պահպանել սա։ Մենք ուզում էինք ձայնագրությունն ավարտել մեկ Gateway aka Events- ավտոբուսի միջոցով, և ահա թե ինչու:

Միջոցառումներ-ավտոբուս

Կամ միջոցառման ավտոբուս: Սա պարզապես քաղաքացիություն չունեցող http դարպաս է, որը ստանձնում է մի քանի կարևոր դեր.

  • Արտադրող վավերացում — մենք ստուգում ենք, որ միջոցառումները համապատասխանում են մեր պահանջներին:
  • Իրադարձությունների վարպետ համակարգ, այսինքն՝ սա ընկերությունում հիմնական ու միակ համակարգն է, որը պատասխանում է այն հարցին, թե որ կառույցների հետ կապված իրադարձություններն են համարվում վավեր։ Վավերացումը պարզապես ներառում է տվյալների տեսակներ և թվեր՝ բովանդակությունը խստորեն նշելու համար:
  • Հեշ ֆունկցիա Sharding-ի համար - Կաֆկայի հաղորդագրության կառուցվածքը բանալի-արժեք է և օգտագործելով բանալու հեշը հաշվարկվում է, թե որտեղ այն տեղադրվի:

Ինչու

Մենք աշխատում ենք խոշոր ընկերությունում՝ պարզեցված գործընթացով: Ինչու՞ ինչ-որ բան փոխել: Սա փորձ է, և մենք ակնկալում ենք մի քանի օգուտներ քաղել:

1:n+1 փոխանակումներ (մեկից շատ)

Kafka-ն շատ հեշտ է դարձնում նոր սպառողներին միացնել API-ին:

Ենթադրենք, դուք ունեք գրացուցակ, որը դուք պետք է թարմացնեք միանգամից մի քանի համակարգերում (և որոշ նորերում): Նախկինում մենք հայտնագործեցինք մի փաթեթ, որն իրականացնում էր set-API, և վարպետ համակարգը տեղեկացվում էր սպառողների հասցեների մասին: Այժմ վարպետ համակարգը թարմացումներ է ուղարկում թեմային, և բոլոր հետաքրքրվողները կարդում են այն։ Հայտնվել է նոր համակարգ՝ մենք ստորագրել ենք այն թեմայի համար։ Այո, նաև փաթեթ, բայց ավելի պարզ:

Refund-tool-ի դեպքում, որը BOB-ի մի կտոր է, մեզ համար հարմար է դրանք համաժամանակացնել Կաֆկայի միջոցով։ Վճարում ասվում է, որ գումարը վերադարձվել է. BOB-ը, RT-ն իմացել են այս մասին, փոխել են իրենց կարգավիճակները, Ֆիսկալիզացիայի ծառայությունն իմացել է և չեկ տվել։

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Մենք պլաններ ունենք ստեղծել ծանուցումների միասնական ծառայություն, որը հաճախորդին կտեղեկացնի իր պատվերի/վերադարձի մասին նորությունների մասին: Այժմ այդ պատասխանատվությունը բաշխված է համակարգերի միջև։ Բավական կլինի, որ մենք Ծանուցումների ծառայությանը սովորեցնենք Կաֆկայից համապատասխան տեղեկատվություն որսալ և արձագանքել դրան (և անջատել այդ ծանուցումները այլ համակարգերում): Նոր ուղղակի փոխանակումներ չեն պահանջվի:

Տվյալների վրա հիմնված

Համակարգերի միջև տեղեկատվությունը դառնում է թափանցիկ՝ անկախ նրանից, թե ինչ «արյունոտ ձեռնարկություն» ունես և որքան էլ որ լինես քո կուտակումները: Lamoda-ն ունի Տվյալների վերլուծության բաժին, որը հավաքում է տվյալները համակարգերից և դրանք դնում է բազմակի օգտագործման ձևի, ինչպես բիզնեսի, այնպես էլ խելացի համակարգերի համար: Կաֆկան թույլ է տալիս արագ տալ նրանց շատ տվյալներ և թարմացնել այդ տեղեկատվության հոսքը:

Կրկնօրինակման մատյան

Հաղորդագրությունները կարդալուց հետո չեն անհետանում, ինչպես RabbitMQ-ում: Երբ իրադարձությունը պարունակում է բավարար տեղեկատվություն մշակման համար, մենք ունենք օբյեկտի վերջին փոփոխությունների պատմություն և, ցանկության դեպքում, այդ փոփոխությունները կիրառելու հնարավորություն:

Կրկնօրինակման մատյանի պահպանման ժամկետը կախված է այս թեմային գրելու ինտենսիվությունից: Կաֆկան թույլ է տալիս ճկուն կերպով սահմանել պահպանման ժամանակի և տվյալների ծավալի սահմանափակումներ: Ինտենսիվ թեմաների համար կարևոր է, որ բոլոր սպառողները ժամանակ ունենան կարդալու տեղեկատվությունը մինչև այն անհետանալը, նույնիսկ կարճաժամկետ անգործունակության դեպքում: Սովորաբար հնարավոր է տվյալներ պահել օրերի միավոր, ինչը միանգամայն բավարար է աջակցության համար։

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Հաջորդը, մի փոքր վերապատմություն փաստաթղթի, նրանց համար, ովքեր ծանոթ չեն Կաֆկային (նկարը նույնպես փաստաթղթերից է)

AMQP-ն ունի հերթեր. մենք հաղորդագրություններ ենք գրում սպառողի համար հերթում: Որպես կանոն, մեկ հերթ մշակվում է մեկ համակարգի կողմից՝ նույն բիզնես տրամաբանությամբ: Եթե ​​Ձեզ անհրաժեշտ է տեղեկացնել մի քանի համակարգերի, կարող եք սովորեցնել հավելվածին գրել մի քանի հերթերի կամ կարգավորել փոխանակումը fanout մեխանիզմով, որն ինքնին կլոնավորում է դրանք:

Կաֆկան նման աբստրակցիա ունի թեմա, որոնցում գրում եք հաղորդագրություններ, բայց դրանք չեն անհետանում կարդալուց հետո։ Լռելյայնորեն, երբ միանում եք Kafka-ին, դուք ստանում եք բոլոր հաղորդագրությունները և հնարավորություն ունեք պահպանել այնտեղ, որտեղ դադարեցրել եք: Այսինքն, դուք հաջորդաբար կարդում եք, կարող եք չնշել հաղորդագրությունը որպես կարդացված, բայց պահպանել ID-ն, որից հետո կարող եք շարունակել կարդալ: Id-ը, որի վրա հաստատվել եք, կոչվում է օֆսեթ, իսկ մեխանիզմը՝ commit offset:

Ըստ այդմ, տարբեր տրամաբանություն կարող է իրականացվել։ Օրինակ, մենք ունենք BOB 4 օրինակով տարբեր երկրների համար. Lamoda-ն գտնվում է Ռուսաստանում, Ղազախստանում, Ուկրաինայում, Բելառուսում: Քանի որ դրանք տեղակայված են առանձին, նրանք ունեն մի փոքր տարբեր կազմաձևեր և իրենց սեփական բիզնես տրամաբանությունը: Հաղորդագրության մեջ նշում ենք, թե որ երկրին է խոսքը։ Յուրաքանչյուր BOB սպառող յուրաքանչյուր երկրում կարդում է տարբեր groupId-ով, և եթե հաղորդագրությունը չի վերաբերում նրանց, նրանք բաց են թողնում այն, այսինքն. անմիջապես կատարում է օֆսեթ +1: Եթե ​​նույն թեման կարդում է մեր վճարային ծառայությունը, ապա դա անում է առանձին խմբի հետ, և հետևաբար օֆսեթները չեն հատվում:

Միջոցառման պահանջները.

  • Տվյալների ամբողջականությունը. Կցանկանայի, որ միջոցառումն ունենա բավականաչափ տվյալներ, որպեսզի այն կարողանա մշակվել։

  • Ամբողջականություն Մենք պատվիրակում ենք Events-bus-ին ստուգումը, որ միջոցառումը հետևողական է, և այն կարող է մշակել այն:
  • Կարևոր է կարգը. Վերադարձի դեպքում մենք ստիպված ենք աշխատել պատմության հետ։ Ծանուցումների դեպքում պատվերը կարևոր չէ, եթե դրանք միատարր ծանուցումներ են, էլփոստը նույնն է լինելու՝ անկախ նրանից, թե որ պատվերն է առաջինը հասել։ Գումարի վերադարձի դեպքում կա հստակ գործընթաց, եթե մենք փոխենք կարգը, կառաջանան բացառություններ, վերադարձը չի ստեղծվի կամ չի մշակվի, մենք կհայտնվենք այլ կարգավիճակում:
  • Հետևողականություն. Մենք ունենք խանութ, և այժմ մենք ստեղծում ենք իրադարձություններ API-ի փոխարեն: Մեզ անհրաժեշտ է միջոց՝ արագ և էժան կերպով նոր իրադարձությունների և գոյություն ունեցողների փոփոխությունների մասին տեղեկատվությունը մեր ծառայություններին փոխանցելու համար: Սա ձեռք է բերվում առանձին git պահոցի և կոդերի գեներատորների ընդհանուր ճշգրտման միջոցով: Հետևաբար, տարբեր ծառայություններում հաճախորդները և սերվերները համակարգված են:

Կաֆկան Լամոդայում

Մենք ունենք երեք Կաֆկա ինստալացիա.

  1. Տեղեկամատյաններ;
  2. R&D;
  3. Միջոցառումներ-ավտոբուս.

Այսօր մենք խոսում ենք միայն վերջին կետի մասին. Events-bus-ում մենք չունենք շատ մեծ ինստալացիաներ՝ 3 բրոքեր (սերվեր) և ընդամենը 27 թեմա։ Որպես կանոն, մեկ թեման մեկ գործընթաց է։ Բայց սա նուրբ կետ է, և մենք հիմա կանդրադառնանք դրան:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Վերևում rps գրաֆիկն է: Փոխհատուցման գործընթացը նշվում է փիրուզագույն գծով (այո, X առանցքի վրա), իսկ վարդագույն գիծը բովանդակության թարմացման գործընթացն է։

Lamoda-ի կատալոգը պարունակում է միլիոնավոր ապրանքներ, և տվյալները մշտապես թարմացվում են: Որոշ հավաքածուներ դուրս են գալիս նորաձեւությունից, թողարկվում են նորերը՝ փոխարինելու համար, իսկ կատալոգում անընդհատ հայտնվում են նոր մոդելներ։ Մենք փորձում ենք գուշակել, թե ինչն է հետաքրքիր վաղը մեր հաճախորդներին, ուստի անընդհատ նոր բաներ ենք գնում, լուսանկարում և թարմացնում ցուցափեղկը։

Վարդագույն գագաթները արտադրանքի թարմացումներն են, այսինքն, ապրանքների փոփոխությունները: Երևում է, որ տղերքը նկարել են, նկարվել, հետո էլի! — բեռնել է իրադարձությունների փաթեթ:

Lamoda Events-ի օգտագործման պատյաններ

Մենք օգտագործում ենք կառուցված ճարտարապետությունը հետևյալ գործողությունների համար.

  • Վերադարձի կարգավիճակի հետևումԳործողության կոչ և կարգավիճակի հետևում բոլոր ներգրավված համակարգերից: Վճարումներ, կարգավիճակներ, ֆիսկալիզացիա, ծանուցումներ: Այստեղ մենք փորձարկեցինք մոտեցումը, պատրաստեցինք գործիքներ, հավաքեցինք բոլոր սխալները, գրեցինք փաստաթղթեր և պատմեցինք մեր գործընկերներին, թե ինչպես օգտագործել այն:
  • Ապրանքի քարտերի թարմացում. կոնֆիգուրացիա, մետատվյալներ, բնութագրեր: Մի համակարգ կարդում է (որը ցուցադրում է), իսկ մի քանիսը գրում են:
  • Փոստ, հրում և smsՊատվերը հավաքվել է, պատվերը հասել է, վերադարձն ընդունվել է և այլն, դրանք շատ են։
  • Պահեստի, պահեստի նորացում — ապրանքների քանակական թարմացում, ընդամենը թվեր՝ ժամանում պահեստ, վերադարձ։ Անհրաժեշտ է, որ ապրանքների պահուստավորման հետ կապված բոլոր համակարգերը գործեն ամենաարդիական տվյալներով։ Ներկայումս բաժնետոմսերի թարմացման համակարգը բավականին բարդ է, Կաֆկան կպարզեցնի այն:
  • Տվյալների վերլուծություն (R&D բաժին), ՓԼ գործիքներ, վերլուծություն, վիճակագրություն: Մենք ցանկանում ենք, որ տեղեկատվությունը լինի թափանցիկ. Կաֆկան լավ է հարմար դրա համար:

Այժմ ավելի հետաքրքիր հատվածը մեծ բախումների և հետաքրքիր բացահայտումների մասին, որոնք տեղի են ունեցել վերջին վեց ամիսների ընթացքում:

Դիզայնի խնդիրներ

Ենթադրենք՝ ուզում ենք նոր բան անել, օրինակ՝ առաքման ողջ գործընթացը փոխանցել Կաֆկային: Այժմ գործընթացի մի մասն իրականացվում է BOB-ում Պատվերների մշակման մեջ: Պատվերը առաքման ծառայություն տեղափոխելու, միջանկյալ պահեստ տեղափոխելու և այլնի հետևում կա կարգավիճակի մոդել: Կա մի ամբողջ մոնոլիտ, նույնիսկ երկու, գումարած մի փունջ API-ներ, որոնք նվիրված են առաքմանը: Նրանք շատ ավելին գիտեն առաքման մասին:

Թվում է, թե դրանք նման ոլորտներ են, բայց BOB-ում պատվերի մշակումը և առաքման համակարգն ունեն տարբեր կարգավիճակներ: Օրինակ՝ որոշ սուրհանդակային ծառայություններ չեն ուղարկում միջանկյալ կարգավիճակներ, այլ միայն վերջնական՝ «առաքված» կամ «կորած»։ Մյուսները, ընդհակառակը, շատ մանրամասն հայտնում են ապրանքների շարժի մասին։ Յուրաքանչյուր ոք ունի վավերացման իր կանոնները. ոմանց համար էլփոստը վավեր է, ինչը նշանակում է, որ այն կմշակվի; մյուսների համար դա վավեր չէ, բայց պատվերը դեռ կմշակվի, քանի որ կապի համար կա հեռախոսահամար, և ինչ-որ մեկը կասի, որ նման պատվերը ընդհանրապես չի մշակվի:

Տվյալների հոսք

Կաֆկայի դեպքում առաջանում է տվյալների հոսքի կազմակերպման հարցը։ Այս խնդիրը ներառում է մի քանի կետերի վրա հիմնված ռազմավարության ընտրություն, եկեք անցնենք բոլորին:

Մեկ թեմայում, թե՞ տարբեր.

Մենք ունենք իրադարձության հստակեցում: BOB-ում գրում ենք, որ այսինչ պատվերը պետք է առաքվի, և նշում ենք՝ պատվերի համարը, դրա կազմը, որոշ SKU և շտրիխ կոդեր և այլն: Երբ ապրանքը հասնի պահեստ, առաքումը կկարողանա ստանալ կարգավիճակներ, ժամանակի դրոշմանիշեր և այն ամենը, ինչ անհրաժեշտ է: Բայց հետո մենք ցանկանում ենք թարմացումներ ստանալ այս տվյալների վերաբերյալ BOB-ում: Մենք ունենք առաքումից տվյալների ստացման հակառակ գործընթաց: Արդյո՞ք սա նույն իրադարձությունն է: Թե՞ սա առանձին փոխանակում է, որն արժանի է իր թեմային:

Ամենայն հավանականությամբ դրանք շատ նման կլինեն, իսկ մեկ թեմա սարքելու գայթակղությունն անհիմն չէ, քանի որ առանձին թեմա նշանակում է առանձին սպառողներ, առանձին կոնֆիգուրներ, այս ամենի առանձին սերունդ։ Բայց ոչ փաստ։

Նոր դաշտ, թե՞ նոր իրադարձություն.

Բայց եթե դուք օգտագործում եք նույն իրադարձությունները, ապա այլ խնդիր է առաջանում. Օրինակ, ոչ բոլոր առաքման համակարգերը կարող են առաջացնել այնպիսի DTO, որը կարող է առաջացնել BOB-ը: Մենք նրանց ուղարկում ենք ID-ն, բայց նրանք չեն պահպանում այն, քանի որ դրա կարիքը չունեն, և իրադարձություն-ավտոբուսի գործընթացը սկսելու տեսանկյունից այս դաշտը պարտադիր է։

Եթե ​​իրադարձություն-ավտոբուսի համար մտցնենք կանոն, որ այս դաշտը պարտադիր է, ապա մենք ստիպված կլինենք սահմանել լրացուցիչ վավերացման կանոններ BOB-ում կամ մեկնարկային իրադարձությունների մշակիչում: Վավերացումը սկսում է տարածվել ամբողջ ծառայության ընթացքում, սա այնքան էլ հարմար չէ:

Մեկ այլ խնդիր է աստիճանական զարգացման գայթակղությունը: Մեզ ասում են, որ միջոցառմանը պետք է ինչ-որ բան ավելացնել, և գուցե, եթե մտածենք, դա պետք է առանձին միջոցառում լիներ։ Բայց մեր սխեմայում առանձին միջոցառումն առանձին թեմա է։ Առանձին թեմա է ամբողջ գործընթացը, որը նկարագրեցի վերևում: Մշակողը գայթակղվում է պարզապես մեկ այլ դաշտ ավելացնել JSON սխեմային և վերականգնել այն:

Գումարի վերադարձի դեպքում մենք իրադարձությունների իրադարձությանը հասանք կես տարուց։ Մենք ունեինք մեկ մետա-իրադարձություն, որը կոչվում էր վերադարձի թարմացում, որն ուներ տիպի դաշտ, որը նկարագրում էր, թե իրականում ինչ է այս թարմացումը: Դրա պատճառով մենք «հրաշալի» անջատիչներ ունեինք վավերացնողների հետ, ովքեր մեզ ասացին, թե ինչպես վավերացնել այս իրադարձությունը այս տեսակի հետ:

Միջոցառումների տարբերակավորում

Կաֆկայում հաղորդագրությունները վավերացնելու համար կարող եք օգտագործել Avro, բայց անհրաժեշտ էր անմիջապես պառկել դրա վրա և օգտագործել Confluent-ը։ Մեր դեպքում մենք պետք է զգույշ լինենք տարբերակման հարցում։ Միշտ չէ, որ հնարավոր կլինի վերընթերցել հաղորդագրությունները կրկնօրինակման մատյանից, քանի որ մոդելը «հեռացել է»: Հիմնականում ստացվում է, որ կառուցվում են տարբերակներ այնպես, որ մոդելը հետին համատեղելի լինի. օրինակ՝ դաշտը ժամանակավորապես ընտրովի դարձնել: Եթե ​​տարբերությունները չափազանց ուժեղ են, մենք սկսում ենք գրել նոր թեմայում, իսկ հաճախորդներին փոխանցում ենք, երբ նրանք ավարտեն հինի ընթերցումը:

Միջնորմների ընթերցման երաշխավորված կարգը

Կաֆկայի ներսում թեմաները բաժանված են միջնորմների: Սա այնքան էլ կարևոր չէ, երբ մենք նախագծում ենք կազմակերպություններ և բորսաներ, բայց կարևոր է, երբ որոշում ենք, թե ինչպես սպառել և մեծացնել այն:

Սովորական դեպքում մի թեմա գրում ես Կաֆկայում։ Լռելյայնորեն օգտագործվում է մեկ բաժին, և այս թեմայի բոլոր հաղորդագրությունները գնում են դրան: Եվ սպառողը հետևաբար կարդում է այս հաղորդագրությունները հաջորդաբար: Եկեք ասենք, որ հիմա մենք պետք է ընդլայնենք համակարգը, որպեսզի հաղորդագրությունները կարդան երկու տարբեր սպառողների կողմից: Եթե, օրինակ, SMS եք ուղարկում, ապա կարող եք Կաֆկային ասել, որ լրացուցիչ բաժանում կատարի, և Կաֆկան կսկսի հաղորդագրությունները բաժանել երկու մասի` կեսը այստեղ, կեսը այստեղ:

Ինչպե՞ս է Կաֆկան դրանք բաժանում: Յուրաքանչյուր հաղորդագրություն ունի մարմին (որում մենք պահում ենք JSON) և բանալի: Այս ստեղնին կարող եք կցել հեշ ֆունկցիա, որը կորոշի, թե որ բաժանման մեջ է մտնելու հաղորդագրությունը:

Հետվճարների մեր դեպքում սա կարևոր է, եթե վերցնենք երկու բաժանմունք, ապա հնարավորություն կա, որ զուգահեռ սպառողը վերամշակի երկրորդ իրադարձությունը առաջինից առաջ և խնդիրներ առաջանան: Հեշ ֆունկցիան ապահովում է, որ նույն բանալիով հաղորդագրությունները հայտնվում են նույն բաժանման մեջ:

Իրադարձություններ ընդդեմ հրամանների

Սա ևս մեկ խնդիր է, որին մենք հանդիպեցինք։ Իրադարձությունը որոշակի իրադարձություն է. մենք ասում ենք, որ ինչ-որ տեղ ինչ-որ բան է տեղի ունեցել (ինչ-որ բան_պատահել է), օրինակ՝ ապրանքը չեղարկվել է կամ գումարի վերադարձ է տեղի ունեցել: Եթե ​​ինչ-որ մեկը լսում է այս իրադարձությունները, ապա ըստ «տարրը չեղարկված է», կստեղծվի գումարի վերադարձման միավորը, և կարգավորումներում ինչ-որ տեղ կգրվի «հատվածի վերադարձը»:

Բայց սովորաբար, երբ միջոցառումներ եք նախագծում, դուք չեք ցանկանում դրանք իզուր գրել, դուք ապավինում եք այն փաստին, որ ինչ-որ մեկը դրանք կկարդա: Մեծ գայթակղություն կա գրելու ոչ թե ինչ-որ բան_պատահել է (նյութ_չեղարկված, գումար վերադարձված_վերադարձված), այլ ինչ_որ_պետք_կատարվի։ Օրինակ, ապրանքը պատրաստ է վերադարձման:

Մի կողմից հուշում է, թե ինչպես է օգտագործվելու միջոցառումը։ Մյուս կողմից, այն շատ ավելի քիչ է նմանվում սովորական իրադարձության անվանմանը: Բացի այդ, այստեղից հեռու չէ do_something հրամանը: Բայց դուք երաշխիք չունեք, որ ինչ-որ մեկը կարդացել է այս իրադարձությունը. իսկ եթե կարդում ես, ուրեմն հաջողությամբ ես կարդում; և եթե այն հաջողությամբ կարդացել ես, ուրեմն ինչ-որ բան ես արել, և այդ ինչ-որ բան հաջողվել է: Այն պահին, երբ իրադարձությունը դառնում է do_something, արձագանքը դառնում է անհրաժեշտ, և դա խնդիր է:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

RabbitMQ-ում ասինխրոն փոխանակման ժամանակ, երբ կարդում եք հաղորդագրությունը, անցեք http, դուք պատասխան ունեք՝ համենայն դեպս, որ հաղորդագրությունը ստացվել է: Երբ գրում ես Կաֆկային, կա հաղորդագրություն, որ դու գրել ես Կաֆկային, բայց դու ոչինչ չգիտես, թե ինչպես է այն մշակվել:

Հետևաբար, մեր դեպքում մենք պետք է ներդնեինք արձագանքման միջոցառում և մոնիթորինգ սահմանեինք, որպեսզի եթե այսքան իրադարձություն ուղարկվեր, այսքան ժամից հետո նույն թվով արձագանքման իրադարձություններ գան։ Եթե ​​դա տեղի չունենա, ապա կարծես ինչ-որ բան սխալ է տեղի ունեցել: Օրինակ, եթե մենք ուղարկել ենք «item_ready_to_refund» միջոցառումը, մենք ակնկալում ենք, որ կստեղծվի գումարի վերադարձ, գումարը կվերադարձվի հաճախորդին, և «money_refunded» միջոցառումը կուղարկվի մեզ: Բայց դա միանշանակ չէ, ուստի անհրաժեշտ է մոնիտորինգ:

Նամակներ

Բավականին ակնհայտ խնդիր կա. եթե հաջորդաբար կարդաք թեմայից, և ինչ-որ վատ հաղորդագրություն ունեք, սպառողը կընկնի, և դուք ավելի հեռու չեք գնա։ Քեզ պետք է դադարեցնել բոլոր սպառողներին, փոխհատուցեք հետագա ընթերցումը շարունակելու համար:

Մենք գիտեինք դրա մասին, հույս էինք դրել դրա վրա, բայց դա եղավ: Եվ դա տեղի ունեցավ, քանի որ իրադարձությունը վավեր էր իրադարձությունների-ավտոբուսի տեսանկյունից, իրադարձությունը վավեր էր հավելվածի վավերացնողի տեսանկյունից, բայց վավեր չէր PostgreSQL-ի տեսանկյունից, քանի որ մեր մեկ համակարգում MySQL-ը UNSIGNED INT-ով, իսկ նոր գրվածում համակարգն ուներ PostgreSQL հենց INT-ով։ Նրա չափսը մի փոքր ավելի փոքր է, իսկ Id-ը չէր տեղավորվում։ Սիմֆոնին մահացավ բացառությամբ։ Մենք, իհարկե, բռնեցինք բացառությունը, քանի որ մենք ապավինում էինք դրա վրա և պատրաստվում էինք կատարել այս փոխհատուցումը, բայց մինչ այդ մենք ցանկանում էինք մեծացնել խնդրի հաշվիչը, քանի որ հաղորդագրությունը անհաջող էր մշակվել: Այս նախագծի հաշվիչները նույնպես գտնվում են տվյալների բազայում, և Symfony-ն արդեն փակել է կապը տվյալների բազայի հետ, և երկրորդ բացառությունը սպանեց ամբողջ գործընթացը՝ առանց օֆսեթ կատարելու հնարավորության:

Ծառայությունը որոշ ժամանակ պառկեց. բարեբախտաբար, Կաֆկայի մոտ դա այնքան էլ վատ չէ, քանի որ հաղորդագրությունները մնում են: Երբ աշխատանքը վերականգնվի, կարող եք ավարտել դրանք կարդալը: Հարմարավետ է։

Կաֆկան ունի գործիքավորման միջոցով կամայական փոխհատուցում սահմանելու ունակություն: Բայց դա անելու համար դուք պետք է դադարեցնեք բոլոր սպառողներին. մեր դեպքում պատրաստեք առանձին թողարկում, որում սպառողներ, վերաբաշխումներ չեն լինի: Այնուհետև Կաֆկայում դուք կարող եք փոխել օֆսեթը գործիքավորման միջոցով, և հաղորդագրությունը կանցնի:

Մեկ այլ նրբություն - replication log ընդդեմ rdkafka.so - կապված է մեր նախագծի առանձնահատկությունների հետ: Մենք օգտագործում ենք PHP, իսկ PHP-ում, որպես կանոն, բոլոր գրադարանները շփվում են Կաֆկայի հետ rdkafka.so պահեստի միջոցով, իսկ հետո կա ինչ-որ փաթաթան։ Միգուցե սրանք մեր անձնական դժվարություններն են, բայց պարզվեց, որ մեր արդեն կարդացածից մի կտոր պարզապես վերընթերցելն այնքան էլ հեշտ չէ։ Ընդհանուր առմամբ, կային ծրագրային խնդիրներ։

Վերադառնալով միջնորմների հետ աշխատելու յուրահատկությանը, դա գրված է հենց փաստաթղթերում սպառողներ >= թեմայի բաժանումներ. Բայց ես այս մասին իմացա շատ ավելի ուշ, քան կցանկանայի։ Եթե ​​ցանկանում եք մասշտաբավորել և ունենալ երկու սպառող, ձեզ անհրաժեշտ է առնվազն երկու միջնորմ: Այսինքն, եթե ունեիք մեկ բաժանում, որում կուտակվել էր 20 հազար հաղորդագրություն, և դուք դարձնեիք թարմը, հաղորդագրությունների թիվը շուտով չի հավասարվի։ Հետեւաբար, երկու զուգահեռ սպառող ունենալու համար պետք է գործ ունենալ միջնապատերի հետ։

Մոնիտորինգ

Կարծում եմ՝ ինչպես մենք վերահսկում ենք, ավելի պարզ կլինի, թե ինչ խնդիրներ կան առկա մոտեցման մեջ։

Օրինակ, մենք հաշվարկում ենք, թե տվյալների բազայում քանի ապրանք է վերջերս փոխել իրենց կարգավիճակը, և, համապատասխանաբար, իրադարձություններ պետք է տեղի ունենային այդ փոփոխությունների հիման վրա, և մենք ուղարկում ենք այս թիվը մեր մոնիտորինգի համակարգին: Հետո Կաֆկայից ստանում ենք երկրորդ թիվը, թե իրականում քանի իրադարձություն է գրանցվել։ Ակնհայտ է, որ այս երկու թվերի տարբերությունը միշտ պետք է լինի զրո:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Բացի այդ, դուք պետք է վերահսկեք, թե ինչպես է արտադրողը, արդյոք միջոցառումներ-ավտոբուսը հաղորդագրություններ է ստացել և ինչպես է սպառողը: Օրինակ, ստորև բերված գծապատկերներում Refund Tool-ը լավ է աշխատում, բայց BOB-ն ակնհայտորեն որոշ խնդիրներ ունի (կապույտ գագաթներ):

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Ես արդեն նշեցի սպառողների խմբի ուշացումը։ Կոպիտ ասած՝ սա չընթերցված հաղորդագրությունների թիվն է։ Ընդհանուր առմամբ, մեր սպառողները արագ են աշխատում, ուստի հետաձգումը սովորաբար 0 է, բայց երբեմն կարող է լինել կարճաժամկետ գագաթնակետ: Կաֆկան կարող է դա անել առանց տուփի, բայց դուք պետք է որոշակի միջակայք սահմանեք:

Նախագիծ կա Burrowորը ձեզ ավելի շատ տեղեկություններ կտա Կաֆկայի մասին: Այն պարզապես օգտագործում է սպառողների խմբի API-ն՝ այս խմբի գործունեության կարգավիճակը տալու համար: Բացի OK-ից և Failed-ից, կա նախազգուշացում, և դուք կարող եք պարզել, որ ձեր սպառողները չեն կարող հաղթահարել արտադրության տեմպերը. նրանք ժամանակ չունեն գրվածը սրբագրելու համար: Համակարգը բավականին խելացի է և հեշտ օգտագործման համար:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Ահա թե ինչ տեսք ունի API-ի պատասխանը: Ահա bob-live-fifa խումբը, partition refund.update.v1, կարգավիճակը OK, ուշացում 0 - վերջին վերջնական օֆսեթ այսինչը:

Kafka-ում ասինխրոն API-ով Refund Tool ծառայության մշակման փորձ

Մոնիտորինգ updated_at SLA (խրված) Ես արդեն նշեցի. Օրինակ, ապրանքը փոխվել է այն կարգավիճակի, որ այն պատրաստ է վերադարձի: Մենք տեղադրում ենք Cron-ը, որն ասում է, որ եթե 5 րոպեի ընթացքում այս օբյեկտը չի գնացել վերադարձման (մենք շատ արագ ենք վերադարձնում գումարը վճարային համակարգերի միջոցով), ապա ինչ-որ բան հաստատ սխալ է տեղի ունեցել, և սա միանշանակ աջակցության դեպք է: Հետևաբար, մենք պարզապես վերցնում ենք Cron-ը, որը կարդում է նման բաներ, և եթե դրանք 0-ից մեծ են, ապա այն ահազանգ է ուղարկում։

Ամփոփելու համար, իրադարձությունների օգտագործումը հարմար է, երբ:

  • տեղեկատվությունը անհրաժեշտ է մի քանի համակարգերի համար.
  • մշակման արդյունքը կարևոր չէ.
  • կան քիչ իրադարձություններ կամ փոքր իրադարձություններ:

Թվում է, թե հոդվածը շատ կոնկրետ թեմա ունի՝ ասինխրոն API Կաֆկայի վրա, բայց դրա հետ կապված ես կցանկանայի միանգամից շատ բաներ խորհուրդ տալ։
Առաջին, հաջորդ Բարձր բեռնում ++ մենք պետք է սպասենք մինչև նոյեմբեր, ապրիլին կլինի Սանկտ Պետերբուրգի տարբերակը, իսկ հունիսին մենք կխոսենք Նովոսիբիրսկում բարձր բեռների մասին:
Երկրորդ, զեկույցի հեղինակ Սերգեյ Զաիկան գիտելիքի կառավարման մեր նոր համաժողովի ծրագրային հանձնաժողովի անդամ է։ Գիտելիքի կոնֆ. Համաժողովը մեկօրյա է, տեղի կունենա ապրիլի 26-ին, սակայն դրա ծրագիրը շատ լարված է։
Եվ դա կլինի մայիսին PHP Ռուսաստան и RIT++ (ներառյալ DevOpsConf) - կարող եք նաև առաջարկել ձեր թեման այնտեղ, խոսել ձեր փորձի մասին և բողոքել ձեր լցոնված կոների մասին:

Source: www.habr.com

Добавить комментарий