Cyfluniad cryno o system ddosbarthedig

Yn y post hwn hoffem rannu ffordd ddiddorol o ddelio â chyfluniad system ddosbarthedig.
Cynrychiolir y ffurfweddiad yn uniongyrchol yn iaith Scala mewn modd math diogel. Disgrifir gweithrediad enghreifftiol yn fanwl. Trafodir agweddau amrywiol ar y cynnig, gan gynnwys dylanwad ar y broses ddatblygu gyffredinol.

Cyfluniad cryno o system ddosbarthedig

(yn Rwseg)

Cyflwyniad

Mae adeiladu systemau gwasgaredig cadarn yn gofyn am ddefnyddio cyfluniad cywir a chydlynol ar bob nod. Ateb nodweddiadol yw defnyddio disgrifiad defnydd testunol (terraform, ansible neu rywbeth fel ei gilydd) a ffeiliau ffurfweddu a gynhyrchir yn awtomatig (yn aml - wedi'u neilltuo ar gyfer pob nod / rôl). Byddem hefyd am ddefnyddio'r un protocolau o'r un fersiynau ar bob nod cyfathrebu (fel arall byddem yn profi problemau anghydnawsedd). Ym myd JVM mae hyn yn golygu y dylai'r llyfrgell negeseuon o leiaf fod o'r un fersiwn ar bob nod cyfathrebu.

Beth am brofi'r system? Wrth gwrs, dylem gael profion uned ar gyfer yr holl gydrannau cyn dod i brofion integreiddio. Er mwyn gallu allosod canlyniadau profion ar amser rhedeg, dylem sicrhau bod fersiynau pob llyfrgell yn union yr un fath mewn amgylcheddau amser rhedeg ac amgylcheddau profi.

Wrth redeg profion integreiddio, mae'n aml yn llawer haws cael yr un llwybr dosbarth ar bob nod. Does ond angen i ni wneud yn siŵr bod yr un llwybr dosbarth yn cael ei ddefnyddio wrth leoli. (Mae'n bosibl defnyddio gwahanol lwybrau dosbarth ar wahanol nodau, ond mae'n anoddach cynrychioli'r ffurfwedd hon a'i ddefnyddio'n gywir.) Felly er mwyn cadw pethau'n syml byddwn ond yn ystyried llwybrau dosbarth union yr un fath ar bob nod.

Mae cyfluniad yn tueddu i esblygu ynghyd â'r meddalwedd. Rydym fel arfer yn defnyddio fersiynau i nodi amrywiol
camau esblygiad meddalwedd. Mae'n ymddangos yn rhesymol cwmpasu cyfluniad o dan reolaeth fersiwn a nodi gwahanol ffurfweddiadau gyda rhai labeli. Os mai dim ond un ffurfweddiad sydd wrth gynhyrchu, efallai y byddwn yn defnyddio fersiwn sengl fel dynodwr. Weithiau efallai y bydd gennym amgylcheddau cynhyrchu lluosog. Ac ar gyfer pob amgylchedd efallai y bydd angen cangen ar wahân o gyfluniad arnom. Felly gellir labelu ffurfweddiadau gyda changen a fersiwn i nodi gwahanol ffurfweddiadau yn unigryw. Mae pob label cangen a fersiwn yn cyfateb i gyfuniad sengl o nodau dosbarthedig, porthladdoedd, adnoddau allanol, fersiynau llyfrgell llwybr dosbarth ar bob nod. Yma byddwn ond yn cwmpasu'r gangen sengl ac yn nodi ffurfweddau gan fersiwn degol tair cydran (1.2.3), yn yr un modd ag arteffactau eraill.

Mewn amgylcheddau modern nid yw ffeiliau cyfluniad yn cael eu haddasu â llaw mwyach. Yn nodweddiadol rydym yn cynhyrchu
ffurfweddu ffeiliau ar amser defnyddio a peidiwch byth â chyffwrdd â nhw wedyn. Felly gallai rhywun ofyn pam rydyn ni'n dal i ddefnyddio fformat testun ar gyfer ffeiliau ffurfweddu? Opsiwn ymarferol yw gosod y ffurfweddiad y tu mewn i uned grynhoi ac elwa ar ddilysiad cyfluniad amser llunio.

Yn y swydd hon byddwn yn archwilio'r syniad o gadw'r ffurfweddiad yn yr arteffact a luniwyd.

Ffurfweddiad cryno

Yn yr adran hon byddwn yn trafod enghraifft o ffurfweddiad statig. Mae dau wasanaeth syml - gwasanaeth adlais a chleient y gwasanaeth adlais yn cael eu ffurfweddu a'u gweithredu. Yna mae dwy system ddosbarthedig wahanol gyda'r ddau wasanaeth yn cael eu cychwyn. Mae un ar gyfer cyfluniad nod sengl ac un arall ar gyfer cyfluniad dau nod.

Mae system ddosbarthedig nodweddiadol yn cynnwys ychydig o nodau. Gellir adnabod y nodau gan ddefnyddio rhyw fath:

sealed trait NodeId
case object Backend extends NodeId
case object Frontend extends NodeId

neu dim ond

case class NodeId(hostName: String)

neu hyd yn oed

object Singleton
type NodeId = Singleton.type

Mae'r nodau hyn yn cyflawni rolau amrywiol, yn rhedeg rhai gwasanaethau a dylent allu cyfathrebu â'r nodau eraill trwy gysylltiadau TCP/HTTP.

Ar gyfer cysylltiad TCP mae angen o leiaf rhif porthladd. Rydym hefyd am wneud yn siŵr bod cleient a gweinydd yn siarad yr un protocol. Er mwyn modelu cysylltiad rhwng nodau gadewch i ni ddatgan y dosbarth canlynol:

case class TcpEndPoint[Protocol](node: NodeId, port: Port[Protocol])

lle Port yn ddim ond Int o fewn yr ystod a ganiateir:

type PortNumber = Refined[Int, Closed[_0, W.`65535`.T]]

Mathau wedi'u mireinio

Gweler wedi'i mireinio llyfrgell. Yn fyr, mae'n caniatáu ychwanegu cyfyngiadau amser llunio at fathau eraill. Yn yr achos hwn Int dim ond gwerthoedd 16-did sy'n gallu cynrychioli rhif porthladd yn cael ei ganiatáu. Nid oes unrhyw ofyniad i ddefnyddio'r llyfrgell hon ar gyfer y dull ffurfweddu hwn. Mae'n ymddangos ei fod yn cyd-fynd yn dda iawn.

Ar gyfer HTTP (REST) ​​efallai y bydd angen llwybr o'r gwasanaeth arnom hefyd:

type UrlPathPrefix = Refined[String, MatchesRegex[W.`"[a-zA-Z_0-9/]*"`.T]]
case class PortWithPrefix[Protocol](portNumber: PortNumber, pathPrefix: UrlPathPrefix)

Math Phantom

Er mwyn nodi protocol yn ystod y broses o lunio, rydym yn defnyddio'r nodwedd Scala o ddatgan math dadl Protocol nad yw'n cael ei ddefnyddio yn y dosbarth. Mae'n enw fel y'i gelwir math rhith. Ar amser rhedeg anaml y mae angen enghraifft o ddynodwr protocol, dyna pam nad ydym yn ei storio. Yn ystod y cyfnod llunio mae'r math rhithiol hwn yn rhoi diogelwch math ychwanegol. Ni allwn basio porthladd gyda phrotocol anghywir.

Un o'r protocolau a ddefnyddir fwyaf yw REST API gyda chyfresoli Json:

sealed trait JsonHttpRestProtocol[RequestMessage, ResponseMessage]

lle RequestMessage yw'r math sylfaenol o negeseuon y gall cleient eu hanfon at y gweinydd a ResponseMessage yw'r neges ymateb gan y gweinydd. Wrth gwrs, efallai y byddwn yn creu disgrifiadau protocol eraill sy'n nodi'r protocol cyfathrebu gyda'r manwl gywirdeb a ddymunir.

At ddibenion y swydd hon byddwn yn defnyddio fersiwn symlach o'r protocol:

sealed trait SimpleHttpGetRest[RequestMessage, ResponseMessage]

Yn y protocol hwn mae neges cais yn cael ei atodi i url a neges ymateb yn cael ei dychwelyd fel llinyn plaen.

Gellid disgrifio cyfluniad gwasanaeth yn ôl enw'r gwasanaeth, casgliad o borthladdoedd a rhai dibyniaethau. Mae yna ychydig o ffyrdd posibl o sut i gynrychioli'r holl elfennau hyn yn Scala (er enghraifft, HList, mathau o ddata algebraidd). At ddibenion y swydd hon byddwn yn defnyddio Patrwm Cacen ac yn cynrychioli darnau cyfunadwy (modiwlau) fel nodweddion. (Nid yw Patrwm Cacen yn ofyniad ar gyfer y dull cyfluniad cryno hwn. Dim ond un gweithrediad posibl o'r syniad ydyw.)

Gellid cynrychioli dibyniaethau gan ddefnyddio'r Patrwm Cacen fel diweddbwyntiau nodau eraill:

  type EchoProtocol[A] = SimpleHttpGetRest[A, A]

  trait EchoConfig[A] extends ServiceConfig {
    def portNumber: PortNumber = 8081
    def echoPort: PortWithPrefix[EchoProtocol[A]] = PortWithPrefix[EchoProtocol[A]](portNumber, "echo")
    def echoService: HttpSimpleGetEndPoint[NodeId, EchoProtocol[A]] = providedSimpleService(echoPort)
  }

Dim ond porth wedi'i ffurfweddu sydd ei angen ar wasanaeth eco. Ac rydym yn datgan bod y porthladd hwn yn cefnogi protocol adlais. Sylwch nad oes angen i ni nodi porthladd penodol ar hyn o bryd, oherwydd mae nodweddion yn caniatáu datganiadau dulliau haniaethol. Os byddwn yn defnyddio dulliau haniaethol, bydd angen gweithredu casglwr mewn enghraifft ffurfweddiad. Yma rydym wedi darparu'r gweithrediad (8081) a bydd yn cael ei ddefnyddio fel y gwerth diofyn os byddwn yn ei hepgor mewn cyfluniad concrit.

Gallwn ddatgan dibyniaeth yng nghyfluniad y cleient gwasanaeth adleisio:

  trait EchoClientConfig[A] {
    def testMessage: String = "test"
    def pollInterval: FiniteDuration
    def echoServiceDependency: HttpSimpleGetEndPoint[_, EchoProtocol[A]]
  }

Mae gan ddibyniaeth yr un math â'r echoService. Yn benodol, mae'n gofyn am yr un protocol. Felly, gallwn fod yn sicr os byddwn yn cysylltu'r ddwy ddibyniaeth hon y byddant yn gweithio'n gywir.

Gweithredu gwasanaethau

Mae gwasanaeth angen swyddogaeth i ddechrau a chau i lawr yn osgeiddig. (Mae'r gallu i gau gwasanaeth yn hanfodol ar gyfer profi.) Unwaith eto mae yna ychydig o opsiynau o nodi swyddogaeth o'r fath ar gyfer ffurfwedd benodol (er enghraifft, gallem ddefnyddio dosbarthiadau math). Ar gyfer y swydd hon byddwn yn defnyddio Patrwm Cacen eto. Gallwn gynrychioli gwasanaeth gan ddefnyddio cats.Resource sydd eisoes yn darparu bracedu a rhyddhau adnoddau. Er mwyn caffael adnodd dylem ddarparu cyfluniad a rhywfaint o gyd-destun amser rhedeg. Felly efallai y bydd swyddogaeth cychwyn y gwasanaeth yn edrych fel:

  type ResourceReader[F[_], Config, A] = Reader[Config, Resource[F, A]]

  trait ServiceImpl[F[_]] {
    type Config
    def resource(
      implicit
      resolver: AddressResolver[F],
      timer: Timer[F],
      contextShift: ContextShift[F],
      ec: ExecutionContext,
      applicative: Applicative[F]
    ): ResourceReader[F, Config, Unit]
  }

lle

  • Config — math o ffurfweddiad sy'n ofynnol gan y dechreuwr gwasanaeth hwn
  • AddressResolver — gwrthrych amser rhedeg sydd â'r gallu i gael cyfeiriadau gwirioneddol nodau eraill (darllenwch ymlaen am fanylion).

y mathau eraill yn dod o cats:

  • F[_] — math o effaith (Yn yr achos symlaf F[A] gallai fod yn gyfiawn () => A. Yn y post hwn byddwn yn defnyddio cats.IO.)
  • Reader[A,B] — fwy neu lai yn gyfystyr ar gyfer swyddogaeth A => B
  • cats.Resource — mae ganddo ffyrdd o gaffael a rhyddhau
  • Timer — caniatáu cysgu/mesur amser
  • ContextShift - analog o ExecutionContext
  • Applicative — amlapiwr swyddogaethau mewn gwirionedd (monad bron) (efallai y byddwn yn rhoi rhywbeth arall yn ei le yn y pen draw)

Gan ddefnyddio'r rhyngwyneb hwn gallwn weithredu ychydig o wasanaethau. Er enghraifft, gwasanaeth nad yw'n gwneud dim:

  trait ZeroServiceImpl[F[_]] extends ServiceImpl[F] {
    type Config <: Any
    def resource(...): ResourceReader[F, Config, Unit] =
      Reader(_ => Resource.pure[F, Unit](()))
  }

(Gweler Cod ffynhonnell ar gyfer gweithredu gwasanaethau eraill — gwasanaeth adlais,
cleient adlais ac rheolwyr oes.)

Mae nod yn wrthrych unigol sy'n rhedeg ychydig o wasanaethau (mae cychwyn cadwyn o adnoddau wedi'i alluogi gan Patrwm Cacen):

object SingleNodeImpl extends ZeroServiceImpl[IO]
  with EchoServiceService
  with EchoClientService
  with FiniteDurationLifecycleServiceImpl
{
  type Config = EchoConfig[String] with EchoClientConfig[String] with FiniteDurationLifecycleConfig
}

Sylwch ein bod yn y nod yn nodi'r union fath o ffurfweddiad sydd ei angen ar y nod hwn. Ni fydd casglwr yn gadael i ni adeiladu'r gwrthrych (Cacen) heb ddigon o fath, oherwydd mae pob nodwedd gwasanaeth yn datgan cyfyngiad ar y Config math. Hefyd, ni fyddwn yn gallu cychwyn nod heb ddarparu cyfluniad cyflawn.

Cydraniad cyfeiriad nod

Er mwyn sefydlu cysylltiad mae angen cyfeiriad gwesteiwr go iawn arnom ar gyfer pob nod. Efallai ei fod yn hysbys yn ddiweddarach na rhannau eraill o'r cyfluniad. Felly, mae angen ffordd i gyflenwi mapio rhwng nod id a'i gyfeiriad gwirioneddol. Mae'r mapio hwn yn swyddogaeth:

case class NodeAddress[NodeId](host: Uri.Host)
trait AddressResolver[F[_]] {
  def resolve[NodeId](nodeId: NodeId): F[NodeAddress[NodeId]]
}

Mae yna ychydig o ffyrdd posibl o weithredu swyddogaeth o'r fath.

  1. Os ydym yn gwybod cyfeiriadau gwirioneddol cyn eu defnyddio, yn ystod amrantiad gwesteiwr nodau, yna gallwn gynhyrchu cod Scala gyda'r cyfeiriadau gwirioneddol a rhedeg yr adeilad wedyn (sy'n perfformio gwiriadau amser llunio ac yna'n rhedeg cyfres prawf integreiddio). Yn yr achos hwn mae ein swyddogaeth fapio yn hysbys yn statig a gellir ei symleiddio i rywbeth fel a Map[NodeId, NodeAddress].
  2. Weithiau byddwn yn cael cyfeiriadau gwirioneddol dim ond yn ddiweddarach pan fydd y nod wedi'i gychwyn mewn gwirionedd, neu nid oes gennym gyfeiriadau nodau nad ydynt wedi'u cychwyn eto. Yn yr achos hwn efallai y bydd gennym wasanaeth darganfod sy'n cael ei gychwyn cyn pob nod arall a gallai pob nod hysbysebu ei gyfeiriad yn y gwasanaeth hwnnw a thanysgrifio i ddibyniaethau.
  3. Os gallwn addasu /etc/hosts, gallwn ddefnyddio enwau gwesteiwr wedi'u diffinio ymlaen llaw (fel my-project-main-node ac echo-backend) a chysylltwch yr enw hwn â'r cyfeiriad ip adeg defnyddio.

Yn y swydd hon nid ydym yn ymdrin â'r achosion hyn yn fwy manwl. Mewn gwirionedd yn ein hesiampl tegan bydd gan bob nod yr un cyfeiriad IP — 127.0.0.1.

Yn y swydd hon byddwn yn ystyried dau gynllun system ddosbarthedig:

  1. Cynllun nod sengl, lle mae'r holl wasanaethau'n cael eu gosod ar yr un nod.
  2. Cynllun dau nod, lle mae'r gwasanaeth a'r cleient ar nodau gwahanol.

Mae'r cyfluniad ar gyfer a nod sengl mae'r gosodiad fel a ganlyn:

Cyfluniad nod sengl

object SingleNodeConfig extends EchoConfig[String] 
  with EchoClientConfig[String] with FiniteDurationLifecycleConfig
{
  case object Singleton // identifier of the single node 
  // configuration of server
  type NodeId = Singleton.type
  def nodeId = Singleton

  /** Type safe service port specification. */
  override def portNumber: PortNumber = 8088

  // configuration of client

  /** We'll use the service provided by the same host. */
  def echoServiceDependency = echoService

  override def testMessage: UrlPathElement = "hello"

  def pollInterval: FiniteDuration = 1.second

  // lifecycle controller configuration
  def lifetime: FiniteDuration = 10500.milliseconds // additional 0.5 seconds so that there are 10 requests, not 9.
}

Yma rydym yn creu un ffurfweddiad sy'n ymestyn cyfluniad gweinydd a chleient. Hefyd rydym yn ffurfweddu rheolydd cylch bywyd a fydd fel arfer yn terfynu cleient a gweinydd ar ôl lifetime pasys egwyl.

Gellir defnyddio'r un set o weithrediadau a chyfluniadau gwasanaeth i greu cynllun system gyda dau nod ar wahân. Mae angen i ni greu dau configs nod ar wahân gyda’r gwasanaethau priodol:

Cyfluniad dau nod

  object NodeServerConfig extends EchoConfig[String] with SigTermLifecycleConfig
  {
    type NodeId = NodeIdImpl

    def nodeId = NodeServer

    override def portNumber: PortNumber = 8080
  }

  object NodeClientConfig extends EchoClientConfig[String] with FiniteDurationLifecycleConfig
  {
    // NB! dependency specification
    def echoServiceDependency = NodeServerConfig.echoService

    def pollInterval: FiniteDuration = 1.second

    def lifetime: FiniteDuration = 10500.milliseconds // additional 0.5 seconds so that there are 10 request, not 9.

    def testMessage: String = "dolly"
  }

Gweler sut rydym yn nodi'r ddibyniaeth. Soniwn am wasanaeth a ddarperir gan y nodau eraill fel dibyniaeth ar y nod presennol. Mae'r math o ddibyniaeth yn cael ei wirio oherwydd ei fod yn cynnwys math ffug sy'n disgrifio protocol. Ac ar amser rhedeg bydd gennym yr id nod cywir. Dyma un o agweddau pwysig y dull cyfluniad arfaethedig. Mae'n rhoi'r gallu i ni osod porthladd unwaith yn unig a gwneud yn siŵr ein bod yn cyfeirio at y porthladd cywir.

Gweithredu dau nod

Ar gyfer y cyfluniad hwn rydym yn defnyddio'r un gweithrediadau gwasanaethau yn union. Dim newidiadau o gwbl. Fodd bynnag, rydym yn creu dau weithrediad nod gwahanol sy'n cynnwys set wahanol o wasanaethau:

  object TwoJvmNodeServerImpl extends ZeroServiceImpl[IO] with EchoServiceService with SigIntLifecycleServiceImpl {
    type Config = EchoConfig[String] with SigTermLifecycleConfig
  }

  object TwoJvmNodeClientImpl extends ZeroServiceImpl[IO] with EchoClientService with FiniteDurationLifecycleServiceImpl {
    type Config = EchoClientConfig[String] with FiniteDurationLifecycleConfig
  }

Mae'r nod cyntaf yn gweithredu gweinydd a dim ond cyfluniad ochr y gweinydd sydd ei angen arno. Mae'r ail nod yn gweithredu cleient ac mae angen rhan arall o config. Mae angen rhywfaint o fanyleb oes ar y ddau nod. At ddibenion y gwasanaeth post hwn bydd gan nod gwasanaeth anfeidrol y gellid ei derfynu gan ddefnyddio SIGTERM, tra bydd cleient adlais yn dod i ben ar ôl y cyfnod cyfyngedig wedi'i ffurfweddu. Gweler y cais cychwynnol am fanylion.

Proses ddatblygu gyffredinol

Gadewch i ni weld sut mae'r dull hwn yn newid y ffordd yr ydym yn gweithio gyda chyfluniad.

Bydd y ffurfweddiad fel cod yn cael ei lunio ac yn cynhyrchu arteffact. Mae'n ymddangos yn rhesymol gwahanu arteffact cyfluniad oddi wrth arteffactau cod eraill. Yn aml gallwn gael llu o ffurfweddiadau ar yr un sylfaen cod. Ac wrth gwrs, gallwn gael fersiynau lluosog o wahanol ganghennau cyfluniad. Mewn ffurfweddiad gallwn ddewis fersiynau penodol o lyfrgelloedd a bydd hyn yn aros yn gyson pryd bynnag y byddwn yn defnyddio'r ffurfwedd hon.

Mae newid cyfluniad yn dod yn newid cod. Felly dylai gael ei gwmpasu gan yr un broses sicrhau ansawdd:

Tocyn -> Cysylltiadau Cyhoeddus -> adolygu -> uno -> integreiddio parhaus -> defnydd parhaus

Mae canlyniadau'r dull gweithredu canlynol:

  1. Mae'r ffurfweddiad yn gydlynol ar gyfer enghraifft system benodol. Mae'n ymddangos nad oes unrhyw ffordd i gael cysylltiad anghywir rhwng nodau.
  2. Nid yw'n hawdd newid cyfluniad mewn un nod yn unig. Mae'n ymddangos yn afresymol mewngofnodi a newid rhai ffeiliau testun. Felly mae drifft cyfluniad yn dod yn llai posibl.
  3. Nid yw newidiadau cyfluniad bach yn hawdd i'w gwneud.
  4. Bydd y rhan fwyaf o'r newidiadau cyfluniad yn dilyn yr un broses ddatblygu, a bydd yn pasio rhywfaint o adolygiad.

A oes angen ystorfa ar wahân arnom ar gyfer cyfluniad cynhyrchu? Gallai'r ffurfweddiad cynhyrchu gynnwys gwybodaeth sensitif yr hoffem ei chadw allan o gyrraedd llawer o bobl. Felly efallai y byddai'n werth cadw ystorfa ar wahân gyda mynediad cyfyngedig a fydd yn cynnwys y ffurfwedd cynhyrchu. Efallai y byddwn yn rhannu'r cyfluniad yn ddwy ran - un sy'n cynnwys y paramedrau cynhyrchu mwyaf agored ac un sy'n cynnwys rhan gyfrinachol y cyfluniad. Byddai hyn yn galluogi mynediad i'r rhan fwyaf o'r datblygwyr i'r mwyafrif helaeth o baramedrau tra'n cyfyngu mynediad i bethau sensitif iawn. Mae'n hawdd cyflawni hyn gan ddefnyddio nodweddion canolradd gyda gwerthoedd paramedr rhagosodedig.

amrywiadau

Gadewch i ni weld manteision ac anfanteision y dull arfaethedig o'i gymharu â'r technegau rheoli cyfluniad eraill.

Yn gyntaf oll, byddwn yn rhestru ychydig o ddewisiadau amgen i'r gwahanol agweddau ar y ffordd arfaethedig o ddelio â chyfluniad:

  1. Ffeil testun ar y peiriant targed.
  2. Storfa ganolog gwerth allwedd (fel etcd/zookeeper).
  3. Cydrannau is-brosesu y gellid eu hailgyflunio/ailgychwyn heb ailgychwyn y broses.
  4. Ffurfweddiad y tu allan i reolaeth arteffactau a fersiynau.

Mae ffeil testun yn rhoi rhywfaint o hyblygrwydd o ran atgyweiriadau ad-hoc. Gall gweinyddwr system fewngofnodi i'r nod targed, gwneud newid ac ailgychwyn y gwasanaeth. Efallai na fydd hyn cystal ar gyfer systemau mwy. Nid oes unrhyw olion ar ôl i'r newid. Nid yw'r newid yn cael ei adolygu gan bâr arall o lygaid. Gall fod yn anodd darganfod beth sydd wedi achosi'r newid. Nid yw wedi cael ei brofi. O safbwynt system ddosbarthedig, gall gweinyddwr anghofio diweddaru'r ffurfweddiad yn un o'r nodau eraill.

(Btw, os bydd angen dechrau defnyddio ffeiliau ffurfweddu testun yn y pen draw, dim ond parser + dilysydd fydd yn rhaid i ni ei ychwanegu a allai gynhyrchu'r un peth Config teipiwch a byddai hynny'n ddigon i ddechrau defnyddio ffurfweddiadau testun. Mae hyn hefyd yn dangos bod cymhlethdod cyfluniad amser llunio ychydig yn llai na chymhlethdod cyfluniadau testun, oherwydd mewn fersiwn testun mae angen rhywfaint o god ychwanegol arnom.)

Mae storio gwerth allweddol canolog yn fecanwaith da ar gyfer dosbarthu paramedrau meta cymwysiadau. Yma mae angen inni feddwl am yr hyn yr ydym yn ei ystyried yn werthoedd cyfluniad a beth yw data yn unig. O gael swyddogaeth C => A => B fel arfer rydym yn galw gwerthoedd sy'n newid yn anaml C "cyfluniad", tra bod data'n cael ei newid yn aml A - dim ond mewnbynnu data. Dylid darparu cyfluniad i'r swyddogaeth yn gynharach na'r data A. O ystyried y syniad hwn gallwn ddweud ei fod yn amledd newidiadau disgwyliedig yr hyn y gellid ei ddefnyddio i wahaniaethu rhwng data ffurfwedd a data yn unig. Hefyd mae data fel arfer yn dod o un ffynhonnell (defnyddiwr) a chyfluniad yn dod o ffynhonnell wahanol (gweinyddol). Mae delio â pharamedrau y gellir eu newid ar ôl y broses gychwyn yn arwain at gynnydd yng nghymhlethdod y cais. Ar gyfer paramedrau o'r fath bydd yn rhaid i ni drin eu mecanwaith cyflwyno, dosrannu a dilysu, gan drin gwerthoedd anghywir. Felly, er mwyn lleihau cymhlethdod rhaglenni, byddai'n well i ni leihau nifer y paramedrau a all newid yn ystod amser rhedeg (neu hyd yn oed eu dileu yn gyfan gwbl).

O safbwynt y swydd hon dylem wahaniaethu rhwng paramedrau statig a deinamig. Os yw rhesymeg gwasanaeth yn gofyn am newid prin rhai paramedrau ar amser rhedeg, yna efallai y byddwn yn eu galw'n baramedrau deinamig. Fel arall, maent yn statig a gellid eu ffurfweddu gan ddefnyddio'r dull arfaethedig. Ar gyfer ad-drefnu deinamig efallai y bydd angen dulliau eraill. Er enghraifft, efallai y bydd rhannau o'r system yn cael eu hailddechrau gyda'r paramedrau cyfluniad newydd mewn ffordd debyg i ailgychwyn prosesau ar wahân system ddosbarthedig.
(Fy marn ostyngedig yw osgoi ad-drefnu amser rhedeg oherwydd ei fod yn cynyddu cymhlethdod y system.
Gallai fod yn symlach dibynnu ar gefnogaeth OS i ailgychwyn prosesau. Er, efallai na fydd bob amser yn bosibl.)

Un agwedd bwysig ar ddefnyddio cyfluniad statig sydd weithiau'n gwneud i bobl ystyried cyfluniad deinamig (heb resymau eraill) yw amser segur gwasanaeth yn ystod diweddariad cyfluniad. Yn wir, os oes rhaid i ni wneud newidiadau i ffurfweddiad statig, mae'n rhaid i ni ailgychwyn y system fel bod gwerthoedd newydd yn dod yn effeithiol. Mae'r gofynion ar gyfer amser segur yn amrywio ar gyfer systemau gwahanol, felly efallai na fydd mor hanfodol â hynny. Os yw'n hanfodol, yna mae'n rhaid i ni gynllunio ymlaen llaw ar gyfer unrhyw system ailgychwyn. Er enghraifft, gallem weithredu Cysylltiad AWS ELB yn draenio. Yn y senario hwn pryd bynnag y bydd angen i ni ailgychwyn y system, rydym yn dechrau enghraifft newydd o'r system ochr yn ochr, yna'n newid ELB iddi, tra'n gadael i'r hen system gwblhau gwasanaethu'r cysylltiadau presennol.

Beth am gadw cyfluniad y tu mewn i arteffact fersiwniedig neu'r tu allan? Mae cadw cyfluniad y tu mewn i arteffact yn golygu yn y rhan fwyaf o achosion bod y cyfluniad hwn wedi pasio'r un broses sicrhau ansawdd ag arteffactau eraill. Felly efallai y bydd rhywun yn sicr bod y cyfluniad o ansawdd da ac yn ddibynadwy. I'r gwrthwyneb, mae ffurfweddiad mewn ffeil ar wahân yn golygu nad oes unrhyw olion o bwy a pham y gwnaeth newidiadau i'r ffeil honno. Ydy hyn yn bwysig? Credwn ei bod yn well cael cyfluniad sefydlog o ansawdd uchel ar gyfer y rhan fwyaf o systemau cynhyrchu.

Mae fersiwn o'r arteffact yn caniatáu i chi ddarganfod pryd y cafodd ei greu, pa werthoedd sydd ynddo, pa nodweddion sy'n cael eu galluogi / anabl, pwy oedd yn gyfrifol am wneud pob newid yn y ffurfweddiad. Efallai y bydd angen peth ymdrech i gadw cyfluniad y tu mewn i arteffact ac mae'n ddewis dylunio i'w wneud.

Manteision ac anfanteision

Yma hoffem dynnu sylw at rai manteision a thrafod rhai o anfanteision y dull arfaethedig.

manteision

Nodweddion cyfluniad cryno system ddosbarthedig gyflawn:

  1. Gwiriad statig o gyfluniad. Mae hyn yn rhoi lefel uchel o hyder, bod y ffurfweddiad yn gywir o ystyried cyfyngiadau math.
  2. Iaith gyfluniad gyfoethog. Yn nodweddiadol, mae dulliau cyfluniad eraill wedi'u cyfyngu i amnewidion amrywiol ar y mwyaf.
    Gan ddefnyddio Scala gall un ddefnyddio ystod eang o nodweddion iaith i wneud cyfluniad yn well. Er enghraifft, gallwn ddefnyddio nodweddion i ddarparu gwerthoedd diofyn, gwrthrychau i osod cwmpas gwahanol, y gallwn gyfeirio atynt vals diffinio unwaith yn unig yn y cwmpas allanol (Sych). Mae'n bosibl defnyddio dilyniannau llythrennol, neu enghreifftiau o ddosbarthiadau penodol (Seq, Map, Etc).
  3. DSL. Mae gan Scala gefnogaeth weddus i awduron DSL. Gall un ddefnyddio'r nodweddion hyn i sefydlu iaith gyfluniad sy'n fwy cyfleus a chyfeillgar i'r defnyddiwr terfynol, fel bod y cyfluniad terfynol o leiaf yn ddarllenadwy gan ddefnyddwyr parth.
  4. Uniondeb a chydlyniad ar draws nodau. Un o fanteision cael cyfluniad ar gyfer y system ddosbarthedig gyfan mewn un lle yw bod yr holl werthoedd yn cael eu diffinio'n llym unwaith ac yna'n cael eu hailddefnyddio ym mhob man lle mae eu hangen arnom. Hefyd teipiwch ddatganiadau porthladd diogel yn sicrhau y bydd nodau'r system yn siarad yr un iaith ym mhob ffurfweddiad cywir posibl. Mae dibyniaethau amlwg rhwng nodau sy'n ei gwneud hi'n anodd anghofio darparu rhai gwasanaethau.
  5. Newidiadau o ansawdd uchel. Mae'r dull cyffredinol o basio newidiadau cyfluniad trwy'r broses cysylltiadau cyhoeddus arferol yn sefydlu safonau ansawdd uchel hefyd mewn cyfluniad.
  6. Newidiadau cyfluniad ar yr un pryd. Pryd bynnag y byddwn yn gwneud unrhyw newidiadau yn y cyfluniad, mae defnyddio'n awtomatig yn sicrhau bod pob nod yn cael ei ddiweddaru.
  7. Symleiddio cais. Nid oes angen i'r rhaglen ddosrannu a dilysu cyfluniad a thrin gwerthoedd cyfluniad anghywir. Mae hyn yn symleiddio'r cais cyffredinol. (Mae rhywfaint o gynnydd cymhlethdod yn y cyfluniad ei hun, ond mae'n gyfaddawd ymwybodol tuag at ddiogelwch.) Mae'n eithaf syml dychwelyd i gyfluniad cyffredin - ychwanegwch y darnau coll. Mae'n haws dechrau gyda chyfluniad wedi'i lunio a gohirio gweithredu darnau ychwanegol i rai amseroedd diweddarach.
  8. Ffurfweddiad fersiwn. Oherwydd y ffaith bod newidiadau cyfluniad yn dilyn yr un broses ddatblygu, o ganlyniad rydym yn cael arteffact gyda fersiwn unigryw. Mae'n ein galluogi i newid cyfluniad yn ôl os oes angen. Gallwn hyd yn oed ddefnyddio ffurfwedd a ddefnyddiwyd flwyddyn yn ôl a bydd yn gweithio yn union yr un ffordd. Mae cyfluniad sefydlog yn gwella rhagweladwyedd a dibynadwyedd y system ddosbarthedig. Mae'r ffurfweddiad yn sefydlog ar amser llunio ac ni ellir ei ymyrryd yn hawdd ar system gynhyrchu.
  9. Modiwlaidd. Mae'r fframwaith arfaethedig yn fodiwlaidd a gellid cyfuno modiwlau mewn amrywiol ffyrdd i
    cefnogi gwahanol ffurfweddiadau (gosodiadau / gosodiadau). Yn benodol, mae'n bosibl cael cynllun nod sengl ar raddfa fach a gosodiad aml-nodyn ar raddfa fawr. Mae'n rhesymol cael cynlluniau cynhyrchu lluosog.
  10. Profi. At ddibenion profi efallai y bydd rhywun yn gweithredu gwasanaeth ffug a'i ddefnyddio fel dibyniaeth mewn ffordd ddiogel. Gellid cynnal ychydig o wahanol gynlluniau profi gyda rhannau amrywiol yn lle rhai ffug ar yr un pryd.
  11. Profi integreiddio. Weithiau mewn systemau gwasgaredig mae'n anodd cynnal profion integreiddio. Gan ddefnyddio'r dull a ddisgrifir ar gyfer ffurfweddiad math diogel o'r system ddosbarthedig gyflawn, gallwn redeg yr holl rannau dosbarthedig ar un gweinydd mewn ffordd y gellir ei rheoli. Mae'n hawdd efelychu'r sefyllfa
    pan na fydd un o'r gwasanaethau ar gael.

Anfanteision

Mae'r dull ffurfweddu a luniwyd yn wahanol i gyfluniad “normal” ac efallai na fydd yn addas ar gyfer pob angen. Dyma rai o anfanteision y ffurfwedd a luniwyd:

  1. Cyfluniad statig. Efallai na fydd yn addas ar gyfer pob cais. Mewn rhai achosion mae angen gosod y cyfluniad cynhyrchu yn gyflym gan osgoi'r holl fesurau diogelwch. Mae'r dull hwn yn ei gwneud hi'n anoddach. Mae angen y crynhoad a'r adleoli ar ôl gwneud unrhyw newid yn y cyfluniad. Dyma'r nodwedd a'r baich.
  2. Ffurfweddu cenhedlaeth. Pan fydd cyfluniad yn cael ei gynhyrchu gan ryw offeryn awtomeiddio mae angen llunio'r dull hwn wedyn (a allai yn ei dro fethu). Efallai y bydd angen ymdrech ychwanegol i integreiddio'r cam ychwanegol hwn i'r system adeiladu.
  3. Offerynnau. Mae yna lawer o offer yn cael eu defnyddio heddiw sy'n dibynnu ar gyfluniadau testun. Rhai ohonyn nhw
    ni fydd yn berthnasol pan fydd y cyfluniad yn cael ei lunio.
  4. Mae angen newid meddylfryd. Mae datblygwyr a DevOps yn gyfarwydd â ffeiliau ffurfweddu testun. Efallai y bydd y syniad o lunio cyfluniad yn ymddangos yn rhyfedd iddynt.
  5. Cyn cyflwyno ffurfweddiad y gellir ei grynhoi, mae angen proses datblygu meddalwedd o ansawdd uchel.

Mae rhai cyfyngiadau ar yr enghraifft a weithredwyd:

  1. Os byddwn yn darparu cyfluniad ychwanegol nad yw gweithrediad y nod yn ei ofyn, ni fydd casglwr yn ein helpu i ganfod y gweithrediad absennol. Gellid mynd i'r afael â hyn trwy ddefnyddio HList neu ADTs (dosbarthiadau achos) ar gyfer cyfluniad nodau yn lle nodweddion a Phatrwm Cacen.
  2. Mae'n rhaid i ni ddarparu rhywfaint o boelerplat yn y ffeil ffurfweddu: (package, import, object datganiadau;
    override def's ar gyfer paramedrau sydd â gwerthoedd rhagosodedig). Gellir mynd i'r afael â hyn yn rhannol gan ddefnyddio DSL.
  3. Yn y swydd hon nid ydym yn ymdrin ag ad-drefnu deinamig o glystyrau o nodau tebyg.

Casgliad

Yn y swydd hon rydym wedi trafod y syniad o gynrychioli cyfluniad yn uniongyrchol yn y cod ffynhonnell mewn ffordd math diogel. Gellid defnyddio'r dull hwn mewn llawer o gymwysiadau yn lle xml- a chyfluniadau eraill sy'n seiliedig ar destun. Er gwaethaf bod ein hesiampl wedi'i rhoi ar waith yn Scala, gellid ei chyfieithu hefyd i ieithoedd crynodol eraill (fel Kotlin, C#, Swift, ac ati). Gallai rhywun roi cynnig ar y dull hwn mewn prosiect newydd a, rhag ofn nad yw'n ffitio'n dda, newid i'r ffordd hen ffasiwn.

Wrth gwrs, mae ffurfweddiad y gellir ei lunio yn gofyn am broses ddatblygu o ansawdd uchel. Yn gyfnewid, mae'n addo darparu cyfluniad cadarn o ansawdd yr un mor uchel.

Gellir ymestyn y dull hwn mewn gwahanol ffyrdd:

  1. Gallai un ddefnyddio macros i berfformio dilysiad cyfluniad a methu ar amser llunio rhag ofn y bydd unrhyw fethiannau o ran cyfyngiadau rhesymeg busnes.
  2. Gellid gweithredu DSL i gynrychioli ffurfweddiad mewn ffordd sy'n hawdd i'w defnyddio gan barthau.
  3. Rheoli adnoddau deinamig gydag addasiadau cyfluniad awtomatig. Er enghraifft, pan fyddwn yn addasu nifer y nodau clwstwr efallai y byddwn am (1) y nodau i gael cyfluniad wedi'i addasu ychydig; (2) rheolwr clwstwr i dderbyn gwybodaeth nodau newydd.

diolch

Hoffwn ddiolch i Andrey Saksonov, Pavel Popov, Anton Nehaev am roi adborth ysbrydoledig ar ddrafft y swydd hon a helpodd fi i'w wneud yn gliriach.

Ffynhonnell: hab.com