حرکت تیندر به کوبنتس

نوشته شده توسط: کریس اوبراین ، مدیر مهندسی | کریس توماس ، مدیر مهندسی | جینیونگ لی ، مهندس ارشد نرم افزار | ویرایش توسط: کوپر جکسون ، مهندس نرم افزار

چرا

تقریبا دو سال پیش ، تیندر تصمیم گرفت سکوی خود را به Kubernetes منتقل کند. Kubernetes فرصتی را برای ما فراهم کرد تا مهندسی Tinder را به سمت کانتینر کردن و عملکرد کم لمس از طریق استقرار غیرقابل تغییر سوق دهیم. ساخت برنامه ، استقرار و زیرساختها به عنوان كد تعریف می شوند.

ما همچنین به دنبال رفع چالش های مقیاس و ثبات بودیم. هنگامی که مقیاس گذاری بسیار مهم شد ، ما اغلب چندین دقیقه انتظار برای انتشار موارد جدید EC2 را متحمل می شویم. ایده ظروف برنامه ریزی و سرویس دهی به ترافیک در عرض چند ثانیه و نه بر خلاف دقیقه ، برای ما جذاب بود.

کار آسانی نبود در طی مهاجرت در اوایل سال 2019 ، در خوشه Kubernetes خود به توده حیاتی رسیدیم و به دلیل حجم ترافیک ، اندازه خوشه و DNS با چالش های مختلفی روبرو شدیم. ما برای مهاجرت 200 سرویس و اجرای یک خوشه Kubernetes در مقیاس در مجموع 1000 گره ، 15،000 غلاف و 48000 ظروف در حال اجرا چالش های جالبی را حل کردیم.

چگونه

با شروع ژانویه سال 2018 ، ما مراحل خود را طی مراحل مختلف تلاش برای مهاجرت انجام دادیم. ما با مخلوط کردن کلیه خدمات خود و اعزام آنها به مجموعه ای از Kubernetes به میزبانی محیط های صحنه سازی شروع کردیم. با شروع ماه اکتبر ، ما به روش متدولی شروع به جابجایی کلیه خدمات میراث خود به کوبنتس کردیم. تا مارس سال بعد ، مهاجرت خود را نهایی کردیم و اکنون بسترهای نرم افزاری Tinder به طور انحصاری در Kubernetes اجرا می شود.

ساخت تصاویر برای Kubernetes

بیش از 30 مخزن کد منبع برای میکرو سرویس هایی که در خوشه Kubernetes در حال اجرا هستند وجود دارد. کد موجود در این مخازن به زبانهای مختلف (به عنوان مثال Node.js ، Java ، Scala ، Go) با محیط های مختلف اجرا برای همان زبان نوشته شده است.

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

شکل 1-1 فرآیند ساخت استاندارد از طریق ظرف Builder

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

اجرای ظرف Builder به تعدادی از تکنیک های پیشرفته Docker نیاز داشت. این کانتینر سازنده ، از شناسه و اسرار کاربر محلی (به عنوان مثال ، کلید SSH ، اعتبار AWS و غیره) در صورت نیاز برای دسترسی به مخازن خصوصی Tinder به ارث می برد. این دایرکتوری های محلی را که شامل کد منبع هستند ، نصب می کند تا روشی طبیعی برای ذخیره مصنوعات ساخت داشته باشد. این روش عملکرد را بهبود می بخشد ، زیرا کپی کردن مصنوعات ساخته شده بین ظرف سازنده و دستگاه میزبان را از بین می برد. مصنوعات ساختمانی ذخیره شده دفعه دیگر بدون پیکربندی بیشتر مورد استفاده مجدد قرار می گیرند.

برای برخی از خدمات ، ما نیاز به ایجاد یک ظرف دیگر در Builder برای مطابقت با محیط کامپایل با محیط زمان اجرا (به عنوان مثال ، نصب کتابخانه bcrypt Node.js باعث ایجاد آثار باینری خاص برای پلتفرم می شود). الزامات زمان کامپایل ممکن است در بین خدمات متفاوت باشد و Dockerfile نهایی در پرواز تشکیل شده است.

معماری و مهاجرت خوشهای Kubernetes

اندازه خوشه

ما تصمیم گرفتیم برای تهیه خوشه خودکار در نمونه های EC2 آمازون از kube-aws استفاده کنیم. اوایل ، ما همه چیز را در یک استخر گره عمومی اجرا می کردیم. ما به سرعت لزوم جداسازی حجم کار به اندازه و انواع مختلف را به سرعت شناسایی کردیم تا از منابع بهتر استفاده کنیم. استدلال این بود که دویدن غلافهای با نخ کمتر با هم ، نتایج عملکرد قابل پیش بینی بیشتری را برای ما به ارمغان می آورند تا اینکه اجازه دهیم آنها با تعداد بیشتری غلاف تک رشته ای همزیستی شوند.

ما حل و فصل کردیم:

  • m5.4x بزرگنمایی برای نظارت (پرومتئوس)
  • c5.4 بزرگنمایی برای حجم کار Node.js (حجم کار تک رشته ای)
  • بزرگنمایی c5.2 برای جاوا و Go (حجم کار چند رشته ای)
  • c5.4 بزرگنمایی برای صفحه کنترل (3 گره)

مهاجرت

یکی از مراحل آماده سازی برای انتقال از زیرساخت های میراث ما به Kubernetes ، تغییر ارتباطات سرویس به سرویس های دیگر برای اشاره به Balancers Loading Balastic جدید (ELB) جدید است که در یک زیر شبکه خاص Virtual Private Cloud (VPC) ایجاد شده اند. این زیر شبکه متعلق به Kubernetes VPC بود. این به ما امکان می دهد تا بدون در نظر گرفتن سفارش خاص برای وابستگی های خدمات ، ماژول ها را به صورت انبوه مهاجرت کنیم.

این نقاط پایانی با استفاده از مجموعه های ضبط شده DNS وزنی ایجاد شده که دارای CNAME بود که به هر ELB جدید اشاره می کردند. برای برش ، ما یک رکورد جدید اضافه کردیم ، با اشاره به سرویس جدید Kubernetes ELB ، با وزن 0. ما سپس Time to Live (TTL) را روی رکورد تنظیم کردیم تا 0. وزن قدیم و جدید پس از آن به آرامی تنظیم شد. سرانجام با 100٪ سرور جدید روبرو می شوید. پس از تکمیل برش ، TTL روی چیزی معقول تر قرار گرفت.

ماژول های جاوا ما DNS TTL کم را تحسین کردند ، اما برنامه های Node ما این کار را نکردند. یکی از مهندسان ما بخشی از کد استخر اتصال را بازنویسی می کند تا آن را در یک مدیر بپیوندد که استخرها را هر 60 ثانیه تازه کند. این خیلی خوب برای ما کار کرد و عملکرد قابل توجهی نداشت.

یادگیری

محدودیت پارچه شبکه

در ساعات اولیه صبح روز 8 ژانویه 2019 ، بسترهای نرم افزاری تیندر دچار خاموشی مداوم شد. در پاسخ به افزایش نامربوط در تأخیر بسترهای نرم افزاری در اوایل صبح ، شمارش غلاف و گره ها بر روی خوشه اندازه گیری شد. این منجر به خستگی کش ARP در تمام گره های ما شد.

سه مقدار لینوکس مربوط به حافظه پنهان ARP وجود دارد:

اعتبار

gc_thresh3 یک کلاه سخت است. اگر ورودی های ورود به سیستم "سرریز همسایه" را دریافت می کنید ، این نشان می دهد که حتی پس از جمع آوری زباله های همزمان (GC) از حافظه نهان ARP ، فضای کافی برای ذخیره ورودی همسایه وجود ندارد. در این حالت ، هسته فقط بسته را به طور کامل ریخته است.

ما از كلنل به عنوان پارچه شبكه خود در كوبنتن استفاده می كنیم. بسته ها از طریق VXLAN ارسال می شوند. VXLAN یک طرح پوشش Layer 2 از طریق شبکه Layer 3 است. با استفاده از MAC آدرس-در-کاربر پروتکل Datagram (MAC-in-UDP) محصور سازی می کند تا وسیله ای برای گسترش بخش های شبکه Layer 2 فراهم شود. پروتکل حمل و نقل از طریق شبکه داده های فیزیکی IP به علاوه UDP است.

شکل 2-1 نمودار فلانل (اعتبار)

شکل 2-2 بسته VXLAN (اعتبار)

هر گره کارگر Kubernetes فضای اختصاصی خود را / 24 آدرس آدرس مجازی از یک بلوک بزرگتر / 9 اختصاص می دهد. برای هر گره ، این نتایج شامل 1 جدول ورود به جدول مسیر ، 1 ورودی جدول ARP (در رابط flannel.1) و 1 ورودی بانک اطلاعاتی حمل و نقل (FDB) است. اینها هنگامی که گره کارگر ابتدا راه اندازی می شود یا هر گره جدید کشف می شود ، اضافه می شوند.

علاوه بر این ، ارتباط گره به غلاف (یا غلاف به غلاف) در نهایت بر روی رابط eth0 (که در نمودار فلانل در بالا نشان داده شده است) جریان می یابد. این منجر به ورود اضافی در جدول ARP برای هر منبع گره مربوطه و مقصد گره خواهد شد.

در محیط ما ، این نوع ارتباطات بسیار متداول است. برای اشیاء خدمات ما Kubernetes ، یک ELB ایجاد می شود و Kubernetes هر گره را با ELB ثبت می کند. ELB غلاف نیست و گره انتخاب شده ممکن است مقصد نهایی بسته نباشد. این امر به این دلیل است که وقتی گره بسته را از ELB دریافت می کند ، قوانین iptables آن را برای سرویس ارزیابی می کند و بطور تصادفی یک غلاف را روی یک گره دیگر انتخاب می کند.

در زمان قطع ، 605 گره در کل خوشه وجود داشت. به دلایلی که در بالا ذکر شد ، این کافی بود تا مقدار پیش فرض gc_thresh3 را به دست آورید. هنگامی که این اتفاق می افتد ، نه تنها بسته ها از بین می روند ، بلکه کل Flannel / 24 های فضای آدرس مجازی از جدول ARP گم نمی شوند. ارتباط گره به غلاف و جستجوی DNS با شکست مواجه می شوند. (DNS در داخل خوشه میزبانی می شود ، که بعدا در این مقاله با جزئیات بیشتر توضیح داده می شود.)

برای برطرف کردن ، مقادیر gc_thresh1 ، gc_thresh2 و gc_thresh3 مطرح شده و باید Flannel مجدداً راه اندازی شود تا مجدداً شبکه های از دست رفته را ثبت کنید.

به طور غیر منتظره در حال اجرا DNS در مقیاس است

برای پذیرش مهاجرت ، ما DNS را به شدت برای تسهیل شکل دادن به ترافیک و کاهش افزایشی از میراث به Kubernetes برای خدمات خود ، به کار گرفتیم. ما مقادیر TTL نسبتاً کم را روی Route53 RecordSets مربوط تنظیم می کنیم. هنگامی که زیرساختهای میراث خود را در موارد EC2 اجرا کردیم ، پیکربندی حلال ما به DNS آمازون اشاره کرد. ما این کار را بطور واضح در نظر گرفتیم و هزینه TTL نسبتاً کم برای خدمات ما و خدمات آمازون (مانند DynamoDB) تا حد زیادی غافل شد.

هرچه بیشتر خدمات بیشتری به Kubernetes سوار کردیم ، متوجه شدیم که سرویس DNS را اجرا می کنیم که به 250،000 درخواست در ثانیه پاسخ می داد. ما در برنامه های ما با زمان بندی جستجوی DNS متناوب و تأثیرگذار روبرو بودیم. این اتفاق با وجود تلاش فراگیر تنظیم و یک ارائه دهنده DNS به استقرار CoreDNS رخ داد که در یک زمان به 1000 غلاف با 120 هسته رسیده بود.

در حالی که به بررسی علل و راه حلهای ممکن دیگر می پردازیم ، ما مقاله ای را توصیف کردیم که شرایط مسابقه را تحت تأثیر قرار دادن چارچوب فیلتر بسته بندی لینوکس به طور کامل فیلتر نشده توصیف می کند. زمان بندی DNS که مشاهده می کردیم ، به همراه یک پیشخوان افزایشی insert_failed در رابط کاربری Flannel ، با یافته های مقاله مطابقت داشت.

این مسئله هنگام ترجمه آدرس منبع و مقصد شبکه (SNAT و DNAT) و درج بعدی در جدول کنترل رخ می دهد. یك راه حلی كه در داخل مورد بحث قرار گرفته و توسط جامعه پیشنهاد شده ، انتقال DNS به خود گره كارگر بود. در این مورد:

  • SNAT ضروری نیست ، زیرا ترافیک به صورت محلی روی گره می ماند. نیازی به انتقال به رابط eth0 نیست.
  • DNAT ضروری نیست زیرا IP مقصد برای گره موضعی است و یک غلاف به طور تصادفی انتخاب شده براساس قوانین iptables انتخاب نمی شود.

ما تصمیم گرفتیم با این رویکرد به جلو حرکت کنیم. CoreDNS به عنوان DaemonSet در Kubernetes مستقر شد و ما با پیکربندی کردن پرچم فرمان kubelet - cluster-dns ، سرور DNS محلی گره را به هر یک از رزول.conf هر غلاف تزریق کردیم. راه حل برای موقت DNS مؤثر بود.

با این حال ، ما هنوز بسته های افتاده و افزونه insert_failed رابط Flannel را می بینیم. این حتی بعد از راه حل بالا ادامه خواهد یافت زیرا ما فقط از SNAT و / یا DNAT برای ترافیک DNS اجتناب می کنیم. شرایط مسابقه هنوز هم برای انواع دیگر ترافیک رخ می دهد. خوشبختانه ، اکثر بسته های ما TCP هستند و در صورت بروز شرایط ، بسته ها با موفقیت ارسال می شوند. رفع طولانی مدت برای انواع ترافیک چیزی است که ما هنوز در مورد آن صحبت می کنیم.

استفاده از فرستاده برای دستیابی به تعادل بهتر بار

همانطور که ما خدمات باطن خود را به Kubernetes مهاجرت کردیم ، ما از یک بار نامتعادل در غلاف رنج می بریم. ما فهمیدیم که به دلیل HTTP Keepalive ، اتصالات ELB به اولین غلافهای آماده استقرار در هر پله چسبیده اند ، بنابراین بیشتر ترافیک در درصد کمی از غلافهای موجود جریان می یابد. یکی از اولین تخفیفاتی که سعی کردیم استفاده از 100٪ MaxSurge در استقرارهای جدید برای بدترین متخلفان بود. این با استفاده از برخی از استقرارهای بزرگ در دراز مدت بسیار مؤثر و پایدار نبود.

یکی دیگر از کاهشهای مورد استفاده ما باد کردن مصنوعی درخواست منابع در سرویسهای مهم بود تا غلافهای رنگی دارای صندلی بیشتری در کنار غلافهای سنگین باشند. همچنین این به دلیل هدر رفتن منابع در طولانی مدت قابل تحمل نخواهد بود و برنامه های گره ما به صورت تک رشته ای بوده و بنابراین به طور موثر در 1 هسته قرار می گیرند. تنها راه حل روشن استفاده از تعادل بهتر بار بود.

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

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

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

برای استقرار ، ما از قلاب preStop در برنامه و غلاف sidecar استفاده کردیم. این قلاب که به آن چک بهداشتی sidecar نامیده می شود ، سرانجام مدیر را به همراه یک خواب کوچک از بین نمی برد تا مدتی وقت بگذارید تا اتصالات نورپردازی کامل و تخلیه شود.

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

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

شکل 3-1 همگرایی CPU یک سرویس در طول انتقال برای فرستاده

نتیجه نهایی

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

در زیرساخت های میراث ما ، هنگامی که مقیاس اضافی لازم بود ، ما اغلب با چند دقیقه انتظار برای انتشار موارد جدید EC2 متحمل می شویم. کانتینرها اکنون برخلاف دقایقی ، در عرض چند ثانیه برنامه ریزی و سرویس می کنند. برنامه ریزی چندین ظروف در یک نمونه EC2 تنها باعث افزایش تراکم افقی می شود. در نتیجه ، ما صرفه جویی قابل توجهی در هزینه در EC2 در سال 2019 در مقایسه با سال گذشته انجام می دهیم.

نزدیک به دو سال طول کشید ، اما ما مهاجرت خود را در مارس 2019 نهایی کردیم. Tinder Platform منحصراً بر روی خوشه Kubernetes متشکل از 200 سرویس ، 1000 گره ، 15000 غلاف و 48000 ظروف در حال اجرا اجرا می شود. زیرساختها دیگر وظیفه ای نیست که برای تیم های عملیاتی ما اختصاص داده شود. درعوض ، مهندسین سراسر سازمان در این مسئولیت سهیم هستند و بر نحوه ساخت و استقرار برنامه های خود با همه چیز به عنوان کد کنترل دارند.

همچنین ببینید

چگونه مانع از ذکر کسی در اینستاگرام می شوید؟دوست دختر توسط یک پسر در اسنپ چت خود مورد ضرب و شتم قرار می گیرد. او موفق شد وی را حذف کند یا به او بگویید که با درخواست من عقب نشینی کند ، بنابراین من پیام خصوصی را در اینستاگرام برای او ارسال می کنم و به او می گویم که تمام مخاطبین را از او قطع کند. حالا او دیوانه است و مرا صدا می کند دیوانه است. چه کسی درست است؟آیا از خطوط SnapChat خود استرس دارید؟ چرا می خواهید آنها را ادامه دهید؟چگونه می توانم برای کسب درآمد از یک Instagram BioLink استفاده کنم؟چرا نمی توانم داستانهای اینستاگرام را ارسال کنم؟آیا راهی برای غیرفعال کردن بارگیری خودکار پیام های صوتی در واتس اپ وجود دارد؟ اگر بله ، فرایند انجام این کار چیست؟آیا باید سابق خود را به عنوان دنبال کننده از اینستاگرام حذف کنم؟ تازه فهمیدم این امکان پذیر است. داستان کوتاه طولانی: این یک وقفه سرد بود و ما از آن زمان (نزدیک به 3 سال) صحبت نکردیم. کدام یک بیشتر صدمه می زند: او در زندگی من به روز می شود یا قطع می شود؟چگونه می توانم در پست های اینستاگرام شخصی خود را نادیده بگیرم؟