تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

ماضی میں آرٹیکل ہم نے رد عمل کے فن تعمیر کی نظریاتی بنیادوں کا جائزہ لیا۔ اب وقت آگیا ہے کہ ڈیٹا کے بہاؤ، ری ایکٹو ایرلنگ/ایلیکسیر سسٹم کو لاگو کرنے کے طریقے اور ان میں پیغام رسانی کے نمونوں کے بارے میں بات کریں:

  • درخواست کا جواب
  • Request-Chunked جواب
  • درخواست کے ساتھ جواب دیں۔
  • شائع کریں سبسکرائب کریں۔
  • الٹا پبلش سبسکرائب کریں۔
  • ٹاسک کی تقسیم

SOA، MSA اور پیغام رسانی

ایس او اے، ایم ایس اے سسٹم آرکیٹیکچرز ہیں جو سسٹمز کی تعمیر کے اصولوں کی وضاحت کرتے ہیں، جب کہ پیغام رسانی ان کے نفاذ کے لیے ابتدائی معلومات فراہم کرتی ہے۔

میں اس یا اس سسٹم کے فن تعمیر کو فروغ نہیں دینا چاہتا۔ میں کسی خاص پروجیکٹ اور کاروبار کے لیے انتہائی موثر اور مفید طریقوں کو استعمال کرنے کے لیے ہوں۔ ہم جو بھی نمونہ منتخب کرتے ہیں، بہتر ہے کہ یونیکس وے پر نظر رکھ کر سسٹم بلاکس بنائیں: کم سے کم رابطے والے اجزاء، انفرادی اداروں کے لیے ذمہ دار۔ API کے طریقے اداروں کے ساتھ آسان ترین ممکنہ کارروائیاں انجام دیتے ہیں۔

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

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

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

سسٹم کے اجزاء براہ راست یا بروکر کے ذریعے بات چیت کرتے ہیں۔ پیغام رسانی کے نقطہ نظر سے، ہر سروس کی زندگی کے کئی مراحل ہوتے ہیں:

  • سروس کی شروعات۔
    اس مرحلے پر، سروس کو انجام دینے والے عمل اور انحصار کنفیگر اور لانچ کیے جاتے ہیں۔
  • ایکسچینج پوائنٹ بنانا۔
    سروس نوڈ کنفیگریشن میں متعین ایک سٹیٹک ایکسچینج پوائنٹ استعمال کر سکتی ہے، یا متحرک طور پر ایکسچینج پوائنٹس بنا سکتی ہے۔
  • سروس رجسٹریشن۔
    سروس کے لیے درخواستیں پیش کرنے کے لیے، اسے ایکسچینج پوائنٹ پر رجسٹرڈ ہونا چاہیے۔
  • عام کام کرنا۔
    سروس مفید کام پیدا کرتی ہے۔
  • شٹ ڈاؤن۔
    شٹ ڈاؤن کی 2 قسمیں ممکن ہیں: نارمل اور ایمرجنسی۔ عام آپریشن کے دوران، سروس ایکسچینج پوائنٹ سے منقطع ہو جاتی ہے اور رک جاتی ہے۔ ہنگامی حالات میں، پیغام رسانی فیل اوور اسکرپٹس میں سے ایک پر عمل کرتی ہے۔

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

تبادلے

ایکسچینج پوائنٹ ایک پیغام رسانی کا عمل ہے جو پیغام رسانی کے سانچے کے اندر اجزاء کے ساتھ تعامل کی منطق کو نافذ کرتا ہے۔ ذیل میں پیش کی گئی تمام مثالوں میں، اجزاء ایکسچینج پوائنٹس کے ذریعے تعامل کرتے ہیں، جس کا مجموعہ پیغام رسانی کو تشکیل دیتا ہے۔

پیغام کے تبادلے کے پیٹرن (MEPs)

عالمی سطح پر، تبادلے کے پیٹرن کو دو طرفہ اور ایک طرفہ میں تقسیم کیا جا سکتا ہے۔ سابقہ ​​آنے والے پیغام کے جواب کا مطلب ہے، مؤخر الذکر ایسا نہیں کرتے۔ کلائنٹ سرور فن تعمیر میں دو طرفہ پیٹرن کی ایک بہترین مثال Request-response پیٹرن ہے۔ آئیے ٹیمپلیٹ اور اس کی ترمیمات کو دیکھتے ہیں۔

درخواست جواب یا RPC

RPC کا استعمال اس وقت ہوتا ہے جب ہمیں کسی دوسرے عمل سے جواب موصول کرنے کی ضرورت ہوتی ہے۔ یہ عمل ایک ہی نوڈ پر چل رہا ہے یا کسی مختلف براعظم پر واقع ہو سکتا ہے۔ ذیل میں پیغام رسانی کے ذریعے کلائنٹ اور سرور کے درمیان تعامل کا خاکہ ہے۔

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

چونکہ پیغام رسانی مکمل طور پر متضاد ہے، اس لیے کلائنٹ کے لیے تبادلے کو 2 مراحل میں تقسیم کیا گیا ہے:

  1. درخواست بھیج رہا ہے۔

    messaging:request(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).

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

  2. جواب پر کارروائی ہو رہی ہے۔

    handle_info(#'$msg'{exchange = EXCHANGE, tag = ResponseMatchingTag,message = ResponsePayload}, State)

    رسپانس پے لوڈ - سرور کا جواب۔

سرور کے لیے، یہ عمل بھی 2 مراحل پر مشتمل ہے:

  1. ایکسچینج پوائنٹ شروع کرنا
  2. موصول ہونے والی درخواستوں پر کارروائی

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

سرور کوڈ

آئیے api.hrl میں سروس API کی وضاحت کرتے ہیں:

%% =====================================================
%%  entities
%% =====================================================
-record(time, {
  unixtime :: non_neg_integer(),
  datetime :: binary()
}).

-record(time_error, {
  code :: non_neg_integer(),
  error :: term()
}).

%% =====================================================
%%  methods
%% =====================================================
-record(time_req, {
  opts :: term()
}).
-record(time_resp, {
  result :: #time{} | #time_error{}
}).

آئیے time_controller.erl میں سروس کنٹرولر کی وضاحت کرتے ہیں۔

%% В примере показан только значимый код. Вставив его в шаблон gen_server можно получить рабочий сервис.

%% инициализация gen_server
init(Args) ->
  %% подключение к точке обмена
  messaging:monitor_exchange(req_resp, ?EXCHANGE, default, self())
  {ok, #{}}.

%% обработка события потери связи с точкой обмена. Это же событие приходит, если точка обмена еще не запустилась.
handle_info(#exchange_die{exchange = ?EXCHANGE}, State) ->
  erlang:send(self(), monitor_exchange),
  {noreply, State};

%% обработка API
handle_info(#time_req{opts = _Opts}, State) ->
  messaging:response_once(Client, #time_resp{
result = #time{ unixtime = time_utils:unixtime(now()), datetime = time_utils:iso8601_fmt(now())}
  });
  {noreply, State};

%% завершение работы gen_server
terminate(_Reason, _State) ->
  messaging:demonitor_exchange(req_resp, ?EXCHANGE, default, self()),
  ok.

کلائنٹ کوڈ

سروس کو درخواست بھیجنے کے لیے، آپ کلائنٹ میں کہیں بھی پیغام رسانی کی درخواست API کو کال کر سکتے ہیں:

case messaging:request(?EXCHANGE, tag, #time_req{opts = #{}}, self()) of
    ok -> ok;
    _ -> %% repeat or fail logic
end

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

handle_info(#'$msg'{exchange = ?EXCHANGE, tag = tag, message = #time_resp{result = #time{unixtime = Utime}}}, State) ->
  ?debugVal(Utime),
  {noreply, State};

handle_info(#'$msg'{exchange = ?EXCHANGE, tag = tag, message = #time_resp{result = #time_error{code = ErrorCode}}}, State) ->
  ?debugVal({error, ErrorCode}),
  {noreply, State};

Request-Chunked جواب

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

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

میں آپ کو اس طرح کے واقعات کی چند مثالیں دیتا ہوں:

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

میں ان ردعمل کو لوکوموٹیو کہتا ہوں۔ کسی بھی صورت میں، 1024 MB کے 1 پیغامات 1 GB کے ایک پیغام سے بہتر ہیں۔

ایرلنگ کلسٹر میں، ہمیں ایک اضافی فائدہ ملتا ہے - ایکسچینج پوائنٹ اور نیٹ ورک پر بوجھ کو کم کرنا، کیونکہ ایکسچینج پوائنٹ کو نظرانداز کرتے ہوئے فوری طور پر جواب وصول کنندہ کو بھیجے جاتے ہیں۔

درخواست کے ساتھ جواب دیں۔

یہ ڈائیلاگ سسٹم بنانے کے لیے RPC پیٹرن کی ایک غیر معمولی تبدیلی ہے۔

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

شائع کریں سبسکرائب کریں (ڈیٹا کی تقسیم کا درخت)

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

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

اس پیٹرن کو استعمال کرنے کی بہترین مثالیں ریاست کی تقسیم ہیں: کمپیوٹر گیمز میں گیم کی دنیا، تبادلے پر مارکیٹ ڈیٹا، ڈیٹا فیڈز میں مفید معلومات۔

آئیے سبسکرائبر کوڈ دیکھیں:

init(_Args) ->
  %% подписываемся на обменник, ключ = key
  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),
  {ok, #{}}.

handle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) ->
  %% если точка обмена недоступна, то пытаемся переподключиться
  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),
  {noreply, State};

%% обрабатываем пришедшие сообщения
handle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) ->
  ?debugVal(Msg),
  {noreply, State};

%% при остановке потребителя - отключаемся от точки обмена
terminate(_Reason, _State) ->
  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),
  ok.

ذریعہ کسی بھی مناسب جگہ پر پیغام شائع کرنے کے لیے فنکشن کو کال کر سکتا ہے:

messaging:publish_message(Exchange, Key, Message).

ایکسچینج - ایکسچینج پوائنٹ کا نام،
کلیدی - روٹنگ کلید
پیغام --.پے لوڈ n

الٹا پبلش سبسکرائب کریں۔

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

پب-سب کو بڑھا کر، آپ لاگنگ کے لیے آسان نمونہ حاصل کر سکتے ہیں۔ ذرائع اور صارفین کا سیٹ بالکل مختلف ہو سکتا ہے۔ اعداد و شمار ایک صارف اور متعدد ذرائع کے ساتھ ایک کیس دکھاتا ہے۔

کام کی تقسیم کا نمونہ

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

آئیے 3 ہینڈلرز کی مثال استعمال کرتے ہوئے پیدا ہونے والے حالات کو دیکھیں۔ یہاں تک کہ کام کی تقسیم کے مرحلے پر، تقسیم کی منصفانہ اور ہینڈلرز کے زیادہ بہاؤ کا سوال پیدا ہوتا ہے۔ راؤنڈ رابن کی تقسیم انصاف کے لیے ذمہ دار ہوگی، اور ہینڈلرز کے زیادہ بہاؤ کی صورت حال سے بچنے کے لیے، ہم ایک پابندی متعارف کرائیں گے۔ prefetch_limit. عارضی حالات میں prefetch_limit ایک ہینڈلر کو تمام کام حاصل کرنے سے روکے گا۔

پیغام رسانی قطاروں اور پروسیسنگ کی ترجیح کا انتظام کرتی ہے۔ پروسیسر آتے ہی ٹاسک وصول کرتے ہیں۔ کام کامیابی سے مکمل یا ناکام ہو سکتا ہے:

  • messaging:ack(Tack) - کہا جاتا ہے اگر میسج پر کامیابی سے کارروائی ہو جاتی ہے۔
  • messaging:nack(Tack) - تمام ہنگامی حالات میں بلایا جاتا ہے۔ ایک بار جب ٹاسک واپس آجائے گا، پیغام رسانی اسے دوسرے ہینڈلر کو دے گی۔

تقسیم شدہ ایپلی کیشنز کے بلڈنگ بلاکس۔ پہلا نقطہ نظر

فرض کریں کہ تین کاموں پر کارروائی کرتے وقت ایک پیچیدہ ناکامی واقع ہوئی: پروسیسر 1، ٹاسک حاصل کرنے کے بعد، ایکسچینج پوائنٹ پر کچھ بھی اطلاع دینے کا وقت نہ ہونے کے بعد کریش ہو گیا۔ اس صورت میں، ایکسچینج پوائنٹ AC ٹائم آؤٹ ختم ہونے کے بعد کام کو دوسرے ہینڈلر کو منتقل کر دے گا۔ کسی وجہ سے، ہینڈلر 3 نے ٹاسک چھوڑ دیا اور نیک بھیج دیا؛ نتیجے کے طور پر، کام دوسرے ہینڈلر کو بھی منتقل کر دیا گیا جس نے اسے کامیابی سے مکمل کیا۔

ابتدائی خلاصہ

ہم نے تقسیم شدہ نظاموں کے بنیادی بلڈنگ بلاکس کا احاطہ کیا ہے اور Erlang/Elixir میں ان کے استعمال کی بنیادی سمجھ حاصل کی ہے۔

بنیادی نمونوں کو ملا کر، آپ ابھرتے ہوئے مسائل کو حل کرنے کے لیے پیچیدہ نمونے بنا سکتے ہیں۔

سیریز کے آخری حصے میں، ہم خدمات کو منظم کرنے، روٹنگ اور توازن کے عمومی مسائل پر غور کریں گے، اور اسکیل ایبلٹی کے عملی پہلو اور سسٹمز کی غلطی کو برداشت کرنے کے بارے میں بھی بات کریں گے۔

دوسرے حصے کا اختتام۔

تصویر ماریئس کرسٹینسن
websequencediagrams.com کا استعمال کرتے ہوئے تیار کردہ عکاسی۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں