...

Obsługa limitu czasu połączenia MySQL w hostingu: porady i rozwiązania

Timeouty MySQL na hostingu często występują właśnie wtedy, gdy zapytania czekają lub połączenia pozostają otwarte zbyt długo. Pokażę ci, jak rozpoznać przyczyny, ustawić timeouty w ukierunkowany sposób, a tym samym Awarie oraz Komunikaty o błędach zmniejszyć.

Punkty centralne

  • PrzyczynyNieaktywne połączenia, powolne zapytania, opóźnienia
  • DiagnozaDziennik powolnych zapytań, EXPLAIN, dzienniki
  • Ustawieniawait_timeout, connect_timeout, Pool
  • Optymalizacjaindeksy, złączenia, max_execution_time
  • HostingLimity połączeń, ochrona DoS

Dlaczego limity czasu połączenia MySQL występują na hostingu

W środowiskach hostingowych wiele aplikacji działa równolegle, współdzieląc zasoby, a tym samym generując Czas oczekiwania oraz Obciążenie szczytowe. Limity czasu pojawiają się, gdy połączenie pozostaje nieaktywne zbyt długo lub zapytanie przekroczy limit; zmienne wait_timeout (dla klientów nieinteraktywnych) i interactive_timeout (dla połączeń konsolowych) są tutaj szczególnie skuteczne. Connect_timeout liczy się dla nawiązania połączenia, podczas gdy net_read_timeout i net_write_timeout są istotne dla procesów odczytu i zapisu. Pojedyncze powolne żądanie bez odpowiedniego indeksu może zająć minuty i zapchać pulę połączeń, blokując dalsze żądania. Wysokie opóźnienia sieciowe lub duża odległość między serwerem aplikacji a bazą danych zaostrzają problem, dlatego zawsze oceniam timeouty wraz z jakością zapytań i ścieżką sieciową.

Poprawnie klasyfikuj komunikaty o błędach

Najpierw rozróżniam „Connection timed out“ (nieudana konfiguracja) i „Command timeout“ (komenda działa zbyt długo), ponieważ oba są różne. Przyczyny oraz Rozwiązania mieć. Komunikaty takie jak „Serwer MySQL zniknął“ często wskazują na przerwane połączenia, zbyt małe pakiety (max_allowed_packet) lub trudny restart. Rozpoznaję wzorce w dziennikach: jeśli timeouty kumulują się w godzinach szczytu, jest bardziej prawdopodobne, że jest to spowodowane obciążeniem lub brakiem poolingu; jeśli występują natychmiast, sprawdzam sieć, DNS lub zapory ogniowe. Aby uzyskać ustrukturyzowane głębokie nurkowanie, używam dziennika powolnych zapytań i patrzę na krytyczne instrukcje za pomocą EXPLAIN. Podsumowuję tutaj kompaktowy przegląd przyczyn i ograniczeń: Przyczyny i limity serwera.

Ustawianie zmiennych systemowych

Najpierw dostosowuję limity czasu w sesji i sprawdzam zachowanie przed uruchomieniem globalnych limitów czasu. Ustawienia domyślne oraz Pliki zmiana. Na przykład, ustawiam sesję opartą na. SET SESSION wait_timeout = 3600;, globalny na SET GLOBAL wait_timeout = 3600;, gdzie globalne zmiany są tracone po restarcie. Wprowadzam stałe wartości w my.cnf/my.ini, na przykład pod [mysqld] z wait_timeout, interactive_timeout, connect_timeout, net_read_timeout i net_write_timeout. Następnie ponownie uruchamiam usługę i mierzę, czy wskaźniki błędów i czasy odpowiedzi uległy poprawie. Unikam bardzo wysokich limitów czasu, ponieważ otwarte bezczynne połączenia wiążą zasoby i mogą później wywołać reakcje łańcuchowe.

Diagnoza: Dzienniki, powolne zapytania i czasy wykonywania

Na potrzeby analizy aktywuję dziennik powolnych zapytań (slow_query_log = 1) i sprawdzić, które stwierdzenia regularnie przekraczają próg, ponieważ często jest to miejsce, w którym prawdziwe Hamulce oraz Zamki. Używam EXPLAIN, aby zidentyfikować brakujące indeksy, niekorzystne sekwencje łączenia lub używanie plików tymczasowych, co wskazuje na potrzebę optymalizacji. W godzinach szczytu sprawdzam za pomocą SHOW PROCESSLIST, czy połączenia oczekują na siebie nawzajem oraz z SHOW VARIABLES LIKE '%timeout%', czy ustawienia sesji są inne niż oczekiwane. W PHP patrzę na max_execution_time; Jeśli wartość jest zbyt mała, skrypt kończy działanie, mimo że baza danych nadal wykonuje obliczenia. Aby uzyskać miarodajne porównanie, uruchamiam te same zapytania lokalnie na kopii i sprawdzam, czy buforowanie, mniejsze ilości danych lub inne bufory zniekształcają obraz.

Wyraźne rozgraniczenie limitów czasu serwera WWW, serwera proxy i klienta

Ściśle oddzielam limity czasu MySQL od limitów web/proxy i klienta, aby nie zostały one przekręcone w niewłaściwym miejscu. Na przykład w Nginx. proxy_read_timeout, fastcgi_read_timeout oraz keepalive_timeout czas oczekiwania na upstream; w Apache Limit czasu oraz ProxyTimeout Istotne. PHP-FPM kończy żądania poprzez request_terminate_timeout, nawet jeśli MySQL nadal oblicza. Wpływ HAProxy timeout klienta, timeout serwera oraz limit czasu tunelu długie połączenia. Po stronie klienta wyraźnie ustawiam limity czasowe, aby nie były one dziedziczone niejawnie:

// PHP PDO
$pdo = new PDO($dsn, $user, $pass, [
  PDO::ATTR_TIMEOUT => 5, // sekund na nawiązanie połączenia
  PDO::ATTR_PERSISTENT => false
]);

// mysqli
$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5); // connect_timeout
$mysqli->options(MYSQLI_OPT_READ_TIMEOUT, 10); // net_read_timeout (po stronie klienta)
$mysqli->real_connect($host, $user, $pass, $db);

// Node.js (mysql2)
const pool = createPool({
  host, użytkownik, hasło, baza danych,
  connectionLimit: 20, waitForConnections: true, queueLimit: 100,
  connectTimeout: 7000, acquireTimeout: 10000, enableKeepAlive: true
});

Ważne: Suma czasu serwera WWW, aplikacji i DB nie może skutkować „kanapką“, w której zewnętrzna warstwa (np. Nginx) kończy się wcześniej niż warstwy wewnętrzne (aplikacja / DB). Dostosowuję wartości tak, aby błędy mogły być wyraźnie przypisane.

Ukierunkowane wykorzystanie schematu wydajności i schematu systemu

Schemat wydajności i schemat systemu zapewniają mi powtarzalny wgląd poza powolnym dziennikiem zapytań. Aktywuję odpowiednie instrumenty i analizuję hotspoty za pomocą skrótu:

-- Najlepsze instrukcje według 95. percentyla
SELECT * FROM sys.statements_with_runtimes_in_95th_percentile
ORDER BY avg_timer_wait DESC LIMIT 20;

-- Aktywne zdarzenia oczekiwania (blokady, wejścia/wyjścia, muteksy)
SELECT EVENT_NAME, SUM_TIMER_WAIT, COUNT_STAR
FROM performance_schema.events_waits_summary_global_by_event_name
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;

-- Bieżące „wiszące“ instrukcje
SELECT THREAD_ID, DIGEST_TEXT, TIMER_WAIT, CURRENT_SCHEMA
FROM performance_schema.events_statements_current
WHERE TIMER_WAIT IS NOT NULL;

Pozwala mi to rozpoznać, czy timeouty są bardziej prawdopodobne z powodu czasu oczekiwania I/O, łańcuchów blokad lub planów intensywnie wykorzystujących procesor. Sprawdzam również sys.user_summary oraz sys.host_summary, aby zawęzić rozpoznawalne wartości odstające według konta/hosta. Zapobiega to symptomatycznemu „wydłużaniu“ timeoutów, nawet jeśli blokady lub I/O są w rzeczywistości wąskim gardłem.

Optymalne wartości limitu czasu według scenariusza

Dostosowuję limity czasu do zamierzonego zastosowania, ponieważ interaktywność, czasy wykonywania zadań i Opóźnienie oraz ilość danych znacznie się różnią. Aplikacje internetowe z wieloma krótkimi żądaniami korzystają z mniejszych limitów czasu bezczynności, dzięki czemu pula jest czyszczona, a nowi użytkownicy natychmiast otrzymują połączenia. Przetwarzanie danych z godzinnymi raportami wymaga bardziej hojnych limitów, w przeciwnym razie ważne zadania kończą się limitami czasu. W przypadku dużych opóźnień umiarkowanie zwiększam connect_timeout, aby czasy konfiguracji połączenia nie pojawiały się fałszywie jako błędy. Poniższa tabela zapewnia stabilne wartości początkowe, które następnie dostrajam przy użyciu rzeczywistych zmierzonych wartości.

Ustawienie Aplikacje internetowe o dużym natężeniu ruchu Przetwarzanie danych Wskazówka
wait_timeout 60–300 s 3600-7200 s Krótszy dla wielu użytkowników, dłuższy dla zadań wsadowych
interactive_timeout 1800 s 7200 s Dla CLI/konsoli, rzadko krytyczne dla sieci
connect_timeout 5-10 s 10-20 s Umiarkowany wzrost przy dużych opóźnieniach
innodb_lock_wait_timeout 10-30 s 50-120 s W zależności od czasu trwania transakcji

Pula połączeń i czasy bezczynności

Prawidłowo skonfigurowana pula zapobiega bezczynności połączeń i zapewnia szybsze przekazywanie żądań do wolnego połączenia. Zasoby oraz Połączenie przyjść. Ustawiłem limit czasu bezczynności puli na około 10-15 % poniżej limitu czasu oczekiwania MySQL, aby sesje były zamykane w uporządkowany sposób przed wygaśnięciem. Pula ogranicza również jednoczesne połączenia, co zapobiega przepełnieniom na serwerach współdzielonych. W przypadku WordPressa, Nextcloud i podobnych narzędzi monitoruję brak aktywności po fazach logowania i konfiguruję połączenia w puli, aby nie umierały zbyt wcześnie. Więcej informacji i praktycznych przykładów podsumowałem tutaj: Pula połączeń w hostingu.

Blokady, impasy i transakcje powinny być krótkie i zwięzłe.

Wiele timeoutów jest spowodowanych długimi transakcjami i łańcuchami blokad. Utrzymuję małe transakcje, najpierw odczytuję dane bez blokad i otwieram tylko transakcję zapisu bezpośrednio przed aktualizacją/wstawieniem. W przypadku problemów z oczekiwaniem, sprawdzam innodb_lock_wait_timeout a przede wszystkim impasów:

-- Martwe punkty i status InnoDB
SHOW ENGINE INNODB STATUS\G

-- Wyświetl aktywne blokady (MySQL 8+)
SELECT * FROM performance_schema.data_locks\G
SELECT * FROM performance_schema.data_lock_waits\G

Unikam wzorców nieprzyjaznych dla autocommit (np. długich otwartych sesji z „zapomnianymi“ kursorami). Upewniam się, że wzorce izolacji i zapisu są zgodne (np. REPEATABLE READ vs. READ COMMITTED) i że procesy drugorzędne (raporty, eksporty) nie utrzymują niepotrzebnie długich blokad. Rozwiązuję impasy za pomocą logiki ponawiania prób w aplikacji, ale nigdy przez ślepe zwiększanie limitów czasu.

Szybsze wykonywanie zapytań: Indeksy i sprzężenia

Najpierw przyspieszam zapytania za pomocą odpowiednich Wskaźniki i szczuplejszy Dołącza, zanim zwiększę limit czasu. W EXPLAIN oczekuję wykorzystania indeksu dla filtrów i sortowania; jeśli nie, dodaję klucz specjalnie lub zmieniam warunek. W przypadku dużych tabel nie przechowuję szerokich pól TEXT/BLOB w tej samej ścieżce dostępu, jeśli są one nieistotne dla zapytania. Sprawdzam również, czy LEFT JOIN jest naprawdę konieczne lub czy INNER JOIN jest wystarczające, ponieważ zmniejsza to zestaw wyników. Te kroki zauważalnie skracają czas działania, a pula pozostaje dostępna.

Tuning PHP, Node i WordPress w praktyce

W PHP, dla długich raportów zwiększam max_execution_time umiarkowanie i zapobiegać anulowaniom, które wyglądają jak błędy bazy danych, ale są spowodowane przez skrypt. kłamstwo. Tam, gdzie to możliwe, aktywuję automatyczne ponowne połączenia w sterowniku lub obsługuję błędy, aby nowa próba połączenia rozpoczęła się czysto. W Node.js utrzymuję keep-alive, rozmiary puli i czasy bezczynności w oparciu o rzeczywiste pomiary opóźnień i przepustowości. W przypadku WordPressa zwracam uwagę na buforowanie, odchudzone wtyczki i zadania cron poza godzinami szczytu. Dzięki temu obciążenie MySQL jest niskie, a timeouty zdarzają się rzadko.

Monitorowanie ścieżki sieciowej, DNS i TLS

Sprawdzam całą ścieżkę między aplikacją a bazą danych: rozdzielczość DNS, routing, zapory ogniowe, NAT i uściski dłoni TLS. Jeśli to możliwe, używam stabilnych adresów IP lub wewnętrznych DNS z krótkimi, ale niezbyt agresywnymi TTL. Zapobieganie po stronie serwera skip_name_resolve kosztowne wyszukiwanie wsteczne (uwaga w środowiskach współdzielonych). W przypadku TLS zwracam uwagę na wznawianie sesji i utrzymuję niski narzut uzgadniania. TCP-Keepalive pomaga szybciej rozpoznawać martwe połączenia; na poziomie systemu operacyjnego keepalive_time oraz keepalive_intvl Aktywuję Keep-Alive w sterowniku w aplikacji. W konfiguracjach chmurowych uwzględniam limity czasu bezczynności NAT, aby połączenia w puli nie były „po cichu“ usuwane, podczas gdy aplikacja nadal uważa je za aktywne.

Limity i numery połączeń w hostingu

Hosting współdzielony często ogranicza jednoczesne połączenia, co oznacza, że pomimo krótkich czasów działania w Wskazówki lub Błąd run. Konfiguruję pulę aplikacji tak, aby przestrzegała tych górnych limitów i rozpoznawała przepełnienia na wczesnym etapie monitorowania. Jeśli liczba błędów 500 wzrasta, sprawdzam zależność między max_connections, rozmiarem puli i limitami czasu. Jeśli optymalizacja jest mało przydatna, rozmawiam z dostawcą o odpowiednich limitach lub rozważam większe plany (vServer, dedykowany DB). Kompaktowy przewodnik rozwiązywania problemów można znaleźć tutaj: Limity połączeń i błędy 500.

Realistycznie wybierz budżet zasobów i max_connections

Każde połączenie kosztuje pamięć RAM: bufory sortowania, łączenia i odczytu są używane przez każdy wątek. Dlatego planuję max_connections nie przez szczytowe żądanie, ale przez dostępną pamięć. Zbyt wiele jednoczesnych wątków generuje przełączanie kontekstu i presję we/wy, co zwykle zachęca do timeoutów. Trzymam thread_cache_size oraz table_open_cache aby zmiany połączeń i tabel nie były niepotrzebnie kosztowne. Duży max_allowed_packet-Ustawiam wysokie wartości tylko tam, gdzie wymaga tego eksport/upload - globalnie zbyt duże pakiety zużywają pamięć RAM i w połączeniu z wieloma połączeniami mogą powodować wąskie gardła.

Replikacja, przełączanie awaryjne i skalowanie odczytu

W konfiguracjach replikowanych sprawdzam, czy aplikacja reaguje odpowiednio w przypadku przełączenia awaryjnego lub opóźnienia repliki. Używam replik do odczytu dla obciążeń odczytu, ale zwracam uwagę na opóźnienia: zbyt małe net_read_timeout lub limit czasu aplikacji może interpretować długie odpowiedzi replikacji jako błędy. Wdrażam kontrole kondycji i backoff przy rozłączeniach zamiast agresywnego ponawiania. W przypadku podziału na odczyt/zapis upewniam się, że spójne transakcyjnie żądania odczytu nie trafiają błędnie do opóźnionych replik - w przeciwnym razie pojawiają się pozorne „przekroczenia limitu czasu“, które w rzeczywistości wynikają z oczekiwania na świeże dane.

Konserwacja, kopie zapasowe i DDL bez niespodzianek

Kopie zapasowe, DDL online i tworzenie indeksów mogą zwiększyć liczbę operacji we/wy i blokad. Planuję takie prace poza godzinami szczytu i używam algorytmów online tam, gdzie to możliwe. Podczas DDL sprawdzam innodb_lock_wait_timeout konserwatywnie, aby transakcje produkcyjne nie blokowały się na zawsze. Mierzę wykorzystanie we/wy podczas tworzenia kopii zapasowych; jeśli szybkość odczytu i przepustowość puli buforów kolidują ze sobą, czasy odpowiedzi i wskaźnik przekroczenia limitu czasu w dół wzrastają. Ponadto SPŁUKIWANIE TABEL Z BLOKADĄ ODCZYTU Używam go tylko selektywnie, ponieważ może blokować globalnie.

Monitorowanie kluczowych danych i wartości docelowych

Definiuję SLO i mierzę je konsekwentnie: opóźnienie p95/p99 najważniejszych zapytań, wskaźnik błędów według typu (connect vs. command timeout) i wykorzystanie. Ważne metryki obejmują. Threads_running (przytrzymaj krótko), Threads_connected (dostosowanie wielkości puli), Aborted_connects oraz Connection_errors_* (problemy z siecią/autoryzacją), oraz Handler_read_* (wykorzystanie indeksu). Stale wysoki odsetek „pełnych skanów tabel“ często koreluje ze szczytami timeoutów. Używam również skrótu do wyświetlania największych konsumentów w CPU, I / O i czasie oczekiwania, aby zastosować optymalizacje tam, gdzie naprawdę zmniejszają współczynnik limitu czasu.

Bezpieczne limity czasu a ryzyko DoS

Wyważam limity czasu między przyjaznością dla użytkownika a ochroną, tak aby żaden z nich nie był Nadużycie Jeszcze Przerwania przeważają. Przy dużych opóźnieniach sieci ostrożnie zwiększam connect_timeout, aby połączenia nie kończyły się zbyt wcześnie. W wrażliwych konfiguracjach obniżam tę samą wartość, aby ataki z długimi uściskami dłoni miały mniejszy wpływ. W przypadku przesyłania lub dużych zestawów wyników zwiększam max_allowed_packet, aby transfery nie zostały przerwane. Zawsze wdrażam te interwencje, monitorując poziom błędów i czasy odpowiedzi, dzięki czemu mogę natychmiast zobaczyć efekty i skutki uboczne.

Unikanie typowych błędów

Nigdy nie zwiększam timeoutów na ślepo, ponieważ otwierają się wydłużone okna oczekiwania Spotkania oraz Zamki akumulować. Zamiast tego najpierw naprawiam powolne zapytania, a następnie minimalnie dostosowuję wartości limitów. Oddzielam długie transakcje, ustawiam rozsądne punkty kontrolne i sprawdzam, czy innodb_lock_wait_timeout pasuje do wzorca zapisu. Jeśli wymagane są duże pakiety, zwiększam max_allowed_packet tylko w niezbędnym zakresie i realistycznie testuję ścieżki przesyłania, eksportu i importu. Dzięki ciągłemu monitorowaniu wcześnie rozpoznaję nawroty i utrzymuję niezawodność systemu.

Podsumowanie: Jak zapewnić niezawodność połączeń

Zaczynam od przejrzystej diagnostyki, oddzielam błędy połączenia od limitów czasu poleceń i sprawdzam Dzienniki oraz Zapytania w dzienniku powolnych zapytań. Następnie optymalizuję indeksy i złączenia, ustawiam czas bezczynności puli na nieco poniżej wait_timeout i ustawiam realistyczne limity czasu połączenia, odczytu i zapisu. Wybieram krótkie wartości idle dla ruchu sieciowego i dłuższe limity dla zadań wsadowych; testuję oba warianty pod obciążeniem. Harmonizuję limity PHP/węzłów i parametry MySQL, aby aplikacja i baza danych oddychały przez ten sam czas. Zmniejsza to liczbę błędów, zapytania pozostają szybkie, a limity czasu MySQL tracą swój horror.

Artykuły bieżące