کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

در گروه Mail.ru ما Tarantool را داریم - این یک سرور برنامه در Lua است که به عنوان پایگاه داده نیز دو برابر می شود (یا برعکس؟). این سریع و جالب است، اما قابلیت های یک سرور هنوز نامحدود نیست. مقیاس بندی عمودی نیز نوشدارویی نیست، بنابراین Tarantool ابزارهایی برای مقیاس بندی افقی دارد - ماژول vshard [1]. این به شما امکان می‌دهد داده‌ها را در چندین سرور به اشتراک بگذارید، اما برای راه‌اندازی و پیوست کردن منطق کسب‌وکار باید با آن دستکاری کنید.

خبر خوب: ما چند عکس بزرگ جمع آوری کرده ایم (مثلا [2], [3]) و چارچوب دیگری ایجاد کرد که راه حل این مشکل را به طور قابل توجهی ساده می کند.

کارتریج Tarantool یک چارچوب جدید برای توسعه سیستم های پیچیده توزیع شده است. این به شما امکان می دهد به جای حل مشکلات زیرساختی، روی نوشتن منطق تجاری تمرکز کنید. در زیر برش به شما خواهم گفت که این چارچوب چگونه کار می کند و چگونه با استفاده از آن سرویس های توزیع شده را بنویسید.

و دقیقاً مشکل چیست؟

ما رتیل داریم، وشارد داریم - بیشتر از این چه چیزی می خواهید؟

اولاً، موضوع راحتی است. پیکربندی vshard از طریق جداول Lua پیکربندی می شود. برای اینکه یک سیستم توزیع شده از چندین فرآیند Tarantool به درستی کار کند، پیکربندی باید در همه جا یکسان باشد. هیچ کس نمی خواهد این کار را به صورت دستی انجام دهد. بنابراین، انواع اسکریپت ها، Ansible و سیستم های استقرار استفاده می شود.

کارتریج خودش پیکربندی vshard را مدیریت می کند، این کار را بر اساس آن انجام می دهد پیکربندی توزیع شده خود. این در اصل یک فایل YAML ساده است که یک کپی از آن در هر نمونه Tarantool ذخیره می شود. ساده‌سازی این است که خود چارچوب بر پیکربندی آن نظارت می‌کند و اطمینان می‌دهد که در همه جا یکسان است.

ثانیاً، دوباره موضوع راحتی است. پیکربندی vshard هیچ ارتباطی با توسعه منطق تجاری ندارد و فقط برنامه نویس را از کار خود منحرف می کند. هنگامی که در مورد معماری یک پروژه بحث می کنیم، اغلب در مورد اجزای جداگانه و تعامل آنها صحبت می کنیم. خیلی زود است که به توسعه یک خوشه در 3 مرکز داده فکر کنید.

ما این مشکلات را بارها و بارها حل کردیم و در مقطعی موفق شدیم رویکردی را توسعه دهیم که کار با برنامه را در کل چرخه عمر آن ساده می کند: ایجاد، توسعه، آزمایش، CI/CD، نگهداری.

کارتریج مفهوم نقش را برای هر فرآیند Tarantool معرفی می کند. نقش ها مفهومی هستند که به توسعه دهندگان اجازه می دهد روی نوشتن کد تمرکز کنند. تمام نقش های موجود در پروژه را می توان بر روی یک نمونه Tarantool اجرا کرد و این برای تست ها کافی خواهد بود.

ویژگی های کلیدی کارتریج Tarantool:

  • ارکستراسیون خوشه ای خودکار؛
  • گسترش عملکرد برنامه با استفاده از نقش های جدید؛
  • قالب برنامه برای توسعه و استقرار؛
  • اشتراک گذاری خودکار داخلی؛
  • ادغام با چارچوب تست Luatest؛
  • مدیریت خوشه با استفاده از WebUI و API.
  • ابزارهای بسته بندی و استقرار

سلام دنیا!

من نمی توانم صبر کنم تا خود چارچوب را نشان دهم، بنابراین داستان معماری را برای بعد می گذاریم و با چیزی ساده شروع می کنیم. اگر فرض کنیم که خود Tarantool قبلاً نصب شده است، تنها کاری که باقی می ماند انجام است

$ tarantoolctl rocks install cartridge-cli
$ export PATH=$PWD/.rocks/bin/:$PATH

این دو دستور ابزارهای خط فرمان را نصب می کنند و به شما امکان می دهند اولین برنامه خود را از قالب ایجاد کنید:

$ cartridge create --name myapp

و این چیزی است که به دست می آوریم:

myapp/
├── .git/
├── .gitignore
├── app/roles/custom.lua
├── deps.sh
├── init.lua
├── myapp-scm-1.rockspec
├── test
│   ├── helper
│   │   ├── integration.lua
│   │   └── unit.lua
│   ├── helper.lua
│   ├── integration/api_test.lua
│   └── unit/sample_test.lua
└── tmp/

این یک مخزن git با یک "Hello, World!" آماده است. کاربرد. بیایید با نصب قبلی وابستگی ها (از جمله خود چارچوب) فوراً آن را اجرا کنیم:

$ tarantoolctl rocks make
$ ./init.lua --http-port 8080

بنابراین، ما یک گره داریم که برای برنامه های خرد شده آینده اجرا می شود. یک فرد عادی کنجکاو می تواند بلافاصله رابط وب را باز کند، مجموعه ای از یک گره را با ماوس پیکربندی کند و از نتیجه لذت ببرد، اما برای خوشحالی خیلی زود است. تا اینجای کار، برنامه نمی تواند کار مفیدی انجام دهد، بنابراین من بعداً در مورد استقرار به شما خواهم گفت، اما اکنون زمان نوشتن کد است.

توسعه برنامه

فقط تصور کنید، ما در حال طراحی پروژه ای هستیم که باید داده ها را دریافت کند، آن را ذخیره کند و یک گزارش در روز بسازد.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

ما شروع به کشیدن یک نمودار می کنیم و سه جزء را روی آن قرار می دهیم: دروازه، ذخیره سازی و زمانبندی. ما بیشتر روی معماری کار می کنیم. از آنجایی که ما از vshard به عنوان ذخیره سازی استفاده می کنیم، vshard-router و vshard-storage را به طرح اضافه می کنیم. نه گیت‌وی و نه زمان‌بندی‌کننده مستقیماً به فضای ذخیره‌سازی دسترسی نخواهند داشت؛ این همان چیزی است که روتر برای آن ساخته شده است.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

این نمودار هنوز دقیقاً چیزی را که ما در پروژه می سازیم نشان نمی دهد زیرا اجزا به نظر انتزاعی هستند. ما هنوز باید ببینیم که چگونه بر روی Tarantool واقعی پیش بینی می شود - بیایید اجزای خود را بر اساس فرآیند گروه بندی کنیم.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

نگه داشتن vshard-router و gateway در نمونه های جداگانه، فایده ای ندارد. چرا باید یک بار دیگر در شبکه گشت و گذار کنیم اگر این مسئولیت از قبل بر عهده روتر است؟ آنها باید در همان فرآیند اجرا شوند. یعنی هم gateway و هم vshard.router.cfg در یک فرآیند مقداردهی اولیه می‌شوند و اجازه می‌دهند به صورت محلی تعامل داشته باشند.

در مرحله طراحی، کار با سه مؤلفه راحت بود، اما من به عنوان یک توسعه دهنده، هنگام نوشتن کد، نمی خواهم به راه اندازی سه نمونه از Tarnatool فکر کنم. باید تست ها را اجرا کنم و بررسی کنم که gateway را درست نوشته ام. یا شاید بخواهم یک ویژگی را به همکارانم نشان دهم. چرا باید از طریق استقرار سه نسخه دردسر کنم؟ مفهوم نقش ها اینگونه متولد شد. نقش یک ماژول معمولی luash است که چرخه زندگی آن توسط کارتریج مدیریت می شود. در این مثال چهار مورد از آنها وجود دارد - دروازه، روتر، ذخیره سازی، زمانبندی. ممکن است در پروژه دیگری موارد بیشتری وجود داشته باشد. همه نقش ها را می توان در یک فرآیند اجرا کرد و این کافی خواهد بود.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

و وقتی نوبت به استقرار در مرحله‌بندی یا تولید می‌رسد، ما به هر فرآیند Tarantool بسته به قابلیت‌های سخت‌افزار، مجموعه‌ای از نقش‌های خاص خود را اختصاص می‌دهیم:

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

مدیریت توپولوژی

اطلاعات مربوط به محل اجرای نقش ها باید در جایی ذخیره شود. و این "جایی" پیکربندی توزیع شده است که قبلاً در بالا ذکر کردم. مهمترین چیز در مورد آن توپولوژی خوشه ای است. در اینجا 3 گروه تکرار از 5 فرآیند Tarantool آورده شده است:

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

ما نمی‌خواهیم داده‌ها را از دست بدهیم، بنابراین اطلاعات مربوط به فرآیندهای در حال اجرا را با دقت بررسی می‌کنیم. کارتریج پیکربندی را با استفاده از یک تعهد دو فازی پیگیری می کند. هنگامی که می خواهیم پیکربندی را به روز کنیم، ابتدا بررسی می کند که همه نمونه ها در دسترس هستند و آماده پذیرش پیکربندی جدید هستند. بعد از این مرحله دوم پیکربندی را اعمال می کند. بنابراین، حتی اگر یک نسخه به طور موقت در دسترس نباشد، هیچ اتفاق بدی نخواهد افتاد. پیکربندی به سادگی اعمال نخواهد شد و از قبل یک خطا را مشاهده خواهید کرد.

همچنین در بخش توپولوژی، پارامتر مهمی به عنوان رهبر هر گروه تکرار نشان داده شده است. معمولاً این نسخه ای است که در حال ضبط است. بقیه اغلب فقط خواندنی هستند، اگرچه ممکن است استثناهایی وجود داشته باشد. گاهی اوقات توسعه دهندگان شجاع از درگیری نمی ترسند و می توانند داده ها را به صورت موازی روی چندین نسخه بنویسند، اما برخی از عملیات ها وجود دارد که هر چه باشد، نباید دو بار انجام شود. برای این نشانه ای از یک رهبر وجود دارد.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

زندگی نقش ها

برای اینکه نقشی انتزاعی در چنین معماری وجود داشته باشد، چارچوب باید به نحوی آنها را مدیریت کند. به طور طبیعی، کنترل بدون راه اندازی مجدد فرآیند Tarantool اتفاق می افتد. 4 تماس برای مدیریت نقش ها وجود دارد. خود کارتریج بسته به آنچه در پیکربندی توزیع شده آن نوشته شده است آنها را فراخوانی می کند و بدین ترتیب پیکربندی را برای نقش های خاص اعمال می کند.

function init()
function validate_config()
function apply_config()
function stop()

هر نقشی کارکردی دارد init. زمانی که نقش فعال است یا زمانی که Tarantool مجدداً راه اندازی می شود، یک بار فراخوانی می شود. در آنجا راحت است، برای مثال، مقداردهی اولیه box.space.create، یا زمانبندی می تواند مقداری فیبر پس زمینه را راه اندازی کند که در فواصل زمانی معینی کار را انجام دهد.

یک تابع init ممکن است کافی نباشد کارتریج به نقش ها اجازه می دهد تا از تنظیمات توزیع شده ای که برای ذخیره توپولوژی استفاده می کند استفاده کنند. ما می توانیم یک بخش جدید را در همان پیکربندی اعلام کنیم و بخشی از پیکربندی تجاری را در آن ذخیره کنیم. در مثال من، این می تواند یک طرح داده یا تنظیمات زمانبندی برای نقش زمانبندی باشد.

تماس های خوشه ای validate_config и apply_config هر بار که پیکربندی توزیع شده تغییر می کند. هنگامی که یک پیکربندی توسط یک commit دو مرحله ای اعمال می شود، خوشه بررسی می کند که آیا هر نقش آماده پذیرش این پیکربندی جدید است و در صورت لزوم، یک خطا را به کاربر گزارش می دهد. وقتی همه موافقند که پیکربندی عادی است، apply_config.

همچنین نقش ها روشی دارند stop، که برای پاکسازی خروجی نقش مورد نیاز است. اگر بگوییم که زمان‌بندی دیگر در این سرور مورد نیاز نیست، می‌تواند فیبرهایی را که با آن شروع کرده است متوقف کند init.

نقش ها می توانند با یکدیگر تعامل داشته باشند. ما به نوشتن فراخوانی تابع در Lua عادت کرده ایم، اما ممکن است اتفاق بیفتد که یک فرآیند معین نقش مورد نیاز ما را نداشته باشد. برای تسهیل تماس ها از طریق شبکه، ما از ماژول کمکی rpc (تماس از راه دور) استفاده می کنیم که بر اساس نت باکس استاندارد تعبیه شده در Tarantool ساخته شده است. این می تواند مفید باشد، به عنوان مثال، دروازه شما بخواهد مستقیماً از زمانبندی بخواهد کار را در حال حاضر انجام دهد، نه اینکه یک روز منتظر بماند.

نکته مهم دیگر اطمینان از تحمل خطا است. کارتریج از پروتکل SWIM برای نظارت بر سلامت استفاده می کند [4]. به طور خلاصه، فرآیندها با یکدیگر «شایعات» را از طریق UDP رد و بدل می کنند - هر فرآیند آخرین اخبار را به همسایگان خود می گوید و آنها پاسخ می دهند. اگر ناگهان جواب نداد، ترانتول شروع به شک می کند که چیزی اشتباه است و پس از مدتی مرگ را می خواند و شروع به گفتن این خبر به همه اطرافیان می کند.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

بر اساس این پروتکل، کارتریج پردازش خودکار شکست را سازماندهی می کند. هر فرآیند محیط خود را نظارت می کند و اگر رهبر به طور ناگهانی پاسخ را متوقف کند، ماکت می تواند نقش آن را بر عهده بگیرد و کارتریج بر اساس آن نقش های در حال اجرا را پیکربندی می کند.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

در اینجا باید مراقب باشید، زیرا جابجایی مکرر به جلو و عقب می تواند منجر به تضاد داده ها در طول تکرار شود. البته، شما نباید Failover خودکار را به صورت تصادفی فعال کنید. ما باید به وضوح درک کنیم که چه اتفاقی می افتد و مطمئن باشیم که پس از ترمیم رهبر و بازگرداندن تاج به او، تکرار شکسته نخواهد شد.

از همه اینها، ممکن است این احساس را به دست آورید که نقش ها شبیه به میکروسرویس ها هستند. به یک معنا، آنها فقط به عنوان ماژول در فرآیندهای Tarantool هستند. اما تعدادی تفاوت اساسی نیز وجود دارد. اول، همه نقش های پروژه باید در یک پایگاه کد زندگی کنند. و همه فرآیندهای Tarantool باید از یک پایه کد راه‌اندازی شوند، به طوری که هیچ غافلگیری مانند مواردی که می‌خواهیم زمان‌بندی را مقداردهی کنیم، وجود نداشته باشد، اما به سادگی وجود ندارد. همچنین نباید اجازه دهید تفاوت در نسخه های کد وجود داشته باشد، زیرا پیش بینی و اشکال زدایی رفتار سیستم در چنین شرایطی بسیار دشوار است.

برخلاف داکر، ما نمی‌توانیم فقط یک نقش را "تصویر" بگیریم، آن را به ماشین دیگری ببریم و در آنجا اجرا کنیم. نقش های ما به اندازه کانتینرهای داکر مجزا نیست. همچنین، ما نمی توانیم دو نقش یکسان را در یک نمونه اجرا کنیم. یک نقش یا وجود دارد یا نیست؛ به یک معنا، یک تک‌تن است. و ثالثاً، نقش ها باید در کل گروه تکرار یکسان باشند، زیرا در غیر این صورت پوچ خواهد بود - داده ها یکسان هستند، اما پیکربندی متفاوت است.

ابزارهای استقرار

من قول دادم نشان دهم که کارتریج چگونه به استقرار برنامه ها کمک می کند. برای آسان‌تر کردن زندگی دیگران، چارچوب بسته‌های RPM را بسته‌بندی می‌کند:

$ cartridge pack rpm myapp -- упакует для нас ./myapp-0.1.0-1.rpm
$ sudo yum install ./myapp-0.1.0-1.rpm

بسته نصب شده شامل تقریباً همه چیزهایی است که شما نیاز دارید: هم برنامه و هم وابستگی های نصب شده. Tarantool نیز به عنوان وابستگی بسته RPM به سرور می رسد و سرویس ما آماده راه اندازی است. این کار از طریق systemd انجام می شود، اما ابتدا باید کمی پیکربندی بنویسید. حداقل، URI هر فرآیند را مشخص کنید. برای مثال سه مورد کافی است.

$ sudo tee /etc/tarantool/conf.d/demo.yml <<CONFIG
myapp.router: {"advertise_uri": "localhost:3301", "http_port": 8080}
myapp.storage_A: {"advertise_uri": "localhost:3302", "http_enabled": False}
myapp.storage_B: {"advertise_uri": "localhost:3303", "http_enabled": False}
CONFIG

یک نکته جالب در اینجا وجود دارد. به جای اینکه فقط پورت پروتکل باینری را مشخص کنیم، کل آدرس عمومی فرآیند از جمله نام میزبان را مشخص می کنیم. این امر ضروری است تا گره های خوشه بدانند چگونه به یکدیگر متصل شوند. این ایده بدی است که از 0.0.0.0 به عنوان آدرس advertise_uri استفاده کنید؛ این آدرس باید یک آدرس IP خارجی باشد نه یک اتصال سوکت. بدون آن، هیچ چیز کار نخواهد کرد، بنابراین کارتریج به سادگی به شما اجازه راه اندازی یک گره با advertise_uri اشتباه را نمی دهد.

اکنون که پیکربندی آماده است، می توانید فرآیندها را شروع کنید. از آنجایی که یک واحد systemd معمولی اجازه نمی دهد بیش از یک فرآیند شروع شود، برنامه های کاربردی روی کارتریج به اصطلاح نصب می شوند. واحدهای نمونه ای که به این صورت کار می کنند:

$ sudo systemctl start myapp@router
$ sudo systemctl start myapp@storage_A
$ sudo systemctl start myapp@storage_B

در پیکربندی، پورت HTTP را مشخص کردیم که کارتریج در آن رابط وب را ارائه می کند - 8080. بیایید به آن برویم و نگاهی بیندازیم:

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

می بینیم که اگرچه فرآیندها در حال اجرا هستند، اما هنوز پیکربندی نشده اند. کارتریج هنوز نمی داند چه کسی باید با چه کسی تکرار کند و نمی تواند به تنهایی تصمیم بگیرد، بنابراین منتظر اقدامات ما است. اما ما انتخاب زیادی نداریم: زندگی یک خوشه جدید با پیکربندی اولین گره آغاز می شود. سپس بقیه را به خوشه اضافه می‌کنیم، نقش‌هایی را به آن‌ها اختصاص می‌دهیم و در این مرحله استقرار را می‌توان با موفقیت به پایان رساند.

بیایید یک لیوان از نوشیدنی مورد علاقه خود را بریزیم و بعد از یک هفته کاری طولانی استراحت کنیم. اپلیکیشن قابل استفاده است.

کارتریج Tarantool: به اشتراک گذاری باطن Lua در سه خط

نمایش نتایج: از

نتایج چیست؟ آن را امتحان کنید، از آن استفاده کنید، بازخورد بگذارید، در Github بلیط ایجاد کنید.

مراجع

[1] Tarantool » 2.2 » Reference » Rocks Reference » Module vshard

[2] چگونه هسته کسب و کار سرمایه گذاری آلفا بانک را بر اساس Tarantool پیاده سازی کردیم

[3] معماری صدور صورت حساب نسل جدید: تحول با انتقال به Tarantool

[4] SWIM - پروتکل ساخت خوشه

[5] GitHub - tarantool/cartridge-cli

[6] GitHub - رتیل/کارتریج

منبع: www.habr.com

اضافه کردن نظر