دليل النشر

QuestDB على خادم VPS: قاعدة سلاسل زمنية بلغة SQL

انشر على VPS Cloud ←

دليل عملي

QuestDB على خادم VPS: قاعدة سلاسل زمنية بلغة SQL

الاستضافة الذاتية7 دقائق للقراءةعدد الخطوات: 4

القياسات المؤرَّخة تأتي من كل مكان: الحساسات، وأزمنة استجابة واجهة برمجية، وأسعار الأسواق، وأحداث التطبيقات. تخزينها في قاعدة علائقية تقليدية ينجح في البداية، ثم تكبر الجداول ويصبح التجميع لكل ساعة بطيئًا. QuestDB قاعدة بيانات مفتوحة المصدر للسلاسل الزمنية (رخصة Apache-2.0) صُممت لهذه الحالة بالضبط: تستقبل البيانات بشكل متواصل وتجعلها قابلة للاستعلام فورًا بلغة SQL. يثبّتها هذا الدليل على خادم افتراضي باستخدام Docker Compose، ويحميها بكلمة مرور، ويرسل إليها بيانات من curl وPython، ثم يتناول الاستعلام واستيراد CSV والاحتفاظ بالبيانات والنسخ الاحتياطي.

المحتويات· لماذا قاعدة بيانات للسلاسل الزمنية1/14
  1. 01لماذا قاعدة بيانات للسلاسل الزمنية
  2. 02ما تقدّمه QuestDB
  3. 03QuestDB مقارنةً بجدول PostgreSQL تقليدي
  4. 04المتطلبات المسبقة
  5. 05تثبيت QuestDB باستخدام Docker Compose
  6. 06بدون QDB_HTTP_USER تكون الواجهة مفتوحة للجميع
  7. 07إرسال البيانات
  8. 08الاستعلام عن سلاسلك بلغة SQL
  9. 09تصميم جدول السلاسل الزمنية بشكل صحيح
  10. 10استيراد ملفات CSV وتصديرها
  11. 11الاحتفاظ بالبيانات والقرص والنسخ الاحتياطي
  12. 12تحديث QuestDB
  13. 13الأخطاء الشائعة وحلّها
  14. 14تثبيت بنقرة واحدة من متجر ServOrbit

لماذا قاعدة بيانات للسلاسل الزمنية

السلسلة الزمنية تتابع من القيم المؤرَّخة: حرارة مجس كل عشر ثوانٍ، أو عدد الطلبات في الدقيقة. تُكتب كثيرًا ونادرًا ما تُعدَّل، ويُستعلم عنها دائمًا تقريبًا حسب فترة زمنية.

بُنيت QuestDB حول هذا الاستخدام. لكل جدول عمود زمني محدد، ويُقسَّم إلى أقسام (حسب اليوم أو الساعة)، ما يُبقي الاستعلامات على فترة ما سريعة ويجعل حذف البيانات القديمة فوريًا. وتبقى لغتها SQL، مع بعض الكلمات المفتاحية الخاصة بالزمن.

ما تقدّمه QuestDB

  • SQL للسلاسل الزمنية — SAMPLE BY وLATEST ON وASOF JOIN إضافةً إلى SQL القياسية.
  • استيعاب متواصل — InfluxDB Line Protocol فوق HTTP، مع عملاء رسمية لـ Python وGo وJava وNode.js وRust و‎.NET.
  • واجهة ويب — محرر SQL، واستيراد CSV بالسحب والإفلات، ورسوم بيانية للنتائج.
  • واجهة REST — استعلامات واستيراد وتصدير CSV عبر HTTP.
  • بروتوكول PostgreSQL — مشغّلات وأدوات PostgreSQL المعتادة لديك.
  • أقسام زمنية — استعلامات سريعة على فترة، وحذف البيانات القديمة بأمر واحد.

QuestDB مقارنةً بجدول PostgreSQL تقليدي

مرّر الجدول أفقيًا

QuestDBPostgreSQL وحده
مصممة لـقياسات مؤرَّخة متواصلةبيانات علائقية عامة
التجميع حسب الفترةSAMPLE BY 1hdate_trunc وGROUP BY
آخر قيمة لكل سلسلةLATEST ONاستعلام فرعي أو DISTINCT ON
محاذاة تدفقين زمنيًاASOF JOINربط جانبي يجب كتابته
حذف السجل القديمDROP PARTITIONDELETE ثم VACUUM
الاستيعابLine Protocol وCSV وSQLSQL وCOPY

المتطلبات المسبقة

خادم افتراضي بنظام Ubuntu 24.04 بذاكرة 2 غيغابايت على الأقل وقرص 20 غيغابايت، مع تثبيت Docker وإضافة Compose، واسم (نطاق فرعي) يشير إلى الخادم من أجل HTTPS. تعمل QuestDB على JVM: خطّط لذاكرة 4 غيغابايت إذا كنت تستوعب بيانات كثيرة أو تنفّذ استعلامات ثقيلة.

تثبيت QuestDB باستخدام Docker Compose

  1. تجهيز المجلد وكلمة المرور

    أنشئ مجلد التطبيق وملف .env يحمل كلمة مرور المستخدم admin.

    mkdir -p /opt/questdb && cd /opt/questdb
    echo "ADMIN_PASSWORD=$(openssl rand -hex 16)" > .env
    chmod 600 .env
  2. كتابة ملف docker-compose.yml

    لا تُنشر المنافذ إلا على واجهة loopback: وحده nginx يصل إلى الواجهة وواجهة البرمجة. يحمي QDB_HTTP_USER وQDB_HTTP_PASSWORD واجهة HTTP كاملة، ويستبدل QDB_PG_PASSWORD كلمة مرور المصنع لبروتوكول PostgreSQL. يُوقَف الاستيعاب عبر TCP، لأنه بلا مصادقة في النسخة مفتوحة المصدر، ويعطّل QDB_TELEMETRY_ENABLED القياس عن بُعد المجهول.

    services:
      questdb:
        image: questdb/questdb:10.1.0
        restart: unless-stopped
        ports:
          - "127.0.0.1:9000:9000"
          - "127.0.0.1:8812:8812"
        environment:
          QDB_HTTP_USER: "admin"
          QDB_HTTP_PASSWORD: "${ADMIN_PASSWORD}"
          QDB_PG_USER: "admin"
          QDB_PG_PASSWORD: "${ADMIN_PASSWORD}"
          QDB_LINE_TCP_ENABLED: "false"
          QDB_HTTP_SETTINGS_READONLY: "true"
          QDB_TELEMETRY_ENABLED: "false"
        volumes:
          - questdb-data:/var/lib/questdb
    
    volumes:
      questdb-data: {}
  3. التشغيل والتحقق

    يستغرق التشغيل بضع ثوانٍ. بدون بيانات اعتماد تجيب الواجهة بالرمز 401، ومعها تعيد الإصدار المثبّت.

    docker compose up -d
    curl -s -o /dev/null -w '%{http_code}\n' 'http://127.0.0.1:9000/exec?query=SELECT%201'
    curl -u admin:VOTRE_MOT_DE_PASSE 'http://127.0.0.1:9000/exec?query=SELECT%20build()'
  4. النشر عبر HTTPS باستخدام nginx

    في المضيف الافتراضي لنطاقك (بشهادة من certbot)، وجّه الطلبات إلى المنفذ المحلي. ارفع قيمة client_max_body_size من أجل استيراد ملفات CSV.

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 256m;
    }

بدون QDB_HTTP_USER تكون الواجهة مفتوحة للجميع

عند عدم تعريف مستخدم، تقبل QuestDB كل طلب HTTP: يستطيع أي شخص يعرف العنوان قراءة بياناتك وإنشاء الجداول أو تعديلها أو حذفها بلغة SQL. أبقِ المصادقة مفعّلة، وغيّر كلمة مرور المصنع لبروتوكول PostgreSQL، ولا تنشر أبدًا المنافذ 9000 أو 8812 أو 9009 مباشرة على عنوان IP العام: مرّ دائمًا عبر الوكيل العكسي HTTPS.

إرسال البيانات

أبسط طريقة هي InfluxDB Line Protocol فوق HTTP: سطر لكل قياس، يحمل اسم الجدول والوسوم والقيم. يُنشأ الجدول وأعمدته مع أول كتابة.

curl -u admin:VOTRE_MOT_DE_PASSE -X POST \
  --data-binary 'capteurs,sonde=s1 temperature=21.5' \
  https://votre-domaine/write

ومن شيفرتك، يجمّع العميل الرسمي الأسطر ويتولّى إعادة المحاولة. في Python، بعد pip install questdb:

from questdb.ingress import Sender, TimestampNanos

conf = "https::addr=votre-domaine:443;username=admin;password=VOTRE_MOT_DE_PASSE;"
with Sender.from_conf(conf) as sender:
    sender.row(
        "capteurs",
        symbols={"sonde": "s1"},
        columns={"temperature": 21.5},
        at=TimestampNanos.now(),
    )

الاستعلام عن سلاسلك بلغة SQL

في واجهة الويب أو عبر واجهة REST (/exec?query=…)، تعمل SQL القياسية، وتغنيك امتدادات الزمن عن الاستعلامات المعقدة.

-- Moyenne horaire par sonde
SELECT timestamp, sonde, avg(temperature)
FROM capteurs
SAMPLE BY 1h;

-- Dernière valeur connue de chaque sonde
SELECT * FROM capteurs LATEST ON timestamp PARTITION BY sonde;

ويمكن لبرنامج يعمل على الخادم نفسه الاتصال أيضًا عبر بروتوكول PostgreSQL على 127.0.0.1:8812، بقاعدة qdb والمستخدم admin وكلمة المرور نفسها.

تصميم جدول السلاسل الزمنية بشكل صحيح

يكفي الإنشاء التلقائي مع أول كتابة للبدء. أما الجدول المعدّ للبقاء طويلًا فعرّفه بنفسك: تختار الأنواع والعمود الزمني وطريقة التقسيم.

CREATE TABLE capteurs (
  timestamp TIMESTAMP,
  sonde SYMBOL,
  temperature DOUBLE
) TIMESTAMP(timestamp) PARTITION BY DAY WAL
DEDUP UPSERT KEYS(timestamp, sonde);

ثلاثة اختيارات مهمة. العمود الزمني المحدد (TIMESTAMP(...)) هو الذي ترتّب QuestDB البيانات وتقسّمها وفقه: تعتمد عليه كل امتدادات الزمن. النوع SYMBOL يناسب الوسوم المتكررة (اسم المجس، رمز الجهاز، رمز السهم): تُخزَّن القيمة مرة واحدة ويُشار إليها، ما يوفّر القرص ويسرّع التصفية. التقسيم (PARTITION BY DAY أو HOUR) يُختار حسب الحجم: يجب أن يبقى القسم بحجم معقول، وهو الوحدة التي ستحذفها لاحقًا.

تجعل العبارة DEDUP UPSERT KEYS الاستيعاب متساوي الأثر: إذا أعاد عميل إرسال القياس نفسه بعد انقطاع الشبكة، يُستبدل السطر بدل أن يتكرر.

استيراد ملفات CSV وتصديرها

تقبل الواجهة ملفات CSV بالسحب والإفلات. ومن سطر الأوامر، يستورد /imp ملفًا إلى جدول ويصدّر /exp نتيجة استعلام.

curl -u admin:VOTRE_MOT_DE_PASSE -F [email protected] 'https://votre-domaine/imp?name=mesures'
curl -u admin:VOTRE_MOT_DE_PASSE -G --data-urlencode 'query=SELECT * FROM mesures' https://votre-domaine/exp > export.csv

الاحتفاظ بالبيانات والقرص والنسخ الاحتياطي

لا شيء ينتهي من تلقاء نفسه. احذف الأقسام القديمة بلغة SQL وجدول الأمر عند الحاجة. وللحصول على نسخة احتياطية متسقة، جمّد حالة القاعدة أثناء نسخ وحدة التخزين questdb-data.

ALTER TABLE capteurs DROP PARTITION
WHERE timestamp < dateadd('d', -90, now());

CHECKPOINT CREATE;
-- copiez le volume questdb-data, puis :
CHECKPOINT RELEASE;

تحديث QuestDB

اقرأ ملاحظات الإصدار قبل الانتقال إلى إصدار رئيسي جديد، ثم استبدل وسم الصورة وأعد التشغيل: تبقى البيانات في وحدة التخزين محفوظة.

cd /opt/questdb
# changez le tag de l'image dans docker-compose.yml, puis :
docker compose pull && docker compose up -d

الأخطاء الشائعة وحلّها

الرمز 401 على كل طلب. المستخدم أو كلمة المرور لا يطابقان QDB_HTTP_USER وQDB_HTTP_PASSWORD. تحقّق من ملف .env ثم أعد تشغيل الحاوية بعد أي تعديل: لا تُقرأ المتغيرات إلا عند التشغيل.

الرمز 413 أثناء استيراد CSV. يتجاوز الملف حدّ nginx. ارفع client_max_body_size في المضيف الافتراضي وأعد تحميل nginx، أو قسّم الملف.

الحاوية تعيد التشغيل باستمرار. اقرأ docker compose logs questdb. السبب الأكثر شيوعًا هو الذاكرة: تعمل QuestDB على JVM ولا يكفي خادم بذاكرة 1 غيغابايت. انتقل إلى 2 غيغابايت على الأقل.

القرص يمتلئ. لا شيء ينتهي افتراضيًا: جدول حذف الأقسام القديمة وراقب حجم وحدة التخزين questdb-data بالأمر docker system df -v.

تطبيق على الخادم لا يتصل عبر PostgreSQL. استخدم 127.0.0.1:8812 والقاعدة qdb والمستخدم admin وكلمة المرور من .env: كلمة مرور المصنع quest مرفوضة.

تثبيت بنقرة واحدة من متجر ServOrbit

على خادم ServOrbit، يُثبَّت QuestDB من المتجر: ينشر السكربت الحاوية الرسمية، ويولّد كلمة مرور المستخدم admin، ويفعّل المصادقة على واجهة HTTP وبروتوكول PostgreSQL، ويوقف القياس عن بُعد، ويضبط nginx عبر HTTPS، على نطاق فرعي من نطاقك أو على النطاق الفرعي المجاني للخادم. تظهر كلمة المرور في مساحة العميل.

سلاسلك الزمنية على خادمك الخاص

يكفي خادم ServOrbit بنظام Ubuntu 24.04 وذاكرة 2 غيغابايت لتشغيل QuestDB. تثبيت بنقرة واحدة من المتجر، وHTTPS على نطاقك أو على النطاق الفرعي المجاني للخادم، وكلمة مرور مولّدة لك.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـالعربية والفرنسية والإنجليزية.

راسلنا على WhatsAppيُفتح في علامة تبويب جديدة