sourcecode

MySQL 오류 1436:스레드 스택 오버런(간단한 쿼리 포함

copyscript 2023. 10. 26. 21:21
반응형

MySQL 오류 1436:스레드 스택 오버런(간단한 쿼리 포함

저는 테이블에 대해 매우 간단한 업데이트를 수행하고 있는데, 이것은 또한 정말 간단한 트리거를 트리거하고, 그것은 저에게 오류를 줍니다.

#1436 - Thread stack overrun:  6136 bytes used of a 131072 byte stack, and 128000 bytes needed.

실행하는 쿼리:

UPDATE field_values SET value = 'asaf' WHERE field_values.id =1

값 필드는 다음과 같습니다.text그래서 이론적으로는 조용해질 수 있습니다.이 상황에서는 그렇지 않습니다.

실행되는 트리거는 다음과 같습니다.

DELIMITER $$
    CREATE TRIGGER field_value_update_trigger BEFORE UPDATE ON community_fields_values
    FOR EACH ROW BEGIN
      INSERT INTO user_field_log (user_id, field_id, value) VALUES (NEW.user_id, NEW.field_id, NEW.value);
    END;
$$
DELIMITER ;

이 오류가 표시되는 이유는 무엇입니까?무거운 질문이 관련된 것은 아닙니다.또한 데이터베이스가 거의 비어있고, 단지 2개의 행에 있습니다.community_fields_values그리고 열이 없습니다.user_field_log

MySQL 버전: 5.1.44

1436 - 스레드 스택 오버런: 131072 바이트 스택에 사용되는 6136 바이트, 그리고 128,000 바이트가 필요합니다.

오류 1436은 ER_에 해당합니다.mysql 5.1 코드의 STACK_OVERRUN_NEED_MORE:

malff@linux-8edv:include> pwd
/home/malff/BZR_TREE/mysql-5.1/include
malff@linux-8edv:include> grep 1436 mysqld_error.h
#define ER_STACK_OVERRUN_NEED_MORE 1436

오류가 표시된 코드 인쇄는 sql/sql_parse.cc, 함수 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));

표시된 값에서 마진은 128000이고 my_thread_stack_size는 131072입니다.

128,000바이트를 예약하려는 check_stack_overrun() 호출은 다음에서 온 것뿐입니다.

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);

STACK_MIN_SIZE의 값은 16000입니다.

malff@linux-8edv:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
malff@linux-8edv:sql> grep STACK_MIN_SIZE *.h
mysql_priv.h:#define STACK_MIN_SIZE          16000   // Abort if less stack during eval.

지금까지 서버에 대한 모든 것이 예상대로 작동합니다.

  • 코드는 sp_head:: execute로 구현된 트리거를 실행합니다.
  • MySQL 런타임은 스택에 최소 128,000 바이트가 있는지 확인합니다.
  • 이 검사가 실패하고(rightly so), 트리거 실행이 오류로 종료됩니다.

MySQL 트리거 실행에 필요한 스택의 양은 트리거 복잡도 자체나 관련 테이블의 내용/구조에 따라 달라지지 않습니다.

진짜 질문은 왜 thread_stack이 128K(131072)에 불과하다는 것입니다.

thread_stack'이라는 이름의 서버 변수는 C에서 sql/mysqld.cc 의 'my_thread_stack_size'로 구현됩니다.

  {"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는 이 파라미터의 최소값입니다.기본값은 DEFAULT_THREAD_STACK이며 include/my_pthread에 정의되어 있습니다.h:

#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

따라서 기본적으로 스택 크기는 192K(32비트) 또는 256K(64비트 아키텍처)여야 합니다.

먼저 mysqld 이진을 컴파일한 방법을 확인하여 기본값이 무엇인지 확인합니다.

malff@linux-8edv:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
malff@linux-8edv:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack
...
  --thread_stack=#    The stack size for each thread.
thread_stack                      262144

제 시스템에서는 64비트 플랫폼에서 256K를 얻었습니다.

값이 서로 다른 경우 -DDEFACT_THREAD_STACK(또는 소스 수정)과 같이 다른 컴파일 옵션을 사용하여 서버를 구축할 수도 있습니다.저는 그 경우에 이진법이 어디서 오는지 의문이 듭니다.

둘째, 구성 파일 자체에 제공된 기본값을 my.cnf에서 확인합니다.값을 thread_stack으로 명시적으로 설정하면(낮은 값으로) 분명히 표시되는 오류가 발생합니다.

마지막으로 서버 로그 파일에서 다음과 같은 오류가 있는지 확인합니다(sql/mysqld.cc 참조).

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

서버 코드는 다음을 호출합니다.

  • pthread_attr_set 스택 크기를 ()(으)로 설정하여 스택 크기를 설정합니다.
  • pthread_attr_getstacksize ()는 스레드의 실제 스택 양을 확인하는 데 사용되며 pthread 라이브러리의 사용량이 적으면 로그에 불만을 제기합니다.

간단히 말하면 thread_stack이 서버와 함께 제공되는 기본값에 비해 너무 작기 때문에 오류가 발생합니다.다음과 같은 경우가 발생할 수 있습니다.

  • 서버의 사용자 지정 빌드를 수행할 때 다른 컴파일 옵션을 사용합니다.
  • my.cnf 파일에서 기본값을 변경할 때
  • pthread 라이브러리 자체에서 무언가가 잘못되었다면(이론적으로 코드를 읽은 것으로 볼 때, 나는 그것을 직접 본 적이 없습니다.

이 질문에 대한 답을 얻기를 바랍니다.

안녕하세요 -- 마크 앨프

업데이트(2014-03-11), "고치는 방법"을 보다 명확하게 할 수 있습니다.

아마 sread_stack 파일의 기본값이 my.cnf 파일에서 변경되었을 것입니다.

그렇다면 이를 수정하는 방법은 사소한 것입니다. my.cnf 파일에서 thread_stack이 설정된 위치를 찾아 설정을 제거하거나(서버 코드를 신뢰하여 괜찮은 기본값을 제공하므로 다음 번에는 이런 일이 발생하지 않음) 스택 크기를 늘립니다.

업데이트(2021-04-28), thread_stack의 출처 확인:

사용표performance_schema.variables_info특정 변수가 어디서 왔는지를 찾는 것입니다.

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)

여기서 기본값은 공장도 값(mysqld 이진법으로 컴파일됨)입니다.

또 다른 예:

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)

여기서 thread_stack은 보고된 my.cnf 파일에 설정됩니다.

Refman:

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

해결책은 아니지만 my.cnf에서 thread_stack size를 증가시켜 sread_stack size를 증가시키는 것이 빠른 해결책이 될 수 있습니다.

thread_stack = 256K

사용자 "foo"가 지적했듯이 실제 문제를 감지하려면 전체 트리거 코드를 게시하는 것이 더 도움이 될 수 있습니다.

언급URL : https://stackoverflow.com/questions/8821575/mysql-error-1436-thread-stack-overrun-with-simple-query

반응형