重啟後Apache 2處理請求非常慢
我們有一個使用 NodeJS 的 GPS 設備套接字處理伺服器,它將接收到的 HTTPS 請求發送到 Apache 安裝的伺服器並將數據保存到 MySQL 數據庫中。當我們重新啟動 NodeJS 或 Apache 安裝的伺服器時,Apache 安裝的伺服器的請求處理速度變得非常慢。到目前為止,我們已經檢查了 MySQL 的性能及其正常工作。每秒只能從 NodeJS 伺服器觸發 5 到 15 個請求,在正常情況下它工作正常,但重啟後伺服器變得非常糟糕。幾個小時後,問題自動解決。請指導,如何解決此問題以及共享監視它所需的詳細資訊?
伺服器詳情:
Ubuntu server with 8GB RAM and 4 Cores processor.
MySQL 配置:
key_buffer_size = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 query_cache_limit = 1M query_cache_size = 16M max_binlog_size = 100M innodb_log_file_size=512M innodb_buffer_pool_size=6G innodb_buffer_pool_instances=6 innodb_flush_log_at_trx_commit=2 innodb_flush_method=O_DIRECT_NO_FSYNC innodb_log_files_in_group=5 innodb_open_files=1000 sync_binlog=0 max_connections=512 table_open_cache=1000 table_open_cache_instances=16 back_log=1000 query_cache_limit=2M query_cache_size=0 query_cache_type=0 sort_buffer_size=32M read_rnd_buffer_size=32M
頂級命令: 頂級程序列表,MySQL 使用 6.8GB
一段時間後,MySQL 自動重新啟動,伺服器再次變慢。
阿帕奇夥伴
[ -- ] Parent PID: 19547. [ OK ] Memory usage of parent PID is less than 50MB: 7268 Kilobytes. [ -- ] Apache has been running 0d 23h 19m 11s. [ !! ] *** LOW UPTIME ***. [ @@ ] The following recommendations may be misleading - apache has been restarted within the last 24 hours. [ -- ] Your server has 7976 MB of PHYSICAL memory. [ -- ] Your ServerLimit setting is 512. [ -- ] Your MaxRequestWorkers setting is 512. [ OK ] Current Apache Process Count is 45, including the parent PID. [ -- ] Number of vhosts detected: 5. [ -- ] |________ of which 3 are HTTP (specifically, port 80). [ -- ] |________ of which 2 are HTTPS (specifically, port 443). [ OK ] Current Apache vHost Count is less than maxrequestworkers. [ >> ] MaxRequestsPerChild directive not found. [ -- ] This server is NOT running Plesk. [ -- ] This server is NOT running cPanel. [ -- ] This server is NOT running Virtualmin. [ -- ] Your PHP Memory Limit (Per-Process) is 128M. [ -- ] MySQL Detected => Using 7038.63 MB of memory. [ OK ] No large log files were found in /var/log/apache2. [ OK ] MaxClients has not been hit recently. [ >> ] Apache only logs maxclients/maxrequestworkers hits once in a lifetime, if no restart has happened this event may have been rotated away. [ >> ] As a backup check, please compare number of running apache processes (minus 1 for parent) against maxclients/maxrequestworkers. [ OK ] No PHP Fatal Errors were found. [ -- ] apache2 is currently using 1308.65 MB of memory. [ -- ] The smallest apache process is using 9.73 MB of memory [ -- ] The average apache process is using 9.82 MB of memory [ -- ] The largest apache process is using 10.19 MB of memory [ !! ] Going by the average Apache process, Apache can potentially use 5027.85 MB RAM: Without considering services: 63.04 % of total installed RAM Considering extra services: 536.38 % of remaining RAM [ !! ] Going by the largest Apache process, Apache can potentially use 5217.28 MB RAM: Without considering services: 65.42 % of total installed RAM Considering extra services: 556.59 % of remaining RAM -------------------------------------------------------------------------------- ### GENERAL FINDINGS & RECOMMENDATIONS ### -------------------------------------------------------------------------------- Apache2buddy.pl report for server: Settings considered for this report: [ !! ] *** LOW UPTIME ***. [ @@ ] The following recommendations may be misleading - apache has been restarted within the last 24 hours. Your server's physical RAM: 7976 MB Remaining Memory after other services considered: 937 MB Apache's MaxRequestWorkers directive: 512 <--------- Current Setting Apache MPM Model: prefork Largest Apache process (by memory): 10 MB [ !! ] Your MaxRequestWorkers setting is too high. Your recommended MaxRequestWorkers setting (based on available memory) is between 81 and 91. <------- Acceptable Range (10% of MAX) Max potential memory usage: 5217 MB Percentage of TOTAL RAM allocated to Apache: 65.42 % Percentage of REMAINING RAM allocated to Apache: 556.59 % -------------------------------------------------------------------------------- A log file entry has been made in: /var/log/apache2buddy.log for future reference. Last 5 entries: 2019/12/19 07:37:28 Uptime: "0d 02h 26m 52s" Model: "Prefork" Memory: "7976 MB" MaxRequestWorkers: "512" Recommended: "352" Smallest: "9.81 MB" Avg: "10.28 MB" Largest: "12.35 MB" Highest Pct Remaining RAM: "145.16%" (79.28% TOTAL RAM) 2019/12/20 07:06:41 Uptime: "0d 23h 19m 11s" Model: "Prefork" Memory: "7976 MB" MaxRequestWorkers: "512" Recommended: "91" Smallest: "9.73 MB" Avg: "9.82 MB" Largest: "10.19 MB" Highest Pct Remaining RAM: "556.59%" (65.42% TOTAL RAM)
位置表:
CREATE TABLE `locations` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `device_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'Device Associated with Location', `driver_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'Driver associated with the Device', `packet_type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '1=Login\\n2=Heartbeat\\n3=Ping\\n4=Alarm', `latlng` point DEFAULT NULL COMMENT 'Longitude, Latitude', `lng` decimal(10,7) NOT NULL DEFAULT '0.0000000' COMMENT 'Longitude', `lat` decimal(10,7) NOT NULL DEFAULT '0.0000000' COMMENT 'Latitude', `device_time` datetime DEFAULT NULL, `server_time` datetime DEFAULT NULL, `imei` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `satellite` tinyint(3) unsigned NOT NULL DEFAULT '0', `speed` tinyint(3) unsigned NOT NULL DEFAULT '0', `acc` tinyint(3) unsigned NOT NULL DEFAULT '0', `heading` smallint(5) unsigned NOT NULL DEFAULT '0', `gsm_mcc` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Mobile Country Code', `gsm_mnc` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Mobile Network Code', `gsm_lac` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Location Area Code', `gsm_cid` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Cell Tower ID', `gsm_signal` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'GSM Signal Percentage', `battery_level` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Battery Level Percentage', `alarm_code` varchar(5) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Alarm Code sent by GPS Device', `raw_data` varchar(300) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `raw_json` varchar(3000) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '0=Not Active\\n1=Active\\n2=Deleted', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), KEY `locations_device_id_index` (`device_id`), KEY `locations_status_index` (`status`), KEY `locations_created_at_index` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
行程表
CREATE TABLE `trips` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `device_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'Device Associated with Trip', `last_location_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'Last Location associated with the Trip Date', `trip_date` date NOT NULL, `items` longtext COLLATE utf8mb4_unicode_ci COMMENT 'Trips with points', `points` longtext COLLATE utf8mb4_unicode_ci COMMENT 'Received points', `is_place` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT 'When enabled, Need to get places', `is_fetch` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT 'When enabled, Need to fetch points from locations table', `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '0=Not Active\\n1=Active\\n2=Deleted', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `trips_device_id_index` (`device_id`), KEY `trips_trip_date_index` (`trip_date`), KEY `trips_is_place_index` (`is_place`), KEY `trips_is_fetch_index` (`is_fetch`), KEY `trips_status_index` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
關鍵方案
**Lat/lng:**我們正計劃實施地理圍欄,所以認為我們需要點進行地理空間搜尋,所以保留了這個欄位。我們還沒有實現它,如果不需要,我們將刪除它。
**BIGINT:**設備將不斷增長。但目前只有400台設備。希望我們目前可以使用small int。
raw將刪除兩個欄位
updated_at我們從未使用過
created_at為我們在選擇時使用的目前日期生成行程
status我不知道複合索引我會嘗試實現它。
記憶體問題
降低到
innodb_buffer_pool_size=5G
。我懷疑系統記憶體不足,要麼崩潰,要麼使用 OOM 殺手搞得一團糟。
MySQL 為 88%——但 Apache 需要多少?作業系統?其他事情?不要讓它達到 100%。交換對於 MySQL 的性能來說是很糟糕的。
降低 Apache 的 MaxRequestWorkers。
關鍵方案
縮小磁碟佔用空間會有所幫助,因為此表中有大量流量。
Lat/lng:你需要
POINT
(25 個字節)和一對數字(每個 6 個字節)嗎?你需要這麼精確的數字嗎?見http://mysql.rjweb.org/doc.php/latlng#representation_choicesIMEI——不是 15 位數字嗎?當然不需要utf8mb4。varchar(20) 中的 15 位數字將佔用 17 個字節。在
DECIMAL(15)
中,需要 7。GSM: mcc, mnc, lac, cid 可以被規範化到另一個表中並且有一個 3 字節
MEDIUMINT UNSIGNED
的JOINing
.BIGINT – 每個 8 個字節。您希望擁有多少設備和驅動程序?
raw* – 你可能不使用這些?它們可以移動到不太方便的文件(例如),以節省表中的大量空間。(我假設您“永遠不會”查看文件。)
raw* – 如果您選擇將它們保留在表中,壓縮它們並使用
VARBINARY
會將空間縮小大約 3 倍。(在客戶端執行壓縮/解壓縮。)created_at, updated_at – 聽起來像是從未使用過的樣板文件。(每個 5 個字節)。
狀態——單獨索引低基數列很少有用。您有可能需要的查詢嗎?如果是這樣,也許複合(多列)索引會很有用。
我懷疑這些更改會將這張表縮小一半。
Buffer_pool 記憶體
插入的每一行都需要插入到每個索引中:
- PK——到數據的末尾(1個熱點)
- device_id – 每個設備 1 個熱點。有多少設備?
- 狀態——2?熱點
- 創建於 – 幾乎每一行都進入該索引的“末尾”。(1)
結論:對於插入,實際使用的緩衝池很少。16KB(塊大小)乘以 (D+4) 其中 D 是設備數。總計:幾兆?
你有什麼大的選擇嗎?這些可能會掃過桌子,迫使方塊來來去去。任何表掃描都可能導致一堆 I/O。所以,盡量避免表掃描。