پانچ طلباء اور تین تقسیم شدہ کلیدی قیمت والے اسٹور

یا ہم نے ZooKeeper، etcd اور Consul KV کے لیے کلائنٹ C++ لائبریری کیسے لکھی۔

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

پانچ طلباء اور تین تقسیم شدہ کلیدی قیمت والے اسٹور

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

اس مسئلے کو حل کرنے کا خیال ایک آسٹریلوی مشاورتی ایجنسی میں شروع ہوا، اور اس پر عمل درآمد کرنے کے لیے، طلبہ کی ایک چھوٹی ٹیم نے، جس کے بارے میں میں بات کرنے جا رہا ہوں۔

ہم ایک لائبریری بنانے میں کامیاب ہو گئے جو ZooKeeper، etcd اور Consul KV کے ساتھ کام کرنے کے لیے ایک مشترکہ انٹرفیس فراہم کرتی ہے۔ لائبریری C++ میں لکھی گئی ہے، لیکن اسے دوسری زبانوں میں پورٹ کرنے کا منصوبہ ہے۔

ڈیٹا ماڈلز

تین مختلف سسٹمز کے لیے ایک مشترکہ انٹرفیس تیار کرنے کے لیے، آپ کو یہ سمجھنے کی ضرورت ہے کہ ان میں کیا مشترک ہے اور وہ کیسے مختلف ہیں۔ آئیے اس کا پتہ لگائیں۔

زوکیپر

پانچ طلباء اور تین تقسیم شدہ کلیدی قیمت والے اسٹور

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

وغیرہ

پانچ طلباء اور تین تقسیم شدہ کلیدی قیمت والے اسٹور

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

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

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

قونصل K.V.

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

پانچ طلباء اور تین تقسیم شدہ کلیدی قیمت والے اسٹور
گھڑیوں کے بجائے، قونصل نے HTTP درخواستوں کو مسدود کر دیا ہے۔ خلاصہ یہ ہے کہ یہ ڈیٹا پڑھنے کے طریقہ کار کی عام کالیں ہیں، جس کے لیے، دیگر پیرامیٹرز کے ساتھ، ڈیٹا کے آخری معلوم ورژن کی نشاندہی کی گئی ہے۔ اگر سرور پر متعلقہ ڈیٹا کا موجودہ ورژن متعین کردہ سے زیادہ ہے، تو جواب فوری طور پر واپس کر دیا جاتا ہے، بصورت دیگر - جب قدر میں تبدیلی آتی ہے۔ ایسے سیشن بھی ہیں جو کسی بھی وقت چابیاں سے منسلک ہو سکتے ہیں۔ یہ بات قابل غور ہے کہ etcd اور ZooKeeper کے برعکس، جہاں سیشنز کو حذف کرنا متعلقہ کیز کو حذف کرنے کا باعث بنتا ہے، وہاں ایک موڈ ہوتا ہے جس میں سیشن کو ان سے الگ کر دیا جاتا ہے۔ دستیاب لین دین, شاخوں کے بغیر، لیکن ہر قسم کے چیک کے ساتھ۔

یہ سب ایک ساتھ ڈالنا

زو کیپر کے پاس سب سے سخت ڈیٹا ماڈل ہے۔ etcd میں دستیاب اظہاری رینج کے سوالات کو زو کیپر یا قونصل میں مؤثر طریقے سے نقل نہیں کیا جا سکتا۔ تمام خدمات سے بہترین فائدہ اٹھانے کی کوشش کرتے ہوئے، ہم نے مندرجہ ذیل اہم استثناء کے ساتھ ZooKeeper انٹرفیس کے تقریباً مساوی ایک انٹرفیس حاصل کیا۔

  • ترتیب، کنٹینر اور ٹی ٹی ایل نوڈس سہولت مہیا نہیں
  • ACL تعاون یافتہ نہیں ہیں۔
  • سیٹ طریقہ ایک کلید بناتا ہے اگر یہ موجود نہیں ہے (ZK setData میں اس معاملے میں ایک غلطی واپس آتی ہے)
  • سیٹ اور کیس کے طریقے الگ ہیں (ZK میں وہ بنیادی طور پر ایک ہی چیز ہیں)
  • مٹانے کا طریقہ ایک نوڈ کو اس کے سب ٹری کے ساتھ ڈیلیٹ کر دیتا ہے (ZK ڈیلیٹ میں اگر نوڈ کے بچے ہیں تو ایک غلطی لوٹاتا ہے)
  • ہر کلید کے لیے صرف ایک ورژن ہے - ویلیو ورژن (ZK میں ان میں سے تین ہیں)

ترتیب وار نوڈس کو مسترد کرنا اس حقیقت کی وجہ سے ہے کہ etcd اور Consul کے پاس ان کے لیے بلٹ ان سپورٹ نہیں ہے، اور ان کو صارف آسانی سے نتیجے میں لائبریری انٹرفیس کے اوپر لاگو کر سکتا ہے۔

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

نفاذ کی باریکیاں

آئیے مختلف سسٹمز میں لائبریری انٹرفیس کو لاگو کرنے کے کچھ پہلوؤں پر گہری نظر ڈالتے ہیں۔

وغیرہ میں درجہ بندی

etcd میں درجہ بندی کے نقطہ نظر کو برقرار رکھنا سب سے دلچسپ کاموں میں سے ایک نکلا۔ رینج کے سوالات ایک مخصوص سابقہ ​​کے ساتھ کلیدوں کی فہرست کو بازیافت کرنا آسان بناتے ہیں۔ مثال کے طور پر، اگر آپ کو ہر اس چیز کی ضرورت ہے جو شروع ہوتی ہے۔ "/foo"، آپ ایک حد کے لئے پوچھ رہے ہیں۔ ["/foo", "/fop"). لیکن یہ کلید کا پورا ذیلی درخت واپس کر دے گا، جو سب ٹری بڑا ہونے کی صورت میں قابل قبول نہیں ہو سکتا۔ سب سے پہلے ہم نے ایک کلیدی ترجمے کا طریقہ کار استعمال کرنے کا منصوبہ بنایا، zetcd میں لاگو کیا گیا۔. اس میں کلید کے شروع میں ایک بائٹ شامل کرنا شامل ہے، درخت میں نوڈ کی گہرائی کے برابر۔ میں آپ کو ایک مثال دیتا ہوں۔

"/foo" -> "u01/foo"
"/foo/bar" -> "u02/foo/bar"

پھر کلید کے تمام فوری بچے حاصل کریں۔ "/foo" رینج کی درخواست کرکے ممکن ہے۔ ["u02/foo/", "u02/foo0"). ہاں، ASCII میں "0" اس کے بعد کھڑا ہے "/".

لیکن اس معاملے میں چوٹی کو ہٹانے کو کیسے نافذ کیا جائے؟ یہ پتہ چلتا ہے کہ آپ کو قسم کی تمام حدود کو حذف کرنے کی ضرورت ہے۔ ["uXX/foo/", "uXX/foo0") XX کے لیے 01 سے FF تک۔ اور پھر ہم اندر بھاگ گئے۔ آپریشن نمبر کی حد ایک لین دین کے اندر۔

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

"/very" -> "/u00very"
"/very/long" -> "/very/u00long"
"/very/long/path" -> "/very/long/u00path"

پھر کلید کو حذف کرنا "/very" حذف میں بدل جاتا ہے۔ "/u00very" اور رینج ["/very/", "/very0")، اور تمام بچوں کو حاصل کرنا - رینج سے چابیاں کی درخواست میں ["/very/u00", "/very/u01").

زو کیپر میں کلید کو ہٹانا

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

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

زو کیپر میں سیٹ کریں۔

ZooKeeper میں الگ الگ طریقے ہیں جو درخت کے ڈھانچے (create, delete, getChildren) کے ساتھ کام کرتے ہیں اور جو کہ نوڈس میں ڈیٹا کے ساتھ کام کرتے ہیں (setData, getData) مزید یہ کہ تمام طریقوں کی سخت پیشگی شرائط ہیں: اگر نوڈ پہلے سے موجود ہے تو تخلیق ایک غلطی واپس کر دے گا۔ ڈیٹا بنایا گیا، حذف یا سیٹ کیا گیا – اگر یہ پہلے سے موجود نہیں ہے۔ ہمیں ایک سیٹ طریقہ کی ضرورت تھی جسے کلید کی موجودگی کے بارے میں سوچے بغیر کہا جا سکے۔

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

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

مزید تکنیکی تفصیلات

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

شروع سے ہی، ہم نے خدمات تک رسائی کے لیے ریڈی میڈ لائبریریوں کو استعمال کرنے کی کوشش کی۔ ZooKeeper کے معاملے میں، انتخاب گر گیا زو کیپر C++، جو بالآخر ونڈوز پر مرتب کرنے میں ناکام رہا۔ تاہم، یہ حیران کن نہیں ہے: لائبریری کو صرف لینکس کے طور پر رکھا گیا ہے۔ قونصل کے لیے واحد آپشن تھا۔ پی پی قونصل. اس میں حمایت کا اضافہ کرنا پڑا سیشن и لین دین. etcd کے لیے، پروٹوکول کے تازہ ترین ورژن کی حمایت کرنے والی ایک مکمل لائبریری نہیں ملی، لہذا ہم صرف تیار کردہ grpc کلائنٹ.

ZooKeeper C++ لائبریری کے غیر مطابقت پذیر انٹرفیس سے متاثر ہو کر، ہم نے ایک غیر مطابقت پذیر انٹرفیس کو بھی نافذ کرنے کا فیصلہ کیا۔ ZooKeeper C++ اس کے لیے مستقبل/ وعدہ پرائمٹیوز کا استعمال کرتا ہے۔ STL میں، بدقسمتی سے، وہ بہت معمولی طور پر لاگو ہوتے ہیں. مثال کے طور پر، نہیں۔ پھر طریقہ، جو پاس شدہ فنکشن کو مستقبل کے نتائج پر لاگو کرتا ہے جب یہ دستیاب ہوتا ہے۔ ہمارے معاملے میں، نتیجہ کو ہماری لائبریری کے فارمیٹ میں تبدیل کرنے کے لیے ایسا طریقہ ضروری ہے۔ اس مسئلے کو حل کرنے کے لیے، ہمیں اپنے سادہ تھریڈ پول کو لاگو کرنا پڑا، کیونکہ گاہک کی درخواست پر ہم تیسری پارٹی کی بھاری لائبریریوں جیسے بوسٹ کو استعمال نہیں کر سکتے تھے۔

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

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

کل

اپنے آپ کے لئے ملاحظہ کریں: liboffkv.

ہماری ٹیم: رائد رومانوف, ایوان گلوشینکوف, دمتری کمالدینوف, وکٹر کرپیونسکی, وٹالی ایوانن.

ماخذ: www.habr.com

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