NewSQL = NoSQL+ACID

NewSQL = NoSQL+ACID
کچھ عرصہ پہلے تک، Odnoklassniki ایس کیو ایل سرور میں ریئل ٹائم میں پروسیس شدہ ڈیٹا کا تقریباً 50 TB ذخیرہ کرتا تھا۔ اس طرح کے حجم کے لیے، ایس کیو ایل ڈی بی ایم ایس کا استعمال کرتے ہوئے تیز رفتار اور قابل اعتماد، اور حتیٰ کہ ڈیٹا سینٹر کی ناکامی برداشت کرنے والی رسائی فراہم کرنا تقریباً ناممکن ہے۔ عام طور پر، ایسے معاملات میں، NoSQL سٹوریجز میں سے ایک استعمال کیا جاتا ہے، لیکن ہر چیز NoSQL میں منتقل نہیں کی جا سکتی: کچھ اداروں کو ACID ٹرانزیکشن کی ضمانت کی ضرورت ہوتی ہے۔

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

یہ کیسے کام کرتا ہے اور کیا ہوا - کٹ کے نیچے پڑھیں۔

آج، Odnoklassniki کے ماہانہ سامعین 70 ملین سے زیادہ منفرد زائرین ہیں۔ ہم ہم سب سے اوپر پانچ میں ہیں دنیا کے سب سے بڑے سوشل نیٹ ورکس، اور ان بیس سائٹس میں سے جن پر صارفین سب سے زیادہ وقت گزارتے ہیں۔ اوکے انفراسٹرکچر بہت زیادہ بوجھ کو سنبھالتا ہے: ایک ملین سے زیادہ HTTP درخواستیں/سیکنڈ فی فرنٹ۔ 8000 سے زیادہ ٹکڑوں کے سرور کے بیڑے کے حصے ایک دوسرے کے قریب واقع ہیں - ماسکو کے چار ڈیٹا سینٹرز میں، جس کی وجہ سے ان کے درمیان 1 ms سے کم نیٹ ورک کی تاخیر کو یقینی بنانا ممکن ہو جاتا ہے۔

ہم 2010 سے Cassandra استعمال کر رہے ہیں، ورژن 0.6 سے شروع ہو رہا ہے۔ آج کئی درجن کلسٹرز کام کر رہے ہیں۔ سب سے تیز کلسٹر فی سیکنڈ 4 ملین سے زیادہ آپریشنز پر عملدرآمد کرتا ہے، اور سب سے بڑا ذخیرہ 260 TB۔

تاہم، یہ تمام عام NoSQL کلسٹرز ہیں جو اسٹوریج کے لیے استعمال ہوتے ہیں۔ کمزور مربوط ڈیٹا ہم بنیادی مستقل اسٹوریج، مائیکروسافٹ ایس کیو ایل سرور کو تبدیل کرنا چاہتے تھے، جو Odnoklassniki کے قیام کے بعد سے استعمال کیا جا رہا ہے۔ سٹوریج میں 300 سے زیادہ SQL سرور سٹینڈرڈ ایڈیشن مشینیں شامل تھیں، جن میں 50 TB ڈیٹا - کاروباری اداروں کا تھا۔ اس ڈیٹا میں ACID ٹرانزیکشنز کے حصے کے طور پر ترمیم کی گئی ہے اور اس کی ضرورت ہے۔ اعلی مستقل مزاجی.

ایس کیو ایل سرور نوڈس میں ڈیٹا تقسیم کرنے کے لیے، ہم نے عمودی اور افقی دونوں کا استعمال کیا۔ تقسیم (شارڈنگ)۔ تاریخی طور پر، ہم نے ایک سادہ ڈیٹا شارڈنگ اسکیم کا استعمال کیا: ہر ہستی ایک ٹوکن سے منسلک تھی - entity ID کا ایک فنکشن۔ ایک ہی ٹوکن والی ہستیوں کو ایک ہی SQL سرور پر رکھا گیا تھا۔ ماسٹر ڈیٹیل ریلیشن شپ کو لاگو کیا گیا تھا تاکہ مین اور چائلڈ ریکارڈز کے ٹوکن ہمیشہ مماثل ہوں اور ایک ہی سرور پر واقع ہوں۔ سوشل نیٹ ورک میں، تقریباً تمام ریکارڈز صارف کی جانب سے تیار کیے جاتے ہیں - جس کا مطلب یہ ہے کہ ایک فنکشنل سب سسٹم کے اندر صارف کا تمام ڈیٹا ایک سرور پر محفوظ کیا جاتا ہے۔ یعنی، ایک کاروباری لین دین میں تقریباً ہمیشہ ایک ایس کیو ایل سرور سے ٹیبل شامل ہوتے ہیں، جس نے مقامی ACID ٹرانزیکشنز کا استعمال کرتے ہوئے ڈیٹا کی مستقل مزاجی کو یقینی بنایا، بغیر استعمال کے۔ سست اور ناقابل اعتماد تقسیم شدہ ACID ٹرانزیکشنز۔

شارڈنگ اور ایس کیو ایل کو تیز کرنے کا شکریہ:

  • ہم غیر ملکی کلیدی رکاوٹوں کا استعمال نہیں کرتے ہیں، کیونکہ جب ہستی ID کو شارڈ کیا جائے تو دوسرے سرور پر واقع ہو سکتا ہے۔
  • DBMS CPU پر اضافی بوجھ کی وجہ سے ہم ذخیرہ شدہ طریقہ کار اور محرکات استعمال نہیں کرتے ہیں۔
  • ہم اوپر کی تمام چیزوں اور ڈسک سے بے ترتیب پڑھنے کی وجہ سے JOINs کا استعمال نہیں کرتے ہیں۔
  • لین دین کے باہر، ہم تعطل کو کم کرنے کے لیے غیر متعلقہ تنہائی کی سطح کا استعمال کرتے ہیں۔
  • ہم صرف مختصر لین دین کرتے ہیں (اوسطاً 100 ایم ایس سے کم)۔
  • تعطل کی بڑی تعداد کی وجہ سے ہم ملٹی قطار اپ ڈیٹ اور ڈیلیٹ کا استعمال نہیں کرتے ہیں - ہم ایک وقت میں صرف ایک ریکارڈ اپ ڈیٹ کرتے ہیں۔
  • ہم ہمیشہ استفسارات صرف اشاریہ جات پر کرتے ہیں - ہمارے لیے مکمل ٹیبل اسکین پلان کے ساتھ استفسار کا مطلب ڈیٹا بیس کو اوورلوڈ کرنا اور اسے ناکام بنانا ہے۔

ان اقدامات نے ہمیں SQL سرورز سے تقریباً زیادہ سے زیادہ کارکردگی کو نچوڑنے کی اجازت دی۔ تاہم، مسائل زیادہ سے زیادہ بے شمار ہوتے گئے. آئیے ان کو دیکھتے ہیں۔

ایس کیو ایل کے ساتھ مسائل

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

لیکن اصل مسئلہ یہ ہے۔

غلطی کی رواداری

کلاسک ایس کیو ایل سرور میں خرابی کی رواداری ہے۔ فرض کریں کہ آپ کے پاس صرف ایک ڈیٹا بیس سرور ہے، اور یہ ہر تین سال میں ایک بار ناکام ہو جاتا ہے۔ اس دوران سائٹ 20 منٹ تک بند رہتی ہے، جو قابل قبول ہے۔ اگر آپ کے پاس 64 سرور ہیں، تو سائٹ ہر تین ہفتوں میں ایک بار ڈاؤن ہوتی ہے۔ اور اگر آپ کے پاس 200 سرور ہیں، تو سائٹ ہر ہفتے کام نہیں کرتی۔ یہ مسئلہ ہے۔

ایس کیو ایل سرور کی فالٹ ٹولرنس کو بہتر بنانے کے لیے کیا کیا جا سکتا ہے؟ ویکیپیڈیا ہمیں تعمیر کرنے کی دعوت دیتا ہے۔ انتہائی دستیاب کلسٹر: جہاں کسی بھی اجزاء کی ناکامی کی صورت میں ایک بیک اپ ہوتا ہے۔

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

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

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

ان تمام مسائل کا ایک بنیادی حل درکار تھا، اور ہم نے ان کا تفصیلی تجزیہ کرنا شروع کیا۔ یہاں ہمیں SQL سرور بنیادی طور پر کیا کرتا ہے - لین دین سے واقف ہونے کی ضرورت ہے۔

سادہ لین دین

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

  1. ہم کلید کے ذریعہ البم کو لاک کرتے ہیں۔
  2. فوٹو ٹیبل میں ایک اندراج بنائیں۔
  3. اگر تصویر کی عوامی حیثیت ہے، تو البم میں عوامی تصویر کا کاؤنٹر شامل کریں، ریکارڈ کو اپ ڈیٹ کریں اور لین دین کا ارتکاب کریں۔

یا pseudocode میں:

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

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

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

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

دیگر، کم اہم نہیں، ضروریات یہ تھیں:

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

فیصلے، فیصلے

ممکنہ حلوں کا تجزیہ کرتے ہوئے، ہم فن تعمیر کے دو ممکنہ انتخاب پر پہنچے:

سب سے پہلے کسی بھی ایس کیو ایل سرور کو لینا اور مطلوبہ فالٹ ٹولرنس، اسکیلنگ میکانزم، فیل اوور کلسٹر، تنازعات کا حل اور تقسیم شدہ، قابل اعتماد اور تیز رفتار ACID ٹرانزیکشنز کو نافذ کرنا ہے۔ ہم نے اس اختیار کو انتہائی غیر معمولی اور محنت طلب قرار دیا۔

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

کیسینڈرا اور سی کیو ایل

تو، کیسینڈرا کے بارے میں کیا دلچسپ ہے، اس میں کیا صلاحیتیں ہیں؟

سب سے پہلے، یہاں آپ مختلف قسم کے ڈیٹا کو سپورٹ کرنے والے ٹیبل بنا سکتے ہیں؛ آپ بنیادی کلید پر SELECT یا UPDATE کر سکتے ہیں۔

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

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

نقطہ نظر جب ہم تین نوڈس سے رابطہ کرتے ہیں اور دو سے جواب وصول کرتے ہیں تو اسے کہا جاتا ہے۔ قیاس: اضافی نقلوں کی درخواست "گرنے" سے پہلے ہی بھیجی جاتی ہے۔

Cassandra کا ایک اور فائدہ Batchlog ہے، ایک ایسا طریقہ کار جو اس بات کو یقینی بناتا ہے کہ آپ کی تبدیلیوں کا ایک بیچ یا تو مکمل طور پر لاگو ہوتا ہے یا بالکل لاگو نہیں ہوتا ہے۔ یہ ہمیں ACID میں A کو حل کرنے کی اجازت دیتا ہے - باکس سے باہر جوہری۔

کیسینڈرا میں لین دین کی قریب ترین چیز نام نہاد "ہلکے لین دین" لیکن وہ "حقیقی" ACID لین دین سے بہت دور ہیں: حقیقت میں، یہ کرنے کا ایک موقع ہے۔ سی اے ایس ہیوی ویٹ Paxos پروٹوکول کا استعمال کرتے ہوئے اتفاق رائے کا استعمال کرتے ہوئے، صرف ایک ریکارڈ سے ڈیٹا پر۔ لہذا، اس طرح کے لین دین کی رفتار کم ہے.

کیسینڈرا میں ہم کیا کھو رہے تھے۔

لہذا، ہمیں کیسنڈرا میں حقیقی ACID لین دین کو لاگو کرنا پڑا۔ جس کا استعمال کرتے ہوئے ہم کلاسک DBMS کی دو دیگر آسان خصوصیات کو آسانی سے نافذ کر سکتے ہیں: مستقل تیز انڈیکسز، جو ہمیں نہ صرف بنیادی کلید کے ذریعے ڈیٹا کا انتخاب کرنے کی اجازت دیتا ہے، اور monotonic auto-incrementing IDs کا باقاعدہ جنریٹر۔

سی* ایک

اس طرح ایک نیا DBMS پیدا ہوا۔ سی* ایک، تین قسم کے سرور نوڈس پر مشتمل ہے:

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

NewSQL = NoSQL+ACID

تمام اقسام کے سرور ایک مشترکہ کلسٹر کا حصہ ہیں، ایک دوسرے کے ساتھ بات چیت کرنے کے لیے اندرونی کیسنڈرا میسج پروٹوکول کا استعمال کریں اور گپ شپ کلسٹر معلومات کے تبادلے کے لیے۔ ہارٹ بیٹ کے ساتھ، سرور باہمی ناکامیوں کے بارے میں سیکھتے ہیں، ایک واحد ڈیٹا اسکیما کو برقرار رکھتے ہیں - میزیں، ان کی ساخت اور نقل؛ تقسیم کاری اسکیم، کلسٹر ٹوپولوجی، وغیرہ۔

گاہک

NewSQL = NoSQL+ACID

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

C*ون ٹرانزیکشن کوآرڈینیٹر

کوآرڈینیٹر وہ چیز ہے جسے ہم نے شروع سے C*One کے لیے نافذ کیا ہے۔ یہ لین دین، تالے اور اس ترتیب کے انتظام کے لیے ذمہ دار ہے جس میں لین دین کا اطلاق ہوتا ہے۔

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

تالے

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

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

چونکہ ہمارے معاملے میں ڈیٹا پہلے ہی ایس کیو ایل میں مقامی لین دین کے گروپوں میں تقسیم کیا جاتا ہے، اس لیے مقامی ٹرانزیکشن گروپس کو کوآرڈینیٹرز کو تفویض کرنے کا فیصلہ کیا گیا: ایک کوآرڈینیٹر 0 سے 9 تک کے ٹوکنز کے ساتھ تمام لین دین کرتا ہے، دوسرا - 10 سے 19 تک کے ٹوکنز کے ساتھ، اور اسی طرح. نتیجے کے طور پر، کوآرڈینیٹر مثالوں میں سے ہر ایک ٹرانزیکشن گروپ کا ماسٹر بن جاتا ہے۔

اس کے بعد کوآرڈینیٹر کی یاد میں ایک عام HashMap کی شکل میں تالے لاگو کیے جا سکتے ہیں۔

کوآرڈینیٹر کی ناکامی۔

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

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

NewSQL = NoSQL+ACID

دوسروں سے ان کے دل کی دھڑکن کے پیغامات کے حصے کے طور پر اسی طرح کی معلومات حاصل کرتے ہوئے، ہر کوآرڈینیٹر خود فیصلہ کرتا ہے کہ کون سے کلسٹر نوڈس کام کر رہے ہیں اور کون سے نہیں، کورم کے اصول کے مطابق: اگر نوڈ X کو کلسٹر میں موجود نوڈس کی اکثریت سے نارمل کے بارے میں معلومات موصول ہوئی ہیں۔ نوڈ Y سے پیغامات کی وصولی، پھر Y کام کرتا ہے۔ اور اس کے برعکس، جیسے ہی اکثریت نے نوڈ Y سے پیغامات غائب ہونے کی اطلاع دی، تو Y نے انکار کر دیا۔ یہ دلچسپ ہے کہ اگر کورم نوڈ X کو بتاتا ہے کہ اسے اب اس سے پیغامات موصول نہیں ہو رہے ہیں، تو نوڈ X خود کو ناکام سمجھے گا۔

دل کی دھڑکن کے پیغامات ہائی فریکوئنسی کے ساتھ بھیجے جاتے ہیں، تقریباً 20 بار فی سیکنڈ، 50 ایم ایس کی مدت کے ساتھ۔ جاوا میں، ردی کی ٹوکری جمع کرنے والے کی وجہ سے وقفے کی لمبائی کی وجہ سے 50 ایم ایس کے اندر درخواست کے جواب کی ضمانت دینا مشکل ہے۔ ہم G1 ردی کی ٹوکری کے جمع کرنے والے کا استعمال کرتے ہوئے اس جوابی وقت کو حاصل کرنے کے قابل تھے، جو ہمیں GC کے وقفوں کی مدت کے لیے ایک ہدف کی وضاحت کرنے کی اجازت دیتا ہے۔ تاہم، بعض اوقات، بہت ہی کم، کلکٹر کا وقفہ 50 ایم ایس سے زیادہ ہوتا ہے، جو غلط غلطی کا پتہ لگانے کا باعث بن سکتا ہے۔ ایسا ہونے سے روکنے کے لیے، کوآرڈینیٹر ریموٹ نوڈ کی ناکامی کی اطلاع نہیں دیتا جب اس سے دل کی دھڑکن کا پہلا پیغام غائب ہو جاتا ہے، صرف اس صورت میں جب کئی مسلسل غائب ہو گئے ہوں۔ MS.

لیکن یہ جلدی سمجھنا کافی نہیں ہے کہ کون سے نوڈ نے کام کرنا بند کر دیا ہے۔ ہمیں اس بارے میں کچھ کرنے کی ضرورت ہے۔

بکنگ

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

NewSQL = NoSQL+ACID

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

یہ اسکیم عالمگیر الگورتھم سے زیادہ قابل اعتماد ہے، کیونکہ نئے ماسٹر کو چالو کرنے کے لیے یہ پرانے کی ناکامی کا تعین کرنے کے لیے کافی ہے۔

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

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

لین دین کیسے کام کرتا ہے۔

مان لیں کہ ایک کلائنٹ نے کوآرڈینیٹر کو ایک درخواست بھیجی ہے کہ فلاں فلاں ادارے کے لیے فلاں اور فلاں بنیادی کلید کے ساتھ لین دین کھولیں۔ کوآرڈینیٹر اس ہستی کو لاک کر دیتا ہے اور اسے میموری میں لاک ٹیبل میں رکھتا ہے۔ اگر ضروری ہو تو، کوآرڈینیٹر اس ہستی کو سٹوریج سے پڑھتا ہے اور نتیجے میں آنے والے ڈیٹا کو کوآرڈینیٹر کی میموری میں لین دین کی حالت میں محفوظ کرتا ہے۔

NewSQL = NoSQL+ACID

جب ایک کلائنٹ کسی ٹرانزیکشن میں ڈیٹا کو تبدیل کرنا چاہتا ہے، تو وہ کوآرڈینیٹر کو ہستی میں ترمیم کرنے کی درخواست بھیجتا ہے، اور کوآرڈینیٹر نئے ڈیٹا کو ٹرانزیکشن اسٹیٹس ٹیبل میں میموری میں رکھتا ہے۔ یہ ریکارڈنگ مکمل کرتا ہے - اسٹوریج میں کوئی ریکارڈنگ نہیں کی جاتی ہے۔

NewSQL = NoSQL+ACID

جب کوئی کلائنٹ ایک فعال لین دین کے حصے کے طور پر اپنے تبدیل شدہ ڈیٹا کی درخواست کرتا ہے، تو کوآرڈینیٹر مندرجہ ذیل کام کرتا ہے:

  • اگر ID پہلے سے ہی لین دین میں ہے، تو ڈیٹا میموری سے لیا جاتا ہے۔
  • اگر ID میموری میں نہیں ہے، تو گمشدہ ڈیٹا کو اسٹوریج نوڈس سے پڑھا جاتا ہے، جو پہلے سے میموری میں موجود ہیں، اور نتیجہ کلائنٹ کو دیا جاتا ہے۔

اس طرح، کلائنٹ اپنی تبدیلیوں کو پڑھ سکتا ہے، لیکن دوسرے کلائنٹس کو یہ تبدیلیاں نظر نہیں آتیں، کیونکہ یہ صرف کوآرڈینیٹر کی یاد میں محفوظ ہوتی ہیں؛ وہ ابھی تک کیسینڈرا نوڈس میں نہیں ہیں۔

NewSQL = NoSQL+ACID

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

NewSQL = NoSQL+ACID

اور رول بیک کرنے کے لیے، کوآرڈینیٹر کو صرف لین دین کی حالت کے زیر قبضہ میموری کو آزاد کرنے کی ضرورت ہے۔

مندرجہ بالا بہتریوں کے نتیجے میں، ہم نے ACID اصولوں کو نافذ کیا:

  • جوہری. یہ اس بات کی گارنٹی ہے کہ سسٹم میں کوئی بھی لین دین جزوی طور پر ریکارڈ نہیں کیا جائے گا؛ یا تو اس کے تمام کام مکمل ہو جائیں گے، یا کوئی بھی مکمل نہیں ہو گا۔ ہم کیسینڈرا میں لاگ ان بیچ کے ذریعے اس اصول پر عمل پیرا ہیں۔
  • مستقل مزاجی. ہر کامیاب لین دین، تعریف کے مطابق، صرف درست نتائج ریکارڈ کرتا ہے۔ اگر، ایک ٹرانزیکشن کھولنے اور آپریشن کا حصہ انجام دینے کے بعد، یہ پتہ چلتا ہے کہ نتیجہ غلط ہے، ایک رول بیک کیا جاتا ہے.
  • علیحدگی. جب کوئی لین دین عمل میں آتا ہے، تو ہم آہنگی کے لین دین سے اس کے نتائج کو متاثر نہیں کرنا چاہیے۔ مسابقتی لین دین کو آرڈینیٹر پر مایوسی کے تالے کا استعمال کرتے ہوئے الگ تھلگ کیا جاتا ہے۔ ٹرانزیکشن کے باہر پڑھنے کے لیے، الگ تھلگ اصول کو Read Committed سطح پر دیکھا جاتا ہے۔
  • استحکام. نچلی سطح پر مسائل سے قطع نظر — سسٹم بلیک آؤٹ، ہارڈ ویئر کی ناکامی — کامیابی کے ساتھ مکمل ہونے والی ٹرانزیکشن کے ذریعے کی گئی تبدیلیوں کو محفوظ رہنا چاہیے جب آپریشنز دوبارہ شروع ہوں۔

اشاریہ جات کے حساب سے پڑھنا

آئیے ایک سادہ ٹیبل لیتے ہیں:

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

اس میں ایک ID (بنیادی کلید)، مالک اور ترمیم کی تاریخ ہے۔ آپ کو ایک بہت ہی آسان درخواست کرنے کی ضرورت ہے - "آخری دن کے لیے" تبدیلی کی تاریخ کے ساتھ مالک پر ڈیٹا منتخب کریں۔

SELECT *
WHERE owner=?
AND modified>?

اس طرح کے استفسار پر تیزی سے کارروائی کرنے کے لیے، کلاسک SQL DBMS میں آپ کو کالم (مالک، ترمیم شدہ) کے حساب سے ایک انڈیکس بنانے کی ضرورت ہے۔ ہم یہ بہت آسانی سے کر سکتے ہیں، کیونکہ اب ہمارے پاس ACID کی ضمانتیں ہیں!

سی*ون میں اشاریہ جات

تصاویر کے ساتھ ایک سورس ٹیبل ہے جس میں ریکارڈ ID بنیادی کلید ہے۔

NewSQL = NoSQL+ACID

ایک انڈیکس کے لیے، C*Oن ایک نیا ٹیبل بناتا ہے جو کہ اصل کی کاپی ہے۔ کلید انڈیکس ایکسپریشن جیسی ہی ہے، اور اس میں سورس ٹیبل سے ریکارڈ کی بنیادی کلید بھی شامل ہے:

NewSQL = NoSQL+ACID

اب "آخری دن کے لیے مالک" کے لیے استفسار کو کسی اور ٹیبل سے منتخب کے طور پر دوبارہ لکھا جا سکتا ہے:

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

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

ACID کا استعمال کرتے ہوئے، ہم SQL جیسے اشاریہ جات کو نافذ کرنے کے قابل تھے۔ وہ مستقل، توسیع پذیر، تیز، کمپوز ایبل، اور CQL استفسار کی زبان میں شامل ہیں۔ اشاریہ جات کو سپورٹ کرنے کے لیے ایپلیکیشن کوڈ میں کسی تبدیلی کی ضرورت نہیں ہے۔ سب کچھ اتنا ہی آسان ہے جتنا SQL میں۔ اور سب سے اہم بات، اشاریہ جات اصل ٹرانزیکشن ٹیبل میں ترمیم کی رفتار کو متاثر نہیں کرتے ہیں۔

کیا ہوا

ہم نے C*One کو تین سال پہلے تیار کیا اور اسے کمرشل آپریشن میں شروع کیا۔

آخر ہمیں کیا ملا؟ آئیے فوٹو پروسیسنگ اور اسٹوریج سب سسٹم کی مثال استعمال کرتے ہوئے اس کا اندازہ کرتے ہیں، جو کہ سوشل نیٹ ورک میں ڈیٹا کی سب سے اہم اقسام میں سے ایک ہے۔ ہم خود تصویروں کی لاشوں کے بارے میں بات نہیں کر رہے ہیں، بلکہ ہر قسم کی میٹا معلومات کے بارے میں بات کر رہے ہیں۔ اب Odnoklassniki کے پاس تقریباً 20 بلین ایسے ریکارڈز ہیں، سسٹم 80 ہزار پڑھنے کی درخواستوں کو فی سیکنڈ پروسیس کرتا ہے، ڈیٹا میں ترمیم سے منسلک 8 ہزار ACID لین دین فی سیکنڈ تک۔

جب ہم نے نقلی عنصر = 1 (لیکن RAID 10 میں) کے ساتھ SQL کا استعمال کیا تو، فوٹو میٹینفارمیشن کو Microsoft SQL Server (پلس 32 بیک اپ) چلانے والی 11 مشینوں کے انتہائی دستیاب کلسٹر پر محفوظ کیا گیا تھا۔ بیک اپ کو ذخیرہ کرنے کے لیے 10 سرورز بھی مختص کیے گئے تھے۔ کل 50 مہنگی کاریں۔ ایک ہی وقت میں، نظام ریزرو کے بغیر، ریٹیڈ لوڈ پر کام کرتا ہے۔

نئے سسٹم میں منتقل ہونے کے بعد، ہمیں نقل کا عنصر = 3 موصول ہوا - ہر ڈیٹا سینٹر میں ایک کاپی۔ یہ نظام کل 63 سرورز کے لیے 6 کیسنڈرا اسٹوریج نوڈس اور 69 کوآرڈینیٹر مشینوں پر مشتمل ہے۔ لیکن یہ مشینیں بہت سستی ہیں، ان کی کل لاگت SQL سسٹم کی لاگت کا تقریباً 30% ہے۔ ایک ہی وقت میں، بوجھ 30٪ پر رکھا جاتا ہے.

C*One کے متعارف ہونے کے ساتھ، تاخیر میں بھی کمی آئی: ایس کیو ایل میں، تحریری آپریشن میں تقریباً 4,5 ms کا وقت لگتا ہے۔ سی*ون میں - تقریباً 1,6 ایم ایس۔ لین دین کا دورانیہ اوسطاً 40 ایم ایس سے کم ہے، کمٹ 2 ایم ایس میں مکمل ہوتا ہے، پڑھنے اور لکھنے کا دورانیہ اوسطاً 2 ایم ایس ہے۔ 99واں پرسنٹائل - صرف 3-3,1 ms، ٹائم آؤٹ کی تعداد میں 100 گنا کمی آئی ہے - یہ سب قیاس آرائیوں کے وسیع استعمال کی وجہ سے ہے۔

اب تک، زیادہ تر SQL سرور نوڈس کو ختم کر دیا گیا ہے؛ نئی مصنوعات صرف C*One کا استعمال کرتے ہوئے تیار کی جا رہی ہیں۔ ہم نے اپنے کلاؤڈ میں کام کرنے کے لیے C*One کو ڈھال لیا۔ ایک بادلجس نے نئے کلسٹرز کی تعیناتی کو تیز کرنا، ترتیب کو آسان بنانا اور خودکار آپریشن کو ممکن بنایا۔ سورس کوڈ کے بغیر، ایسا کرنا بہت زیادہ مشکل اور بوجھل ہوگا۔

اب ہم اپنی دیگر اسٹوریج کی سہولیات کو کلاؤڈ میں منتقل کرنے پر کام کر رہے ہیں - لیکن یہ بالکل مختلف کہانی ہے۔

ماخذ: www.habr.com

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