معماریهای سنتی پایگاه داده بر این فرض استوار بودند که هر اپلیکیشن تنها یک یا دو کلاستر (Cluster) بزرگ دارد که معمولاً با یک راهکار Connection Pooling همراه است. اما ظهور توسعههای مبتنی بر هوش مصنوعی و پلتفرمهای Vibe Coding، این مدل را تغییر داده و اپلیکیشنها را به سمت استفاده از تعداد زیادی پایگاه داده کوچک (مثلاً یک دیتابیس برای هر کاربر، هر مستاجر یا هر محیط پیشنمایش) سوق داده است.
اصول مهندسی در طراحی D1
سرویس D1 که یک پایگاه داده Serverless مبتنی بر SQLite است، برای مدیریت میلیونها دیتابیس بدون ایجاد گلوگاه (Bottleneck) در مسیر درخواستها، از چندین اصل کلیدی پیروی میکند:
- طراحی با پیشفرض شکست و Idempotency: سیستم باید بهگونهای باشد که در صورت بروز خطا، بتواند خود را اصلاح کرده و به پیشروی ادامه دهد.
- حذف اجزای متمرکز در مسیرهای حساس (Hot Path): برای عملیات Data Plane (مانند اجرای کوئریها)، از هرگونه وابستگی به اجزای تکمنطقهای متمرکز اجتناب شده است.
- استفاده از Workers KV: برای ذخیره متادیتای مسیریابی در سطح جهانی استفاده میشود تا در صورت Cache Miss، نیاز به مراجعه به دیتابیسهای مرکزی کاهش یابد.
- بهرهگیری از Hyperdrive: برای دسترسی به دیتابیسهای مرکزی Postgres، جهت بهینهسازی Connection Pooling و مسیریابی.
- سازگاری نهایی (Eventual Consistency): در بخشهایی که نیاز به سازگاری آنی (Strong Consistency) نیست، از صفها و مدل Eventual Consistency برای افزایش پایداری و در دسترس بودن استفاده شده است.
معماری سطح بالا و تفکیک لایهها
در معماری D1، هر پایگاه داده توسط یک SQLite Durable Object پشتیبانی میشود. عملیاتها به سه دسته کلی تقسیم شدهاند:
- Data Plane: تمام درخواستهای مربوط به کوئریهای دیتابیس که باید در سریعترین زمان ممکن و در لبه شبکه (Edge) پاسخ داده شوند.
- Control Plane: عملیات مدیریتی مانند ایجاد، حذف و لیست کردن دیتابیسها که میتوانند به اجزای متمرکز در دیتاسنترهای مرکزی (Core) وابسته باشند.
- Background Asynchronous Plane: جریانهای کاری مربوط به تحلیلها و صورتحساب (Billing) که بهصورت غیرهمزمان اجرا میشوند.
بهینهسازی مسیر اجرای کوئریها
برای جلوگیری از کندی، درخواستهای کوئری هرگز مستقیماً با Postgres ارتباط برقرار نمیکنند. روند به این صورت است که Edge API Worker ابتدا متادیتای مورد نیاز را از Workers KV میخواند. در صورت عدم وجود، از Hyperdrive برای خواندن از Read Replicaهای Postgres استفاده میکند. سپس درخواست از طریق Eyeball Worker (به عنوان پروکسی) به Durable Object مربوطه ارسال میشود تا کوئری SQLite اجرا گردد.
مکانیزم خود-اصلاحی با استفاده از Heartbeat
هر Durable Object بهصورت دورهای (هر ۳۰ ثانیه) یک سیگنال Heartbeat به Control Plane ارسال میکند تا آخرین وضعیت خود (فعال یا حذف شده) و محدودیتهای حساب کاربری را دریافت کند. این مکانیسم باعث میشود که اگر در جریان ایجاد دیتابیس خطایی رخ دهد و متادیتای Postgres با وضعیت Durable Object ناهماهنگ شود، سیستم بهطور خودکار وضعیت را اصلاح کرده و اشیاء یتیم (Orphaned Objects) را پاکسازی کند.
مدیریت محدودیتهای ذخیرهسازی در مقیاس بالا
برای اعمال محدودیتهای حجمی (مثلاً ۵ گیگابایت برای طرح رایگان) در حسابهایی که میلیونها دیتابیس دارند، اجرای کوئریهای SUM() روی جداول بزرگ باعث کندی شدید میشود. Cloudflare برای حل این مشکل از استراتژی زیر استفاده میکند:
- بهروزرسانیهای حجم ذخیرهسازی از طریق یک صف (Queue) مشابه Kafka ارسال میشوند.
- تغییرات در یک جدول واسط (
account_database_stats_changes) ثبت شده و بهصورت دستهای (Batch) پردازش میشوند. - یک Job زمانبندی شده هر ثانیه این تغییرات را تجمیع کرده و جدول نهایی
account_database_statsرا بهروز میکند تا هنگام بررسی محدودیت، تنها یک Read ساده از یک ردیف انجام شود.