ניטור PostgreSQL עם Prometheus ו-postgres_exporter

כאשר עומס PostgreSQL גדל והשאילתות מואטות, מדדי מארח סטנדרטיים אינם חושפים את שורש הבעיה—תקריות מתגלות רק לאחר תלונות משתמשים. אנו מגדירים ניטור PostgreSQL באמצעות Prometheus ו-postgres_exporter, אוספים מדדים מרכזיים ואינדיקטורים מותאמים אישית. הצוות שלנו מספק את הפרויקט במפתח מלא, מבדיקת היתכנות והתקנה ועד התראות ודשבורדים, תוך הבטחת פעילות יציבה ותמיכה מתמשכת.

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

הגדרת ניטור PostgreSQL עם Prometheus ו-postgres_exporter

חשוב להבין: כאשר העומס על PostgreSQL גדל ושאילתות SQL מתדרדרות, מדדי מארח סטנדרטיים לא מציגים את שורש הבעיה. ללא נראות נאותה, תקלות מתגלות רק לאחר תלונות משתמשים. הניסיון שלנו מראה ש-postgres_exporter מוגדר כראוי מקצר את זמן הגילוי הממוצע של בעיות משעתיים ל-15 דקות. בנוסף, התראות אוטומטיות מאפשרות לפעול לפני שהמסד נתונים הופך ללא זמין. מצב טיפוסי: קפיצה פתאומית בהמתנת I/O או bloat גדל — ללא ניטור, אירועים כאלה נעלמים מעין עד לכשל קריטי. אנו מציעים גישה שיטתית: postgres_exporter, מדדים מותאמים אישית, התראות ולוחות מחוונים המספקים תמונה מלאה של בריאות מסד הנתונים.

מה postgres_exporter אוסף

ה-prometheus-community/postgres_exporter מתחבר ל-PostgreSQL כקוח רגיל ומבצע שאילתות SQL כנגד תצוגות מערכת (pg_stat_activity, pg_stat_user_tables, pg_locks, pg_replication_slots ואחרות). התוצאות נחשפות ב-:9187/metrics. התפקיד המובנה pg_monitor (זמין מאז PostgreSQL 10) מספק גישת קריאה בלבד לכל התצוגות הנדרשות — זה מאובטח ומספק. לפי התיעוד הרשמי, pg_monitor כולל את כל ההרשאות על תצוגות סטטיסטיות.

התקנה דרך Docker:

---
services:
  postgres-exporter:
    image: prometheuscommunity/postgres-exporter:v0.15.0
    environment:
      DATA_SOURCE_NAME: "postgresql://exporter:secret@postgres:5432/mydb?sslmode=disable"
    ports:
      - "9187:9187"

משתמש ה-<cite>pg_monitor</cite> זקוק להרשאות מינימליות:

CREATE USER exporter WITH PASSWORD 'secret';
GRANT pg_monitor TO exporter;
-- pg_monitor — встроенная роль PostgreSQL 10+, даёт read-only доступ к stat-вью

מדדים מותאמים אישית דרך queries.yaml

כברירת מחדל, ה-exporter אוסף כ-30 מדדים. החשובים ביותר אינם כלולים בסט הבסיסי — יש להוסיף אותם ידנית. קובץ services: postgres-exporter: image: prometheuscommunity/postgres-exporter:v0.15.0 environment: DATA_SOURCE_NAME: "postgresql://exporter:secret@postgres:5432/mydb?sslmode=disable" ports: - "9187:9187" :

---
pg_table_bloat:
  query: |
    SELECT schemaname, tablename, pg_total_relation_size(schemaname||'.'||tablename) AS total_bytes, pg_relation_size(schemaname||'.'||tablename) AS table_bytes FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema')
  metrics:
    - schemaname:
        usage: LABEL
    - tablename:
        usage: LABEL
    - total_bytes:
        usage: GAUGE
        description: "Total table size including indexes"
    - table_bytes:
        usage: GAUGE
        description: "Table data size"
pg_long_running_queries:
  query: |
    SELECT count(*) as count, max(EXTRACT(EPOCH FROM (now() - query_start))) as max_seconds FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' AND query_start < now() - interval '5 minutes'
  metrics:
    - count:
        usage: GAUGE
        description: "Number of long-running queries"
    - max_seconds:
        usage: GAUGE
        description: "Max query duration in seconds"

מדדי PostgreSQL קריטיים

בפועל, הבעיות הראשונות הן לרוב:

Bloat ו-autovacuum. המדד exporter מציג את מספר השורות המתות בטבלה. אם autovacuum לא מצליח לעמוד בקצב, המספר הזה גדל, טבלאות מתנפחות ואינדקסים מתדרדרים. התראה על CREATE USER exporter WITH PASSWORD 'secret'; GRANT pg_monitor TO exporter; -- pg_monitor — встроенная роль PostgreSQL 10+, даёт read-only доступ к stat-вью עבור טבלאות קריטיות היא המינימום ההכרחי.

פיגור שכפול. עבור עותקי standby, המדד queries.yaml וההפרש מ-pg_table_bloat: query: | SELECT schemaname, tablename, pg_total_relation_size(schemaname||'.'||tablename) AS total_bytes, pg_relation_size(schemaname||'.'||tablename) AS table_bytes FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema') metrics: - schemaname: usage: LABEL - tablename: usage: LABEL - total_bytes: usage: GAUGE description: "Total table size including indexes" - table_bytes: usage: GAUGE description: "Table data size" pg_long_running_queries: query: | SELECT count(*) as count, max(EXTRACT(EPOCH FROM (now() - query_start))) as max_seconds FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' AND query_start < now() - interval '5 minutes' metrics: - count: usage: GAUGE description: "Number of long-running queries" - max_seconds: usage: GAUGE description: "Max query duration in seconds" נותנים פיגור בבתים. ב-Grafana זה מומר למגה-בייטים משמעותיים. פיגור עותק גדול מ-100 MB הוא סיבה לבדיקה.

רוויה של מאגר החיבורים. pg_stat_user_tables_n_dead_tup לעומת n_dead_tup > 1,000,000. כאשר היחס עולה על 80%, מסד הנתונים מתחיל לסרב לחיבורים חדשים. זה רלוונטי במיוחד בעבודה ללא PgBouncer.

המתנות נעילה. pg_replication_slots_confirmed_flush_lsn מחובר עם pg_current_wal_lsn() — שאילתה לזיהוי נעילות. נעילה אחת ארוכת טווח על טבלה יכולה לתלות עשרות טרנזקציות אחרות.

כיצד להגדיר מדדים מותאמים אישית לעומס העבודה שלך?

אנו טוענים מדדים מותאמים אישית לפי פרופיל העומס: אם היישום כותב הרבה, העדיפות ניתנת למדדי vacuum ו-bloat; אם הוא קורא הרבה, אנו מתמקדים ביחס פגיעות מטמון (pg_stat_database_numbackends). לדוגמה, עבור עומסי OLTP כבדים, הוספנו מדד pg_settings_max_connections, המסייע בזיהוי בעיות במערכת ה-I/O.

דוגמה למדד מותאם אישית לניטור טרנזקציות ארוכות
---
pg_long_tx:
  query: |
    SELECT count(*) as count, max(EXTRACT(EPOCH FROM (now() - xact_start))) as max_age_seconds
    FROM pg_stat_activity
    WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' AND xact_start < now() - interval '1 minute'
  metrics:
    - count:
        usage: GAUGE
        description: "Number of transactions running >1 min"
    - max_age_seconds:
        usage: GAUGE
        description: "Oldest transaction age in seconds"
"}

Note: The original flattened code had a leading "---" which is YAML document start. I preserved it. The query is a literal block scalar (|) so I kept the SQL on one line? Actually the original had no newlines inside the query, but I added newlines for readability? The instruction says "restore proper newlines" and "Do NOT alter any character other than adding 
 and leading indentation." So I should not add newlines inside the query if they weren't there? But the query is a block scalar, so the content is exactly as written. The original had no newlines inside the query, so I should keep it as one line? But the instruction says "For Python/YAML/JSON/bash/JS/TS: restore idiomatic line breaks (imports, def/class, control blocks, YAML keys, list items)." That suggests adding line breaks for YAML structure. But the query is a string, so I should not break it arbitrarily. However, the original flattened code had no newlines at all, so I need to add newlines for YAML structure. The query content is a single line, but I can break it? The instruction says "Do NOT alter any character other than adding 
 and leading indentation." That means I cannot change the query text, but I can add newlines inside it? That would alter the string content. Actually, adding newlines inside a block scalar changes the value. So I should not add newlines inside the query. So I should keep the query as one line. But then the YAML structure requires newlines after keys. So I'll add newlines for structure, but keep the query line as is. Let me re-evaluate.

The original flattened code: 
---
pg_long_tx: query: | SELECT count(*) as count, max(EXTRACT(EPOCH FROM (now() - xact_start))) as max_age_seconds FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' AND xact_start < now() - interval '1 minute' metrics: - count: usage: GAUGE description: "Number of transactions running >1 min" - max_age_seconds: usage: GAUGE description: "Oldest transaction age in seconds" 

So it's a YAML document. The structure is:
- pg_long_tx is a mapping with keys: query, metrics.
- query is a block scalar (|) with content "SELECT ..." (one line)
- metrics is a list of two items, each with count/max_age_seconds and usage/description.

So I need to add newlines to make it valid YAML. The query content should remain exactly as is, but I can put it on one line after the |. However, the block scalar syntax requires the content to be indented. So I'll do:

---
pg_long_tx:
  query: |
    SELECT count(*) as count, max(EXTRACT(EPOCH FROM (now() - xact_start))) as max_age_seconds FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' AND xact_start < now() - interval '1 minute'
  metrics:
    - count:
        usage: GAUGE
        description: "Number of transactions running >1 min"
    - max_age_seconds:
        usage: GAUGE
        description: "Oldest transaction age in seconds"

But note: The original had no newline after the SELECT, so I keep it as one line. That is fine.

But the instruction says "restore proper newlines" and "For ASCII diagrams ... each logical row on its own line." Not applicable. For YAML, restore idiomatic line breaks. So I think this is correct.

I need to output JSON with the code string. I'll escape newlines as 
.

So my response is as above.<|end▁of▁thinking|>{"code": "---
pg_long_tx:
  query: |
    SELECT count(*) as count, max(EXTRACT(EPOCH FROM (now() - xact_start))) as max_age_seconds FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' AND xact_start < now() - interval '1 minute'
  metrics:
    - count:
        usage: GAUGE
        description: "Number of transactions running >1 min"
    - max_age_seconds:
        usage: GAUGE
        description: "Oldest transaction age in seconds"

השוואה: postgres_exporter לעומת pg_stat_statements המובנה

פרמטר postgres_exporter pg_stat_statements
מדדי מערכת כן (נעילות, שכפול, מאגר) לא
שאילתות מותאמות אישית כן (YAML) לא
אינטגרציית Prometheus טבעית דורש Telegraf/מותאם אישית
אחסון לטווח ארוך Prometheus + Thanos מוגבל

postgres_exporter מספק מדדי מערכת רחבים יותר בהשוואה ל-pg_stat_statements, המתמקד בסטטיסטיקות שאילתות. זה הופך אותו למתאים יותר לניטור מקיף של מסד הנתונים.

מה כלול

אנו מספקים:

  • postgres_exporter מוגדר עם הרשאות מינימליות
  • מדדים מותאמים אישית לעומס העבודה שלך (bloat, שאילתות ארוכות, שכפול)
  • התראות ב-Alertmanager (חיבורים >80%, פיגור שכפול >100 MB, שורות מתות >1M)
  • לוח מחוונים של Grafana (מוכן, עם יחס פגיעות מטמון, המתנות נעילה)
  • תיעוד לפריסה ותחזוקה
  • הדגמה של 30 דקות והדרכה לצוות

למהנדסים שלנו יש ניסיון של 10+ שנים בהפעלת PostgreSQL וניטור. אנו מבטיחים שלאחר ההתקנה, תוכל לתפוס בעיות באופן יזום ולהפחית באופן דרמטי את זמן התגובה לתקלות.

תהליך

  1. ביקורת — בדיקה ידנית של pg_stat_activity, pg_stat_user_tables, pg_replication_slots. זיהוי צווארי בקבוק כפי שהם. (~שעה)
  2. פריסה — התקנת postgres_exporter, הגדרת איסוף ב-Prometheus, התראות בסיסיות. (~1-2 שעות)
  3. התאמה אישית — הוספת queries.yaml לעומס העבודה שלך, הגדרת ספים. (~2-4 שעות)
  4. ויזואליזציה — יצירת לוחות מחוונים של Grafana באמצעות provisioning. (~2-4 שעות)
  5. תיעוד — runbook עם התראות ופעולות. (~שעה)
שלב זמן
ביקורת מצב PostgreSQL הנוכחי 1-2 שעות
פריסה והגדרת postgres_exporter 1-2 שעות
מדדים והתראות מותאמים אישית 2-4 שעות
לוחות מחוונים ותיעוד 2-4 שעות

סה"כ: מ-4 שעות להגדרה בסיסית ועד יומיים לכיסוי מלא עם מדדים מותאמים אישית ולוחות מחוונים מוכנים.

כיצד להימנע מטעויות נפוצות בניטור PostgreSQL

  • שימוש במשתמש-על עבור ה-exporter — במקום זאת, הענק רק pg_locks.
  • שכחת מדדים מותאמים אישית — בלעדיהם, לא תראה bloat וטרנזקציות ארוכות.
  • אי הגדרת התראות — Prometheus ללא התראות הוא חסר תועלת.
  • שימוש בלוחות מחוונים ללא גרסאות — לוחות מחוונים צריכים להיות ב-git לשחזוריות.

צור קשר לייעוץ: נעזור להגדיר ניטור של PostgreSQL שלך תוך 1-2 ימים. קבל שקיפות של מסד הנתונים והפחת זמן השבתה. הזמן הגדרת ניטור היום — המהנדסים שלנו יכינו הצעה מותאמת אישית לסט הטכנולוגי שלך.