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

قبل خمس سنوات حاولت العمل مع Tarantool ، لكن بعد ذلك لم يأت لي. لكني استضفت مؤخرًا ندوة عبر الإنترنت تحدثت فيها عن Hadoop ، حول كيفية عمل MapReduce. هناك سئل سؤال - "لماذا لا تستخدم Tarantool لهذه المهمة؟"



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







ما هو التارانتول



يضع Tarantool نفسه كقاعدة بيانات فائقة السرعة. يمكنك دفع أي بيانات تريدها هناك. بالإضافة إلى ذلك ، قم بتكرارها ، وقم بتقسيم كمية هائلة من البيانات عبر العديد من الخوادم ودمج النتائج منها - لإنشاء حزم "رئيسية - رئيسية" تتسامح مع الأخطاء.



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



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



حول مثل هذا الخادم ، مجرد خادم بسيط ، سأحاول وصفه في هذه المقالة.



التركيب



للاختبار ، بدأت بثلاثة أجهزة افتراضية قياسية - محرك أقراص ثابت سعة 20 غيغابايت ، Ubuntu 18.04. 2 وحدة معالجة مركزية افتراضية و 4 جيجا بايت من الذاكرة.



نقوم بتثبيت Tarantool - قم بتشغيل البرنامج النصي bash أو إضافة مستودع والقيام بتثبيت Tarantool. رابط البرنامج النصي هو (curl -L https://tarantool.io/installer.sh | VER = 2.4 sudo -E bash). لدينا أوامر مثل:



tarantoolctl - الأمر الرئيسي لإدارة حالات الرتيلاء.

/ etc / tarantool - كل الإعدادات هنا.

var / log / tarantool - هذا هو المكان الذي توجد فيه السجلات.

var / lib / tarantool - هذا هو المكان الذي يتم فيه تخزين البيانات ، ثم يتم تقسيمها إلى حالات.



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



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



إدارة المثيل



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



يمكنك رؤية حالة المثيل - مثال حالة tarantoolctl. بنفس الطريقة التي يمكنك بها البدء والتوقف وإعادة التشغيل.



عند تشغيل المثيل ، هناك طريقتان للاتصال به.



1. وحدة التحكم الإدارية



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



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



هذه الطريقة ضرورية للأشياء الإدارية. للعمل مع البيانات ، استخدم الطريقة الثانية - البروتوكول الثنائي.



2. استخدام بروتوكول ثنائي للاتصال بمنفذ معين



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



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



مسجل البيانات ووحدة الصندوق



نظرًا لأن Tarantool عبارة عن قاعدة بيانات وخادم تطبيق ، فإنه يحتوي على وحدات نمطية مختلفة. نحن مهتمون بالوحدة النمطية الصندوقية - فهي تنفذ العمل بالبيانات. عندما تكتب شيئًا ما في المربع ، يكتب Tarantool البيانات على القرص أو يخزنها في الذاكرة أو يفعل شيئًا آخر بها.



تسجيل



على سبيل المثال ، نذهب إلى الوحدة النمطية Box وندعو الوظيفة box.once. سيجعل Tarantool يقوم بتشغيل الكود الخاص بنا عند تهيئة الخادم. نقوم بإنشاء مساحة يتم فيها تخزين بياناتنا.



local function bootstrap()
    local space = box.schema.create_space('example')
    space:create_index('primary')
    box.schema.user.grant('guest', 'read,write,execute', 'universe')

    -- Keep things safe by default
    --  box.schema.user.create('example', { password = 'secret' })
    --  box.schema.user.grant('example', 'replication')
    --  box.schema.user.grant('example', 'read,write,execute', 'space', 'example')
end


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



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



بالمقارنة مع قواعد البيانات التقليدية ، كل شيء بسيط للغاية هنا. لدينا مساحة - منطقة تخزن بياناتنا ببساطة. كل إدخال يسمى tuple. هي معبأة في MessagePack. هذا تنسيق رائع للغاية - وهو ثنائي ويشغل مساحة أقل - 18 بايت مقابل 27.







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



يمكننا النظر إلى جميع المسافات باستخدام الأمر Box.space. لتحديد مثيل معين - اكتب مثال box.space واحصل على معلومات كاملة عنه.



يحتوي Tarantool على محركين مدمجين: Memory و Vinyl. تخزن الذاكرة جميع البيانات في الذاكرة. لذلك ، كل شيء يعمل ببساطة وبسرعة. يتم تفريغ البيانات على القرص ، وهناك أيضًا آلية تسجيل كتابة مسبقة ، لذلك لن نفقد أي شيء في حالة تعطل الخادم.



يقوم فينيل بتخزين البيانات على القرص في شكل مألوف أكثر - أي أنه يمكنك تخزين بيانات أكثر مما لدينا ذاكرة ، وسيقوم الرتيلاء بقراءتها من القرص.



سنستخدم الآن الذاكرة.



unix/:/var/run/tarantool/example.control> box.space.example
---
- engine: memtx
  before_replace: 'function: 0x41eb02c8'
  on_replace: 'function: 0x41eb0568'
  ck_constraint: []
  field_count: 0
  temporary: false
  index:
    0: &0
      unique: true
      parts:
      - type: unsigned
        is_nullable: false
        fieldno: 1
      id: 0
      space_id: 512
      type: TREE
      name: primary
    primary: *0
  is_local: false
  enabled: true
  name: example
  id: 512
...

unix/:/var/run/tarantool/example.control>


الفهرس:



يجب إنشاء الفهرس الأساسي لأي مساحة ، لأنه بدونها لن يعمل شيء. كما هو الحال مع أي قاعدة بيانات ، نقوم بإنشاء الحقل الأول - معرف السجل.



الأجزاء:



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



ثم يمكننا إدخال البيانات باستخدام الأمر insert.



unix/:/var/run/tarantool/example.control> box.space.example:insert{1, 'test1', 'test2'}
---
- [1, 'test1', 'test2']
...

unix/:/var/run/tarantool/example.control> box.space.example:insert{2, 'test2', 'test3', 'test4'}
---
- [2, 'test2', 'test3', 'test4']
...

unix/:/var/run/tarantool/example.control> box.space.example:insert{3, 'test3'}
---
- [3, 'test3']
...

unix/:/var/run/tarantool/example.control> box.space.example:insert{4, 'test4'}
---
- [4, 'test4']
...

unix/:/var/run/tarantool/example.control>


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



إخراج البيانات



ثم يمكننا عرض البيانات باستخدام الأمر select.



Box.example.select باستخدام المفتاح {1} سيعرض السجل المطلوب. إذا حذفنا المفتاح ، فسنرى جميع السجلات التي لدينا. كلهم مختلفون في عدد الأعمدة ، لكن هنا ، من حيث المبدأ ، لا يوجد مفهوم للأعمدة - هناك أرقام الحقول.



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




box.space.example:create_index( ‘secondary’, { type = ‘TREE’, unique = false, parts = {{field = 2, type =’string’} }}) 


نستخدم الأمر Create_index.

نسميها الثانوية.



بعد ذلك ، تحتاج إلى تحديد المعلمات. نوع الفهرس هو TREE. قد لا يكون فريدًا ، لذلك نقوم بإدخال Unique = false.



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



unix/:/var/run/tarantool/example.control> box.space.example:create_index('secondary', { type = 'TREE', unique = false, parts = {{field = 2, type = 'string'}}})
---
- unique: false
  parts:
  - type: string
    is_nullable: false
    fieldno: 2
  id: 1
  space_id: 512
  type: TREE
  name: secondary
...

unix/:/var/run/tarantool/example.control>


الآن هذه هي الطريقة التي يمكننا تسميتها:



unix/:/var/run/tarantool/example.control> box.space.example.index.secondary:select('test1')
---
- - [1, 'test1', 'test2']
...


الحفظ



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



لن ينجح توفير كل ثانية أيضًا - لأن تفريغ 20 جيجابايت باستمرار على القرص يعد أمرًا صعبًا.



لهذا ، تم اختراع مفهوم سجل الكتابة المسبقة وتنفيذه. يقوم بإنشاء إدخال في ملف سجل صغير للكتابة المسبقة لكل تغيير في البيانات.



يتم حفظ كل إدخال قبل نقطة التفتيش فيها. بالنسبة لهذه الملفات ، قمنا بتعيين الحجم - على سبيل المثال ، 64 ميغابايت. عندما تملأ ، يبدأ التسجيل في الانتقال إلى الملف الثاني. وبعد إعادة التشغيل ، يستعيد Tarantool من آخر نقطة تفتيش ثم يتنقل عبر جميع المعاملات اللاحقة حتى يتوقف.







لإجراء مثل هذا التسجيل ، تحتاج إلى تحديد الخيار في إعدادات box.cfg (في ملف example.lua):



wal_mode = “write”;


استخدام البيانات



مع ما كتبناه الآن ، يمكنك استخدام الرتيلاء لتخزين البيانات وستعمل بسرعة كبيرة كقاعدة بيانات. والآن الكرز فوق الكعكة - ماذا يمكنك أن تفعل بكل شيء.



كتابة طلب



على سبيل المثال ، دعنا نكتب مثل هذا التطبيق عن الرتيلاء



انظر التطبيق تحت المفسد
box.cfg {
    listen = '0.0.0.0:3301';
    io_collect_interval = nil;
    readahead = 16320;
    memtx_memory = 128 * 1024 * 1024; -- 128Mb
    memtx_min_tuple_size = 16;
    memtx_max_tuple_size = 128 * 1024 * 1024; -- 128Mb
    vinyl_memory = 128 * 1024 * 1024; -- 128Mb
    vinyl_cache = 128 * 1024 * 1024; -- 128Mb
    vinyl_max_tuple_size = 128 * 1024 * 1024; -- 128Mb
    vinyl_write_threads = 2;
    wal_mode = "write";
    wal_max_size = 256 * 1024 * 1024;
    checkpoint_interval = 60 * 60; -- one hour
    checkpoint_count = 6;
    force_recovery = true;
    log_level = 5;
    log_nonblock = false;
    too_long_threshold = 0.5;
    read_only   = false
}

local function bootstrap()
    local space = box.schema.create_space('example')
    space:create_index('primary')

    box.schema.user.create('example', { password = 'secret' })
    box.schema.user.grant('example', 'read,write,execute', 'space', 'example')

    box.schema.user.create('repl', { password = 'replication' })
    box.schema.user.grant('repl', 'replication')
end

-- for first run create a space and add set up grants
box.once('replica', bootstrap)

-- enabling console access
console = require('console')
console.listen('127.0.0.1:3302')

-- http config
local charset = {}  do -- [0-9a-zA-Z]
    for c = 48, 57  do table.insert(charset, string.char(c)) end
    for c = 65, 90  do table.insert(charset, string.char(c)) end
    for c = 97, 122 do table.insert(charset, string.char(c)) end
end

local function randomString(length)
    if not length or length <= 0 then return '' end
    math.randomseed(os.clock()^5)
    return randomString(length - 1) .. charset[math.random(1, #charset)]
end

local http_router = require('http.router')
local http_server = require('http.server')
local json = require('json')

local httpd = http_server.new('0.0.0.0', 8080, {
    log_requests = true,
    log_errors = true
})

local router = http_router.new()

local function get_count()
 local cnt = box.space.example:len()
 return cnt
end

router:route({method = 'GET', path = '/count'}, function()
    return {status = 200, body = json.encode({count = get_count()})}
end)

router:route({method = 'GET', path = '/token'}, function()
    local token = randomString(32)
    local last = box.space.example:len()
    box.space.example:insert{ last + 1, token }
    return {status = 200, body = json.encode({token = token})}
end)

prometheus = require('prometheus')

fiber = require('fiber')
tokens_count = prometheus.gauge("tarantool_tokens_count",
                              "API Tokens Count")

function monitor_tokens_count()
  while true do
    tokens_count:set(get_count())
    fiber.sleep(5)
  end
end
fiber.create(monitor_tokens_count)

router:route( { method = 'GET', path = '/metrics' }, prometheus.collect_http)

httpd:set_router(router)
httpd:start()




نعلن عن بعض الملصقات في lua التي تحدد الرموز. هذه اللوحة ضرورية لتوليد خط عشوائي.



local charset = {}  do -- [0-9a-zA-Z]
    for c = 48, 57  do table.insert(charset, string.char(c)) end
    for c = 65, 90  do table.insert(charset, string.char(c)) end
    for c = 97, 122 do table.insert(charset, string.char(c)) end
end


بعد ذلك ، نعلن عن دالة - randomString ونعطي قيمة الطول بين قوسين.



local function randomString(length)
    if not length or length <= 0 then return '' end
    math.randomseed(os.clock()^5)
    return randomString(length - 1) .. charset[math.random(1, #charset)]
end


ثم نقوم بتوصيل http-router و http-server بخادم Tarantula ، JSON ، والذي سنرسله إلى العميل.



local http_router = require('http.router')
local http_server = require('http.server')
local json = require('json')


بعد ذلك ، نبدأ على المنفذ 8080 على جميع واجهات خادم http ، والذي سيسجل جميع الطلبات والأخطاء.



local httpd = http_server.new('0.0.0.0', 8080, {
    log_requests = true,
    log_errors = true
})


بعد ذلك ، نعلن عن المسار أنه إذا وصل طلب باستخدام طريقة GET إلى المنفذ 8080 / count ، فإننا نستدعي الوظيفة من سطر واحد. تقوم بإرجاع الحالة - 200 أو 404 أو 403 أو أي شيء نحدده.



router:route({method = 'GET', path = '/count'}, function()
    return {status = 200, body = json.encode({count = get_count()})}
end)


في الجسم ، نعيد json.encode ، حيث نحدد count و getcount ، وهو ما يسمى ويظهر عدد السجلات في قاعدة البيانات الخاصة بنا.



الطريقة الثانية



router:route({method = 'GET', path = '/token'}, function() 
    local token = randomString(32) 
    local last = box.space.example:len() 
    box.space.example:insert{ last + 1, token } 
    return {status = 200, body = json.encode({token = token})}
end)


حيث في خط التوجيه: المسار ({الطريقة = ' GET' ، المسار = '/ الرمز'} ، الوظيفة () ، نستدعي الوظيفة وننشئ رمزًا مميزًا.



شريط الرمز المحلي = سلسلة عشوائية (32) - عبارة عن سلسلة عشوائية مكونة من 32 حرفًا.

سطر local last = box.space.example: len () نسحب العنصر الأخير ،

وفي مربع السطر .space.example: أدخل {last + 1 ، token} نكتب إلى قاعدة البيانات الخاصة بنا ، أي أننا نزيد المعرف بمقدار 1. يمكن القيام بذلك بالمناسبة ، ليس فقط بهذه الطريقة الخرقاء. في الرتيلاء ، هناك تسلسلات لهذا العمل.



نكتب رمزًا هناك.



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



يستمع إلى http ويعمل مع البيانات ، كل شيء في مثيل واحد - التطبيق والبيانات. لذلك ، كل شيء يحدث بسرعة كافية.



للتشغيل ، نقوم بتثبيت وحدة http:



كيف نفعل ذلك ، ننظر تحت المفسد
root@test2:/# tarantoolctl rocks install http
Installing http://rocks.tarantool.org/http-scm-1.src.rock
Missing dependencies for http scm-1:
   checks >= 3.0.1 (not installed)

http scm-1 depends on checks >= 3.0.1 (not installed)
Installing http://rocks.tarantool.org/checks-3.0.1-1.rockspec

Cloning into 'checks'...
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 28 (delta 1), reused 16 (delta 1), pack-reused 0
Receiving objects: 100% (28/28), 12.69 KiB | 12.69 MiB/s, done.
Resolving deltas: 100% (1/1), done.
Note: checking out '580388773ef11085015b5a06fe52d61acf16b201'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

No existing manifest. Attempting to rebuild...
checks 3.0.1-1 is now installed in /.rocks (license: BSD)

-- The C compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Found TARANTOOL: /usr/include (found version "2.4.2-80-g18f2bc82d")
-- Tarantool LUADIR is /.rocks/share/tarantool/rocks/http/scm-1/lua
-- Tarantool LIBDIR is /.rocks/share/tarantool/rocks/http/scm-1/lib
-- Configuring done
-- Generating done
CMake Warning:
  Manually-specified variables were not used by the project:

    version


-- Build files have been written to: /tmp/luarocks_http-scm-1-V4P9SM/http/build.luarocks
Scanning dependencies of target httpd
[ 50%] Building C object http/CMakeFiles/httpd.dir/lib.c.o
In file included from /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:32:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c: In functiontpl_term’:
/usr/include/tarantool/lauxlib.h:144:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
    (*(B)->p++ = (char)(c)))
    ~~~~~~~~~~~^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:62:7: note: in expansion of macro ‘luaL_addchar’
       luaL_addchar(b, '\\');
       ^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:63:6: note: here
      default:
      ^~~~~~~
In file included from /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:39:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h: In functiontpe_parse’:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:147:9: warning: this statement may fall through [-Wimplicit-fallthrough=]
    type = TPE_TEXT;
    ~~~~~^~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:149:3: note: here
   case TPE_LINECODE:
   ^~~~
In file included from /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:40:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h: In functionhttpfast_parse’:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:372:22: warning: this statement may fall through [-Wimplicit-fallthrough=]
                 code = 0;
                 ~~~~~^~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:374:13: note: here
             case status:
             ^~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:393:23: warning: this statement may fall through [-Wimplicit-fallthrough=]
                 state = message;
                 ~~~~~~^~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:395:13: note: here
             case message:
             ^~~~
[100%] Linking C shared library lib.so
[100%] Built target httpd
[100%] Built target httpd
Install the project...
-- Install configuration: "Debug"
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/VERSION.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lib/http/lib.so
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/init.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/tsgi_adapter.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/nginx_server/init.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/init.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/fs.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/matching.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/middleware.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/request.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/response.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/tsgi.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/utils.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/mime_types.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/codes.lua
http scm-1 is now installed in /.rocks (license: BSD)

root@test2:/#




نحتاج أيضًا إلى بروميثيوس لتشغيل:



root@test2:/# tarantoolctl rocks install prometheus
Installing http://rocks.tarantool.org/prometheus-scm-1.rockspec

Cloning into 'prometheus'...
remote: Enumerating objects: 19, done.
remote: Counting objects: 100% (19/19), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 19 (delta 2), reused 5 (delta 0), pack-reused 0
Receiving objects: 100% (19/19), 10.73 KiB | 10.73 MiB/s, done.
Resolving deltas: 100% (2/2), done.
prometheus scm-1 is now installed in /.rocks (license: BSD)

root@test2:/#


نبدأ ويمكننا الوصول إلى الوحدات



root@test2:/# curl -D - -s http://127.0.0.1:8080/token
HTTP/1.1 200 Ok
Content-length: 44
Server: Tarantool http (tarantool v2.4.2-80-g18f2bc82d)
Connection: keep-alive

{"token":"e2tPq9l5Z3QZrewRf6uuoJUl3lJgSLOI"}

root@test2:/# curl -D - -s http://127.0.0.1:8080/token
HTTP/1.1 200 Ok
Content-length: 44
Server: Tarantool http (tarantool v2.4.2-80-g18f2bc82d)
Connection: keep-alive

{"token":"fR5aCA84gj9eZI3gJcV0LEDl9XZAG2Iu"}

root@test2:/# curl -D - -s http://127.0.0.1:8080/count
HTTP/1.1 200 Ok
Content-length: 11
Server: Tarantool http (tarantool v2.4.2-80-g18f2bc82d)
Connection: keep-alive

{"count":2}root@test2:/#


/ count يعطينا حالة 200.

/ يصدر رمز مميز ويكتب هذا الرمز المميز إلى قاعدة البيانات.



سرعة الاختبار



دعونا نجري اختبارًا مع 50000 استفسار. سيكون هناك 500 طلب تنافسي.



root@test2:/# ab -c 500 -n 50000 http://127.0.0.1:8080/token
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Completed 30000 requests
Completed 35000 requests
Completed 40000 requests
Completed 45000 requests
Completed 50000 requests
Finished 50000 requests


Server Software:        Tarantool
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /token
Document Length:        44 bytes

Concurrency Level:      500
Time taken for tests:   14.578 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      7950000 bytes
HTML transferred:       2200000 bytes
Requests per second:    3429.87 [#/sec] (mean)
Time per request:       145.778 [ms] (mean)
Time per request:       0.292 [ms] (mean, across all concurrent requests)
Transfer rate:          532.57 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   10 103.2      0    3048
Processing:    12   69 685.1     15   13538
Waiting:       12   69 685.1     15   13538
Total:         12   78 768.2     15   14573

Percentage of the requests served within a certain time (ms)
  50%     15
  66%     15
  75%     16
  80%     16
  90%     16
  95%     16
  98%     21
  99%     42
 100%  14573 (longest request)
root@test2:/#


يتم إصدار الرموز. ونحن نسجل البيانات باستمرار. تم إكمال 99٪ من الطلبات في 42 مللي ثانية. وفقًا لذلك ، لدينا حوالي 3500 طلبًا في الثانية على جهاز صغير ، حيث يوجد مركزان و 4 غيغابايت من الذاكرة.



يمكنك أيضًا تحديد حوالي 50000 رمز مميز ومعرفة قيمتها.



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



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



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



سيتم تنفيذ ذلك بواسطة الرتيلاء نفسه ، ولن تضطر إلى كتابة طلب منفصل.



أخيرا



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



إذا كنت مهتمًا بحضور الأحداث حيث نقوم بإنشاء مثل هذه الأشياء عبر الإنترنت وطرح الأسئلة في الوقت الفعلي ، فقم بالانضمام إلى قناة DevOps by REBRAIN .



إذا كنت بحاجة إلى الانتقال إلى السحابة أو كانت لديك أسئلة حول بنيتك التحتية ، فلا تتردد في ترك طلب .



ملاحظة: لدينا عمليتا تدقيق مجانيتان شهريًا ، وربما يكون مشروعك من بينها.



All Articles