Имплементација микросервиса у производним окружењима

Последње ажурирање: КСНУМКС априла КСНУМКС
  • Микросервиси захтевају пажљиво дизајнирање услуга, података, отпорности и уговора како би били одрживи у продукцији.
  • Kubernetes/OpenShift, CI/CD и GitOps омогућавају аутоматизацију великих имплементација, скалирања и рада.
  • Безбедност са нултим поверењем, робусно управљање конфигурацијом и видљивост помоћу OpenTelemetry су стубови платформе.
  • Организација производног тима и дистрибуирано управљање су једнако важни као и изабрана технологија.

Архитектура микросервиса у продукцији

Усвајање микросервисне архитектуре у реалном окружењу не значи само разбијање монолита на мање делове; то подразумева преиспитивање инфраструктуре, тимова, процеса, података, безбедности и операција . Када систем пређе из теорије у производни кластер, јављају се проблеми у вези са откривањем сервиса, уговорима између тимова, CI/CD, видљивошћу, отпорношћу и скалабилношћу. Ако се ови проблеми не реше правилно, могу претворити микросервисе у дистрибуирани хаос.

Добра вест је да данас имамо богато акумулирано искуство организација попут Netflix-а, Amazon-а, Google-а и других великих корпорација које покрећу стотине микросервиса у продукцији . Надовезујући се на ове лекције, заједно са најбољим праксама у пословним окружењима која користе Kubernetes и OpenShift, можемо развити веома робустан приступ пројектовању, имплементацији и управљању микросервисима у великим размерама без губитка контроле.

Зашто примењивати микросервисе у продукцији (и када се то не исплати)

Добро осмишљена архитектура микросервиса вам омогућава да радите са малим, аутономним и међуфункционалним тимовима који преузимају одговорност за услугу од почетка до краја. Сваки тим ради у добро дефинисаном контексту, може често да примењује услуге и преузима пуну одговорност за своју услугу, смањујући време развојног циклуса и убрзавајући испоруку нових функција.

Још једна кључна предност је независно скалирање по сервису . Не морате превелико повећавати величину целе апликације ако само каталог, плаћање или јавни API доживљавају скокове саобраћаја. Можете подесити сваки микросервис хоризонтално или вертикално према његовом обрасцу оптерећења, прецизно измерити трошкове сваке функције и одржати доступност чак и ако одређено подручје доживи нагли пораст потрошње.

Начин на који су ови сервиси упаковани и распоређени олакшава континуирану имплементацију са ниским ризиком . Објављивање сваког микросервиса независно чини тестирање нових идеја и враћање проблематичних верзија много једноставнијим: „canary“ имплементације, „плаво/зелено“ враћање претходних верзија и аутоматизовано враћање претходних верзија смањују трошкове квара и пружају простор за експериментисање.

Са технолошког становишта, микросервиси подстичу слободу избора језика, оквира и база података за сваку услугу. Не уклапају се све потребе у исти технолошки стек: можете имати пословне сервисе у .NET-у или Јави, обраду података у Scala/Spark-у, специјализоване сервисе у Python-у или F#-у или AI микросервисе у R-у. Ова контролисана разноликост вам омогућава да користите прави алат за сваки случај, без присиљавања целе апликације на глобални технолошки помак.

Штавише, разбијање система на мале, добро дефинисане делове олакшава поновну употребу функционалности као градивних блокова . Микросервис првобитно креиран као део веће функционалности може се касније поново користити као зависност других делова система без преписивања логике. А пошто су сервиси изоловани, квар у једном од њих обично доводи до делимичне деградације система, а не до потпуног испада система, под условом да је отпорност пројектована од самог почетка.

Архитектонски и сервисни дизајн

Дизајн микросервиса у продукцији

Да би микросервиси добро функционисали у продукцији, неопходно је почети са пажљивим дизајнирањем граница сервиса и одговорности . У практичном смислу, ово обично почиње идентификовањем крупнозрнастих сервиса унутар постојећег монолита: великих функционалних области или пословних домена (нпр. поруџбине, каталог, корисници, наплата) који већ имају одређену логичку раздвојеност.

Почевши од ових великих градивних блокова, процес укључује усавршавање дизајна како би се добили фино гранулирани микросервиси који раде на кохерентном скупу података , поседују сопствени модел и тачно знају шта треба да читају или пишу у друге сервисе. Овај процес се обично ослања на концепте дизајна вођеног доменом (DDD) и ограничене контексте, спречавајући да микросервис постане „мини монолит“.

API-ји који пружају ове сервисе морају имати добро дефинисане и стабилне уговоре . То подразумева ригорозну документацију (REST са OpenAPI, gRPC са .proto датотекама итд.), експлицитно верзионисање, одржавање компатибилности са претходним верзијама где је то могуће и аутоматизацију валидације уговора како би се откриле кључне промене пре него што стигну до производне верзије.

У окружењима са десетинама или стотинама сервиса, кључно је укључити обрасце отпорности од фазе пројектовања, како би систем био спреман за делимичне кварове . Обрасци као што су прекидачи, поновни покушаји са застојем, добро дефинисана временска ограничења, преграде и повратни притисак помажу у спречавању да квар једног сервиса доведе до пада осталих. Алати за хаос инжењеринг попут ChaosMonkey-а или Gremlin-а су корисни за практично тестирање како се платформа понаша током симулираних прекида.

Многи сложени системи комбинују релативно једноставне CRUD сервисе са софистициранијим који обрађују еволуирајућа пословна правила. Нису сви микросервиси потребни сложеним интерним архитектурама : неки могу бити једноставни HTTP контролери са основним приступом подацима, док други, као што су сервиси за поруџбине или наплату, могу користити напредније обрасце (DDD, CQRS, догађаји домена итд.).

Производна инфраструктура: облак, контејнери и Kubernetes/OpenShift

Искуство из стварног света показује да микросервиси раде много боље када су распоређени на клауд инфраструктури са контејнерима и оркестрацијом него на изолованим виртуелним машинама. Платформе попут Kubernetes-а и OpenShift-а пружају неопходне примитиве за паковање сервиса као контејнера, скалирање, ажурирање, балансирање оптерећења и управљање високом доступношћу.

  Отпорност података на сајбер простор у ери више облака

Типично, сваки микросервис је упакован у контејнерску слику засновану на корпоративној основној слици (на пример, OpenJDK 21 за Јава сервисе) којом управља инфраструктурни тим. Ова основна слика се ажурира безбедносним закрпама, а када се објави нова верзија, развојни тимови су одговорни за поновну изградњу и поновно распоређивање својих сервиса у одговарајућим окружењима.

У Kubernetes/OpenShift-у, основна јединица за распоређивање је pod (под), који обухвата један или више контејнера . Типично, микросервис одговара типу pod-а и распоређује се коришћењем ресурса као што су Deployments (за услуге без стања) или StatefulSets (када постоји повезано стање). Од самог почетка, дефинисан је минималан број реплика по окружењу тако да тестна, претпродукцијска и продукцијска окружења имају нивое доступности који одговарају њиховој критичности.

Аутоматско скалирање се имплементира помоћу HorizontalPodAutoscaler-а (HPA) , који подешава број реплика на основу метрика као што су процесор, меморија или друге прилагођене метрике. Платформа такође мора да конфигурише правила против афинитета подова како би дистрибуирала реплике исте услуге на различитим чворовима, спречавајући да квар једног чвора обустави све инстанце.

Што се тиче вертикалног димензионисања, resources.requests и resources.limits се користе за дефинисање опсега процесора и меморије коју под може да користи. На пример, резервисање минимума од 100MB процесора и 256MB меморије, и дозвољавање до 500MB и 2GB респективно за Java сервис, подешавање JVM-а (Xms, Xmx, Xss) како би се добро искористили ресурси контејнера.

Управљање стањем: микросервиси са и без стања

Већина пословних микросервиса је дизајнирана као сервиси без стања . То значи да под не чува информације које морају да преживе поновна покретања; стање се чува у екстерним базама података, редовима порука или другим складиштима. Овај приступ олакшава динамичко хоризонтално скалирање и беспрекорно имплементирање, јер свака реплика може да обради било који захтев.

Међутим, постоје сценарији где нема алтернативе осим да постоје статефул микросервиси које подржавају перзистентни волумени . То је случај са неким базама података, дистрибуираним фајл системима или компонентама које захтевају одржавање локалних података. Ови подови се обично распоређују са StatefulSets-овима, повезаним са PersistentVolumes-ом користећи PersistentVolumeClaims и скалирају се вертикално, а не хоризонтално.

Када микросервису треба трајно складиштење, захтева се PersistentVolumeClaim (PVC) са његовом величином, режимом приступа и намењеном употребом , а оперативни тим га обезбеђује у складу са политикама платформе. Овај PVC се референцира у манифесту имплементације и монтира се на под тако да сервис може трајно да чита и пише податке.

Иако модели са очувањем стања могу бити неопходни у одређеним случајевима, општа препорука је да се што више сервиса држи без очувања стања . Ово поједностављује имплементацију, скалирање, отпорност и опоравак од катастрофе, и смањује оперативну сложеност у окружењима са много микросервиса.

Децентрализација података и суверенитет услуга

У традиционалним инфраструктурама, уобичајено је централизовати базе података и складиштење како би се максимизирала ефикасност. Код микросервиса, овај приступ је у сукобу са аутономијом тима и раздвајањем . Ако многи сервиси деле исту релациону шему, свака структурна промена може блокирати више тимова и ненамерно прекинути компатибилност.

Стога се препоручује да сваки микросервис поседује сопствени модел података и базу података , иако се у развојном окружењу та база података покреће као контејнер унутар кластера ради поједностављења имплементације. У продукцији се обично користе инстанце којима управља облак или други сервери база података високе доступности, уз увек одржавање јасне границе власништва.

То не значи да нема интеграције података; то значи да се конзистентност између сервиса управља догађајима и асинхроним порукама , прихватајући евентуалну конзистентност када је то разумно. Уобичајено је користити магистрале догађаја (RabbitMQ, Azure Service Bus, Kafka, итд.) за пропагирање промена стања између микросервиса, смањујући јаке зависности од једне базе података.

Клауд платформа олакшава тимовима да изаберу оптималан тип базе података за сваку услугу (релациону, документарну, кључ-вредност, временске серије итд.), без наметања јединствене технологије. Кључно је да дизајн узме у обзир могућност миграције шема и структура без прекида уговора са другим услугама и да се одлуке о подацима доносе у складу са границама домена сваког микросервиса.

Дистрибуирано управљање, тимови и организација

Прелазак на микросервисе без промене организације тражи проблеме. Уместо класичних функционалних силоса мрежа, система, база података, развоја и операција , подстиче се структура заснована на тимовима за производе, која обједињује профиле из развоја, контроле квалитета, DevOps-а и, где је то применљиво, пословних или аналитичара података.

Сваки тим је одговоран за један или више микросервиса унутар истог функционалног домена, бавећи се и развојем и радом (ви га градите, ви га покрећете) . То значи да тим управља својим CI/CD цевоводима, сарађује са инфраструктуром за специфичне потребе и учествује у праћењу и реаговању на инциденте. Инфраструктура и cloud платформа се фокусирају на пружање заједничких и стандардизованих услуга.

  Где могу да студирам развој софтвера?

Да би се спречило да ово дистрибуирано управљање падне у анархију, кључно је дефинисати једноставне стандарде и дељене каталоге : одобрене основне слике, обрасце имплементације, конвенције именовања за именске просторе и услуге, API смернице, Dockerfile и Kustomize шаблоне итд. Ове смернице служе као „ограде“ које оријентишу тимове без блокирања њихове способности да доносе одлуке.

У многим пословним окружењима, за сваки пројекат или домен се користе одвојени именски простори , са најмање једним по окружењу (развој, претпродукција, продукција). Велики пројекат може дистрибуирати своје микросервисе у неколико именских простора, под условом да су интерне комуникације правилно конфигурисане и да се поштују безбедносна правила.

CI/CD, аутоматизација и GitOps модел

Када архитектура обухвата десетине или стотине микросервиса, једини начин да се они одрже оперативним јесте значајно улагање у аутоматизацију од почетка до краја . То укључује конзистентне CI/CD цевоводе, декларативне дефиниције распоређивања, аутоматизовано тестирање и аутоматске механизме враћања уназад.

Типичан континуирани интеграциони и испоручни процес обрађује компајлирање кода, покретање тестова, анализу квалитета помоћу алата као што је SonarQube , изградњу слике контејнера из корпоративног Dockerfile-а и ажурирање манифеста имплементације. Одатле, систем као што је ArgoCD или сличан примењује промене на кластер користећи GitOps приступ.

Сваки репозиторијум микросервиса обично укључује стандардизовани Dockerfile, конфигурациону датотеку цевовода (нпр. ci.json) , својства за анализу квалитета и директоријум за имплементацију са Kubernetes дефиницијама (Kustomize или Helm) раздвојеним по окружењу. Вебхукови репозиторијума покрећу цевовод када се догоде догађаји као што су слање ознака или захтеви за спајање.

GitOps шаблон успоставља Git репозиторијум као извор истине за инфраструктуру и имплементацију . Манифести за имплементације, услуге, ConfigMaps, PVC-ове, SealedSecrets и друге ресурсе се тамо верзионишу, а специфични алати се баве синхронизацијом стања кластера са оним што је дефинисано у Git-у. Ово пружа могућност праћења, прегледе захтева за повлачење и једноставне могућности враћања на претходну функцију.

Подешавања, тајне и безбедност

У развијеној платформи микросервиса, управљање конфигурацијом се ослања на ConfigMaps за неосетљиве параметре и Secrets за поверљиве информације . Сваки микросервис обично има свој ConfigMap специфичан за окружење, који чува својства као што су URL-ови зависних сервиса, заставице функционалности и параметри подешавања.

Тајне (акредитиви, кључеви, токени, сертификати) се обрађују строгим безбедносним политикама . У мање критичним окружењима, може бити прихватљиво чувати их у обичном тексту којим управља развојни тим, али у предпродукционим и продукционим окружењима препоручује се њихово шифровање помоћу алата као што су Sealed Secrets или специфични екстерни менаџери засновани на облаку.

Када је потребно да се тајна дели између више сервиса (на пример, акредитиви OTEL колектора или заједничко складиште кључева ), она може бити централизована у спремишту конфигурације по именском простору. Пројекти који деле тај именски простор координирају се како би га ажурирали по потреби, одржавајући контролу над тим ко може да чита или мења ове ресурсе.

Што се тиче безбедности комуникација, доминантни образац је нулто поверење : ништа се не узима здраво за готово само зато што је саобраћај „интерни“. Сви позиви између сервиса, и интерних и екстерних, морају бити аутентификовани и одобрени, идеално помоћу mTLS, JWT токена или других еквивалентних механизама. Микросервиси не делегирају слепо безбедност API менаџеру или мрежи; они такође обављају сопствене провере.

Комуникација између микросервиса, API-ја и размене порука

У зрелој архитектури микросервиса, комуникациони слој је подељен на неколико случајева. За саобраћај од клијената (прегледача, мобилних апликација, трећих страна) до бекенда, користе се објављени API-ји којима управља API Manager . Ови API-ји су обично RESTful (често користе OpenAPI) или, у неким случајевима, gRPC изложени преко gateway-а.

Позиве између микросервиса који се налазе у истом именском простору, или чак између више именских простора унутар истог пројекта, обично обрађују интерни Kubernetes сервиси са интерним DNS-ом . Ови позиви заобилазе јавни API Manager, али се придржавају политика безбедности, аутентификације и ауторизације. За ове сценарије може се користити мрежа сервиса или интерни gateway-и који спроводе заједничке политике.

Када микросервиси припадају различитим функционалним доменима или пројектима , комуникација се сматра „јавном“ на организационом нивоу. У тим случајевима, уобичајена је пракса да се користи API Manager или магистрала за интероперабилност, где се управљају уговорима, квотама, безбедношћу, верзијама и ревизијом, спречавајући директно повезивање између независних кластера или именских простора.

Што се тиче интеграције са застарелим или екстерним системима, који не морају увек да изложе модерне API-је, уобичајено је ослањање на специфичне конекторе преко магистрале за интероперабилност . На овај начин, микросервиси говоре заједничким језиком (на пример, догађаји или интерни REST API-ји), а конектор обрађује превод ка и из застарелог система, увек уз побољшану безбедност.

Поред синхроне комуникације, асинхрона размена порука игра кључну улогу . Користи се за раздвајање процеса, апсорпцију скокова, ширење пословних догађаја између сервиса и побољшање отпорности. Сваки догађај обично има добро дефинисану и верзионисану шему, са механизмима праћења како би се спречили прекиди између произвођача и потрошача како се они развијају.

Видљивост, OTEL колектор и рад

У систему састављеном од многих микросервиса, дијагностиковање проблема без добре видљивости је готово немогуће. Зато су метрике, централизовано евидентирање и дистрибуирани трагови интегрисани од фазе пројектовања , омогућавајући разумевање шта се дешава и на нивоу сервиса и на нивоу платформе.

  Боотстрап 5: Дефиниција и конфигурација и пример

Централна компонента ове шеме је OpenTelemetry Collector (OTEL Collector) , који је распоређен у именском простору или централно за прикупљање метрика, логова и трагова из свих компоненти. Микросервиси треба само да знају да треба да пошаљу своју телеметрију Колектору; Колектор је затим прослеђује системима за посматрање (Prometheus, Grafana, Jaeger, Elastic, итд.) без потребе да сервис зна детаље.

За инфраструктурни слој, колектори и извозници на нивоу чворова се користе за прикупљање метрика процесора, меморије, диска, мреже и логова из подова, шаљући их Prometheus-у и Elasticsearch-у, респективно. Алати попут Grafana-е и Kibana-е користе се за визуелизацију ових информација, израду контролних табли и дефинисање упозорења са паметним праговима и повезаним runbook-овима.

Када пројекту треба веома специфична обрада метрика или трагова, може да распореди сопствену инстанцу OTEL Collector-а у свом именском простору, под условом да има оперативно одобрење и да је модел одржавања производње јасан.

Стратегија тестирања, уговори и искуство у локалном развоју

Тестирање дистрибуиране архитектуре микросервиса захтева софистициранију стратегију тестирања од тестирања монолита. Јединични тестови остају неопходни, али уговорни тестови (за API-је и догађаје), интеграциони тестови између сервиса и end-to-end тестови који пролазе кроз комплетне токове постају све важнији.

Да би се спречили проблеми са компатибилношћу, користе се технике као што је тестирање уговора оријентисано на потрошаче , где клијенти дефинишу очекивања од API-ја, а добављачи услуга их испуњавају. Свака промена уговора пролази кроз аутоматско тестирање унутар CI цевовода, спречавајући имплементације које нарушавају рад било ког познатог потрошача.

Када број сервиса пређе стотину, локално репликирање целог система постаје непрактично. Стога се развој ослања на симулације зависних сервиса или тунелирање ка удаљеним окружењима . Програмери обично покрећу само подскуп микросервиса, а остатак блокирају помоћу имитација, лажних верзија или симулатора, или преусмеравају одређене позиве на дељено интеграционо окружење.

Тестирање од почетка до краја све више се ослања на ефемерна окружења или „прегледе“ креиране из грана функција , које успостављају изоловано окружење са услугама релевантним за ту функционалност. Ово минимизира трење између тимова, смањује ефекат „ради на мојој машини“ и открива проблеме интеграције пре него што се стигне до скупљих окружења попут предпродукције.

Шаблони распоређивања микросервиса у продукцији

Поред Кубернетеса, постоји неколико образаца распоређивања микросервиса у продукцији које вреди знати јер се баве различитим сценаријима изолације, трошкова и зрелости . Један од најстаријих образаца је вишеструке инстанце сервиса по хосту, где један физички или виртуелни хост покреће неколико инстанци различитих сервиса, обично на дељеном серверу апликација.

У обрасцу инстанце сервиса по виртуелној машини , сваки сервис је упакован као слика виртуелне машине (на пример, EC2 AMI) и покреће се на сопственој инстанци. Ово нуди јаку изолацију по цену веће потрошње ресурса и споријег времена покретања. Алати попут Packer-а или решења специфична за добављача облака олакшавају генерисање слика виртуелних машина спремних за производњу.

Најраспрострањенији образац данас је инстанца сервиса по контејнеру , где се сваки микросервис гради као слика контејнера и распоређује на оркестратору (Kubernetes, OpenShift, итд.). Контејнери су лакши од виртуелних машина, покрећу се веома брзо и омогућавају вам да спакујете све што је потребно за сервис, поједностављујући распоређивање и омогућавајући аутоматско скалирање.

Коначно, приступи без сервера, као што је AWS Lambda , стекли су популарност. Ови пакети садрже функције које одговарају на HTTP захтеве или догађаје из других сервиса (S3, DynamoDB, редови чекања итд.), при чему корисници плаћају само за оно што користе. Овај образац је посебно погодан за веома мале микросервисе или краткотрајне задатке вођене догађајима, иако уводи додатна разматрања у вези са видљивошћу, хладним покретањем и ограничењима извршавања.

У пракси, многе организације завршавају са хибридним екосистемом: основни део система ради на контејнерима и оркестраторима, док су одређене помоћне компоненте имплементиране као функције без сервера или као специјализоване виртуелне машине, увек са јасним интерфејсима и добро дефинисаним протоколима за њихову интеграцију у целину.

Када је у питању преношење свега овога у продукцију, оно што прави разлику није само изабрана технологија, већ изградња архитектуре која толерише грешке, скалира се где је потребно, аутоматски се имплементира и видљива је . Са тимовима усклађеним са производима, добро управљаним уговорима, децентрализованим подацима и робусном облачном платформом, микросервиси прелазе из обећања у ефикасан и одржив начин за развој сложених апликација годинама.