Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL-Fehler 1436:Thread-Stack-Überlauf, mit einfacher Abfrage

1436 - Thread-Stack-Überlauf:6136 Bytes von einem 131072-Byte-Stack verwendet und 128000 Bytes benötigt.

Der Fehler 1436 entspricht ER_STACK_OVERRUN_NEED_MORE im mysql 5.1-Code:

[email protected]:include> pwd
/home/malff/BZR_TREE/mysql-5.1/include
[email protected]:include> grep 1436 mysqld_error.h
#define ER_STACK_OVERRUN_NEED_MORE 1436

Der Code, der den angezeigten Fehler ausgibt, befindet sich in sql/sql_parse.cc, function check_stack_overrun() :

bool check_stack_overrun(THD *thd, long margin,
                         uchar *buf __attribute__((unused)))
{
  long stack_used;
  DBUG_ASSERT(thd == current_thd);
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) (my_thread_stack_size - margin))
  {
    char ebuff[MYSQL_ERRMSG_SIZE];
    my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
                stack_used, my_thread_stack_size, margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));

Aus den angezeigten Werten ergibt sich eine Margin von 128000 und eine my_thread_stack_size von 131072.

Der einzige Aufruf von check_stack_overrun(), der versucht, 128000 Bytes zu reservieren, kommt von:

bool
sp_head::execute(THD *thd)
{
  /* Use some extra margin for possible SP recursion and functions */
  if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
    DBUG_RETURN(TRUE);

Der Wert von STACK_MIN_SIZE ist 16000:

[email protected]:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
[email protected]:sql> grep STACK_MIN_SIZE *.h
mysql_priv.h:#define STACK_MIN_SIZE          16000   // Abort if less stack during eval.

Bisher funktioniert für den Server alles wie erwartet:

  • der Code führt einen Trigger aus, der mit sp_head::execute implementiert wird.
  • Die MySQL-Laufzeit prüft, ob sich mindestens 128000 Bytes auf dem Stack befinden
  • diese Prüfung schlägt fehl (zu Recht) und die Ausführung des Triggers endet mit einem Fehler.

Die von der Ausführung des MySQL-Triggers benötigte Stack-Menge hängt nicht von der Komplexität des Triggers selbst oder dem Inhalt/der Struktur der beteiligten Tabellen ab.

Was zum wahren Frage ist, denke ich, warum ist der thread_stack nur bei 128K (131072).

Die Servervariable mit dem Namen „thread_stack“ ist in C als „my_thread_stack_size“ in sql/mysqld.cc implementiert:

  {"thread_stack", OPT_THREAD_STACK,
   "The stack size for each thread.", &my_thread_stack_size,
   &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
   1024L*128L, ULONG_MAX, 0, 1024, 0},

1024L*128L ist der Mindestwert für diesen Parameter. Der Standardwert ist DEFAULT_THREAD_STACK, der in include/my_pthread.h:

definiert ist
#ifndef DEFAULT_THREAD_STACK
#if SIZEOF_CHARP > 4
/*
  MySQL can survive with 32K, but some glibc libraries require > 128K stack
  To resolve hostnames. Also recursive stored procedures needs stack.
*/
#define DEFAULT_THREAD_STACK    (256*1024L)
#else
#define DEFAULT_THREAD_STACK    (192*1024)
#endif
#endif

Daher sollte die Stapelgröße standardmäßig 192 KB (32-Bit-Architekturen) oder 256 KB (64-Bit-Architekturen) betragen.

Überprüfen Sie zuerst, wie die mysqld-Binärdatei kompiliert wurde, um zu sehen, was der Standardwert ist:

[email protected]:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
[email protected]:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack
...
  --thread_stack=#    The stack size for each thread.
thread_stack                      262144

Auf meinem System habe ich 256 KB auf einer 64-Bit-Plattform erhalten.

Wenn es unterschiedliche Werte gibt, baut vielleicht jemand den Server mit anderen Kompilierungsoptionen, wie z. B. -DDEFAULT_THREAD_STACK (oder hat einfach die Quelle geändert) ... Ich würde fragen, woher die Binärdatei in diesem Fall kommt.

Überprüfen Sie zweitens my.cnf auf Standardwerte, die in der Konfigurationsdatei selbst bereitgestellt werden. Eine Zeile, die explizit einen Wert auf thread_stack (und mit einem niedrigen Wert) setzt, würde definitiv den angezeigten Fehler verursachen.

Überprüfen Sie zuletzt die Server-Logdatei auf einen Fehler wie diesen (siehe sql/mysqld.cc) :

sql_print_warning("Asked for %lu thread stack, but got %ld",
                  my_thread_stack_size, (long) stack_size);

Der Servercode ruft auf:

  • pthread_attr_setstacksize() um die Stapelgröße festzulegen
  • pthread_attr_getstacksize(), um zu überprüfen, wie viel Stack ein Thread wirklich hat, und sich im Log beschwert, wenn die pthread-Bibliothek weniger verbraucht hat.

Um es kurz zu machen, der Fehler wird angezeigt, weil der thread_stack im Vergleich zu den Standardwerten, die mit dem Server geliefert werden, zu klein ist. Dies kann passieren:

  • bei benutzerdefinierten Builds des Servers mit unterschiedlichen Kompilierungsoptionen
  • beim Ändern des Standardwerts in der my.cnf-Datei
  • wenn in der pthread-Bibliothek selbst etwas schief gelaufen ist (theoretisch habe ich es beim Lesen des Codes selbst nie gesehen).

Ich hoffe, das beantwortet die Frage.

Grüße,-- Marc Alff

Update (2014-03-11), um die "Wie man es behebt" deutlicher zu machen.

Aller Wahrscheinlichkeit nach wurde der Standardwert für die thread_stack-Datei in der my.cnf-Datei geändert.

Wie man es behebt, ist dann trivial, finden Sie heraus, wo thread_stack in der Datei my.cnf gesetzt ist, und entfernen Sie entweder die Einstellung (vertrauen Sie dem Servercode, dass er einen anständigen Standardwert bereitstellt, damit dies beim nächsten Mal nicht wieder vorkommt) oder erhöhen Sie den Stack Größe.

Update (28.04.2021), prüfen Sie, woher der thread_stack kommt:

Verwenden Sie die Tabelle performance_schema.variables_info um herauszufinden, woher eine bestimmte Variable kommt.

mysql> select * from variables_info where VARIABLE_NAME = 'thread_stack';
+---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
| VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH | MIN_VALUE | MAX_VALUE            | SET_TIME | SET_USER | SET_HOST |
+---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
| thread_stack  | COMPILED        |               | 131072    | 18446744073709550592 | NULL     | NULL     | NULL     |
+---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
1 row in set (0.01 sec)

Hier ist der Standardwert der Werkswert (kompiliert in der mysqld-Binärdatei).

Ein weiteres Beispiel:

mysql> select * from variables_info where VARIABLE_NAME = 'thread_stack';
+---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
| VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH                                                  | MIN_VALUE | MAX_VALUE            | SET_TIME | SET_USER | SET_HOST |
+---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
| thread_stack  | EXPLICIT        | /home/malff/CODE/GIT/GIT_TRUNK/build-dbg/mysql-test/var/my.cnf | 131072    | 18446744073709550592 | NULL     | NULL     | NULL     |
+---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
1 row in set (0.00 sec)

Hier wird der thread_stack in der gemeldeten my.cnf-Datei gesetzt.

Refman:

https://dev.mysql .com/doc/refman/8.0/en/performance-schema-variables-info-table.html