البريد الإلكتروني المقاوم للحوسبة الكمومية: كيف نستخدم صناديق بريد SQLite المشفرة للحفاظ على أمان بريدك الإلكتروني

رسم توضيحي لخدمة البريد الإلكتروني المشفرة الآمنة ضد الحوسبة الكمومية

مقدمة

Important

خدمتنا البريدية مفتوحة المصدر 100% وتركز على الخصوصية من خلال صناديق بريد SQLite المشفرة والآمنة.

حتى أطلقنا دعم IMAP، كنا نستخدم MongoDB لتلبية احتياجاتنا في تخزين البيانات الدائم.

هذه التقنية مذهلة وما زلنا نستخدمها حتى اليوم – ولكن لكي تحصل على التشفير أثناء التخزين مع MongoDB، تحتاج إلى استخدام مزود يقدم MongoDB Enterprise، مثل Digital Ocean أو Mongo Atlas – أو دفع رسوم ترخيص للمؤسسات (وبالتالي التعامل مع تأخير فرق المبيعات).

كان فريقنا في Forward Email بحاجة إلى حل تخزين مشفر، قابل للتطوير، موثوق، وسهل الاستخدام للمطورين لصناديق بريد IMAP. كمطورين مفتوحين المصدر، كان استخدام تقنية تحتاج إلى دفع رسوم ترخيص للحصول على ميزة التشفير أثناء التخزين مخالفًا لـ مبادئنا – لذا قمنا بالتجربة والبحث وتطوير حل جديد من الصفر لتلبية هذه الاحتياجات.

بدلاً من استخدام قاعدة بيانات مشتركة لتخزين صناديق بريدك، نقوم بتخزين صناديق بريدك وتشفيرها بشكل فردي باستخدام كلمة مرورك (التي لا يملكها إلا أنت). خدمتنا البريدية آمنة جدًا لدرجة أنه إذا نسيت كلمة مرورك، فإنك تفقد صندوق بريدك (ويجب عليك الاسترداد من النسخ الاحتياطية غير المتصلة أو البدء من جديد).

تابع القراءة حيث نغوص في التفاصيل أدناه مع مقارنة مزودي خدمة البريد الإلكتروني، كيف تعمل خدمتنا، تقنياتنا، وأكثر.

مقارنة مزودي خدمة البريد الإلكتروني

نحن المزود الوحيد لخدمة البريد الإلكتروني المفتوحة المصدر 100% والمركزة على الخصوصية الذي يخزن صناديق بريد SQLite مشفرة بشكل فردي، ويقدم نطاقات، وأسماء مستعارة، ومستخدمين غير محدودين، ويدعم SMTP الصادر، وIMAP، وPOP3:

على عكس مزودي البريد الإلكتروني الآخرين، لا تحتاج إلى دفع مقابل التخزين على أساس كل نطاق أو اسم مستعار مع Forward Email. التخزين مشترك عبر حسابك بالكامل – لذا إذا كان لديك عدة أسماء نطاقات مخصصة وعدة أسماء مستعارة على كل منها، فنحن الحل المثالي لك. لاحظ أنه يمكنك فرض حدود تخزين إذا رغبت على أساس كل نطاق أو اسم مستعار.

اقرأ مقارنة خدمات البريد الإلكتروني

كيف تعمل الخدمة

  1. باستخدام عميل البريد الإلكتروني الخاص بك مثل Apple Mail، Thunderbird، Gmail، أو Outlook – تتصل بخوادمنا الآمنة IMAP باستخدام اسم المستخدم وكلمة المرور الخاصة بك:

    • اسم المستخدم هو الاسم المستعار الكامل مع النطاق الخاص بك مثل hello@example.com.
    • كلمة المرور يتم إنشاؤها عشوائيًا وتُعرض لك فقط لمدة 30 ثانية عند النقر على إنشاء كلمة مرور من حسابي النطاقات الأسماء المستعارة.
  2. بمجرد الاتصال، سيرسل عميل البريد الإلكتروني الخاص بك أوامر بروتوكول IMAP إلى خادم IMAP الخاص بنا لمزامنة صندوق بريدك. يشمل ذلك كتابة وتخزين رسائل البريد الإلكتروني المسودة والإجراءات الأخرى التي قد تقوم بها (مثل تصنيف بريد إلكتروني كـ مهم أو تعليم بريد إلكتروني كبريد مزعج/بريد غير مرغوب فيه).

  3. تستقبل خوادم تبادل البريد (المعروفة عادةً باسم خوادم "MX") البريد الوارد الجديد وتخزنه في صندوق بريدك. عند حدوث ذلك، سيتم إعلام عميل البريد الإلكتروني الخاص بك ومزامنة صندوق بريدك. يمكن لخوادم تبادل البريد لدينا إعادة توجيه بريدك الإلكتروني إلى مستلم واحد أو أكثر (بما في ذلك webhooks)، أو تخزين بريدك الإلكتروني لك في تخزين IMAP المشفر لدينا، أو كلاهما!

  4. خلف الكواليس، يعمل تصميم تخزين البريد الإلكتروني الآمن لدينا بطريقتين للحفاظ على تشفير صناديق بريدك وجعلها متاحة فقط لك:

    • عندما يتم استلام بريد جديد لك من مرسل، تقوم خوادم تبادل البريد لدينا بالكتابة إلى صندوق بريد مؤقت، فردي، ومشفر خاص بك.

    • عندما تتصل بخادم IMAP الخاص بنا باستخدام عميل البريد الإلكتروني الخاص بك، يتم تشفير كلمة المرور الخاصة بك في الذاكرة وتُستخدم لقراءة وكتابة صندوق بريدك. لا يمكن قراءة أو كتابة صندوق بريدك إلا باستخدام هذه الكلمة السرية. ضع في اعتبارك أنه بما أنك الوحيد الذي يمتلك هذه الكلمة السرية، فقط أنت يمكنك قراءة وكتابة صندوق بريدك عند الوصول إليه. في المرة التالية التي يحاول فيها عميل البريد الإلكتروني الخاص بك الاستعلام عن البريد أو المزامنة، سيتم نقل رسائلك الجديدة من صندوق البريد المؤقت هذا وتخزينها في ملف صندوق بريدك الفعلي باستخدام كلمة المرور التي زودتنا بها. لاحظ أن صندوق البريد المؤقت هذا يتم مسحه وحذفه بعد ذلك بحيث يكون فقط صندوق بريدك المحمي بكلمة المرور يحتوي على الرسائل.

    • إذا كنت متصلاً بـ IMAP (مثل استخدام عميل بريد إلكتروني مثل Apple Mail أو Thunderbird)، فلن نحتاج إلى الكتابة إلى تخزين القرص المؤقت. بدلاً من ذلك، يتم جلب كلمة مرور IMAP المشفرة في الذاكرة واستخدامها. في الوقت الحقيقي، عندما تحاول رسالة التسليم إليك، نرسل طلب WebSocket إلى جميع خوادم IMAP نسألهم إذا كان لديهم جلسة نشطة لك (هذا هو جزء الجلب)، ثم بعد ذلك نمرر كلمة المرور المشفرة في الذاكرة – لذلك لا نحتاج إلى الكتابة إلى صندوق بريد مؤقت، يمكننا الكتابة إلى صندوق بريدك المشفر الفعلي باستخدام كلمة مرورك المشفرة.

  5. يتم عمل نسخ احتياطية لصناديق بريدك المشفرة يوميًا. يمكنك أيضًا طلب نسخة احتياطية جديدة في أي وقت أو تنزيل أحدث نسخة احتياطية من حسابي النطاقات الأسماء المستعارة. إذا قررت التبديل إلى خدمة بريد إلكتروني أخرى، يمكنك بسهولة الترحيل، التنزيل، التصدير، ومسح صناديق بريدك والنسخ الاحتياطية في أي وقت.

التقنيات

قواعد البيانات

استكشفنا طبقات تخزين قواعد بيانات أخرى محتملة، لكن لم ترضِ أي منها متطلباتنا بقدر ما فعلت SQLite:

قاعدة البيانات التشفير أثناء التخزين صناديق بريد معزولة الترخيص مستخدمة في كل مكان
SQLite ✅ نعم مع SQLite3MultipleCiphers ✅ الملكية العامة
MongoDB "متوفر فقط في MongoDB Enterprise" ❌ قاعدة بيانات علائقية ❌ AGPL و SSPL-1.0
rqlite الشبكة فقط ❌ قاعدة بيانات علائقية MIT
dqlite غير مختبر وغير مدعوم بعد؟ غير مختبر وغير مدعوم بعد؟ LGPL-3.0-only
PostgreSQL نعم ❌ قاعدة بيانات علائقية PostgreSQL (مشابه لـ BSD أو MIT)
MariaDB لـ InnoDB فقط ❌ قاعدة بيانات علائقية GPLv2 و BUSL-1.1
CockroachDB ميزة للمؤسسات فقط ❌ قاعدة بيانات علائقية BUSL-1.1 وغيرها

هنا مقالة مدونة تقارن عدة خيارات لتخزين قاعدة بيانات SQLite في الجدول أعلاه.

الأمان

نستخدم في جميع الأوقات التشفير أثناء التخزين (AES-256)، والتشفير أثناء النقل (TLS)، وDNS عبر HTTPS ("DoH") باستخدام 🍊 Tangerine، وsqleet (ChaCha20-Poly1305) لتشفير صناديق البريد. بالإضافة إلى ذلك نستخدم المصادقة الثنائية القائمة على الرموز (بدلاً من الرسائل النصية التي قد تتعرض لهجمات الرجل في الوسط)، ومفاتيح SSH الدوارة مع تعطيل وصول الجذر، والوصول الحصري إلى الخوادم عبر عناوين IP مقيدة، والمزيد. في حالة حدوث هجوم الخادمة الشريرة أو موظف مارق من بائع طرف ثالث، لا يمكن فتح صندوق بريدك إلا باستخدام كلمة المرور التي قمت بإنشائها. كن مطمئنًا، نحن لا نعتمد على أي بائعين طرف ثالث سوى مزودي خوادمنا المتوافقة مع SOC Type 2 من Cloudflare وDataPacket وDigital Ocean وGitHub وVultr.

هدفنا هو تقليل عدد نقاط الفشل الفردية قدر الإمكان.

صناديق البريد

ملخص؛ تستخدم خوادم IMAP لدينا قواعد بيانات SQLite مشفرة بشكل فردي لكل صندوق بريد من صناديق بريدك.

SQLite هي قاعدة بيانات مضمنة شائعة للغاية – وهي تعمل حاليًا على هاتفك وجهاز الكمبيوتر الخاص بك – وتُستخدم من قبل جميع التقنيات الكبرى تقريبًا.

على سبيل المثال، على خوادمنا المشفرة هناك قاعدة بيانات SQLite لكل صندوق بريد مثل linux@example.com وinfo@example.com وhello@example.com وهكذا – واحدة لكل منها كملف قاعدة بيانات .sqlite. نحن لا نستخدم عنوان البريد الإلكتروني لتسمية ملفات قاعدة البيانات – بل نستخدم BSON ObjectID وUUID فريدة يتم إنشاؤها والتي لا تكشف عن صاحب صندوق البريد أو عنوان البريد الإلكتروني الخاص به (مثل 353a03f21e534321f5d6e267.sqlite).

كل من هذه القواعد البيانات مشفرة بنفسها باستخدام كلمة مرورك (التي لا يملكها إلا أنت) باستخدام sqleet (ChaCha20-Poly1305). هذا يعني أن صناديق بريدك مشفرة بشكل فردي، مستقلة، معزولة، وقابلة للنقل.

لقد قمنا بضبط SQLite بدقة باستخدام PRAGMA التالية:

PRAGMA الغرض
cipher=chacha20 تشفير قاعدة بيانات SQLite باستخدام ChaCha20-Poly1305. راجع better-sqlite3-multiple-ciphers تحت Projects لمزيد من التفاصيل.
key="****************" هذه هي كلمة المرور الخاصة بك المفككة في الذاكرة فقط والتي يتم تمريرها عبر اتصال IMAP الخاص بعميل البريد الإلكتروني إلى خادمنا. يتم إنشاء وإغلاق نسخ جديدة من قاعدة البيانات لكل جلسة قراءة وكتابة (لضمان العزل والحماية).
journal_model=WAL سجل الكتابة المسبق ("WAL") الذي يعزز الأداء ويسمح بالوصول المتزامن للقراءة.
busy_timeout=5000 يمنع أخطاء قفل الكتابة أثناء تنفيذ عمليات كتابة أخرى.
synchronous=NORMAL يزيد من متانة المعاملات دون خطر تلف البيانات.
foreign_keys=ON يفرض التحقق من مراجع المفاتيح الأجنبية (مثل العلاقة من جدول إلى آخر). بشكل افتراضي هذا غير مفعل في SQLite، ولكن من أجل التحقق وسلامة البيانات يجب تفعيله.
encoding='UTF-8' الترميز الافتراضي المستخدم لضمان سلامة المطور.

جميع الإعدادات الافتراضية الأخرى من SQLite كما هو محدد في توثيق PRAGMA الرسمي.

التزامن

ملخص؛ نستخدم WebSocket للقراءات والكتابات المتزامنة إلى صناديق البريد المشفرة الخاصة بك في SQLite.

القراءات

قد يقوم عميل البريد الإلكتروني على هاتفك بحل imap.forwardemail.net إلى أحد عناوين IP الخاصة بنا في Digital Ocean – وقد يقوم عميل سطح المكتب بحل عنوان IP منفصل من مزود مختلف تمامًا.

بغض النظر عن خادم IMAP الذي يتصل به عميل البريد الإلكتروني الخاص بك، نريد أن تكون الاتصال لقراءة قاعدة البيانات في الوقت الحقيقي بدقة 100%. يتم ذلك من خلال WebSockets.

الكتابات

الكتابة إلى قاعدة البيانات الخاصة بك مختلفة قليلاً – حيث أن SQLite هي قاعدة بيانات مضمنة وصندوق بريدك يعيش في ملف واحد بشكل افتراضي.

لقد استكشفنا خيارات مثل litestream، و rqlite، و dqlite أدناه – ولكن لم ترق أي منها لمتطلباتنا.

لإنجاز الكتابات مع تمكين تسجيل الكتابة المسبق ("WAL") – نحتاج إلى التأكد من أن خادمًا واحدًا فقط ("الرئيسي") مسؤول عن ذلك. WAL يسرع بشكل كبير التزامن ويسمح لكاتب واحد وعدة قراء.

الخادم الرئيسي يعمل على خوادم البيانات مع الأقراص المركبة التي تحتوي على صناديق البريد المشفرة. من ناحية التوزيع، يمكنك اعتبار جميع خوادم IMAP الفردية خلف imap.forwardemail.net خوادم ثانوية ("ثانوية").

ننجز الاتصال ثنائي الاتجاه باستخدام WebSockets:

  • تستخدم الخوادم الرئيسية نسخة من خادم WebSocketServer من ws.
  • تستخدم الخوادم الثانوية نسخة من عميل WebSocket من ws مغلفة بـ websocket-as-promised و reconnecting-websocket. هذان الغلافان يضمنان أن WebSocket يعيد الاتصال ويمكنه إرسال واستقبال البيانات لكتابات قاعدة بيانات محددة.

النسخ الاحتياطية

ملخص؛ يتم عمل نسخ احتياطية لصناديق بريدك المشفرة يوميًا. يمكنك أيضًا طلب نسخة احتياطية جديدة فورًا أو تنزيل أحدث نسخة احتياطية في أي وقت من حسابي النطاقات الأسماء المستعارة.

بالنسبة للنسخ الاحتياطية، نقوم ببساطة بتشغيل أمر SQLite VACUUM INTO يوميًا أثناء معالجة أوامر IMAP، والذي يستفيد من كلمة المرور المشفرة الخاصة بك من اتصال IMAP في الذاكرة. يتم تخزين النسخ الاحتياطية إذا لم يتم اكتشاف نسخة احتياطية موجودة أو إذا تغيرت قيمة SHA-256 للملف مقارنةً بأحدث نسخة احتياطية.

لاحظ أننا نستخدم أمر VACUUM INTO بدلاً من الأمر المدمج backup لأنه إذا تم تعديل صفحة أثناء عملية أمر backup، فعليه أن يبدأ من جديد. يأخذ أمر VACUUM INTO لقطة. راجع هذه التعليقات على GitHub و Hacker News لمزيد من الفهم.

بالإضافة إلى ذلك، نستخدم VACUUM INTO بدلاً من backup، لأن أمر backup سيترك قاعدة البيانات غير مشفرة لفترة وجيزة حتى يتم استدعاء rekey (انظر هذا التعليق على GitHub comment لفهم أعمق).

سيقوم الخادم الثانوي بإعطاء تعليمات للخادم الرئيسي عبر اتصال WebSocket لتنفيذ النسخ الاحتياطي – ثم يتلقى الخادم الرئيسي الأمر للقيام بذلك وبعدها:

  1. الاتصال بصندوق بريدك المشفر.
  2. الحصول على قفل كتابة.
  3. تشغيل نقطة تحقق WAL عبر wal_checkpoint(PASSIVE).
  4. تشغيل أمر SQLite VACUUM INTO.
  5. التأكد من أن الملف المنسوخ يمكن فتحه باستخدام كلمة المرور المشفرة (كإجراء أمان/تأكيد).
  6. رفعه إلى Cloudflare R2 للتخزين (أو إلى مزودك الخاص إذا تم تحديده).

تذكر أن صناديق بريدك مشفرة – وبينما لدينا قيود على عناوين IP وإجراءات تحقق أخرى للاتصالات عبر WebSocket – في حالة وجود جهة خبيثة، يمكنك الاطمئنان إلى أنه ما لم يكن حمولة WebSocket تحتوي على كلمة مرور IMAP الخاصة بك، فلن تتمكن من فتح قاعدة بياناتك.

يتم تخزين نسخة احتياطية واحدة فقط لكل صندوق بريد في الوقت الحالي، ولكن في المستقبل قد نقدم استعادة نقطة زمنية ("PITR").

تدعم خوادم IMAP لدينا أمر SEARCH مع استعلامات معقدة، وتعبيرات منتظمة، والمزيد.

يعود الأداء السريع للبحث إلى FTS5 و sqlite-regex.

نخزن قيم Date في صناديق بريد SQLite كسلاسل ISO 8601 عبر Date.prototype.toISOString (مع توقيت UTC لكي تعمل مقارنات المساواة بشكل صحيح).

يتم أيضًا تخزين الفهارس لجميع الخصائص التي توجد في استعلامات البحث.

المشاريع

إليك جدول يوضح المشاريع التي نستخدمها في شفرتنا المصدرية وعملية التطوير (مرتبة أبجديًا):

المشروع الغرض
Ansible منصة أتمتة DevOps لصيانة وتوسيع وإدارة أسطول خوادمنا بالكامل بسهولة.
Bree مجدول مهام لـ Node.js و JavaScript مع دعم cron، والتواريخ، و ms، و later، ودعم سهل الاستخدام للبشر.
Cabin مكتبة تسجيل JavaScript و Node.js صديقة للمطور مع مراعاة الأمان والخصوصية.
Lad إطار عمل Node.js الذي يدعم كامل هندستنا وتصميمنا الهندسي مع MVC والمزيد.
MongoDB حل قاعدة بيانات NoSQL نستخدمه لتخزين جميع البيانات الأخرى خارج صناديق البريد (مثل حسابك، الإعدادات، النطاقات، وتكوينات الأسماء المستعارة).
Mongoose نمذجة مستندات MongoDB ("ODM") التي نستخدمها عبر كامل البنية التحتية لدينا. كتبنا مساعدين خاصين يسمحون لنا بالاستمرار ببساطة في استخدام Mongoose مع SQLite 🎉
Node.js Node.js هو بيئة تشغيل جافاسكريبت مفتوحة المصدر وعبر المنصات التي تشغل جميع عمليات الخادم لدينا.
Nodemailer حزمة Node.js لإرسال البريد الإلكتروني، وإنشاء الاتصالات، والمزيد. نحن راعٍ رسمي لهذا المشروع.
Redis قاعدة بيانات في الذاكرة للتخزين المؤقت، وقنوات النشر/الاشتراك، وطلبات DNS عبر HTTPS.
SQLite3MultipleCiphers امتداد تشفير لـ SQLite يسمح بتشفير ملفات قاعدة البيانات بالكامل (بما في ذلك سجل الكتابة المسبق ("WAL"), الدفتر، التراجع، …).
SQLiteStudio محرر SQLite بصري (يمكنك استخدامه أيضًا) لاختبار، وتنزيل، وعرض صناديق البريد التطويرية.
SQLite طبقة قاعدة بيانات مضمنة لتخزين IMAP قابل للتوسع، مستقل، سريع، وموثوق.
Spam Scanner أداة مكافحة البريد المزعج، تصفية البريد الإلكتروني، ومنع التصيد لـ Node.js (بديلنا لـ Spam Assassin و rspamd).
Tangerine طلبات DNS عبر HTTPS مع Node.js والتخزين المؤقت باستخدام Redis – مما يضمن الاتساق العالمي والمزيد.
Thunderbird يستخدم فريق التطوير لدينا هذا (وينصح به أيضًا) كـ عميل البريد الإلكتروني المفضل للاستخدام مع Forward Email.
UTM يستخدم فريق التطوير لدينا هذا لإنشاء آلات افتراضية لنظامي iOS و macOS لاختبار عملاء البريد الإلكتروني المختلفين (بالتوازي) مع خوادم IMAP و SMTP لدينا.
Ubuntu نظام تشغيل خادم حديث مفتوح المصدر مبني على Linux يشغل كل بنيتنا التحتية.
WildDuck مكتبة خادم IMAP – راجع ملاحظاته حول إلغاء تكرار المرفقات و دعم بروتوكول IMAP.
better-sqlite3-multiple-ciphers مكتبة API سريعة وبسيطة لـ Node.js للتفاعل برمجيًا مع SQLite3.
email-templates إطار عمل بريد إلكتروني صديق للمطور لإنشاء، ومعاينة، وإرسال رسائل بريد إلكتروني مخصصة (مثل إشعارات الحساب والمزيد).
json-sql-enhanced منشئ استعلامات SQL باستخدام بناء جملة على نمط Mongo. يوفر هذا الوقت لفريق التطوير لدينا لأننا نستطيع الاستمرار في الكتابة بأسلوب Mongo عبر كامل البنية التحتية مع نهج مستقل عن قاعدة البيانات. كما يساعد على تجنب هجمات حقن SQL باستخدام معلمات الاستعلام.
knex-schema-inspector أداة SQL لاستخراج معلومات حول مخطط قاعدة البيانات الحالي. يسمح لنا هذا بالتحقق بسهولة من أن جميع الفهارس، والجداول، والأعمدة، والقيود، والمزيد صحيحة ومتطابقة 1:1 مع ما يجب أن تكون عليه. كتبنا حتى مساعدين آليين لإضافة أعمدة وفهارس جديدة إذا تم إجراء تغييرات على مخططات قواعد البيانات (مع تنبيهات خطأ مفصلة للغاية أيضًا).
knex منشئ استعلامات SQL نستخدمه فقط لترحيل قواعد البيانات والتحقق من المخطط عبر knex-schema-inspector.
mandarin ترجمة عبارات i18n تلقائية مع دعم Markdown باستخدام Google Cloud Translation API.
mx-connect حزمة Node.js لحل وإنشاء الاتصالات مع خوادم MX والتعامل مع الأخطاء.
pm2 مدير عمليات إنتاج Node.js مع موازن تحميل مدمج (محسن للأداء).
smtp-server مكتبة خادم SMTP – نستخدمها لخوادم تبادل البريد ("MX") وخوادم SMTP الصادرة.
ImapTest أداة مفيدة لاختبار خوادم IMAP مقابل المعايير ومواصفات RFC لبروتوكول IMAP. تم إنشاء هذا المشروع بواسطة فريق Dovecot (خادم IMAP و POP3 مفتوح المصدر نشط منذ يوليو 2002). اختبرنا خادم IMAP لدينا بشكل مكثف باستخدام هذه الأداة.

يمكنك العثور على مشاريع أخرى نستخدمها في رمز المصدر الخاص بنا على GitHub.

المزودون

المزود الغرض
Cloudflare مزود DNS، فحوصات الصحة، موازنات التحميل، وتخزين النسخ الاحتياطية باستخدام Cloudflare R2.
GitHub استضافة رمز المصدر، التكامل المستمر/التسليم المستمر، وإدارة المشاريع.
Digital Ocean استضافة خوادم مخصصة وقواعد بيانات مُدارة.
Vultr استضافة خوادم مخصصة.
DataPacket استضافة خوادم مخصصة.

الأفكار

المبادئ

تم تصميم Forward Email وفقًا لهذه المبادئ:

  1. كن دائمًا صديقًا للمطورين، مع التركيز على الأمان والخصوصية، والشفافية.
  2. الالتزام بـ MVC، Unix، KISS، DRY، YAGNI، Twelve Factor، موسى أوكام، و dogfooding
  3. استهداف المطورين المبتدئين، المعتمدين على الذات، والذين يحققون أرباحًا بالكاد

التجارب

ملخص؛ في النهاية، استخدام تخزين الكائنات المتوافق مع S3 و/أو الجداول الافتراضية ليس ممكنًا تقنيًا لأسباب تتعلق بالأداء وعرضة للأخطاء بسبب قيود الذاكرة.

لقد أجرينا بعض التجارب التي أدت إلى حل SQLite النهائي كما نوقش أعلاه.

كان أحد هذه التجارب محاولة استخدام rclone و SQLite معًا مع طبقة تخزين متوافقة مع S3.

قادنا هذا التجربة إلى فهم واكتشاف حالات حافة حول استخدام rclone و SQLite و VFS:

  • إذا قمت بتمكين العلم --vfs-cache-mode writes مع rclone، فستكون عمليات القراءة جيدة، ولكن عمليات الكتابة سيتم تخزينها مؤقتًا.
    • إذا كان لديك عدة خوادم IMAP موزعة عالميًا، فسيكون التخزين المؤقت غير متزامن بينها ما لم يكن لديك كاتب واحد ومستمعون متعددون (مثل نهج النشر/الاشتراك).
    • هذا معقد للغاية وإضافة أي تعقيد إضافي مثل هذا سيؤدي إلى المزيد من نقاط الفشل الفردية.
    • مزودو التخزين المتوافقون مع S3 لا يدعمون تغييرات الملفات الجزئية – مما يعني أن أي تغيير في ملف .sqlite سيؤدي إلى تغيير كامل وإعادة تحميل قاعدة البيانات.
    • توجد حلول أخرى مثل rsync، لكنها ليست موجهة لدعم سجل الكتابة المسبق ("WAL") – لذلك انتهى بنا الأمر بمراجعة Litestream. لحسن الحظ، استخدامنا للتشفير يقوم بالفعل بتشفير ملفات WAL لنا، لذا لا نحتاج للاعتماد على Litestream لذلك. ومع ذلك، لم نكن واثقين بعد من Litestream للاستخدام في الإنتاج ولدينا بعض الملاحظات أدناه حول ذلك.
    • استخدام هذا الخيار --vfs-cache-mode writes (الطريقة الوحيدة لاستخدام SQLite عبر rclone للكتابة) سيحاول نسخ قاعدة البيانات بالكامل من البداية في الذاكرة – التعامل مع صندوق بريد بحجم 10 جيجابايت مقبول، لكن التعامل مع صناديق بريد متعددة ذات تخزين عالي جدًا سيسبب لخوادم IMAP الوصول إلى حدود الذاكرة وأخطاء ENOMEM، أعطال التقسيم، وتلف البيانات.
  • إذا حاولت استخدام الجداول الافتراضية في SQLite (مثل استخدام s3db) لجعل البيانات تعيش على طبقة تخزين متوافقة مع S3، فستواجه عدة مشاكل أخرى:
    • ستكون عمليات القراءة والكتابة بطيئة جدًا لأن نقاط نهاية API الخاصة بـ S3 ستحتاج إلى استدعاءات HTTP GET، PUT، HEAD، و POST.
    • أظهرت اختبارات التطوير أن تجاوز 500 ألف إلى مليون سجل على الإنترنت الليفي لا يزال محدودًا بمعدل نقل البيانات للكتابة والقراءة إلى مزودي التخزين المتوافقين مع S3. على سبيل المثال، قام مطورونا بتشغيل حلقات for لتنفيذ بيانات SQL INSERT متسلسلة وأخرى تكتب كميات كبيرة من البيانات دفعة واحدة. في كلتا الحالتين، كان الأداء بطيئًا بشكل مذهل.
    • الجداول الافتراضية لا يمكن أن تحتوي على فهارس، أو بيانات ALTER TABLE، وقيود أخرى – مما يؤدي إلى تأخيرات تصل إلى دقيقة أو دقيقتين أو أكثر حسب كمية البيانات.
    • تم تخزين الكائنات بدون تشفير ولا يتوفر دعم تشفير أصلي بسهولة.
  • استكشفنا أيضًا استخدام sqlite-s3vfs الذي يشبه من الناحية المفاهيمية والتقنية النقطة السابقة (لذا لديه نفس المشاكل). من الممكن استخدام بناء مخصص لـ sqlite3 مغلف بالتشفير مثل wxSQLite3 (الذي نستخدمه حاليًا في حلنا أعلاه) من خلال تعديل ملف الإعداد.
  • نهج محتمل آخر هو استخدام امتداد multiplex، لكنه محدود بسعة 32 جيجابايت وسيتطلب بناء معقد ومشاكل تطوير.
  • بيانات ALTER TABLE مطلوبة (لذا هذا يستبعد تمامًا استخدام الجداول الافتراضية). نحن بحاجة إلى بيانات ALTER TABLE لكي يعمل الربط مع knex-schema-inspector بشكل صحيح – مما يضمن عدم تلف البيانات وأن الصفوف المسترجعة يمكن تحويلها إلى مستندات صالحة وفقًا لتعريفات مخطط mongoose الخاصة بنا (والتي تشمل التحقق من القيود، نوع المتغير، والتحقق من صحة البيانات التعسفية).
  • تقريبًا جميع مشاريع S3 المتوافقة مع SQLite في مجتمع المصدر المفتوح مكتوبة بلغة Python (وليس JavaScript التي نستخدمها في 100% من مكدسنا).
  • مكتبات الضغط مثل sqlite-zstd (انظر التعليقات) تبدو واعدة، لكنها قد لا تكون جاهزة للاستخدام الإنتاجي بعد. بدلاً من ذلك، سيكون الضغط على جانب التطبيق لأنواع البيانات مثل String، Object، Map، Array، Set، و Buffer نهجًا أنظف وأسهل (وأيضًا أسهل للهجرة، حيث يمكننا تخزين علم Boolean أو عمود – أو حتى استخدام PRAGMA user_version=1 للضغط أو user_version=0 لعدم الضغط كبيانات وصفية لقاعدة البيانات).
    • لحسن الحظ، لدينا بالفعل إزالة التكرار للمرفقات في تخزين خادم IMAP – لذلك كل رسالة تحتوي على نفس المرفق لن تحتفظ بنسخة من المرفق – بدلاً من ذلك يتم تخزين مرفق واحد لرسائل وخيوط متعددة في صندوق البريد (ويتم استخدام مرجع خارجي لاحقًا).
  • مشروع Litestream، وهو حل تكرار ونسخ احتياطي لـ SQLite، واعد جدًا ومن المرجح أن نستخدمه في المستقبل.
  • يجب أن يكون استعادة النسخ الاحتياطية سهلة وبسيطة. استخدام حل مثل MongoDB مع mongodump و mongoexport ليس فقط مملًا، بل يستغرق وقتًا طويلاً وله تعقيد في الإعداد.
    • قواعد بيانات SQLite تجعل الأمر بسيطًا (إنها ملف واحد).
    • أردنا تصميم حل يمكن للمستخدمين من خلاله أخذ صندوق بريدهم والمغادرة في أي لحظة.
      • أوامر Node.js بسيطة مثل fs.unlink('mailbox.sqlite')) ويتم مسحه نهائيًا من التخزين على القرص.
      • يمكننا أيضًا استخدام API متوافق مع S3 مع HTTP DELETE لإزالة اللقطات والنسخ الاحتياطية بسهولة للمستخدمين.
    • كانت SQLite الحل الأبسط، الأسرع، والأكثر فعالية من حيث التكلفة.

نقص البدائل

حسب علمنا، لا توجد خدمات بريد إلكتروني أخرى مصممة بهذه الطريقة ولا هي مفتوحة المصدر.

نعتقد أن هذا قد يكون بسبب اعتماد خدمات البريد الإلكتروني الحالية على تكنولوجيا قديمة في الإنتاج مع كود معقد 🍝.

معظم، إن لم يكن كل، مزودي خدمات البريد الإلكتروني الحاليين إما مغلقو المصدر أو يعلنون أنهم مفتوحو المصدر، لكن في الواقع فقط الواجهة الأمامية لهم هي مفتوحة المصدر.

أكثر جزء حساس في البريد الإلكتروني (التخزين الفعلي/التفاعل مع IMAP/SMTP) يتم كله في الخلفية (الخادم)، وليس في الواجهة الأمامية (العميل).

جرب Forward Email

سجل اليوم على https://forwardemail.net! 🚀