پرش به محتوای اصلی

پروژهٔ ۱۲

Scale تا میلیون‌ها کاربر

سامانهٔ فروش بلیت پروژهٔ ۱۱ را مقیاس می‌دهید: load balancing، autoscaling، cache چندلایه، read replica، sharding و محافظت در اوج بار. با آزمون بار ثابت می‌کنید که با افزودن سرور، ظرفیت بالا می‌رود.

Seniorزمان پیشنهادی: ۴۵ ساعتزمان مطالعه: ۹ دقیقه
در این صفحه

هدف

در پایان این پروژه:

  • سامانه با افزودن سرور، بار بیشتری می‌کشد و این را با عدد نشان می‌دهید.
  • تعداد نسخه‌های هر سرویس با بالا و پایین رفتن بار، خودکار تغییر می‌کند.
  • داده میان چند پایگاه داده پخش شده و هیچ پایگاه داده‌ای گلوگاه کل سیستم نیست.
  • در لحظهٔ شروع فروش که بار ده‌ها برابر می‌شود، سامانه کند می‌شود ولی از کار نمی‌افتد.
  • یک برنامهٔ ظرفیت دارید که می‌گوید برای ده میلیون کاربر چند سرور لازم است و چرا.

از کاربر تا عدد

پیش از هر تغییری، باید بدانید «میلیون‌ها کاربر» یعنی چه مقدار بار. این برآورد را در گام اول خودتان می‌سازید:

کمیتمقدار فرضی
کاربران ثبت‌نام‌شده۱۰ میلیون
کاربران فعال روزانه۱ میلیون
کاربران هم‌زمان در اوج فروش۲۰۰ هزار
درخواست خواندن در ثانیه، در اوج۵۰ هزار
درخواست خرید در ثانیه، در اوج۵ هزار
صندلی‌های یک رویداد بزرگ۵۰ هزار

از همین جدول دو نتیجه بیرون می‌آید. خواندن ده برابر نوشتن است، پس این دو مسیر جدا مقیاس می‌گیرند. و ۲۰۰ هزار نفر برای ۵۰ هزار صندلی رقابت می‌کنند، پس بیشتر درخواست‌های خرید باید زود و ارزان رد شوند.

معماری هدف

در حال رسم نمودار…

هر لایه یک پرسش را جواب می‌دهد:

  • CDN و cache لبه: کدام درخواست‌ها اصلاً نباید به سرور شما برسند؟
  • load balancer: بار چطور میان نسخه‌ها پخش می‌شود و نسخهٔ خراب چطور کنار گذاشته می‌شود؟
  • waiting room: وقتی تقاضا از ظرفیت بیشتر است، چه کسی وارد می‌شود و بقیه چه می‌بینند؟
  • cache و read replica: خواندن‌های پرتکرار چطور از پایگاه دادهٔ اصلی دور می‌مانند؟
  • shard router: هر سفارش در کدام پایگاه داده است؟
  • partition در Kafka: کار ناهم‌زمان چطور میان مصرف‌کننده‌ها پخش می‌شود و ترتیب کجا حفظ می‌شود؟

پخش داده با sharding

در حال رسم نمودار…

کلید sharding شناسهٔ رویداد است. همهٔ صندلی‌ها و سفارش‌های یک رویداد در یک shard می‌مانند، پس رزرو همچنان با یک تراکنش محلی انجام می‌شود. consistent hashing باعث می‌شود با افزودن یک shard، فقط بخش کوچکی از داده جابه‌جا شود.

مقایسه با دنیای Python

موضوعGoPython
استفاده از هسته‌هایک پروسه روی همهٔ هسته‌هایک worker برای هر هسته، به‌خاطر GIL
حافظهٔ هر نسخهده‌ها مگابایتصدها مگابایت برای هر worker
زمان آماده شدن نسخهٔ تازهزیر یک ثانیهچند ثانیه تا بارگذاری برنامه
اتصال به پایگاه دادهpool درون برنامه با database/sqlمعمولاً نیاز به PgBouncer
ادغام درخواست‌های هم‌زمان یکسانsingleflight درون پروسهقفل بیرونی روی Redis
اثر بر autoscalingواکنش سریع به جهش بارباید زودتر و بیشتر مقیاس بگیرید
مقیاس دادن سرویس Go و سرویس Django

پیش‌نیازها

  • پروژهٔ ۱۱ کامل: همین سامانه را مقیاس می‌دهید.
  • همهٔ درس‌های فاز ۷.
  • از فاز ۵: profiling با pprof و benchmark.

گام‌های پروژه

  1. خط مبنا و نخستین گلوگاه

    برآورد ظرفیت، تعریف SLO، سناریوهای آزمون بار و اندازه‌گیری وضعیت فعلی.

    معیار پذیرش: گزارشی دارید که می‌گوید سامانه با یک نسخه از هر سرویس تا چه نرخی SLO را نگه می‌دارد و نخستین جایی که می‌شکند کجاست. هر گام بعدی با همین سناریوها سنجیده می‌شود.

  2. نسخه‌های متعدد و load balancing

    حذف وضعیت از حافظهٔ سرویس‌ها، load balancer لایهٔ ۷، health check، تخلیهٔ اتصال هنگام خاموشی و پخش بار gRPC در سمت کلاینت.

    معیار پذیرش: با سه نسخه از هر سرویس، بار با اختلاف کمتر از ۱۰ درصد میان نسخه‌ها پخش می‌شود. خاموش کردن یک نسخه زیر بار، هیچ درخواستی را خراب نمی‌کند.

  3. autoscaling

    مقیاس خودکار بر پایهٔ CPU، نرخ درخواست و عقب‌افتادگی مصرف‌کننده‌های Kafka.

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

  4. cache چندلایه

    سرآیندهای cache برای CDN، Redis Cluster، cache درون پروسه، جلوگیری از stampede و باطل کردن cache با رویداد.

    معیار پذیرش: بیش از ۹۵ درصد خواندن‌های فهرست رویدادها به پایگاه داده نمی‌رسد. با منقضی شدن یک کلید پرمصرف، فقط یک درخواست به پایگاه داده می‌رود.

  5. مقیاس خواندن

    read replica، برخورد با تأخیر replication و یک مدل خواندن جدا برای catalog که از رویدادها ساخته می‌شود.

    معیار پذیرش: کاربر پس از خرید، بلیت خودش را همیشه می‌بیند، حتی وقتی replica عقب است. بار خواندن روی پایگاه دادهٔ اصلی نزدیک به صفر است.

  6. sharding

    مسیریاب shard با consistent hashing، افزودن shard تازه و جابه‌جایی داده بدون توقف.

    معیار پذیرش: با دو برابر شدن تعداد shard و نسخه‌ها، نرخ خرید موفق دست‌کم ۱٫۸ برابر می‌شود. هنگام افزودن shard، هیچ سفارشی گم نمی‌شود و هیچ صندلی‌ای دو بار فروخته نمی‌شود.

  7. محافظت در اوج بار

    waiting room برای کنترل ورود، rate limit توزیع‌شده، رد کردن زودهنگام بار اضافه و افت کیفیت کنترل‌شده.

    معیار پذیرش: با باری ده برابر ظرفیت، کاربرانی که وارد شده‌اند با SLO عادی خرید می‌کنند. بقیه در صف می‌مانند و پاسخ سریع می‌گیرند. هیچ سرویسی از کار نمی‌افتد.

  8. آزمون شکست و برنامهٔ ظرفیت

    از کار انداختن node، قطع شبکه میان سرویس‌ها، پخش در چند zone و نوشتن برنامهٔ ظرفیت و هزینه.

    معیار پذیرش: با از دست رفتن یک node زیر بار، نرخ خطا زیر ۰٫۱ درصد می‌ماند. سند ظرفیت، با تکیه بر عددهای اندازه‌گیری‌شده، تعداد سرور لازم برای جدول برآورد بالا را حساب می‌کند.

چه چیزی را اندازه می‌گیرید

SLO این پروژه از اول مشخص است و همهٔ گام‌ها با آن سنجیده می‌شوند:

شاخصهدف
صدک ۹۹ زمان پاسخ خواندنزیر ۲۰۰ میلی‌ثانیه
صدک ۹۹ زمان پاسخ خریدزیر ۸۰۰ میلی‌ثانیه
نرخ خطای سمت سرورزیر ۰٫۱ درصد
فروش دوبارهٔ صندلیصفر، بدون استثنا
نسبت مقیاس با دو برابر شدن منابعدست‌کم ۱٫۸

تصمیم‌های مهندسی که باید از آن‌ها دفاع کنید

  • کلید sharding: چرا شناسهٔ رویداد و نه شناسهٔ کاربر؟ با یک رویداد بسیار بزرگ که یک shard را پر می‌کند چه می‌کنید؟
  • سازگاری خواندن: کجا دادهٔ کمی قدیمی پذیرفتنی است و کجا نه؟
  • جای rate limit: در لبه، در gateway یا در هر سرویس؟
  • صف یا رد کردن: درخواست اضافه را نگه می‌دارید یا همان لحظه رد می‌کنید؟ هزینهٔ هر کدام برای کاربر چیست؟
  • هزینه: ارزان‌ترین پیکربندی‌ای که SLO را نگه می‌دارد کدام است؟

اشتباه‌های رایج

نتیجهٔ نهایی

  • گزارش آزمون بار با نمودار ظرفیت پیش و پس از هر گام
  • اثبات مقیاس خطی: نسبت دست‌کم ۱٫۸ با دو برابر شدن منابع
  • autoscaling و waiting room فعال در خوشهٔ Kubernetes
  • sharding با امکان افزودن shard بدون توقف
  • گزارش آزمون شکست
  • سند برنامهٔ ظرفیت و هزینه برای ده میلیون کاربر

ویرایش این صفحه در GitHub