تقسیم شدہ نظام کی مرتب کنفیگریشن

اس پوسٹ میں ہم تقسیم شدہ نظام کی ترتیب سے نمٹنے کا ایک دلچسپ طریقہ بتانا چاہیں گے۔
ترتیب کو براہ راست اسکالا زبان میں ایک قسم کے محفوظ انداز میں پیش کیا جاتا ہے۔ ایک مثال کے نفاذ کو تفصیل میں بیان کیا گیا ہے۔ تجویز کے مختلف پہلوؤں پر تبادلہ خیال کیا گیا ہے، بشمول مجموعی ترقیاتی عمل پر اثر و رسوخ۔

تقسیم شدہ نظام کی مرتب کنفیگریشن

(روسی میں)

تعارف

مضبوط تقسیم شدہ نظاموں کی تعمیر کے لیے تمام نوڈس پر درست اور مربوط ترتیب کے استعمال کی ضرورت ہوتی ہے۔ ایک عام حل یہ ہے کہ متنی تعیناتی کی تفصیل (ٹیرافارم، قابل جواب یا کچھ یکساں) اور خود کار طریقے سے تیار کردہ کنفیگریشن فائلز (اکثر — ہر نوڈ/رول کے لیے وقف) کا استعمال کریں۔ ہم ہر مواصلاتی نوڈس پر ایک ہی ورژن کے ایک جیسے پروٹوکول کو بھی استعمال کرنا چاہیں گے (بصورت دیگر ہم عدم مطابقت کے مسائل کا سامنا کریں گے)۔ JVM دنیا میں اس کا مطلب ہے کہ کم از کم پیغام رسانی کی لائبریری تمام مواصلاتی نوڈس پر ایک ہی ورژن کی ہونی چاہیے۔

سسٹم کی جانچ کے بارے میں کیا خیال ہے؟ بلاشبہ، انٹیگریشن ٹیسٹ میں آنے سے پہلے ہمیں تمام اجزاء کے یونٹ ٹیسٹ ہونے چاہئیں۔ رن ٹائم پر ٹیسٹ کے نتائج کو نکالنے کے قابل ہونے کے لیے، ہمیں اس بات کو یقینی بنانا چاہیے کہ تمام لائبریریوں کے ورژن رن ٹائم اور ٹیسٹنگ دونوں ماحول میں یکساں رکھے جائیں۔

انٹیگریشن ٹیسٹ چلاتے وقت، تمام نوڈس پر ایک ہی کلاس پاتھ کا ہونا اکثر بہت آسان ہوتا ہے۔ ہمیں صرف یہ یقینی بنانے کی ضرورت ہے کہ تعیناتی پر ایک ہی کلاس پاتھ کا استعمال کیا جائے۔ (مختلف نوڈس پر مختلف کلاس پاتھ استعمال کرنا ممکن ہے، لیکن اس کنفیگریشن کی نمائندگی کرنا اور اسے صحیح طریقے سے تعینات کرنا زیادہ مشکل ہے۔) لہذا چیزوں کو سادہ رکھنے کے لیے ہم تمام نوڈس پر صرف ایک جیسے کلاس پاتھ پر غور کریں گے۔

ترتیب سافٹ ویئر کے ساتھ مل کر تیار ہوتی ہے۔ ہم عام طور پر مختلف کی شناخت کے لیے ورژن استعمال کرتے ہیں۔
سافٹ ویئر کے ارتقاء کے مراحل ورژن کے انتظام کے تحت کنفیگریشن کا احاطہ کرنا اور کچھ لیبلز کے ساتھ مختلف کنفیگریشنز کی شناخت کرنا مناسب معلوم ہوتا ہے۔ اگر پروڈکشن میں صرف ایک کنفیگریشن ہے، تو ہم شناخت کنندہ کے طور پر سنگل ورژن استعمال کر سکتے ہیں۔ بعض اوقات ہمارے پاس متعدد پیداواری ماحول ہو سکتے ہیں۔ اور ہر ماحول کے لیے ہمیں ترتیب کی ایک الگ شاخ کی ضرورت ہو سکتی ہے۔ لہذا مختلف کنفیگریشنز کی منفرد شناخت کرنے کے لیے کنفیگریشنز کو برانچ اور ورژن کے ساتھ لیبل لگایا جا سکتا ہے۔ ہر برانچ لیبل اور ورژن ہر نوڈ پر تقسیم شدہ نوڈس، بندرگاہوں، بیرونی وسائل، کلاس پاتھ لائبریری ورژن کے ایک مجموعہ سے مساوی ہے۔ یہاں ہم صرف ایک شاخ کا احاطہ کریں گے اور کنفیگریشنز کو تین جزو اعشاریہ ورژن (1.2.3) کے ذریعے شناخت کریں گے، اسی طرح دوسرے نمونے کی طرح۔

جدید ماحول میں کنفیگریشن فائلوں کو دستی طور پر تبدیل نہیں کیا جاتا ہے۔ عام طور پر ہم پیدا کرتے ہیں۔
config فائلوں کو تعیناتی کے وقت اور ان کو کبھی نہ چھوئے بعد میں تو کوئی پوچھ سکتا ہے کہ ہم اب بھی کنفیگریشن فائلوں کے لیے ٹیکسٹ فارمیٹ کیوں استعمال کرتے ہیں؟ ایک قابل عمل آپشن یہ ہے کہ کنفیگریشن کو کمپائلیشن یونٹ کے اندر رکھا جائے اور کمپائل ٹائم کنفیگریشن کی توثیق سے فائدہ اٹھایا جائے۔

اس پوسٹ میں ہم مرتب شدہ نمونے میں ترتیب کو برقرار رکھنے کے خیال کا جائزہ لیں گے۔

مرتب کنفیگریشن

اس سیکشن میں ہم جامد ترتیب کی ایک مثال پر بات کریں گے۔ دو آسان خدمات - ایکو سروس اور ایکو سروس کے کلائنٹ کو تشکیل اور لاگو کیا جا رہا ہے۔ پھر دونوں خدمات کے ساتھ دو مختلف تقسیم شدہ نظاموں کو فوری بنایا جاتا ہے۔ ایک سنگل نوڈ کنفیگریشن کے لیے اور دوسرا دو نوڈ کنفیگریشن کے لیے۔

ایک عام تقسیم شدہ نظام چند نوڈس پر مشتمل ہوتا ہے۔ نوڈس کو کچھ قسم کا استعمال کرتے ہوئے شناخت کیا جا سکتا ہے:

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

یا صرف

case class NodeId(hostName: String)

یا اس سے بھی

object Singleton
type NodeId = Singleton.type

یہ نوڈس مختلف کردار ادا کرتے ہیں، کچھ سروسز چلاتے ہیں اور TCP/HTTP کنکشنز کے ذریعے دوسرے نوڈس کے ساتھ بات چیت کرنے کے قابل ہونا چاہیے۔

TCP کنکشن کے لیے کم از کم ایک پورٹ نمبر درکار ہے۔ ہم یہ بھی یقینی بنانا چاہتے ہیں کہ کلائنٹ اور سرور ایک ہی پروٹوکول سے بات کر رہے ہیں۔ نوڈس کے درمیان کنکشن کو ماڈل کرنے کے لیے آئیے درج ذیل کلاس کا اعلان کریں:

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

کہاں Port صرف ایک ہے Int اجازت کی حد کے اندر:

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

بہتر اقسام

ملاحظہ کریں بہتر کتب خانہ. مختصر میں، یہ دوسری اقسام میں مرتب وقت کی رکاوٹوں کو شامل کرنے کی اجازت دیتا ہے۔ اس معاملے میں Int صرف 16 بٹ اقدار کی اجازت ہے جو پورٹ نمبر کی نمائندگی کر سکتی ہے۔ اس ترتیب کے نقطہ نظر کے لیے اس لائبریری کو استعمال کرنے کی کوئی ضرورت نہیں ہے۔ یہ صرف بہت اچھی طرح سے فٹ ہونے لگتا ہے۔

HTTP (REST) ​​کے لیے ہمیں سروس کا راستہ بھی درکار ہو سکتا ہے:

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

پریت کی قسم

تالیف کے دوران پروٹوکول کی شناخت کرنے کے لیے ہم قسم کی دلیل کا اعلان کرنے کی Scala خصوصیت استعمال کر رہے ہیں۔ Protocol جو کلاس میں استعمال نہیں ہوتا۔ یہ ایک نام نہاد ہے۔ پریت کی قسم. رن ٹائم کے وقت ہمیں پروٹوکول شناخت کنندہ کی شاذ و نادر ہی ضرورت ہوتی ہے، اسی لیے ہم اسے ذخیرہ نہیں کرتے ہیں۔ تالیف کے دوران یہ فینٹم قسم اضافی قسم کی حفاظت فراہم کرتی ہے۔ ہم غلط پروٹوکول کے ساتھ پورٹ پاس نہیں کر سکتے۔

سب سے زیادہ استعمال ہونے والے پروٹوکولز میں سے ایک Json سیریلائزیشن کے ساتھ REST API ہے:

sealed trait JsonHttpRestProtocol[RequestMessage, ResponseMessage]

کہاں RequestMessage پیغامات کی بنیادی قسم ہے جو کلائنٹ سرور کو بھیج سکتا ہے اور ResponseMessage سرور کی طرف سے جوابی پیغام ہے۔ بلاشبہ، ہم دیگر پروٹوکول وضاحتیں بنا سکتے ہیں جو مطلوبہ درستگی کے ساتھ کمیونیکیشن پروٹوکول کی وضاحت کرتے ہیں۔

اس پوسٹ کے مقاصد کے لیے ہم پروٹوکول کا ایک آسان ورژن استعمال کریں گے:

sealed trait SimpleHttpGetRest[RequestMessage, ResponseMessage]

اس پروٹوکول میں درخواست کا پیغام یو آر ایل میں شامل کیا جاتا ہے اور جوابی پیغام کو سادہ سٹرنگ کے طور پر واپس کیا جاتا ہے۔

سروس کنفیگریشن کو سروس کے نام، بندرگاہوں کا مجموعہ اور کچھ انحصار سے بیان کیا جا سکتا ہے۔ اسکالا میں ان تمام عناصر کی نمائندگی کرنے کے چند ممکنہ طریقے ہیں (مثال کے طور پر، HList، الجبری ڈیٹا کی اقسام)۔ اس پوسٹ کے مقاصد کے لیے ہم کیک پیٹرن کا استعمال کریں گے اور مشترکہ ٹکڑوں (ماڈیولز) کو خصائل کے طور پر پیش کریں گے۔ (اس مرتب کنفیگریشن اپروچ کے لیے کیک پیٹرن کی ضرورت نہیں ہے۔ یہ خیال کا صرف ایک ممکنہ نفاذ ہے۔)

دیگر نوڈس کے اختتامی نقطہ کے طور پر کیک پیٹرن کا استعمال کرتے ہوئے انحصار کی نمائندگی کی جا سکتی ہے:

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

ایکو سروس کو صرف ایک پورٹ کنفیگر کی ضرورت ہے۔ اور ہم اعلان کرتے ہیں کہ یہ بندرگاہ ایکو پروٹوکول کو سپورٹ کرتی ہے۔ نوٹ کریں کہ ہمیں اس وقت کسی خاص بندرگاہ کی وضاحت کرنے کی ضرورت نہیں ہے، کیونکہ خاصیت تجریدی طریقوں کے اعلانات کی اجازت دیتی ہے۔ اگر ہم تجریدی طریقے استعمال کرتے ہیں تو کمپائلر کو کنفیگریشن مثال میں عمل درآمد کی ضرورت ہوگی۔ یہاں ہم نے نفاذ فراہم کیا ہے (8081) اور اسے ڈیفالٹ ویلیو کے طور پر استعمال کیا جائے گا اگر ہم اسے کنکریٹ کنفیگریشن میں چھوڑ دیتے ہیں۔

ہم ایکو سروس کلائنٹ کی ترتیب میں انحصار کا اعلان کر سکتے ہیں:

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

انحصار کی ایک ہی قسم ہے۔ echoService. خاص طور پر، یہ ایک ہی پروٹوکول کا مطالبہ کرتا ہے. لہذا، ہم یقین کر سکتے ہیں کہ اگر ہم ان دو انحصاروں کو جوڑیں گے تو وہ صحیح طریقے سے کام کریں گے۔

خدمات کا نفاذ

سروس کو شروع کرنے اور خوبصورتی سے بند کرنے کے لیے ایک فنکشن کی ضرورت ہوتی ہے۔ (کسی سروس کو بند کرنے کی اہلیت جانچ کے لیے بہت ضروری ہے۔) ایک بار پھر دی گئی ترتیب کے لیے اس طرح کے فنکشن کی وضاحت کرنے کے چند اختیارات ہیں (مثال کے طور پر، ہم ٹائپ کلاسز استعمال کر سکتے ہیں)۔ اس پوسٹ کے لیے ہم دوبارہ کیک پیٹرن استعمال کریں گے۔ ہم استعمال کرتے ہوئے ایک سروس کی نمائندگی کر سکتے ہیں cats.Resource جو پہلے ہی بریکٹنگ اور وسائل کی رہائی فراہم کرتا ہے۔ وسائل کے حصول کے لیے ہمیں ایک ترتیب اور کچھ رن ٹائم سیاق و سباق فراہم کرنا چاہیے۔ لہذا سروس شروع کرنے کا فنکشن اس طرح نظر آسکتا ہے:

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

کہاں

  • Config - ترتیب کی قسم جو اس سروس اسٹارٹر کو درکار ہے۔
  • AddressResolver - ایک رن ٹائم آبجیکٹ جس میں دوسرے نوڈس کے حقیقی پتے حاصل کرنے کی صلاحیت ہوتی ہے (تفصیلات کے لیے پڑھتے رہیں)۔

دوسری اقسام سے آتے ہیں cats:

  • F[_] - اثر کی قسم (سب سے آسان صورت میں F[A] صرف ہو سکتا ہے () => A. اس پوسٹ میں ہم استعمال کریں گے۔ cats.IO.)
  • Reader[A,B] - کم و بیش کسی فنکشن کا مترادف ہے۔ A => B
  • cats.Resource - حاصل کرنے اور جاری کرنے کے طریقے ہیں۔
  • Timer - سونے / وقت کی پیمائش کرنے کی اجازت دیتا ہے۔
  • ContextShift --.کا ینالاگ n ExecutionContext
  • Applicative - اثر میں افعال کا ریپر (تقریبا ایک مونڈ) (ہم آخرکار اسے کسی اور چیز سے بدل سکتے ہیں)

اس انٹرفیس کا استعمال کرتے ہوئے ہم چند خدمات کو نافذ کر سکتے ہیں۔ مثال کے طور پر، ایسی خدمت جو کچھ نہیں کرتی:

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

(ملاحظہ کریں سورس کوڈ دیگر خدمات کے نفاذ کے لیے - بازگشت سروس,
گونج کلائنٹ اور زندگی بھر کے کنٹرولرز.)

نوڈ ایک واحد شے ہے جو چند خدمات کو چلاتی ہے (وسائل کا سلسلہ شروع کرنا کیک پیٹرن سے فعال ہوتا ہے):

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

نوٹ کریں کہ نوڈ میں ہم درست قسم کی کنفیگریشن بتاتے ہیں جو اس نوڈ کو درکار ہے۔ کمپائلر ہمیں آبجیکٹ (کیک) کو ناکافی قسم کے ساتھ بنانے کی اجازت نہیں دے گا، کیونکہ ہر سروس کی خاصیت اس پر رکاوٹ کا اعلان کرتی ہے۔ Config قسم اس کے علاوہ ہم مکمل کنفیگریشن فراہم کیے بغیر نوڈ شروع نہیں کر سکیں گے۔

نوڈ ایڈریس ریزولوشن

کنکشن قائم کرنے کے لیے ہمیں ہر نوڈ کے لیے ایک حقیقی میزبان ایڈریس کی ضرورت ہوتی ہے۔ یہ ترتیب کے دوسرے حصوں کے مقابلے میں بعد میں معلوم ہو سکتا ہے۔ لہذا، ہمیں نوڈ آئی ڈی اور اس کے اصل ایڈریس کے درمیان میپنگ فراہم کرنے کا ایک طریقہ درکار ہے۔ یہ میپنگ ایک فنکشن ہے:

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

اس طرح کے فنکشن کو نافذ کرنے کے چند ممکنہ طریقے ہیں۔

  1. اگر ہم تعیناتی سے پہلے حقیقی پتے جانتے ہیں، نوڈ ہوسٹ انسٹیٹیشن کے دوران، تو ہم اصل پتوں کے ساتھ Scala کوڈ تیار کر سکتے ہیں اور اس کے بعد بلڈ کو چلا سکتے ہیں (جو کمپائل ٹائم چیک کرتا ہے اور پھر انٹیگریشن ٹیسٹ سوٹ چلاتا ہے)۔ اس صورت میں ہمارے میپنگ فنکشن کو جامد طور پر جانا جاتا ہے اور اسے کچھ آسان بنایا جا سکتا ہے جیسے a Map[NodeId, NodeAddress].
  2. بعض اوقات ہم اصل پتے صرف بعد میں حاصل کرتے ہیں جب نوڈ اصل میں شروع ہوتا ہے، یا ہمارے پاس نوڈس کے ایڈریس نہیں ہوتے ہیں جو ابھی شروع نہیں ہوئے ہیں۔ اس صورت میں ہمارے پاس ایک دریافت سروس ہو سکتی ہے جو دوسرے تمام نوڈس سے پہلے شروع ہوتی ہے اور ہر نوڈ اس سروس میں اپنے ایڈریس کی تشہیر کر سکتا ہے اور انحصار کو سبسکرائب کر سکتا ہے۔
  3. اگر ہم ترمیم کر سکتے ہیں۔ /etc/hosts، ہم پہلے سے طے شدہ میزبان نام استعمال کرسکتے ہیں (جیسے my-project-main-node اور echo-backend) اور تعیناتی کے وقت صرف اس نام کو آئی پی ایڈریس کے ساتھ منسلک کریں۔

اس پوسٹ میں ہم ان کیسز کو مزید تفصیلات میں شامل نہیں کرتے ہیں۔ درحقیقت ہمارے کھلونوں کی مثال میں تمام نوڈس کا ایک ہی IP پتہ ہوگا۔ 127.0.0.1.

اس پوسٹ میں ہم دو تقسیم شدہ نظام کی ترتیب پر غور کریں گے:

  1. سنگل نوڈ لے آؤٹ، جہاں تمام سروسز سنگل نوڈ پر رکھی جاتی ہیں۔
  2. دو نوڈ لے آؤٹ، جہاں سروس اور کلائنٹ مختلف نوڈس پر ہوتے ہیں۔

ایک کے لیے ترتیب سنگل نوڈ ترتیب مندرجہ ذیل ہے:

سنگل نوڈ کنفیگریشن

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

یہاں ہم ایک واحد کنفیگریشن بناتے ہیں جو سرور اور کلائنٹ دونوں کی ترتیب کو بڑھاتا ہے۔ اس کے علاوہ ہم ایک لائف سائیکل کنٹرولر تشکیل دیتے ہیں جو عام طور پر کلائنٹ اور سرور کو ختم کر دے گا۔ lifetime وقفہ گزرتا ہے.

سروس کے نفاذ اور ترتیب کے ایک ہی سیٹ کو دو الگ الگ نوڈس کے ساتھ سسٹم کی ترتیب بنانے کے لیے استعمال کیا جا سکتا ہے۔ ہمیں صرف تخلیق کرنے کی ضرورت ہے۔ دو الگ الگ نوڈ کنفیگرز مناسب خدمات کے ساتھ:

دو نوڈس کی ترتیب

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

دیکھیں کہ ہم انحصار کی وضاحت کیسے کرتے ہیں۔ ہم موجودہ نوڈ کے انحصار کے طور پر دوسرے نوڈ کی فراہم کردہ سروس کا ذکر کرتے ہیں۔ انحصار کی قسم کی جانچ پڑتال کی گئی ہے کیونکہ اس میں پریت کی قسم ہے جو پروٹوکول کو بیان کرتی ہے۔ اور رن ٹائم پر ہمارے پاس صحیح نوڈ آئی ڈی ہوگی۔ یہ مجوزہ ترتیب کے نقطہ نظر کے اہم پہلوؤں میں سے ایک ہے۔ یہ ہمیں صرف ایک بار پورٹ سیٹ کرنے اور اس بات کو یقینی بنانے کی صلاحیت فراہم کرتا ہے کہ ہم صحیح پورٹ کا حوالہ دے رہے ہیں۔

دو نوڈس کا نفاذ

اس ترتیب کے لیے ہم بالکل وہی خدمات کے نفاذ کا استعمال کرتے ہیں۔ بالکل بھی کوئی تبدیلی نہیں۔ تاہم، ہم دو مختلف نوڈ نفاذ بناتے ہیں جن میں خدمات کے مختلف سیٹ ہوتے ہیں:

  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
  }

پہلا نوڈ سرور کو نافذ کرتا ہے اور اسے صرف سرور سائیڈ کنفگ کی ضرورت ہوتی ہے۔ دوسرا نوڈ کلائنٹ کو نافذ کرتا ہے اور اسے تشکیل کے دوسرے حصے کی ضرورت ہوتی ہے۔ دونوں نوڈس کو زندگی بھر کی کچھ تفصیلات درکار ہوتی ہیں۔ اس پوسٹ سروس نوڈ کے مقاصد کے لیے لامحدود زندگی ہوگی جسے استعمال کرتے ہوئے ختم کیا جا سکتا ہے۔ SIGTERM، جبکہ ایکو کلائنٹ کنفیگر شدہ محدود مدت کے بعد ختم ہو جائے گا۔ دیکھیں سٹارٹر کی درخواست تفصیلات کے لئے.

مجموعی ترقی کا عمل

آئیے دیکھتے ہیں کہ یہ نقطہ نظر ہمارے کنفیگریشن کے ساتھ کام کرنے کے طریقے کو کیسے بدلتا ہے۔

کوڈ کے طور پر ترتیب کو مرتب کیا جائے گا اور ایک نمونہ تیار کیا جائے گا۔ کنفیگریشن آرٹفیکٹ کو دوسرے کوڈ آرٹفیکٹس سے الگ کرنا مناسب معلوم ہوتا ہے۔ اکثر ہمارے پاس ایک ہی کوڈ بیس پر بہت سی ترتیبیں ہوسکتی ہیں۔ اور یقینا، ہمارے پاس مختلف کنفیگریشن برانچز کے متعدد ورژن ہو سکتے ہیں۔ ایک کنفیگریشن میں ہم لائبریریوں کے مخصوص ورژن منتخب کر سکتے ہیں اور جب بھی ہم اس کنفیگریشن کو تعینات کریں گے تو یہ مستقل رہے گا۔

ترتیب میں تبدیلی کوڈ کی تبدیلی بن جاتی ہے۔ لہذا اس کا احاطہ اسی کوالٹی اشورینس کے عمل سے کیا جانا چاہئے:

ٹکٹ -> PR -> جائزہ -> انضمام -> مسلسل انضمام -> مسلسل تعیناتی

نقطہ نظر کے مندرجہ ذیل نتائج ہیں:

  1. ترتیب کسی خاص نظام کی مثال کے لیے مربوط ہے۔ ایسا لگتا ہے کہ نوڈس کے درمیان غلط کنکشن کا کوئی طریقہ نہیں ہے۔
  2. صرف ایک نوڈ میں کنفیگریشن کو تبدیل کرنا آسان نہیں ہے۔ لاگ ان کرنا اور کچھ ٹیکسٹ فائلوں کو تبدیل کرنا غیر معقول لگتا ہے۔ لہذا کنفیگریشن ڈرفٹ کم ممکن ہو جاتا ہے۔
  3. چھوٹی کنفیگریشن تبدیلیاں کرنا آسان نہیں ہے۔
  4. زیادہ تر کنفیگریشن تبدیلیاں اسی ترقیاتی عمل کی پیروی کریں گی، اور یہ کچھ جائزہ پاس کرے گی۔

کیا ہمیں پیداوار کی ترتیب کے لیے علیحدہ ذخیرہ کی ضرورت ہے؟ پروڈکشن کنفیگریشن میں حساس معلومات ہو سکتی ہیں جسے ہم بہت سے لوگوں کی پہنچ سے دور رکھنا چاہیں گے۔ لہذا یہ محدود رسائی کے ساتھ ایک علیحدہ ذخیرہ رکھنے کے قابل ہو سکتا ہے جس میں پروڈکشن کنفیگریشن ہو گی۔ ہم کنفیگریشن کو دو حصوں میں تقسیم کر سکتے ہیں - ایک جس میں پروڈکشن کے سب سے زیادہ کھلے پیرامیٹرز ہوتے ہیں اور دوسرا جس میں کنفیگریشن کا خفیہ حصہ ہوتا ہے۔ یہ واقعی حساس چیزوں تک رسائی کو محدود کرتے ہوئے پیرامیٹرز کی وسیع اکثریت تک زیادہ تر ڈویلپرز تک رسائی کے قابل بنائے گا۔ ڈیفالٹ پیرامیٹر اقدار کے ساتھ انٹرمیڈیٹ خصلتوں کا استعمال کرتے ہوئے اسے پورا کرنا آسان ہے۔

تغیرات

آئیے کنفیگریشن مینجمنٹ کی دیگر تکنیکوں کے مقابلے میں مجوزہ نقطہ نظر کے فوائد اور نقصانات کو دیکھتے ہیں۔

سب سے پہلے، ہم ترتیب سے نمٹنے کے مجوزہ طریقے کے مختلف پہلوؤں کے لیے چند متبادلات کی فہرست بنائیں گے:

  1. ٹارگٹ مشین پر ٹیکسٹ فائل۔
  2. مرکزی کلیدی قدر کا ذخیرہ (جیسے etcd/zookeeper).
  3. ذیلی عمل کے اجزاء جو دوبارہ شروع کیے بغیر دوبارہ ترتیب دیئے جاسکتے ہیں۔
  4. آرٹفیکٹ اور ورژن کنٹرول سے باہر کنفیگریشن۔

ٹیکسٹ فائل ایڈہاک اصلاحات کے معاملے میں کچھ لچک دیتی ہے۔ سسٹم کا ایڈمنسٹریٹر ٹارگٹ نوڈ میں لاگ ان کر سکتا ہے، تبدیلی کر سکتا ہے اور بس سروس کو دوبارہ شروع کر سکتا ہے۔ یہ بڑے سسٹمز کے لیے اتنا اچھا نہیں ہو سکتا۔ تبدیلی کے پیچھے کوئی نشان باقی نہیں رہتا۔ تبدیلی کا کسی اور جوڑے کی آنکھوں سے جائزہ نہیں لیا جاتا۔ یہ جاننا مشکل ہو سکتا ہے کہ تبدیلی کی وجہ کیا ہے۔ اس کا تجربہ نہیں کیا گیا ہے۔ تقسیم شدہ نظام کے نقطہ نظر سے ایڈمنسٹریٹر دوسرے نوڈس میں سے کسی ایک میں کنفیگریشن کو اپ ڈیٹ کرنا بھول سکتا ہے۔

(Btw، اگر آخر میں ٹیکسٹ کنفگ فائلوں کا استعمال شروع کرنے کی ضرورت ہو گی، تو ہمیں صرف parser + validator کو شامل کرنا پڑے گا جو ایک ہی پیدا کر سکتا ہے Config ٹائپ کریں اور یہ متن کی تشکیلات کا استعمال شروع کرنے کے لئے کافی ہوگا۔ اس سے یہ بھی ظاہر ہوتا ہے کہ کمپائل ٹائم کنفیگریشن کی پیچیدگی ٹیکسٹ بیسڈ کنفیگریشن کی پیچیدگی سے تھوڑی چھوٹی ہے کیونکہ ٹیکسٹ بیسڈ ورژن میں ہمیں کچھ اضافی کوڈ کی ضرورت ہوتی ہے۔)

سنٹرلائزڈ کلیدی ویلیو اسٹوریج ایپلیکیشن میٹا پیرامیٹرز کی تقسیم کے لیے ایک اچھا طریقہ کار ہے۔ یہاں ہمیں اس بارے میں سوچنے کی ضرورت ہے کہ ہم کنفیگریشن ویلیوز کیا سمجھتے ہیں اور صرف ڈیٹا کیا ہے۔ ایک فنکشن دیا۔ C => A => B ہم عام طور پر شاذ و نادر ہی تبدیل ہونے والی اقدار کو کہتے ہیں۔ C "کنفیگریشن"، جبکہ اکثر ڈیٹا کو تبدیل کیا جاتا ہے۔ A - صرف ان پٹ ڈیٹا۔ ڈیٹا سے پہلے فنکشن کو کنفیگریشن فراہم کی جانی چاہیے۔ A. اس خیال کو دیکھتے ہوئے ہم کہہ سکتے ہیں کہ یہ تبدیلیوں کی متوقع تعدد ہے جسے صرف ڈیٹا سے کنفیگریشن ڈیٹا کو الگ کرنے کے لیے استعمال کیا جا سکتا ہے۔ نیز ڈیٹا عام طور پر ایک ذریعہ (صارف) سے آتا ہے اور ترتیب مختلف ذریعہ (ایڈمن) سے آتی ہے۔ ان پیرامیٹرز سے نمٹنا جنہیں ابتدائی عمل کے بعد تبدیل کیا جا سکتا ہے درخواست کی پیچیدگی میں اضافہ کا باعث بنتا ہے۔ اس طرح کے پیرامیٹرز کے لیے ہمیں ان کی ترسیل کے طریقہ کار، تجزیہ اور توثیق، غلط اقدار کو ہینڈل کرنا پڑے گا۔ لہذا، پروگرام کی پیچیدگی کو کم کرنے کے لیے، ہم بہتر طور پر ان پیرامیٹرز کی تعداد کو کم کریں گے جو رن ٹائم کے وقت تبدیل ہو سکتے ہیں (یا انہیں مکمل طور پر ختم بھی کر سکتے ہیں)۔

اس پوسٹ کے نقطہ نظر سے ہمیں جامد اور متحرک پیرامیٹرز کے درمیان فرق کرنا چاہیے۔ اگر سروس لاجک کو رن ٹائم میں کچھ پیرامیٹرز کی غیر معمولی تبدیلی کی ضرورت ہوتی ہے، تو ہم انہیں ڈائنامک پیرامیٹرز کہہ سکتے ہیں۔ بصورت دیگر وہ جامد ہیں اور مجوزہ نقطہ نظر کا استعمال کرتے ہوئے ترتیب دی جا سکتی ہیں۔ متحرک ری کنفیگریشن کے لیے دوسرے طریقوں کی ضرورت ہو سکتی ہے۔ مثال کے طور پر، نظام کے حصوں کو نئے کنفیگریشن پیرامیٹرز کے ساتھ دوبارہ شروع کیا جا سکتا ہے اسی طرح تقسیم شدہ نظام کے الگ الگ عمل کو دوبارہ شروع کرنے کی طرح۔
(میری عاجزانہ رائے یہ ہے کہ رن ٹائم ری کنفیگریشن سے گریز کیا جائے کیونکہ اس سے سسٹم کی پیچیدگی بڑھ جاتی ہے۔
دوبارہ شروع کرنے کے عمل کے OS سپورٹ پر انحصار کرنا زیادہ سیدھا ہوسکتا ہے۔ اگرچہ، یہ ہمیشہ ممکن نہیں ہوسکتا ہے۔)

جامد کنفیگریشن کے استعمال کا ایک اہم پہلو جو بعض اوقات لوگوں کو متحرک کنفیگریشن پر غور کرنے پر مجبور کرتا ہے (دوسری وجوہات کے بغیر) کنفیگریشن اپ ڈیٹ کے دوران سروس ڈاؤن ٹائم ہے۔ درحقیقت، اگر ہمیں سٹیٹک کنفیگریشن میں تبدیلیاں کرنی ہیں، تو ہمیں سسٹم کو دوبارہ شروع کرنا ہوگا تاکہ نئی قدریں موثر ہوسکیں۔ ڈاؤن ٹائم کے تقاضے مختلف سسٹمز کے لیے مختلف ہوتے ہیں، اس لیے یہ اتنا اہم نہیں ہو سکتا۔ اگر یہ اہم ہے، تو ہمیں کسی بھی نظام کے دوبارہ شروع ہونے کے لیے آگے کی منصوبہ بندی کرنی ہوگی۔ مثال کے طور پر، ہم لاگو کر سکتے ہیں AWS ELB کنکشن کی نکاسی. اس منظر نامے میں جب بھی ہمیں سسٹم کو دوبارہ شروع کرنے کی ضرورت ہوتی ہے، ہم متوازی طور پر سسٹم کی ایک نئی مثال شروع کرتے ہیں، پھر ELB کو اس میں تبدیل کرتے ہیں، جبکہ پرانے سسٹم کو موجودہ کنکشن کی سروسنگ مکمل کرنے دیتے ہیں۔

کنفیگریشن کو ورژنڈ آرٹفیکٹ کے اندر یا باہر رکھنے کے بارے میں کیا خیال ہے؟ کسی نمونے کے اندر کنفیگریشن رکھنے کا مطلب زیادہ تر صورتوں میں یہ ہوتا ہے کہ اس کنفیگریشن نے دوسرے نمونوں کی طرح کوالٹی اشورینس کے عمل کو پاس کیا ہے۔ لہذا کسی کو یقین ہوسکتا ہے کہ ترتیب اچھے معیار اور قابل اعتماد ہے۔ اس کے برعکس ایک علیحدہ فائل میں کنفیگریشن کا مطلب ہے کہ اس فائل میں تبدیلیاں کس نے اور کیوں کی ہیں اس کا کوئی نشان نہیں ہے۔ کیا یہ ضروری ہے؟ ہمیں یقین ہے کہ زیادہ تر پروڈکشن سسٹمز کے لیے مستحکم اور اعلیٰ معیار کی ترتیب کا ہونا بہتر ہے۔

آرٹفیکٹ کا ورژن یہ جاننے کی اجازت دیتا ہے کہ یہ کب بنایا گیا تھا، اس میں کون سی اقدار ہیں، کون سی خصوصیات فعال/غیر فعال ہیں، کنفیگریشن میں ہر تبدیلی کا ذمہ دار کون تھا۔ کسی نمونے کے اندر کنفیگریشن رکھنے کے لیے اسے کچھ محنت درکار ہو سکتی ہے اور یہ ڈیزائن کا انتخاب ہے۔

اچھائی اور برائی

یہاں ہم کچھ فوائد کو اجاگر کرنا چاہتے ہیں اور مجوزہ طریقہ کار کے کچھ نقصانات پر بات کرنا چاہتے ہیں۔

فوائد

مکمل تقسیم شدہ نظام کی مرتب کنفیگریشن کی خصوصیات:

  1. ترتیب کی جامد جانچ۔ اس سے اعلیٰ سطح کا اعتماد ملتا ہے، کہ قسم کی رکاوٹوں کے پیش نظر ترتیب درست ہے۔
  2. ترتیب کی بھرپور زبان۔ عام طور پر دیگر ترتیب کے نقطہ نظر زیادہ تر متغیر متبادل تک محدود ہوتے ہیں۔
    اسکالا کا استعمال کرتے ہوئے کنفیگریشن کو بہتر بنانے کے لیے زبان کی خصوصیات کی ایک وسیع رینج کا استعمال کیا جا سکتا ہے۔ مثال کے طور پر، ہم پہلے سے طے شدہ اقدار فراہم کرنے کے لیے خصلتوں کا استعمال کر سکتے ہیں، مختلف دائرہ کار کو متعین کرنے کے لیے اشیاء، ہم حوالہ دے سکتے ہیں۔ vals کی وضاحت بیرونی دائرہ کار (DRY) میں صرف ایک بار کی گئی ہے۔ لفظی ترتیب، یا بعض کلاسوں کی مثالیں استعمال کرنا ممکن ہے (Seq, Map، وغیرہ).
  3. ڈی ایس ایل۔ اسکالا کو DSL مصنفین کے لئے معقول حمایت حاصل ہے۔ کوئی بھی ان خصوصیات کو کنفیگریشن لینگویج قائم کرنے کے لیے استعمال کر سکتا ہے جو زیادہ آسان اور صارف دوست ہو، تاکہ حتمی کنفیگریشن کم از کم ڈومین صارفین کے لیے پڑھنے کے قابل ہو۔
  4. نوڈس میں سالمیت اور ہم آہنگی۔ پورے تقسیم شدہ نظام کے لیے ایک جگہ پر ترتیب دینے کا ایک فائدہ یہ ہے کہ تمام اقدار کو ایک بار سختی سے بیان کیا جاتا ہے اور پھر ان تمام جگہوں پر دوبارہ استعمال کیا جاتا ہے جہاں ہمیں ان کی ضرورت ہوتی ہے۔ محفوظ پورٹ ڈیکلریشن بھی ٹائپ کریں اس بات کو یقینی بنائیں کہ تمام ممکنہ درست کنفیگریشنز میں سسٹم کے نوڈس ایک ہی زبان بولیں گے۔ نوڈس کے درمیان واضح انحصار ہیں جس کی وجہ سے کچھ خدمات فراہم کرنا بھولنا مشکل ہو جاتا ہے۔
  5. تبدیلیوں کا اعلیٰ معیار۔ عام PR عمل کے ذریعے کنفیگریشن تبدیلیوں کو پاس کرنے کا مجموعی طریقہ کنفیگریشن میں بھی معیار کے اعلیٰ معیارات کو قائم کرتا ہے۔
  6. بیک وقت ترتیب میں تبدیلیاں۔ جب بھی ہم کنفیگریشن میں کوئی تبدیلی کرتے ہیں خودکار تعیناتی یقینی بناتی ہے کہ تمام نوڈس اپ ڈیٹ ہو رہے ہیں۔
  7. درخواست کی آسانیاں۔ ایپلیکیشن کو کنفیگریشن کو پارس اور توثیق کرنے اور کنفیگریشن کی غلط اقدار کو ہینڈل کرنے کی ضرورت نہیں ہے۔ یہ مجموعی درخواست کو آسان بناتا ہے۔ (کچھ پیچیدگی میں اضافہ خود ترتیب میں ہے، لیکن یہ حفاظت کی طرف ایک شعوری تجارت ہے۔) عام کنفیگریشن پر واپس آنا بہت سیدھا ہے — صرف گم شدہ ٹکڑوں کو شامل کریں۔ مرتب کردہ کنفیگریشن کے ساتھ شروع کرنا اور اضافی ٹکڑوں کے نفاذ کو بعد میں کچھ وقت تک ملتوی کرنا آسان ہے۔
  8. ورژن شدہ ترتیب۔ اس حقیقت کی وجہ سے کہ کنفیگریشن تبدیلیاں اسی ترقی کے عمل کی پیروی کرتی ہیں، نتیجے کے طور پر ہمیں منفرد ورژن کے ساتھ ایک نمونہ ملتا ہے۔ یہ ہمیں ضرورت پڑنے پر کنفیگریشن کو واپس سوئچ کرنے کی اجازت دیتا ہے۔ ہم ایک کنفیگریشن بھی لگا سکتے ہیں جو ایک سال پہلے استعمال کی گئی تھی اور یہ بالکل اسی طرح کام کرے گی۔ مستحکم ترتیب تقسیم شدہ نظام کی پیشن گوئی اور وشوسنییتا کو بہتر بناتی ہے۔ ترتیب مرتب وقت پر طے کی جاتی ہے اور پیداواری نظام پر آسانی سے چھیڑ چھاڑ نہیں کی جا سکتی۔
  9. ماڈیولرٹی مجوزہ فریم ورک ماڈیولر ہے اور ماڈیولز کو مختلف طریقوں سے جوڑا جا سکتا ہے۔
    مختلف کنفیگریشنز (سیٹ اپ/لے آؤٹ) کی حمایت کرتے ہیں۔ خاص طور پر، چھوٹے پیمانے پر سنگل نوڈ لے آؤٹ اور بڑے پیمانے پر ملٹی نوڈ سیٹنگ ممکن ہے۔ متعدد پروڈکشن لے آؤٹ کا ہونا مناسب ہے۔
  10. ٹیسٹنگ جانچ کے مقاصد کے لیے کوئی فرضی سروس کو لاگو کر سکتا ہے اور اسے ایک قسم کے محفوظ طریقے سے انحصار کے طور پر استعمال کر سکتا ہے۔ مختلف حصوں کے ساتھ کچھ مختلف ٹیسٹنگ لے آؤٹس کو ایک ساتھ برقرار رکھا جا سکتا ہے۔
  11. انضمام کی جانچ۔ کبھی کبھی تقسیم شدہ نظاموں میں انٹیگریشن ٹیسٹ چلانا مشکل ہوتا ہے۔ مکمل تقسیم شدہ نظام کی محفوظ ترتیب کو ٹائپ کرنے کے لیے بیان کردہ نقطہ نظر کا استعمال کرتے ہوئے، ہم تمام تقسیم شدہ حصوں کو ایک ہی سرور پر قابل کنٹرول طریقے سے چلا سکتے ہیں۔ صورتحال کی تقلید کرنا آسان ہے۔
    جب خدمات میں سے کوئی ایک دستیاب نہ ہو۔

خامیاں

مرتب کردہ ترتیب کا طریقہ "عام" ترتیب سے مختلف ہے اور یہ تمام ضروریات کے مطابق نہیں ہو سکتا۔ یہاں مرتب کردہ ترتیب کے کچھ نقصانات ہیں:

  1. جامد ترتیب۔ ہو سکتا ہے کہ یہ تمام ایپلی کیشنز کے لیے موزوں نہ ہو۔ کچھ معاملات میں تمام حفاظتی اقدامات کو نظرانداز کرتے ہوئے پیداوار میں ترتیب کو فوری طور پر ٹھیک کرنے کی ضرورت ہے۔ یہ نقطہ نظر اسے مزید مشکل بناتا ہے۔ ترتیب میں کوئی تبدیلی کرنے کے بعد تالیف اور دوبارہ تعیناتی کی ضرورت ہے۔ یہ خصوصیت اور بوجھ دونوں ہے۔
  2. کنفیگریشن جنریشن۔ جب config کچھ آٹومیشن ٹول کے ذریعہ تیار کیا جاتا ہے تو اس نقطہ نظر کو بعد میں تالیف کی ضرورت ہوتی ہے (جو بدلے میں ناکام ہوسکتی ہے)۔ اس اضافی قدم کو تعمیراتی نظام میں ضم کرنے کے لیے اضافی کوشش کی ضرورت ہو سکتی ہے۔
  3. آلات آج کل بہت سارے ٹولز استعمال میں ہیں جو ٹیکسٹ پر مبنی کنفیگرز پر انحصار کرتے ہیں۔ ان میں سے کچھ
    کنفیگریشن مرتب ہونے پر لاگو نہیں ہوگا۔
  4. ذہنیت میں تبدیلی کی ضرورت ہے۔ ڈویلپرز اور ڈی او اوپس ٹیکسٹ کنفیگریشن فائلوں سے واقف ہیں۔ ترتیب مرتب کرنے کا خیال ان کے لیے عجیب لگ سکتا ہے۔
  5. مرتب کنفیگریشن کو متعارف کرانے سے پہلے ایک اعلیٰ معیار کے سافٹ ویئر ڈویلپمنٹ کے عمل کی ضرورت ہے۔

نافذ کردہ مثال کی کچھ حدود ہیں:

  1. اگر ہم اضافی کنفیگریشن فراہم کرتے ہیں جس کا مطالبہ نوڈ کے نفاذ کے ذریعے نہیں کیا جاتا ہے، تو کمپائلر غیر حاضر عمل درآمد کا پتہ لگانے میں ہماری مدد نہیں کرے گا۔ اس کو استعمال کرکے حل کیا جاسکتا ہے۔ HList یا ADTs (کیس کلاسز) نوڈ کنفیگریشن کے لیے خصلتوں اور کیک پیٹرن کے بجائے۔
  2. ہمیں کنفگ فائل میں کچھ بوائلر پلیٹ فراہم کرنا ہے: (package, import, object اعلانات
    override defکے پیرامیٹرز کے لیے جن کی ڈیفالٹ قدریں ہیں)۔ یہ جزوی طور پر ڈی ایس ایل کا استعمال کرتے ہوئے حل کیا جا سکتا ہے۔
  3. اس پوسٹ میں ہم ملتے جلتے نوڈس کے کلسٹرز کی متحرک ری کنفیگریشن کا احاطہ نہیں کرتے ہیں۔

نتیجہ

اس پوسٹ میں ہم نے ترتیب کو براہ راست سورس کوڈ میں محفوظ طریقے سے پیش کرنے کے خیال پر تبادلہ خیال کیا ہے۔ نقطہ نظر کو بہت سے ایپلی کیشنز میں xml- اور دیگر ٹیکسٹ پر مبنی کنفیگرس کے متبادل کے طور پر استعمال کیا جا سکتا ہے۔ اس کے باوجود کہ ہماری مثال اسکالا میں لاگو کی گئی ہے، اس کا ترجمہ دوسری مرتب کرنے والی زبانوں میں بھی کیا جا سکتا ہے (جیسے کوٹلن، سی#، سوئفٹ وغیرہ)۔ کوئی ایک نئے پروجیکٹ میں اس انداز کو آزما سکتا ہے اور، اگر یہ اچھی طرح سے فٹ نہیں ہوتا ہے تو، پرانے زمانے کے طریقے پر سوئچ کریں۔

بلاشبہ، مرتب کنفیگریشن کے لیے اعلیٰ معیار کے ترقیاتی عمل کی ضرورت ہوتی ہے۔ بدلے میں یہ اتنا ہی اعلیٰ معیار کی مضبوط کنفیگریشن فراہم کرنے کا وعدہ کرتا ہے۔

اس نقطہ نظر کو مختلف طریقوں سے بڑھایا جا سکتا ہے:

  1. کوئی بھی کنفیگریشن کی توثیق کرنے کے لیے میکروز کا استعمال کر سکتا ہے اور کسی بھی کاروباری منطق کی رکاوٹوں کی ناکامی کی صورت میں مرتب وقت پر ناکام ہو سکتا ہے۔
  2. ڈومین صارف دوست طریقے سے کنفیگریشن کی نمائندگی کرنے کے لیے DSL کو لاگو کیا جا سکتا ہے۔
  3. خودکار کنفیگریشن ایڈجسٹمنٹ کے ساتھ متحرک وسائل کا انتظام۔ مثال کے طور پر، جب ہم کلسٹر نوڈس کی تعداد کو ایڈجسٹ کرتے ہیں تو ہم چاہیں گے (1) نوڈس کو قدرے تبدیل شدہ کنفیگریشن حاصل کرنے کے لیے؛ (2) نئے نوڈس کی معلومات حاصل کرنے کے لیے کلسٹر مینیجر۔

شکریہ

میں اس پوسٹ کے مسودے پر متاثر کن تاثرات دینے کے لیے آندرے ساکسونوف، پاول پوپوف، اینٹون نیہائیف کا شکریہ ادا کرنا چاہوں گا جس نے اسے واضح کرنے میں میری مدد کی۔

ماخذ: www.habr.com