TL؛ DR: شرح معماری سرویس گیرنده-سرور سیستم مدیریت پیکربندی شبکه داخلی ما، QControl. این پروتکل بر اساس یک پروتکل حمل و نقل دو لایه است که با پیام های بسته بندی شده با gzip بدون فشرده سازی بین نقاط پایانی کار می کند. روترها و نقاط پایانی توزیع شده به روز رسانی های پیکربندی را دریافت می کنند و پروتکل خود اجازه نصب رله های میانی محلی را می دهد. این سیستم بر اساس اصل ساخته شده است
آزمایشگاه Qrator یک شبکه کاهش حملات توزیع شده در سطح جهانی را اداره می کند. شبکه ما بر اساس اصل anycast عمل می کند و زیرشبکه ها از طریق BGP تبلیغ می شوند. ما به عنوان یک شبکه anycast BGP که به طور فیزیکی در چندین منطقه از زمین واقع شده است، می توانیم ترافیک نامشروع را نزدیک به هسته اینترنت - اپراتورهای Tier-1 پردازش و فیلتر کنیم.
از سوی دیگر، داشتن یک شبکه پراکنده جغرافیایی کار آسانی نیست. ارتباط بین نقاط حضور شبکه برای ارائهدهنده خدمات امنیتی بسیار مهم است تا پیکربندی ثابتی از تمام گرههای شبکه داشته باشد و آنها را به موقع بهروزرسانی کند. بنابراین، برای ارائه بالاترین سطح ممکن از خدمات اصلی به مصرف کننده، ما باید راهی برای همگام سازی قابل اعتماد داده های پیکربندی در سراسر قاره ها پیدا کنیم.
در آغاز کلمه بود. به سرعت به یک پروتکل ارتباطی تبدیل شد که نیاز به به روز رسانی داشت.
سنگ بنای وجود QControl و در عین حال دلیل اصلی صرف زمان و منابع قابل توجه برای ساخت این نوع پروتکل، نیاز به دستیابی به یک منبع معتبر پیکربندی و در نهایت همگام سازی نقاط حضور ماست. با آن. ذخیره سازی خود تنها یکی از چندین مورد نیاز در طول توسعه QControl بود. علاوه بر این، ما همچنین به ادغام با سرویس های موجود و برنامه ریزی شده در نقاط حضور (POP)، روش های هوشمند (و قابل تنظیم) برای اعتبارسنجی داده ها و همچنین کنترل دسترسی نیاز داشتیم. علاوه بر این، ما همچنین می خواستیم چنین سیستمی را با استفاده از دستورات به جای ایجاد تغییرات در فایل ها کنترل کنیم. قبل از QControl، داده ها تقریباً به صورت دستی به نقاط حضور ارسال می شدند. اگر یکی از نقاط حضور در دسترس نبود و فراموش میکردیم که بعداً آن را بهروزرسانی کنیم، پیکربندی همگام نمیشود و باید برای راهاندازی مجدد و اجرای آن وقت تلف کنیم.
در نتیجه ما به طرح زیر رسیدیم:
سرور پیکربندی مسئول اعتبارسنجی و ذخیره سازی داده ها است؛ روتر دارای چندین نقطه پایانی است که به روز رسانی های پیکربندی را از مشتریان و تیم های پشتیبانی به سرور و از سرور به نقاط حضور دریافت و پخش می کند.
کیفیت اتصال به اینترنت هنوز در سراسر جهان بسیار متفاوت است - برای نشان دادن این نکته، بیایید به یک MTR ساده از پراگ، جمهوری چک تا سنگاپور و هنگ کنگ نگاه کنیم.
تأخیر بالا به معنای سرعت کمتر است. علاوه بر این، از دست دادن بسته وجود دارد. عرض کانال این مشکل را جبران نمی کند، که همیشه باید در هنگام ساخت سیستم های غیرمتمرکز در نظر گرفته شود.
پیکربندی کامل یک نقطه حضور، مقدار قابل توجهی از داده است که باید از طریق اتصالات غیرقابل اعتماد برای بسیاری از گیرندگان ارسال شود. خوشبختانه، اگرچه پیکربندی به طور مداوم تغییر می کند، اما در افزایش های کوچک اتفاق می افتد.
طراحی با ثبات اخیر
می توان گفت که ایجاد یک شبکه توزیع شده بر اساس اصل به روز رسانی افزایشی یک راه حل نسبتا واضح است. اما مشکلات زیادی در رابطه با دیفرانسیل وجود دارد. ما باید تمام تفاوتهای بین نقاط مرجع را ذخیره کنیم، و همچنین بتوانیم در صورتی که کسی بخشی از دادهها را از دست داد، آنها را دوباره ارسال کنیم. هر مقصد باید آنها را در یک توالی مشخص اعمال کند. به طور معمول، در مورد چندین مقصد، چنین عملیاتی میتواند زمان زیادی طول بکشد. گیرنده همچنین باید بتواند قطعات گم شده را درخواست کند و البته قسمت مرکزی باید به چنین درخواستی به درستی پاسخ دهد و فقط داده های از دست رفته را ارسال کند.
در نتیجه، به یک راه حل نسبتاً جالب رسیدیم - ما فقط یک لایه مرجع داریم، ثابت است، بگذارید آن را پایدار بنامیم، و فقط یک تفاوت برای آن - اخیر. هر آخرین بر اساس آخرین پایدار تولید شده است و برای بازسازی داده های پیکربندی کافی است. به محض اینکه تازه تازه به مقصد می رسد، قدیمی دیگر مورد نیاز نیست.
تنها چیزی که باقی میماند این است که هر از گاهی یک پیکربندی پایدار جدید ارسال کنید، برای مثال به دلیل اینکه اخیراً خیلی بزرگ شده است. آنچه در اینجا مهم است این است که ما همه این بهروزرسانیها را در حالت پخش/چندپست ارسال میکنیم، بدون نگرانی در مورد گیرندگان فردی و توانایی آنها برای جمعآوری دادهها. هنگامی که مطمئن شدیم همه افراد دارای استیبل صحیح هستند، فقط موارد جدید جدید را ارسال می کنیم. آیا ارزش توضیح دادن دارد که این کار می کند؟ آثار. Stable در سرور پیکربندی و گیرندگان ذخیره می شود، در صورت نیاز اخیر ایجاد می شود.
معماری حمل و نقل دو سطحی
چرا حمل و نقل خود را در دو سطح ساختیم؟ پاسخ بسیار ساده است - ما می خواستیم مسیریابی را از منطق سطح بالا جدا کنیم و از مدل OSI با لایه های حمل و نقل و کاربردی آن الهام بگیریم. ما از Thrift برای نقش پروتکل انتقال و از قالب سریالسازی msgpack برای قالب سطح بالای پیامهای کنترلی استفاده کردیم. به همین دلیل است که روتر (که چندپخشی/پخش/رله را انجام میدهد) داخل msgpack نگاه نمیکند، محتویات را باز نمیکند یا بسته نمیکند و فقط دادهها را فوروارد میکند.
Thrift (از انگلیسی - Thrift، تلفظ می شود [θrift]) یک زبان توصیف رابط است که برای تعریف و ایجاد خدمات برای زبان های برنامه نویسی مختلف استفاده می شود. این یک چارچوب برای فراخوانی روش از راه دور (RPC) است. یک خط لوله نرم افزار را با یک موتور تولید کد ترکیب می کند تا خدماتی را ایجاد کند که کم و بیش کارآمد و به راحتی بین زبان ها کار کنند.
ما چارچوب Thrift را به دلیل RPC و پشتیبانی از بسیاری از زبان ها انتخاب کردیم. طبق معمول، بخش آسان مشتری و سرور بود. با این حال، روتر یک مهره سخت برای شکستن بود، تا حدی به دلیل عدم وجود راه حل آماده در طول توسعه ما.
گزینه های دیگری مانند protobuf / gRPC وجود دارد، با این حال، زمانی که پروژه خود را شروع کردیم، gRPC کاملا جدید بود و ما جرات نداشتیم آن را در هیئت مدیره بگیریم.
البته، ما می توانستیم (و در واقع باید) دوچرخه خود را بسازیم. ایجاد یک پروتکل برای آنچه ما نیاز داریم آسان تر خواهد بود زیرا اجرای معماری سرویس گیرنده-سرور در مقایسه با ساخت روتر در Thrift نسبتاً ساده است. به هر طریقی، یک سوگیری سنتی نسبت به پروتکلهای خودنویس و پیادهسازی کتابخانههای محبوب وجود دارد (به دلایل خوب)؛ علاوه بر این، در طول بحثها همیشه این سوال مطرح میشود: «چگونه میخواهیم این را به زبانهای دیگر منتقل کنیم؟» بنابراین ما بلافاصله ایده یک دوچرخه را کنار گذاشتیم.
Msgpack مشابه JSON است، اما سریعتر و کوچکتر است. این یک فرمت سریال سازی داده باینری است که امکان تبادل داده بین چندین زبان را فراهم می کند.
در سطح اول ما Thrift را با حداقل اطلاعات لازم برای ارسال پیام توسط روتر داریم. در سطح دوم ساختارهای بسته بندی شده msgpack وجود دارد.
ما msgpack را انتخاب کردیم زیرا در مقایسه با JSON سریعتر و فشرده تر است. اما مهمتر از آن، از انواع دادههای سفارشی پشتیبانی میکند، و به ما امکان میدهد از ویژگیهای جالبی مانند ارسال باینریهای خام یا اشیاء خاص که نشاندهنده عدم وجود داده است، استفاده کنیم، که برای طرح «پایدار اخیر» ما مهم بود.
JMESPath
JMESPath یک زبان جستجوی JSON است.
این دقیقاً همان چیزی است که ما از مستندات رسمی JMESPath دریافت می کنیم، اما در واقع، بسیار بیشتر از این کار می کند. JMESPath به شما این امکان را میدهد که زیردرختها را در یک ساختار درختی دلخواه جستجو و فیلتر کنید، و تغییرات را در دادهها در لحظه اعمال کنید. همچنین به شما امکان می دهد فیلترهای ویژه و روش های تبدیل داده را اضافه کنید. اگرچه البته برای درک آن به تلاش مغزی نیاز دارد.
Jinja
برای برخی از مصرف کنندگان، ما باید پیکربندی را به یک فایل تبدیل کنیم - بنابراین از موتور قالب استفاده می کنیم و Jinja انتخاب واضحی است. با کمک آن، ما یک فایل پیکربندی از الگو و داده های دریافتی در مقصد تولید می کنیم.
برای تولید یک فایل پیکربندی، به یک درخواست JMESPath، یک الگو برای مکان فایل در FS و یک الگو برای خود پیکربندی نیاز داریم. همچنین ایده خوبی است که در این مرحله مجوزهای فایل را روشن کنید. همه اینها با موفقیت در یک فایل ترکیب شد - قبل از شروع الگوی پیکربندی، ما یک هدر در قالب YAML قرار دادیم که بقیه را توضیح می دهد.
به عنوان مثال:
---
selector: "[@][[email protected]._meta.version == `42`] | items([0].fft_config || `{}`)"
destination_filename: "fft/{{ match[0] }}.json"
file_mode: 0644
reload_daemons: [fft]
...
{{ dict(match[1]) | json(indent=2, sort_keys=True) }}
به منظور ایجاد یک فایل پیکربندی برای یک سرویس جدید، ما فقط یک فایل قالب جدید اضافه می کنیم. هیچ تغییری در کد منبع یا نرم افزار در نقاط حضور مورد نیاز نیست.
از زمانی که QControl زنده شد چه چیزی تغییر کرده است؟ اولین و مهمترین چیز، تحویل مداوم و قابل اعتماد به روز رسانی های پیکربندی به تمام گره های شبکه است. دوم دریافت یک ابزار قدرتمند برای بررسی پیکربندی و ایجاد تغییرات در آن توسط تیم پشتیبانی ما و همچنین مصرف کنندگان سرویس است.
ما توانستیم همه این کارها را با استفاده از طرح به روز رسانی اخیر پایدار انجام دهیم تا ارتباط بین سرور پیکربندی و گیرندگان پیکربندی را ساده کنیم. استفاده از یک پروتکل دو لایه برای پشتیبانی از روشی مستقل از محتوا برای مسیریابی داده ها. با موفقیت موتور تولید پیکربندی مبتنی بر Jinja را در یک شبکه فیلتر توزیع شده ادغام کرد. این سیستم طیف گسترده ای از روش های پیکربندی را برای لوازم جانبی توزیع شده و ناهمگن ما پشتیبانی می کند.
با تشکر از کمک شما در نوشتن مطالب.
منبع: www.habr.com