שיפור ביצועים של אלפי inserts בשניה בMYSQL
-
היום היה לי עומסים גדולים יחסית על המסד נתונים
עם 1100 משתמשים בו זמנית (כולם מבצעים insert בתוך כמה שניות)
וזה גרם לאיטיות בשאילתות (לפחות בSELECT, לא יודע כמה דיליי היה בinsert).בדקתי בהיסטוריה בפאנל ניהול שלי (הכל מופיע בממוצע של 5 דקות)
מופיע לי שהיה 234% שימוש במעבד (מתוך 6 ליבות)
49.57 (ops/sec (write
load 22.28
יש משהו שיכול לשפר את הבקשות?
האם יעזור להוסיף מעבדים?עכשיו מצאתי שיש לי לוג מיחוד לMYSQL
הוא כותב שהיה ממוצע של .15.07 insert בשניה ו11.01 SELECT שניה
וממוצע של Slow Queries 0.37
כל זה בממצוע של חמש דקות בפועל אני יודע שכל הבקשות נעשות בחלון זמן הרבה יותר קטן.מצאתי ריפו קטן שמאחד את כל הinsert ל batch-insert אחד גדול.
האם זה ישפר את הביצועים? האם זה גישה נכונה?נ.ב. לבנתיים זה משהו שאפשר לחיות איתו
אני פשוט חושש מה יקרה אם יהיה יותר עומסים
ואז זה יהיה מציק הרבה יותר. -
אני חושב שיש פרמטר בתפוסה של המעבד בהקשר של המתנה לקריאות/כתיבות לדיסק.. (נראלי ראיתי פעם בnetdata)
40M/s בהקשר הזה לא מוכיח כלום כי זה פעולות מאוד קטנות, מה שאומר שהI/Ops גבוה מאוד בכל מקרה.
(בhtop אפשר להוסיף עמודות עם הנתונים האלה. אולי זה יעזור.)בכל מקרה, לפני שאתה רץ לשדרג שרת, הייתי חושב שוב איפה הצווארי בקבוק.
יתכן שכדאי להפריד את הנתונים של mysql אל דיסק נפרד.
(או שבכלל הmysql על שרת אחר?) -
@aaron
הmysql נמצא על אותו שרת של האפליקציה (שרת TCP +שרת HTTP במקרה הזה)
אבל האפליקציה לא תופסת כמעט משאבים.
כך שהעברה לשרת נפרד לא כל כך תועיל.על פניו נראה שהצוואר בקבוק הוא פשוט מאות או אלפי inserts בשניה
אולי יש הגדרה מיוחדת בmysql שתשפר את הביצועים?
או לקבץ את כל השאילתות לבקשה אחת גדולה?
או שפשוט לשדרג שרת?
אני יחכה לערב לשדרוג(זה אמנם לוקח דקה וחצי, אבל צריך להפעיל מחדש את השרת)
ומחר אני יראה האם יש שיפור. -
אולי זה יעזור?
זה המבנה של הטבלהCREATE TABLE `answers` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `room` INT(11) NULL DEFAULT NULL, `questionId` INT(11) NULL DEFAULT NULL, `answerId` INT(11) NULL DEFAULT NULL, `answerText` TEXT NULL DEFAULT NULL, PRIMARY KEY (`id`));
הסטטוס של הטבלה
mysql> show table status WHERE Name = 'answers'; +---------+--------+---------+------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+ | Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment | +---------+--------+---------+------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+ | answers | InnoDB | 10 | Compact | 45984 | 99 | 4554752 | 0 | 0 | 4194304 | 96598 | 2020-04-26 06:17:37 | NULL | NULL | utf8mb4_unicode_ci | NULL | | | +---------+--------+---------+------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+
-
עכשיו שמתי לב שטעיתי
מדובר בטבלה אחרתCREATE TABLE `points` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `room` INT(11) NULL DEFAULT NULL, `user` VARCHAR(20) NULL DEFAULT NULL, `questionId` INT(11) NULL DEFAULT NULL, `points` INT(11) NULL DEFAULT NULL, `time` INT(64) NULL DEFAULT NULL, `grup` VARCHAR(64) NULL DEFAULT NULL, `answerId` INT(11) NULL DEFAULT NULL, PRIMARY KEY (`id`)"
הסטטוס שלה הוא
mysql> show table status WHERE Name = 'points'; +--------+--------+---------+------------+--------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+ | Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment | +--------+--------+---------+------------+--------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+ | points | InnoDB | 10 | Compact | 553311 | 82 | 45678592 | 0 | 0 | 4194304 | 1599099 | 2020-08-11 21:53:07 | NULL | NULL | utf8mb4_unicode_ci | NULL | | | +--------+--------+---------+------------+--------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+
והשאילתא נראת כך
INSERT INTO `points` (`room`,`user`,`questionId`,`points`,`time`,`grup`,`answerId`) VALUES (?,?,?,?,?,?,? )", room, user, questionId, points, time, grup, answerId
קצת יותר גדול
אבל לא נראה לי שאמור להפריע כל כך -
@nigun אני גם לא חושב שזה אמור כל כך להפריע, אבל לפי התאור הראשוני גם מבוצעות שאילתות SELECT ו-INSERT בו זמנית על טבלה זו, ועם חצי מליון שורות אני חושב שכדאי מאוד היה לנרמל את הנתונים עוד יותר, למשל
- כדאי להפוך את כל השדות של ה-VARCHAR ל-INT.
user => UserId
grup => groupId
וליצור טבלאות עבור Groups ו- Users. - לחשוב טוב האם כל השדות האלו הכרחיים לשמירה עבור כל תשובה?
- אם time הוא רק חותמת זמן, הייתי משאיר זאת לבסיס הנתונים לקבוע ערך ברירת מחדל עבור השדה (=לזמן הנוכחי) ומסיר אותו מה-INSERT.
- כמה שתקטין יותר את הטבלה המהירות תהיה כנראה טובה יותר. יש לך 4 גורמים שאחראים על המהירות הכללית: מעבד, זיכרון, דיסק ורשת. תבדוק את כולם. אם למשל כל הנתונים לא נטענים לזיכרון בבת אחת, הDB יבצע קאשינג והמהירות תרד פלאים בשעות העומס...
- אני נזכר שכבר היתה לך איזו בעיה כזו בעבר, וה Execution Plan של ה-DB לא היתה אופטימלית. לפי זכרוני השתמשת בגירסא מיושנת של MySQL, ואולי כדאי לבצע שדרוג.
- כדאי להפוך את כל השדות של ה-VARCHAR ל-INT.
-
עכשיו היה לי כ650 משתמשים על המערכת
וזה אולי נותן קצת יותר תמונה (נראה לי שהנתונים של DO יותר מדוייקים)
כפי שרואים בתמונה אין כל כל הרבה inserts בו זמנית, אלא fetchs
מה זה fetch? ולמה יש לי כל כך הרבה בשניה?
עריכה: אני מבין שזה כתוב השורות במסד נתונים מדפיס בSELECT
אז כנראה שזה לא בעיה.
בכל אופן נראה שהמסד נתונים של DO מתמודד עם זה יפה (הCPU ממש נמוך)
אולי בגלל שהוא משתמש בגירסה 8.0?