صندوق لتخزين البيانات في تطبيقات الذهاب

صورة

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

ولكن أولا ، مقدمة غنائية قليلا. ذات مرة ، عندما كان العشب أكثر خضرة ، تطلب الأمر مني تضمين قاعدة بيانات ذات قيمة أساسية لتطبيق go-application. عند الاطلاع على الحزم المختلفة والالتفاف عليها ، لم أجد بطريقة ما ما أريد (ذاتي) ، وقمت بتطبيق الحل باستخدام قاعدة بيانات خارجية ذات صلة. حل عمل رائع. ولكن كما يقولون ، تم العثور على ملعقة ، ولكن بقيت الرواسب. بادئ ذي بدء ، أردت بالضبط الأصلي ، مكتوبة على قاعدة بيانات Go ، مباشرة الأصليين. وهناك مثل ، مجرد إلقاء نظرة رهيبة. ومع ذلك ، لا يوجد مليون منهم. هذا أمر مثير للدهشة عندما تفكر في أن المبرمج نادر في العالم الذي لم يكتب قاعدة بيانات أو إطار عمل أو لعبة عارضة في حياته.


حسنًا ، يمكنك محاولة تكديس دراجتك على ركبتك ، باستخدام لعبة البلاك جاك وغيرها من الأشياء الجيدة. في الوقت نفسه ، يعلم الجميع ، أو على الأقل يخمنون ، أن كتابة قاعدة بيانات بسيطة ذات قيمة بسيطة تبدو بسيطة فقط للوهلة الأولى. ولكن في الواقع ، كل شيء أكثر متعة (وحدث ذلك). وكنت أشعر بالفضول تجاه الحامض والقلق بشأن المعاملات. المعاملات الحقيقية هي أكثر احتمالا بالمعنى المالي ، لأن كنت مشغولا ثم في fintech.


أمن البيانات


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


كيف في الحالة الأخيرة لمعرفة ما حدث مع العمليات الأخيرة؟ هذا سؤال مثير للاهتمام بشكل غير مباشر ، يمكنك تخمين ذلك (استخلاص النتائج) من خلال النظر في قيمة سجل الاهتمام بعد إطلاق تطبيق جديد من قاعدة البيانات. ومع ذلك ، إذا كانت العمليات متكررة بما فيه الكفاية ، أخشى أن ذلك لن يساعد. يمكنك مشاهدة ملف السجل الأخير (سيكون مع أكبر عدد) ، ولكن هذا غير مريح يدويًا. أعتقد أنه في المستقبل ، يمكنك إضافة القدرة على عرض السجلات في واجهة برمجة التطبيقات (وبطبيعة الحال ، لا ينبغي حذف السجلات في هذه الحالة).


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


قاعدة البيانات غير محمية حاليًا من الاستخدام في تطبيقين مختلفين (أو نفس الشيء ، لا يهم هنا) تم تكوينه للعمل مع نفس الدليل. يرجى أخذ هذه اللحظة في الاعتبار! ومع ذلك ، نظرًا لأن قاعدة البيانات مضمّنة ، ثم تمريرها نوعًا من أنواع المرجع في الوسيطات ، فمن المؤكد أنها لا تستحق تغييرها في مكان ما في goroutine الموازي.



تكوين


تحتوي قاعدة البيانات على عدد قليل من المعلمات التي يمكن تهيئتها ، ومع ذلك ، cof, err, wrn := Db(dirPath).Create() تقريبًا لها قيم افتراضية ، لذلك يمكن أن يكون كل شيء مناسبًا لواحد قصير من سطر واحد cof, err, wrn := Db(dirPath).Create() يتم إرجاع خطأ (إذا حدث خطأ ، cof, err, wrn := Db(dirPath).Create() بمزيد من العمل مع قاعدة البيانات المحظورة) والتحذير ، والتي يمكنك معرفة ، ولكن هذا لا يتعارض مع تشغيل قاعدة البيانات.


لن أقوم بتجميع النص بأوصاف مرهقة ، إذا لزم الأمر ، فالرجاء مشاهدتها في الملف التمهيدي للمستودع - github.com/claygod/coffer/blob/master/README_RU.md#config لاحظ طريقة المعالج التي تربط المعالج بالمعاملة ، سأكتب بضعة أسطر عنه أقل ، أنا هنا فقط قائمة لهم:


  • ديسيبل (dirPath)
  • BatchSize (batchSize)
  • LimitRecordsPerLogfile (limitRecordsPerLogfile)
  • متابعةالوقت (100 * الوقت. الثانية)
  • LogsByCheckpoint (1000)
  • AllowStartupErrLoadLogs (صواب)
  • MaxKeyLength (maxKeyLength)
  • MaxValueLength (maxValueLength)
  • MaxRecsPerOperation (1،000،000)
  • RemoveUnlessLogs (صواب)
  • LimitMemory (100 * 1،000،000)
  • LimitDisk (1000 * 1،000،000)
  • معالج ("handler1" ، و handler1)
  • معالج ("handler2" ، و handler2)
  • معالجات (خريطة [سلسلة] * معالج)
  • إنشاء ()

API


قدر الإمكان ، جعلت واجهة برمجة التطبيقات بسيطة ، ولكي تكون ذات قيمة مفتاح لا تكون ذكية جدًا:


  • البدء - بدء قاعدة البيانات
  • وقف - وقف قاعدة البيانات
  • StopHard - توقف بغض النظر عن العمليات التي يتم تنفيذها في الوقت الحالي (ربما سأقوم بإزالتها)
  • حفظ - حفظ لقطة للحالة الحالية لقاعدة البيانات
  • الكتابة - إضافة سجل واحد إلى قاعدة البيانات
  • WriteList - إضافة عدة سجلات إلى قاعدة البيانات (أوضاع صارمة واختيارية)
  • WriteListUnsafe - إضافة سجلات متعددة إلى قاعدة البيانات دون النظر إلى أمان البيانات
  • قراءة - الحصول على سجل واحد عن طريق المفتاح
  • ReadList - الحصول على قائمة السجلات
  • ReadListUnsafe - الحصول على قائمة السجلات دون النظر إلى أمان البيانات
  • حذف - حذف سجل واحد
  • DeleteList - حذف سجلات متعددة في وضع صارم / اختياري
  • المعاملة - تنفيذ المعاملة
  • العد - كم عدد السجلات في قاعدة البيانات
  • CountUnsafe - كم عدد السجلات في قاعدة البيانات (أسرع قليلاً ، ولكنها غير آمنة)
  • RecordsList - قائمة بجميع مفاتيح قواعد البيانات
  • RecordsListUnsafe - قائمة بجميع مفاتيح قواعد البيانات (أسرع قليلاً ، ولكنها غير آمنة)
  • RecordsListWithPrefix - قائمة بالمفاتيح ذات البادئة المحددة
  • RecordsListWithSuffix - قائمة بالمفاتيح ذات النهاية المحددة

تفسيرات قصيرة لواجهة برمجة التطبيقات:


  • وضع صارم - تفعل كل شيء أو لا شيء.
  • الوضع الاختياري - تفعل كل شيء يعمل.
  • StopHard - ربما يجب إزالة هذه الطريقة من API حتى يتم تحديدها.
  • جميع أساليب قائمة السجلات ليست سريعة ، لأن لا توجد فهارس في المتجر في الوقت الحالي ، في حين أن هذا ملء الشاشة.
  • جميع الطرق غير الآمنة تكون أسرع ، لكن الاتساق لا يعني ضمنيًا عند استخدامها. من المنطقي استخدامها على قاعدة بيانات متوقفة للتعبئة السريعة أو أي شيء آخر في نفس السياق.
  • يتابع المتابع التحديث المنتظم لقطة لقاعدة البيانات ، لذلك من الأرجح أن تكون طريقة الحفظ في بعض الحالات الخاصة عندما تريد بالتأكيد إنشاء لقطة جديدة (حتى تتبادر هذه الحالة إلى ذهني ، ولكن ربما تكون كذلك).

حالة استخدام بسيطة:

 package main import ( "fmt" "github.com/claygod/coffer" ) const curDir = "./" func main() { // STEP init db, err, wrn := coffer.Db(curDir).Create() switch { case err != nil: fmt.Println("Error:", err) return case wrn != nil: fmt.Println("Warning:", err) return } if !db.Start() { fmt.Println("Error: not start") return } defer db.Stop() // STEP write if rep := db.Write("foo", []byte("bar")); rep.IsCodeError() { fmt.Sprintf("Write error: code `%d` msg `%s`", rep.Code, rep.Error) return } // STEP read rep := db.Read("foo") rep.IsCodeError() if rep.IsCodeError() { fmt.Sprintf("Read error: code `%v` msg `%v`", rep.Code, rep.Error) return } fmt.Println(string(rep.Data)) } 

المعاملات


كما ذكر أعلاه ، قد لا يتطابق تعريفي للمعاملات مع ما يتم قبوله عمومًا في إنشاء قواعد البيانات ، وربما يكونون متحدين فقط بفكرة. في تطبيق معين ، تكون المعاملة عبارة عن رأس معين محدد في مرحلة تكوين قاعدة البيانات (طريقة Handler ). عندما نقوم باستدعاء معاملة باستخدام هذا الرأس ، تقوم قاعدة البيانات بحظر السجلات التي سيعمل بها الرأس وتنقل قيمها الحالية إلى الرأس. يعالج الرأس هذه البيانات حسب حاجته ، ويعيد القيم الجديدة لقاعدة البيانات ، ويحفظها في مائة. بعد ذلك ، يتم فتح السجلات وإتاحتها للعمليات الأخرى.


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


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



تلقي ومعالجة الردود


تُرجع قاعدة البيانات تقارير تشير إلى حالة الاستجابة ومع البيانات. نظرًا لوجود العديد من الرموز ، وكتابة رمز التبديل مع معالجة كل منها أمر مزعج ، فقد تحتاج إلى التحقق من التقريب. هذا لا ينبغي القيام به. والحقيقة هي أن الرمز قد يكون حالة موافق ، خطأ ، الذعر. مع حسنًا ، كل شيء واضح ، لكن ماذا عن الاثنين الآخرين؟ إذا كانت الحالة "خطأ" ، فستكمل عملية محددة ، أو لم تكتمل. يجب معالجة هذا الخطأ بشكل مناسب في التطبيق. ومع ذلك ، يمكن إجراء مزيد من العمل مع قاعدة البيانات (وضروري). شيء آخر الذعر - يجب وقف العمل مع قاعدة البيانات.


يؤدي التحقق من IsCodeError تبسيط العمل بكل الأخطاء ، لذلك إذا كنت غير مهتم بالتفاصيل ، IsCodeError العمل.
يغطي التحقق IsCodePanic كافة الحالات التي يجب إيقاف العمل مع قاعدة البيانات.


في الحالة البسيطة ، يكون المفتاح الثلاثي كافياً لمعالجة الاستجابة:


  • IsCodeOk - مواصلة العمل IsCodeOk
  • IsCodeError - تسجيل الخطأ من التقرير والعمل بشكل أكبر
  • IsCodePanic - تسجيل الخطأ من التقرير والتوقف عن العمل مع قاعدة البيانات

Offtop


بالنسبة للاسم ، تم اختيار أحد الخيارات لترجمة الكلمات إلى الإنجليزية ، أفضل box ، بالطبع ، لكن هذه الكلمة شائعة جدًا ، وآمل أن يقوم coffer بذلك.
يبدو لي الموضوع مع ACID كليًا إلى حد ما ، لذلك أود أن أقول إن Coffer ملتزم بذلك ، ولكن ليس حقيقة ، وأنا لا أدعي أنه نجح.



إنتاجية


كتبت على الفور قاعدة بيانات مع مراعاة التزامن والمنافسة. في هذا الوضع يظهر فعاليته (على الرغم من أن هذا يقال بصوت عالٍ للغاية). في النتائج أدناه ، يُظهر المعيار عرض نطاق ترددي قدره 200 كيلو بايت في الثانية. هذا بالطبع مقعد اصطناعي ، والحقيقة ستكون مختلفة تمامًا ، لأن يعتمد الكثير على حجم البيانات المسجلة ، وكمية البيانات المسجلة بالفعل ، وأداء الحديد ومرحلة القمر. لكن الاتجاه مفهوم على الأقل. إذا تم استخدام قاعدة البيانات في وضع أحادي الترابط ، يتم تنفيذ كل طلب فقط بعد تلقي إجابة على السابقة ، وسوف تكون السرعة بطيئة ، وأنصحك أن ننظر إلى قواعد البيانات الأخرى ، ولكن لا Coffer.


  • BenchmarkCofferTransactionSequence-4 2000 227928 ns / op
  • BenchmarkCofferTransactionPar32HalfConcurent-4 100000 4199 ns / op

بالمناسبة ، إذا كان شخص ما يقضي الوقت ويميل لأنفسه إلى مستودع مع Coffer ، إذا كان ذلك ممكنا ، تشغيل مقاعد البدلاء في ذلك. أنا مهتم جدًا بماهية الأجهزة التي سيُظهر الأداء قاعدة البيانات. بادئ ذي بدء ، كل هذا يتوقف على القرص. أصبح هذا واضحًا بشكل خاص بالنسبة لي بعد أن اشتريت مؤخراً Samsung EVO جديدًا. ولكن لا تقلق ، هذا ليس بديلاً عن قرص ميت. تستمر Toshiba القديمة في العمل بشكل صحيح وتقوم الآن بتخزين أرشيف الفيديو الخاص بي.


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



رخصة


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



النتائج


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



شكر


  • لكل من قرأ المقال حتى النهاية
  • المعلقون الذين يرغبون في مشاركة آرائهم
  • إرسالها في معلومات شخصية عن الأخطاء المطبعية والأخطاء في النص
  • الجار تشغيل الموسيقى في الليل

مراجع


مستودع قاعدة بيانات
الوصف باللغة الروسية

Source: https://habr.com/ru/post/ar477154/


All Articles