Ffurfweddiad System Ddosbarthedig Cryno

Hoffwn ddweud wrthych un mecanwaith diddorol ar gyfer gweithio gyda chyfluniad system ddosbarthedig. Cynrychiolir y ffurfweddiad yn uniongyrchol mewn iaith a luniwyd (Scala) gan ddefnyddio mathau diogel. Mae'r swydd hon yn rhoi enghraifft o gyfluniad o'r fath ac yn trafod gwahanol agweddau ar weithredu cyfluniad wedi'i lunio yn y broses ddatblygu gyffredinol.

Ffurfweddiad System Ddosbarthedig Cryno

(Saesneg)

Cyflwyniad

Mae adeiladu system ddosbarthedig ddibynadwy yn golygu bod pob nod yn defnyddio'r cyfluniad cywir, wedi'i gydamseru â nodau eraill. Mae technolegau DevOps (terraform, ansible neu rywbeth tebyg) fel arfer yn cael eu defnyddio i gynhyrchu ffeiliau ffurfweddu yn awtomatig (yn aml yn benodol ar gyfer pob nod). Hoffem hefyd fod yn siŵr bod pob nod cyfathrebu yn defnyddio protocolau unfath (gan gynnwys yr un fersiwn). Fel arall, bydd anghydnawsedd yn cael ei gynnwys yn ein system ddosbarthedig. Yn y byd JVM, un canlyniad i'r gofyniad hwn yw bod yn rhaid defnyddio'r un fersiwn o'r llyfrgell sy'n cynnwys y negeseuon protocol ym mhobman.

Beth am brofi system ddosbarthedig? Wrth gwrs, rydym yn tybio bod gan bob cydran brofion uned cyn i ni symud ymlaen i brofi integreiddio. (Er mwyn i ni allu allosod canlyniadau profion i amser rhedeg, mae'n rhaid i ni hefyd ddarparu set union yr un fath o lyfrgelloedd yn y cam profi ac yn ystod amser rhedeg.)

Wrth weithio gyda phrofion integreiddio, mae'n aml yn haws defnyddio'r un llwybr dosbarth ym mhobman ar bob nod. Y cyfan sy'n rhaid i ni ei wneud yw sicrhau bod yr un llwybr dosbarth yn cael ei ddefnyddio ar amser rhedeg. (Er ei bod yn gwbl bosibl rhedeg nodau gwahanol gyda llwybrau dosbarth gwahanol, mae hyn yn ychwanegu cymhlethdod at y cyfluniad cyffredinol ac anawsterau gyda phrofion lleoli ac integreiddio.) At ddibenion y swydd hon, rydym yn cymryd y bydd pob nod yn defnyddio'r un llwybr dosbarth.

Mae'r cyfluniad yn esblygu gyda'r cais. Rydym yn defnyddio fersiynau i nodi gwahanol gamau yn esblygiad rhaglenni. Mae'n ymddangos yn rhesymegol nodi gwahanol fersiynau o ffurfweddiadau hefyd. A gosodwch y cyfluniad ei hun yn y system rheoli fersiwn. Os mai dim ond un ffurfweddiad sydd wrth gynhyrchu, yna gallwn ddefnyddio rhif y fersiwn yn syml. Os byddwn yn defnyddio llawer o achosion cynhyrchu, yna bydd angen sawl un arnom
canghennau cyfluniad a label ychwanegol yn ychwanegol at y fersiwn (er enghraifft, enw'r gangen). Fel hyn gallwn nodi'n glir yr union ffurfweddiad. Mae pob dynodwr cyfluniad yn cyfateb yn unigryw i gyfuniad penodol o nodau dosbarthedig, porthladdoedd, adnoddau allanol, a fersiynau llyfrgell. At ddibenion y swydd hon byddwn yn cymryd mai dim ond un gangen sydd a gallwn adnabod y ffurfwedd yn y ffordd arferol gan ddefnyddio tri rhif wedi'u gwahanu gan ddot (1.2.3).

Mewn amgylcheddau modern, anaml y caiff ffeiliau cyfluniad eu creu â llaw. Yn amlach maent yn cael eu cynhyrchu wrth eu defnyddio ac nid ydynt bellach yn cael eu cyffwrdd (fel bod peidiwch â thorri unrhyw beth). Mae cwestiwn naturiol yn codi: pam rydyn ni'n dal i ddefnyddio fformat testun i storio cyfluniad? Ymddengys mai dewis arall ymarferol yw'r gallu i ddefnyddio cod rheolaidd ar gyfer cyfluniad ac elwa ar wiriadau amser llunio.

Yn y swydd hon byddwn yn archwilio'r syniad o gynrychioli cyfluniad y tu mewn i arteffact a luniwyd.

Ffurfweddiad wedi'i lunio

Mae'r adran hon yn rhoi enghraifft o ffurfweddiad statig a luniwyd. Mae dau wasanaeth syml yn cael eu gweithredu - y gwasanaeth adleisio a'r cleient gwasanaeth adleisio. Yn seiliedig ar y ddau wasanaeth hyn, mae dau opsiwn system yn cael eu cydosod. Mewn un opsiwn, mae'r ddau wasanaeth wedi'u lleoli ar yr un nod, mewn opsiwn arall - ar nodau gwahanol.

Yn nodweddiadol mae system ddosbarthedig yn cynnwys sawl nod. Gallwch adnabod nodau gan ddefnyddio gwerthoedd o ryw fath NodeId:

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

neu

case class NodeId(hostName: String)

neu hyd yn oed

object Singleton
type NodeId = Singleton.type

Mae nodau'n cyflawni rolau amrywiol, maent yn rhedeg gwasanaethau a gellir sefydlu cysylltiadau TCP/HTTP rhyngddynt.

I ddisgrifio cysylltiad TCP mae angen o leiaf rhif porthladd arnom. Hoffem hefyd adlewyrchu'r protocol a gefnogir ar y porthladd hwnnw i sicrhau bod y cleient a'r gweinydd yn defnyddio'r un protocol. Byddwn yn disgrifio'r cysylltiad gan ddefnyddio'r dosbarth canlynol:

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

lle Port - dim ond cyfanrif Int gan nodi'r ystod o werthoedd derbyniol:

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

Mathau wedi'u mireinio

Gweler y llyfrgell wedi'i mireinio и fy adroddiad. Yn fyr, mae'r llyfrgell yn caniatáu ichi ychwanegu cyfyngiadau at fathau sy'n cael eu gwirio ar amser llunio. Yn yr achos hwn, mae gwerthoedd rhif porthladd dilys yn gyfanrifau 16-bit. Ar gyfer cyfluniad wedi'i lunio, nid yw defnyddio'r llyfrgell wedi'i mireinio yn orfodol, ond mae'n gwella gallu'r casglwr i wirio'r ffurfweddiad.

Ar gyfer protocolau HTTP (REST), yn ogystal â rhif y porthladd, efallai y bydd angen y llwybr i'r gwasanaeth arnom hefyd:

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

Mathau o Phantom

I nodi'r protocol ar amser llunio, rydym yn defnyddio paramedr math nad yw'n cael ei ddefnyddio o fewn y dosbarth. Mae'r penderfyniad hwn oherwydd y ffaith nad ydym yn defnyddio enghraifft protocol ar amser rhedeg, ond hoffem i'r casglwr wirio cydnawsedd protocol. Drwy nodi'r protocol, ni fyddwn yn gallu pasio gwasanaeth amhriodol fel dibyniaeth.

Un o'r protocolau cyffredin yw'r API REST gyda chyfresoli Json:

sealed trait JsonHttpRestProtocol[RequestMessage, ResponseMessage]

lle RequestMessage - math o gais, ResponseMessage - math o ymateb.
Wrth gwrs, gallwn ddefnyddio disgrifiadau protocol eraill sy'n darparu'r cywirdeb disgrifiad sydd ei angen arnom.

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

sealed trait SimpleHttpGetRest[RequestMessage, ResponseMessage]

Yma mae'r cais yn llinyn sydd wedi'i atodi i'r url a'r ymateb yw'r llinyn a ddychwelwyd yng nghorff yr ymateb HTTP.

Disgrifir cyfluniad y gwasanaeth gan enw'r gwasanaeth, porthladdoedd a dibyniaethau. Gellir cynrychioli'r elfennau hyn yn Scala mewn sawl ffordd (er enghraifft, HList-s, mathau o ddata algebraidd). At ddibenion y swydd hon, byddwn yn defnyddio'r Patrwm Cacen ac yn cynrychioli modiwlau gan ddefnyddio trait'ov. (Nid yw’r Patrwm Cacen yn elfen ofynnol o’r dull hwn. Yn syml, un gweithrediad posibl ydyw.)

Gellir cynrychioli dibyniaethau rhwng gwasanaethau fel dulliau sy'n dychwelyd porthladdoedd EndPointo 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)
  }

I greu gwasanaeth adlais, y cyfan sydd ei angen arnoch yw rhif porthladd ac arwydd bod y porthladd yn cefnogi'r protocol adleisio. Efallai na fyddwn yn nodi porthladd penodol, oherwydd ... mae nodweddion yn caniatáu ichi ddatgan dulliau heb eu gweithredu (dulliau haniaethol). Yn yr achos hwn, wrth greu cyfluniad concrit, byddai'r casglwr yn ei gwneud yn ofynnol i ni ddarparu gweithrediad y dull haniaethol a darparu rhif porthladd. Gan ein bod wedi gweithredu'r dull, wrth greu cyfluniad penodol, efallai na fyddwn yn nodi porthladd gwahanol. Bydd y gwerth diofyn yn cael ei ddefnyddio.

Yn y ffurfweddiad cleient rydym yn datgan dibyniaeth ar y gwasanaeth adleisio:

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

Mae'r ddibyniaeth o'r un math â'r gwasanaeth sy'n cael ei allforio echoService. Yn benodol, yn y cleient adlais mae angen yr un protocol arnom. Felly, wrth gysylltu dau wasanaeth, gallwn fod yn sicr y bydd popeth yn gweithio’n iawn.

Gweithredu gwasanaethau

Mae angen swyddogaeth i ddechrau a stopio'r gwasanaeth. (Mae'r gallu i atal y gwasanaeth yn hanfodol ar gyfer profi.) Unwaith eto, mae sawl opsiwn ar gyfer gweithredu nodwedd o'r fath (er enghraifft, gallem ddefnyddio dosbarthiadau math yn seiliedig ar y math o gyfluniad). At ddibenion y swydd hon byddwn yn defnyddio'r Patrwm Cacen. Byddwn yn cynrychioli'r gwasanaeth gan ddefnyddio dosbarth cats.Resource, achos Mae'r dosbarth hwn eisoes yn darparu modd o warantu rhyddhau adnoddau yn ddiogel rhag ofn y bydd problemau. I gael adnodd, mae angen i ni ddarparu cyfluniad a chyd-destun amser rhedeg parod. Gall swyddogaeth cychwyn y gwasanaeth edrych fel hyn:

  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 cyfluniad ar gyfer y gwasanaeth hwn
  • AddressResolver — gwrthrych amser rhedeg sy'n eich galluogi i ddarganfod cyfeiriadau nodau eraill (gweler isod)

a mathau eraill o'r llyfrgell cats:

  • F[_] — math o effaith (yn yr achos symlaf F[A] gallai fod yn swyddogaeth yn unig () => A. Yn y swydd hon byddwn yn defnyddio cats.IO.)
  • Reader[A,B] - fwy neu lai yn gyfystyr â swyddogaeth A => B
  • cats.Resource - adnodd y gellir ei gael a'i ryddhau
  • Timer - amserydd (yn caniatáu ichi syrthio i gysgu am ychydig a mesur cyfnodau amser)
  • ContextShift - analog ExecutionContext
  • Applicative — dosbarth math o effaith sy'n eich galluogi i gyfuno effeithiau unigol (bron monad). Mewn cymwysiadau mwy cymhleth mae'n ymddangos yn well eu defnyddio Monad/ConcurrentEffect.

Gan ddefnyddio'r llofnod swyddogaeth hwn gallwn weithredu sawl gwasanaeth. 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](()))
  }

(Cm. ffynhonnell, lle mae gwasanaethau eraill yn cael eu gweithredu - gwasanaeth adlais, cleient adlais
и rheolwyr oes.)

Mae nod yn wrthrych a all lansio sawl gwasanaeth (sicrheir lansiad cadwyn o adnoddau gan y 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 nodi'r union fath o ffurfweddiad sydd ei angen ar gyfer y nod hwn. Os byddwn yn anghofio nodi un o'r mathau o gyfluniadau sy'n ofynnol gan wasanaeth penodol, bydd gwall llunio. Hefyd, ni fyddwn yn gallu cychwyn nod oni bai ein bod yn darparu rhyw wrthrych o'r math priodol gyda'r holl ddata angenrheidiol.

Datrys Enw Gwesteiwr

I gysylltu â gwesteiwr o bell, mae angen cyfeiriad IP go iawn arnom. Mae'n bosibl y bydd y cyfeiriad yn dod yn hysbys yn ddiweddarach na gweddill y ffurfweddiad. Felly mae angen swyddogaeth sy'n mapio ID y nod i gyfeiriad:

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

Mae sawl ffordd o weithredu'r swyddogaeth hon:

  1. Os daw'r cyfeiriadau yn hysbys i ni cyn eu defnyddio, yna gallwn gynhyrchu cod Scala gyda
    cyfeiriadau ac yna rhedeg yr adeilad. Bydd hyn yn llunio ac yn rhedeg profion.
    Yn yr achos hwn, bydd y swyddogaeth yn cael ei hadnabod yn statig a gellir ei chynrychioli mewn cod fel mapio Map[NodeId, NodeAddress].
  2. Mewn rhai achosion, dim ond ar ôl i'r nod ddechrau y bydd y cyfeiriad gwirioneddol yn hysbys.
    Yn yr achos hwn, gallwn weithredu “gwasanaeth darganfod” sy'n rhedeg cyn nodau eraill a bydd pob nod yn cofrestru gyda'r gwasanaeth hwn ac yn gofyn am gyfeiriadau nodau eraill.
  3. Os gallwn addasu /etc/hosts, yna gallwch chi ddefnyddio enwau gwesteiwr wedi'u diffinio ymlaen llaw (fel my-project-main-node и echo-backend) a chysylltwch yr enwau hyn yn syml
    gyda chyfeiriadau IP yn ystod y defnydd.

Yn y swydd hon ni fyddwn yn ystyried yr achosion hyn yn fwy manwl. Ar gyfer ein
mewn enghraifft tegan, bydd gan bob nod yr un cyfeiriad IP - 127.0.0.1.

Nesaf, rydym yn ystyried dau opsiwn ar gyfer system ddosbarthedig:

  1. Gosod yr holl wasanaethau ar un nod.
  2. A chynnal y gwasanaeth adlais a'r cleient adlais ar wahanol nodau.

Ffurfweddiad ar gyfer un nôd:

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.
}

Mae'r gwrthrych yn gweithredu ffurfweddiad y cleient a'r gweinydd. Defnyddir cyfluniad amser-i-fyw hefyd fel bod ar ôl yr egwyl lifetime terfynu'r rhaglen. (Mae Ctrl-C hefyd yn gweithio ac yn rhyddhau'r holl adnoddau'n gywir.)

Gellir defnyddio'r un set o nodweddion cyfluniad a gweithredu i greu system sy'n cynnwys dau nod ar wahân:

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"
  }

Pwysig! Sylwch sut mae'r gwasanaethau wedi'u cysylltu. Rydym yn nodi gwasanaeth a weithredir gan un nod fel gweithrediad dull dibyniaeth nod arall. Mae'r math o ddibyniaeth yn cael ei wirio gan y casglwr, oherwydd yn cynnwys y math o brotocol. Pan gaiff ei redeg, bydd y ddibyniaeth yn cynnwys yr ID nod targed cywir. Diolch i'r cynllun hwn, rydym yn nodi rhif y porthladd yn union unwaith ac rydym bob amser yn sicr o gyfeirio at y porthladd cywir.

Gweithredu dau nod system

Ar gyfer y cyfluniad hwn, rydym yn defnyddio'r un gweithrediadau gwasanaeth heb newidiadau. Yr unig wahaniaeth yw bod gennym bellach ddau wrthrych sy'n gweithredu gwahanol setiau 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'r gweinydd a dim ond cyfluniad gweinydd sydd ei angen. Mae'r ail nod yn gweithredu'r cleient ac yn defnyddio rhan wahanol o'r cyfluniad. Hefyd mae angen rheolaeth oes ar y ddau nod. Mae nod y gweinydd yn rhedeg am gyfnod amhenodol nes iddo gael ei atal SIGTERM'om, ac mae'r nod cleient yn terfynu ar ôl peth amser. Cm. app lansiwr.

Proses datblygu cyffredinol

Gadewch i ni weld sut mae'r dull cyfluniad hwn yn effeithio ar y broses ddatblygu gyffredinol.

Bydd y ffurfweddiad yn cael ei lunio ynghyd â gweddill y cod a bydd arteffact (.jar) yn cael ei gynhyrchu. Mae'n ymddangos ei bod yn gwneud synnwyr i roi'r ffurfweddiad mewn arteffact ar wahân. Mae hyn oherwydd y gallwn gael ffurfweddiadau lluosog yn seiliedig ar yr un cod. Unwaith eto, mae'n bosibl cynhyrchu arteffactau sy'n cyfateb i wahanol ganghennau cyfluniad. Mae dibyniaethau ar fersiynau penodol o lyfrgelloedd yn cael eu cadw ynghyd â'r ffurfweddiad, a chaiff y fersiynau hyn eu cadw am byth pryd bynnag y byddwn yn penderfynu defnyddio'r fersiwn honno o'r ffurfweddiad.

Mae unrhyw newid cyfluniad yn troi'n newid cod. Ac felly, pob un
bydd y newid yn cael ei gwmpasu gan y broses sicrhau ansawdd arferol:

Tocyn yn y traciwr bygiau -> PR -> adolygu -> uno â changhennau perthnasol ->
integreiddio -> lleoli

Prif ganlyniadau gweithredu cyfluniad wedi'i lunio yw:

  1. Bydd y ffurfweddiad yn gyson ar draws holl nodau'r system ddosbarthedig. Oherwydd y ffaith bod pob nod yn derbyn yr un ffurfweddiad o un ffynhonnell.

  2. Mae'n broblemus newid y ffurfwedd mewn un o'r nodau yn unig. Felly, mae “drifft cyfluniad” yn annhebygol.

  3. Mae'n dod yn anoddach gwneud newidiadau bach i'r cyfluniad.

  4. Bydd y rhan fwyaf o newidiadau cyfluniad yn digwydd fel rhan o'r broses ddatblygu gyffredinol a byddant yn cael eu hadolygu.

A oes angen ystorfa ar wahân arnaf i storio'r cyfluniad cynhyrchu? Gall y ffurfweddiad hwn gynnwys cyfrineiriau a gwybodaeth sensitif arall yr hoffem gyfyngu mynediad iddynt. Yn seiliedig ar hyn, mae'n ymddangos ei bod yn gwneud synnwyr i storio'r cyfluniad terfynol mewn ystorfa ar wahân. Gallwch rannu'r ffurfweddiad yn ddwy ran - un yn cynnwys gosodiadau cyfluniad sy'n hygyrch i'r cyhoedd ac un sy'n cynnwys gosodiadau cyfyngedig. Bydd hyn yn caniatáu i'r rhan fwyaf o ddatblygwyr gael mynediad i osodiadau cyffredin. Mae'r gwahaniad hwn yn hawdd i'w gyflawni gan ddefnyddio nodweddion canolradd sy'n cynnwys gwerthoedd rhagosodedig.

Amrywiadau posibl

Gadewch i ni geisio cymharu'r cyfluniad a luniwyd gyda rhai dewisiadau amgen cyffredin:

  1. Ffeil testun ar y peiriant targed.
  2. Storfa gwerth allwedd ganolog (etcd/zookeeper).
  3. Cydrannau proses y gellir eu hailgyflunio / ailgychwyn heb ailgychwyn y broses.
  4. Storio cyfluniad y tu allan i reolaeth arteffact a fersiwn.

Mae ffeiliau testun yn darparu hyblygrwydd sylweddol o ran newidiadau bach. Gall gweinyddwr y system fewngofnodi i'r nod anghysbell, gwneud newidiadau i'r ffeiliau priodol ac ailgychwyn y gwasanaeth. Ar gyfer systemau mawr, fodd bynnag, efallai na fydd hyblygrwydd o'r fath yn ddymunol. Nid yw'r newidiadau a wnaed yn gadael unrhyw olion mewn systemau eraill. Nid oes neb yn adolygu'r newidiadau. Mae'n anodd penderfynu pwy yn union wnaeth y newidiadau ac am ba reswm. Nid yw newidiadau yn cael eu profi. Os dosberthir y system, yna efallai y bydd y gweinyddwr yn anghofio gwneud y newid cyfatebol ar nodau eraill.

(Dylid nodi hefyd nad yw defnyddio cyfluniad a luniwyd yn cau'r posibilrwydd o ddefnyddio ffeiliau testun yn y dyfodol. Bydd yn ddigon i ychwanegu parser a dilysydd sy'n cynhyrchu'r un math ag allbwn Config, a gallwch ddefnyddio ffeiliau testun. Mae'n dilyn yn syth bod cymhlethdod system gyda chyfluniad wedi'i lunio ychydig yn llai na chymhlethdod system sy'n defnyddio ffeiliau testun, oherwydd mae angen cod ychwanegol ar ffeiliau testun.)

Mae storfa gwerth allweddol ganolog yn fecanwaith da ar gyfer dosbarthu paramedrau meta cymhwysiad dosbarthedig. Mae angen inni benderfynu beth yw paramedrau cyfluniad a beth yw data yn unig. Gadewch inni gael swyddogaeth C => A => B, a'r paramedrau C anaml yn newid, a data A - aml. Yn yr achos hwn gallwn ddweud hynny C - paramedrau cyfluniad, a A - data. Mae'n ymddangos bod paramedrau cyfluniad yn wahanol i ddata gan eu bod yn gyffredinol yn newid yn llai aml na data. Hefyd, mae data fel arfer yn dod o un ffynhonnell (gan y defnyddiwr), a pharamedrau cyfluniad o un arall (gan weinyddwr y system).

Os bydd angen diweddaru paramedrau sy'n newid yn anaml heb ailgychwyn y rhaglen, yna gall hyn yn aml arwain at gymhlethdod y rhaglen, oherwydd bydd angen i ni rywsut ddarparu paramedrau, storio, dosrannu a gwirio, a phrosesu gwerthoedd anghywir. Felly, o safbwynt lleihau cymhlethdod y rhaglen, mae'n gwneud synnwyr i leihau nifer y paramedrau a all newid yn ystod gweithrediad y rhaglen (neu beidio â chefnogi paramedrau o'r fath o gwbl).

At ddibenion y swydd hon, byddwn yn gwahaniaethu rhwng paramedrau statig a deinamig. Os yw rhesymeg y gwasanaeth yn gofyn am newid paramedrau yn ystod gweithrediad y rhaglen, yna byddwn yn galw paramedrau o'r fath yn ddeinamig. Fel arall, mae'r opsiynau'n statig a gellir eu ffurfweddu gan ddefnyddio'r ffurfwedd a luniwyd. Ar gyfer ad-drefnu deinamig, efallai y bydd angen mecanwaith i ailgychwyn rhannau o'r rhaglen gyda pharamedrau newydd, yn debyg i sut mae prosesau system weithredu yn cael eu hailddechrau. (Yn ein barn ni, mae'n ddoeth osgoi ad-drefnu amser real, gan fod hyn yn cynyddu cymhlethdod y system. Os yn bosibl, mae'n well defnyddio'r galluoedd OS safonol ar gyfer ailgychwyn prosesau.)

Un agwedd bwysig ar ddefnyddio cyfluniad statig sy'n gwneud i bobl ystyried ad-drefnu deinamig yw'r amser y mae'n ei gymryd i'r system ailgychwyn ar ôl diweddariad cyfluniad (amser segur). Mewn gwirionedd, os oes angen i ni wneud newidiadau i'r cyfluniad statig, bydd yn rhaid i ni ailgychwyn y system er mwyn i'r gwerthoedd newydd ddod i rym. Mae'r broblem amser segur yn amrywio o ran difrifoldeb ar gyfer gwahanol systemau. Mewn rhai achosion, gallwch drefnu ailgychwyn ar adeg pan fo'r llwyth yn fach iawn. Os oes angen i chi ddarparu gwasanaeth parhaus, gallwch chi weithredu Cysylltiad AWS ELB yn draenio. Ar yr un pryd, pan fydd angen i ni ailgychwyn y system, rydym yn lansio enghraifft gyfochrog o'r system hon, yn newid y balancer iddo, ac yn aros i'r hen gysylltiadau gael eu cwblhau. Ar ôl i'r holl hen gysylltiadau ddod i ben, rydyn ni'n cau'r hen enghraifft o'r system.

Gadewch inni nawr ystyried y mater o storio'r cyfluniad y tu mewn neu'r tu allan i'r arteffact. Os ydym yn storio'r cyfluniad y tu mewn i arteffact, yna o leiaf cawsom gyfle i wirio cywirdeb y ffurfweddiad yn ystod cydosod yr arteffact. Os yw'r ffurfweddiad y tu allan i'r arteffact rheoledig, mae'n anodd olrhain pwy wnaeth newidiadau i'r ffeil hon a pham. Pa mor bwysig yw e? Yn ein barn ni, ar gyfer llawer o systemau cynhyrchu mae'n bwysig cael cyfluniad sefydlog ac o ansawdd uchel.

Mae'r fersiwn o arteffact yn caniatáu ichi benderfynu pryd y cafodd ei greu, pa werthoedd sydd ynddo, pa swyddogaethau sy'n cael eu galluogi / anabl, a phwy sy'n gyfrifol am unrhyw newid yn y ffurfweddiad. Wrth gwrs, mae angen rhywfaint o ymdrech i storio'r cyfluniad y tu mewn i arteffact, felly mae angen i chi wneud penderfyniad gwybodus.

Y manteision a'r anfanteision

Hoffwn ganolbwyntio ar fanteision ac anfanteision y dechnoleg arfaethedig.

Manteision

Isod mae rhestr o brif nodweddion cyfluniad system ddosbarthedig wedi'i llunio:

  1. Gwiriad cyfluniad statig. Yn caniatáu ichi fod yn siŵr hynny
    mae'r cyfluniad yn gywir.
  2. Iaith ffurfweddu gyfoethog. Yn nodweddiadol, mae dulliau cyfluniad eraill yn gyfyngedig i amnewid newidyn llinynnol ar y mwyaf. Wrth ddefnyddio Scala, mae ystod eang o nodweddion iaith ar gael i wella'ch ffurfweddiad. Er enghraifft, gallwn ddefnyddio
    nodweddion ar gyfer gwerthoedd rhagosodedig, gan ddefnyddio gwrthrychau i baramedrau grŵp, gallwn gyfeirio at vals datgan dim ond unwaith (Sych) yn y cwmpas amgáu. Gallwch chi gychwyn unrhyw ddosbarthiadau yn syth y tu mewn i'r ffurfweddiad (Seq, Map, dosbarthiadau arfer).
  3. DSL. Mae gan Scala nifer o nodweddion iaith sy'n ei gwneud hi'n haws creu DSL. Mae'n bosibl manteisio ar y nodweddion hyn a gweithredu iaith ffurfweddu sy'n fwy cyfleus i'r grŵp targed o ddefnyddwyr, fel bod y cyfluniad o leiaf yn ddarllenadwy gan arbenigwyr parth. Gall arbenigwyr, er enghraifft, gymryd rhan yn y broses adolygu cyfluniad.
  4. Uniondeb a chydamseriad rhwng nodau. Un o fanteision cael cyfluniad system ddosbarthedig gyfan wedi'i storio ar un pwynt yw bod yr holl werthoedd yn cael eu datgan yn union unwaith ac yna'n cael eu hailddefnyddio lle bynnag y mae eu hangen. Mae defnyddio mathau ffug i ddatgan porthladdoedd yn sicrhau bod nodau'n defnyddio protocolau cydnaws ym mhob ffurfwedd system gywir. Mae cael dibyniaethau gorfodol amlwg rhwng nodau yn sicrhau bod pob gwasanaeth wedi'i gysylltu.
  5. Newidiadau o ansawdd uchel. Mae gwneud newidiadau i'r cyfluniad gan ddefnyddio proses ddatblygu gyffredin yn ei gwneud hi'n bosibl cyflawni safonau ansawdd uchel ar gyfer y ffurfweddiad hefyd.
  6. Diweddariad cyfluniad ar y pryd. Mae gosod system yn awtomatig ar ôl newidiadau cyfluniad yn sicrhau bod pob nod yn cael ei ddiweddaru.
  7. Symleiddio'r cais. Nid oes angen dosrannu, gwirio cyfluniad na thrin gwerthoedd anghywir ar y rhaglen. Mae hyn yn lleihau cymhlethdod y cais. (Nid yw peth o'r cymhlethdod cyfluniad a welwyd yn ein hesiampl yn nodwedd o'r cyfluniad a luniwyd, ond dim ond penderfyniad ymwybodol sy'n cael ei yrru gan yr awydd i ddarparu mwy o ddiogelwch math.) Mae'n eithaf hawdd dychwelyd i'r cyfluniad arferol - dim ond gweithredu'r goll. rhannau. Felly, gallwch chi, er enghraifft, ddechrau gyda chyfluniad wedi'i lunio, gan ohirio gweithredu rhannau diangen tan yr amser pan fo'i wir angen.
  8. Ffurfweddiad wedi'i wirio. Gan fod newidiadau cyfluniad yn dilyn tynged arferol unrhyw newidiadau eraill, mae'r allbwn a gawn yn arteffact gyda fersiwn unigryw. Mae hyn yn ein galluogi, er enghraifft, i ddychwelyd i fersiwn flaenorol o'r ffurfweddiad os oes angen. Gallwn hyd yn oed ddefnyddio'r ffurfweddiad o flwyddyn yn ôl a bydd y system yn gweithio'n union yr un peth. Mae cyfluniad sefydlog yn gwella rhagweladwyedd a dibynadwyedd system ddosbarthedig. Gan fod y cyfluniad yn sefydlog yn y cam llunio, mae'n eithaf anodd ei ffugio wrth gynhyrchu.
  9. Modiwlaidd. Mae'r fframwaith arfaethedig yn fodiwlaidd a gellir cyfuno'r modiwlau mewn gwahanol ffyrdd i greu systemau gwahanol. Yn benodol, gallwch chi ffurfweddu'r system i redeg ar un nod mewn un ymgorfforiad, ac ar nodau lluosog mewn un arall. Gallwch greu sawl ffurfweddiad ar gyfer achosion cynhyrchu'r system.
  10. Profi. Trwy ddisodli gwasanaethau unigol gyda gwrthrychau ffug, gallwch gael sawl fersiwn o'r system sy'n gyfleus i'w profi.
  11. Profi integreiddio. Mae cael un ffurfweddiad ar gyfer y system ddosbarthedig gyfan yn ei gwneud hi'n bosibl rhedeg yr holl gydrannau mewn amgylchedd rheoledig fel rhan o brofion integreiddio. Mae'n hawdd efelychu, er enghraifft, sefyllfa lle mae rhai nodau'n dod yn hygyrch.

Anfanteision a chyfyngiadau

Mae cyfluniad a luniwyd yn wahanol i ddulliau cyfluniad eraill ac efallai na fydd yn addas ar gyfer rhai cymwysiadau. Isod mae rhai anfanteision:

  1. Cyfluniad statig. Weithiau mae angen i chi gywiro'r cyfluniad wrth gynhyrchu yn gyflym, gan osgoi'r holl fecanweithiau amddiffynnol. Gyda'r dull hwn gall fod yn anoddach. O leiaf, bydd angen casglu a defnyddio'n awtomatig o hyd. Mae hyn yn nodwedd ddefnyddiol o'r dull ac yn anfantais mewn rhai achosion.
  2. Ffurfweddu cenhedlaeth. Rhag ofn y bydd y ffeil ffurfweddu yn cael ei chynhyrchu gan offeryn awtomatig, efallai y bydd angen ymdrechion ychwanegol i integreiddio'r sgript adeiladu.
  3. Offer. Ar hyn o bryd, mae cyfleustodau a thechnegau a gynlluniwyd i weithio gyda chyfluniad yn seiliedig ar ffeiliau testun. Ni fydd yr holl gyfleustodau/technegau o'r fath ar gael mewn ffurfweddiad wedi'i lunio.
  4. Mae angen newid agweddau. Mae datblygwyr a DevOps yn gyfarwydd â ffeiliau testun. Gall yr union syniad o lunio ffurfwedd fod braidd yn annisgwyl ac yn anarferol ac achosi gwrthod.
  5. Mae angen proses ddatblygu o ansawdd uchel. Er mwyn defnyddio'r cyfluniad a luniwyd yn gyfforddus, mae angen awtomeiddio'r broses o adeiladu a defnyddio'r cais (CI/CD) yn llawn. Fel arall bydd yn eithaf anghyfleus.

Gadewch inni hefyd ganolbwyntio ar nifer o gyfyngiadau'r enghraifft ystyriol nad ydynt yn gysylltiedig â'r syniad o gyfluniad wedi'i lunio:

  1. Os byddwn yn darparu gwybodaeth ffurfweddu diangen nad yw'n cael ei defnyddio gan y nod, yna ni fydd y casglwr yn ein helpu i ganfod y gweithrediad coll. Gellir datrys y broblem hon trwy roi'r gorau i'r Patrwm Cacen a defnyddio mathau mwy anhyblyg, er enghraifft, HList neu fathau o ddata algebraidd (dosbarthiadau achos) i gynrychioli cyfluniad.
  2. Mae llinellau yn y ffeil ffurfweddu nad ydynt yn gysylltiedig â'r ffurfwedd ei hun: (package, import,datganiadau gwrthrych; override def's ar gyfer paramedrau sydd â gwerthoedd rhagosodedig). Gellir osgoi hyn yn rhannol os byddwch yn gweithredu eich DSL eich hun. Yn ogystal, mae mathau eraill o gyfluniad (er enghraifft, XML) hefyd yn gosod cyfyngiadau penodol ar strwythur y ffeil.
  3. At ddibenion y swydd hon, nid ydym yn ystyried ad-drefnu deinamig clwstwr o nodau tebyg.

Casgliad

Yn y swydd hon, fe wnaethom archwilio'r syniad o gynrychioli cyfluniad mewn cod ffynhonnell gan ddefnyddio galluoedd uwch system math Scala. Gellir defnyddio'r dull hwn mewn amrywiol gymwysiadau yn lle dulliau ffurfweddu traddodiadol yn seiliedig ar xml neu ffeiliau testun. Er bod ein hesiampl yn cael ei gweithredu yn Scala, gellir trosglwyddo'r un syniadau i ieithoedd eraill a luniwyd (fel Kotlin, C#, Swift, ...). Gallwch roi cynnig ar y dull hwn yn un o'r prosiectau canlynol, ac, os nad yw'n gweithio, symudwch ymlaen i'r ffeil testun, gan ychwanegu'r rhannau coll.

Yn naturiol, mae cyfluniad wedi'i lunio yn gofyn am broses ddatblygu o ansawdd uchel. Yn gyfnewid, sicrheir ansawdd uchel a dibynadwyedd y ffurfweddiadau.

Gellir ehangu’r dull a ystyriwyd:

  1. Gallwch ddefnyddio macros i wneud gwiriadau amser llunio.
  2. Gallwch chi weithredu DSL i gyflwyno'r ffurfweddiad mewn ffordd sy'n hygyrch i ddefnyddwyr terfynol.
  3. Gallwch chi weithredu rheolaeth adnoddau deinamig gydag addasiad cyfluniad awtomatig. Er enghraifft, mae newid nifer y nodau mewn clwstwr yn gofyn (1) bod pob nod yn derbyn cyfluniad ychydig yn wahanol; (2) derbyniodd y rheolwr clwstwr wybodaeth am nodau newydd.

Cydnabyddiaethau

Hoffwn ddiolch i Andrei Saksonov, Pavel Popov ac Anton Nekhaev am eu beirniadaeth adeiladol o'r erthygl ddrafft.

Ffynhonnell: hab.com

Ychwanegu sylw