בריאות ותפקוד

מה הליבה אוספת על בריאות השרת, איך אולג מושך את הנתונים דרך perf_runner, ומה נשאר בפאנל לצורך ניטור חי, קריאת error_log ולוג SQL

⏱ 8 דק' קריאה 1425 מילים ערוך דף זה ב-GitHub

ניתוח הבריאות והביצועים של האתר רץ היום מחוץ לליבה, אצל אולג AI המאוחסן (https://oleg.wizzo.market). בליבה נשאר מה שרק השרת של האתר יכול לעשות: לאסוף נתונים, למדוד תעבורה אמיתית, ולהריץ פעולה מוגנת אחת (בניית אינדקס). בדף הזה: מה נאסף ובאילו ספים, איך המנוע החיצוני קורא את זה, ומה הכלים החיים שנשארו בפאנל (server_load, error_log, sqllog).

מידע

חיבור האתר לאולג מנוהל ב-Wizzo Market. ללא מפתחות אולג באתר (PARAM oleg_ready), כל הפעולות של המנוע מחזירות unauthorized. ראו סקירת Wizzo Market ו-קטלוג השירותים.

SystemHealth: האוסף#

libraries/SystemHealth.php הוא collector בלבד: הוא לא שומר, לא מנתח ולא מציג. שתי מתודות ציבוריות עיקריות, ועוד עוזר אחד.

מתודהערך החזרההערה
SystemHealth::collect(): arrayרשימת ממצאים {source, severity, title, details, count, ref}severity הוא low, med או high. אוסף את כל המקורות שבטבלה למטה
SystemHealth::vitals_now(): array{load_per_core, cores, mem_used_pct, db_threads, db_max, db_conn_pct}מספרים גולמיים, ללא ספים. כל שדה null כשהמקור לא זמין, והקריאה לא זורקת חריגה
SystemHealth::time_ago(string $datetime): string"לפני שעתיים", "לפני יום" וכו'בעברית, עם צורות נקבה וזוגי תקינות
$findings = SystemHealth::collect();

foreach ($findings as $f)
{
    if ($f["severity"] === "high")
    {
        error_log($f["source"] . ": " . $f["title"]);
    }
}

מקורות הנתונים והספים#

sourceמה נבדקספים (med / high)
error_logשגיאות PHP מהשעה האחרונה. קורא את סוף הקובץ בחתיכות, מקבץ לפי חתימה ומזהה "הצפה" של חתימה אחתחזרה של 5 פעמים בשעה היא "חוזרת". הצפה: לפחות 50 רשומות, וחתימה אחת מעל 60% מהשעה
error_log_sizeגודל קובץ ה-error_log128MB / 1GB
heartbeatהאם ה-cron הראשי רץ (cron_runner_heartbeat ב-CRM_params)ישן מ-300 שניות
cron_logמשימות cron שנכשלו בשעה האחרונה (CRM_cron_logs, status='error')לפי כשלים
stuck_taskמשימות עם next_run שעבר לפני יותר מ-10 דקות (CRM_cron_tasks)לפי איחור
server_resourcesדיסק, inodes, load לליבה (ממוצע 15 דקות), זיכרון, swapדיסק 80% / 90% או פחות מ-1GB פנוי. inodes 85% / 95%. load 1.0 / 1.5 לליבה. זיכרון 92% / 97%. swap 80%
db_engineחיבורי DB מול max_connections, והתאמת ה-buffer poolחיבורים 70% / 85%. פגיעות buffer pool מתחת ל-95% / 85%
ssl_expiryתוקף תעודת ה-SSL של הדומיין של האתר21 / 7 ימים
disposable_spaceתיקיות זבל שגדלו (למשל .trash)1GB / 5GB. תקציב סריקה של 20 שניות בסך הכול, 8 לכל תיקייה

הספים הם קבועים בראש הקובץ (DISK_WARN_PCT, ERRLOG_WARN_BYTES ועוד), בכוונה שמרניים: התראה שחוזרת כל שעה ואף אחד לא פועל לפיה מלמדת מנהלים להתעלם מכל הדוח.

הערה
collect() קורא את ה-error_log מהסוף ועוצר בגבול השעה, ולא דרך ADMINMODULE_error_log::get_error(), כי זה האחרון טוען את הקובץ כולו לזיכרון וקורס בלוגים גדולים, וזה בדיוק המצב שהבדיקה אמורה לתפוס.

perf_runner: הדלת של אולג אל האתר#

system/perf_runner הוא controller של הליבה (נתיב system/ מנותב ישירות, בלי שורה ב-CRM_modules), מליבה 5.0.83 ומעלה. המנוע החיצוני קורא לו, והוא מעביר ל-OlegAgent (libraries/OlegAgent.php) את העבודה. הוא זהה בדפוסו ל-seo_runner (ראו חבילת ה-SEO).

אימות וגוף הבקשה#

  • פעולות המנוע דורשות Authorization: Bearer <api_key>:<secret_key> של שירות אולג, שנבדק ב-OlegHosted::request_ok() עם hash_equals. כשה-header נופל בדרך (אירוח cgi-fcgi), WIZZO_KEY::incoming() קורא גם את הערוצים החלופיים.
  • הגוף הוא JSON רגיל, או מעטפת gzip: {"z":"<base64 של gzip של ה-JSON>"}. המעטפת קיימת כי שתי פעולות נושאות SQL בגוף (deep_dive ו-apply_index) ו-WAF עלול לחסום אותן עוד לפני ש-PHP רואה אותן. כשהמעטפת בשימוש, התשובה כוללת "z": 1.
  • כל פעולה מתקבלת גם כ-?do=<action>, למקרה שהשרת מנתב system/<controller>/<action> ל-index() ומאבד את הסגמנט האחרון.
  • כל תשובה היא {"ok":true,...} או {"ok":false,"error":"..."}. לא מאומת: 401 unauthorized. פעולות האתר: 403 admin or engine only.

הפעולות#

פעולהגוף הבקשהמי רשאימה היא עושה
discoveryמנועמי האתר ומה הוא יודע לעשות
capture_startminutes (ברירת מחדל 5), max_bytesמנועפותחת חלון לכידת תעבורה אמיתית. הזרם הגולמי לא יוצא מהאתר
capture_statussession_idמנועמצב הלכידה
capture_collectsession_id, tuningמנועאוספת סיכום של הלכידה
capture_abortsession_idמנועמבטלת לכידה
deep_divetop_queriesמנועEXPLAIN וסכמה לשאילתות הכבדות
health_collectמנועאת התוצאה של SystemHealth::collect(), בלי מגבלת זמן
vitalsמנועמצב המכונה, hazards, ואם לכידה פעילה כרגע
apply_indexsql, runמנועבניית אינדקס מוגנת, ראו למטה
code_bundlelocs, tablesמנועקוד לקריאה בלבד סביב נקודות הקריאה שנלכדו
todo_meta, ticket, ticket_closesubject, details_html, project_id או id, comment_htmlמנועעבודה עם ה-TODO של האתר
exportמנועההיסטוריה המקומית, להעברה חד-פעמית
register, migrate, status, panel_tokenמנהל מחובר או מנועחיבור האתר למנוע, מעבר מההיסטוריה הישנה, מצב, ואסימון לפאנל המוטמע

apply_index: האינדקס היחיד שהמנוע בונה#

OlegAgent::apply_index($sql, $run = false) מקבל רק פקודת CREATE INDEX או ALTER TABLE ... ADD INDEX פשוטה; כל דבר אחר נדחה עם הודעה להריץ ידנית. זה תהליך בשני שלבים:

  1. run ריק: בדיקה בלבד. מוחזרים גודל הטבלה, מנוע האחסון, וסימון אם הבנייה אונליין (mode: "info").
  2. run מלא: ב-InnoDB נבנה ALGORITHM=INPLACE, LOCK=NONE. בטבלת MyISAM או Aria אין בנייה אונליין, ולכן היא מותרת רק לטבלה קטנה (עד 300,000 שורות ו-256MB). טבלה גדולה כזו נדחית עם פקודה להרצה ידנית בשעת שפל.

אם האינדקס כבר קיים, התשובה היא ok עם already: 1.

שימו לב
apply_index משנה את מבנה בסיס הנתונים של האתר. הוא נגיש רק למי שמחזיק במפתחות אולג של האתר. אל תתנו את המפתחות (api_key:secret_key) לשום צד שלישי. ראו מודל האבטחה.

צורת התשובות שנשארו בליבה#

בנוסף ל-perf_runner, שני controllers ישנים נשארו כ"מעטפת" ריקה בכוונה, כדי ששורות cron ישנות באתרים לא יתמלאו באדום:

כתובת cronמה היא עונה
system/system_health/runSKIP: הבדיקה השעתית עברה לאולג. אפשר למחוק את המשימה
system/perf_advisor/runSKIP: המדידה המתוזמנת עברה לאולג והתזמון נקבע שם. אפשר למחוק את המשימה

ראו Cron לניהול המשימות.

הכלים החיים בפאנל#

שלושה כלי ניטור נשארו בפאנל. כולם מופיעים תחת כלים למפתחים ב-{admin}.

server_load: עומסי השרת#

ADMINMODULE_server_load הוא דשבורד של משאבי השרת בזמן אמת, ומתרענן כל 2 שניות. {admin}/server_load/stats מחזיר JSON עם:

מפתחתוכן
loadload average ל-1, 5 ו-15 דקות, ביחס לליבות
cpuניצול רגעי (דגימה של /proc/stat שנמשכת כ-0.2 שניות)
mem, swap, diskזיכרון, swap ודיסק
uptime, hostnameזמן פעולה ושם המארח
phpגרסה, memory_limit, מצב opcache
dbחיבורים מול max_connections, buffer pool, שאילתות איטיות, QPS, המתנות על נעילות שורה

כל מדד נקרא בזהירות: במקום שאין /proc (Windows, אירוח מוגבל) הכרטיס מציג "לא זמין" ואינו שובר את העמוד.

פעולהמה היא עושה
index()הדשבורד
stats()JSON של המדדים הנוכחיים
queries()40 השורות האחרונות מ-sqllog.txt, הכי חדשה ראשונה, כל שאילתה מקוצרת ל-260 תווים
toggle_log()מדליק ומכבה את הפרמטר log_sql. דורש ADMIN::is_admin()

sqllog ולוג SQL#

כש-PARAMS log_sql הוא "1", DB::log_sql_to_file() כותבת כל שאילתה (עם url, date, source שהוא admin או site, ו-backtrace) כשורת JSON לקובץ sqllog.txt בשורש האתר. הקובץ מצמצם את עצמו: מעל 5MB נשמר רק השליש האחרון. הפאנל {admin}/sqllog מציג את הלוג בעמודים של 100 שורות, עם סינון filter_source=admin|site, ומאפשר להפעיל, לכבות ולרוקן.

אזהרה
sqllog.txt יושב בשורש האתר הציבורי ומכיל את כל השאילתות עם הערכים שלהן. הפעילו אותו רק לדיבוג קצר, כבו אותו מיד, ורוקנו את הקובץ. בנוסף, כל הפעלה מוסיפה backtrace לכל שאילתה, עלות אמיתית על כל בקשה. ראו דיבוג מסד נתונים.

error_log#

ADMINMODULE_error_log קורא את הקובץ שמוגדר ב-ini_get('error_log') (עד 10MB האחרונים), מקבץ לפי סוג, קובץ ושורה, ומציג stack traces מקופלים. סינון ומיון נעשים בפרמטרי GET: sort_by, sort_dir, filter_type, filter_text, filter_file, filter_from_date.

מתודהחתימההערה
index()העמוד. ?clear_log=1 מרוקן את הקובץ
get_errorget_error($sortBy = 'last_date', $sortDir = 'desc', $filterType = '', $filterText = '', $filterFile = '', $filterFromDate = '')מחזיר את הרשומות המקובצות. ציבורית, וקוד אחר משתמש בה
שימו לב
server_load ו-error_log מסומנים skip_permission_check = true, כלומר פתוחים לכל מנהל מחובר ולא רק למפתחים. מחיקת הלוג נעשית בבקשת GET בלי אסימון CSRF, והעמוד חושף נתיבי שרת ו-stack traces. כשאתם בונים פאנל חדש אל תעתיקו את הדפוס הזה. ראו הרשאות מנהלים.

ניקויים מתוזמנים#

שני controllers קטנים מנקים בלי מעורבות אדם, ומופעלים כמשימות cron בתיקיית "מערכת":

כתובתזמן מומלץמה היא עושהפלט
system/cache_cleanup/run?type=all|pages|items0 4 * * *cache_engine::cleanup_expired($type, false) מוחק קבצי מטמון שפגו (עם גרייס של 48 שעות, cache_engine::$gc_grace_hours)OK type=… deleted=N freed_mb=X
admin_session_cleanup/run0 3 * * *ADMIN::cleanup_expired_sessions() מוחק סשנים שפגו מ-CRM_adminPanel_sessions, ונסיונות כניסה כושלים בני יותר מ-24 שעות מ-CRM_adminPanel_admins_bad_attemptsOK sessions_cleaned=… attempts_cleaned=…
הערה

הספירה ב-admin_session_cleanup אינה אמינה: attempts_cleaned תמיד 0, ו-sessions_cleaned נקרא אחרי שאילתה אחרת. הניקוי עצמו עובד, אבל אל תסתמכו על המספרים בלוג.

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.