MySQL Benchmarking and error in my_thread_global_end()

mysql-benchmarking

I encountered this error, “Error in my_thread_global_end(): xx threads didn’t exit“, while working on MySQL benchmarking using sysbench. In this blog I’ll share my experience, reveal the fix, and help you avoid lost threads in your future benchmarks.

When it comes to ensuring your MySQL database can handle the heat, benchmarking is your your guiding light. Sysbench is our favorite benchmarking tool. I was happily benchmarking my MySQL database with Sysbench when bam!

Error in my_thread_global_end(): xx threads didn’t exit

Above error popped up, halting my progress and that’s where my investigation begun.

TL;DR – verbosity is a great option in sysbench

sysbench has –verbosity option that comes handy for debugging using which we could identify the root cause of this error.

Investigating Error in my_thread_global_end()

I received this error during multi-threaded benchmarks specifically in my case when we had higher number of threads. For all the threads higher than 32 the error appeared.

Error in my_thread_global_end(): 32 threads didn't exit
Error in my_thread_global_end(): 64 threads didn't exit
Error in my_thread_global_end(): 128 threads didn't exit

Following command was used for benchmarking MySQL using sysbench

[root@benchmark ~]# sysbench --db-driver=mysql --mysql-user=admin --mysql-password=password --mysql-host=mysql-benchmarking-instance --mysql-port=3306 --mysql-db=mysql_benchmark --range_size=500 --table_size=10000000 --tables=100 --threads=64 --events=0 --time=600 --report-interval=5 /usr/share/sysbench/oltp_write_only.lua run > mysql-benchmarking/run_64.log

Above MySQL benchmarking command terminates immediately after the execution with the log having multiple errors “Error in my_thread_global_end(): 64 Threads Lost in Action”

Sysbench version for MySQL benchmarking

[root@benchmark ~]# sysbench --version
sysbench 1.0.20
[root@benchmark ~]#

MySQL error log has nothing logged that could point about this error being related to MySQL. My benchmarking instance had 8 cores and I wondered if that’s something to do with the number of CPU and if that’s the limitation.
But but that doesn’t seem to be the issue of mysql benchmarking server as I ran the CPU test for 5000 threads without any errors:

[root@benchmark ~]# sysbench --test=cpu --threads=5000 --time=1 run
WARNING: the --test option is deprecated. You can pass a script name or path on the command line without any options.
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)

Running the test with following options:
Number of threads: 5000
Initializing random number generator from current time

Prime numbers limit: 10000
Initializing worker threads…
Threads started!
CPU speed:
events per second: 8006.17

General statistics:
total time: 1.0499s
total number of events: 8417

Latency (ms):
min: 0.82
avg: 6.86
max: 972.30
95th percentile: 33.72
sum: 57753.36

Threads fairness:
events (avg/stddev): 1.6834/18.67
execution time (avg/stddev): 0.0116/0.09

I noted that this benchamarking report errors during write workloads only! Sysbench command works with read_only test but read_write and write_only tests fails when threads are 32 or more.

Ofcourse I Googled “Error in my_thread_global_end():” but none of the threads could really helped me which led me further to help of sysbench. I noted the log options having verbosity levels.

sysbench --help

Log options:
--verbosity=N verbosity level {5 - debug, 0 - only critical messages} [3]

I raised the verbosity to 5 and rerun the mysql benchmarking

[root@benchmark ~]# sysbench --verbosity=5 --db-driver=mysql --mysql-user=admin --mysql-password=password --mysql-host=mysql-benchmarking-instance --mysql-port=3306 --mysql-db=mysql_benchmark --range_size=500 --table_size=10000000 --tables=100 --threads=64 --events=0 --time=600 --report-interval=5 /usr/share/sysbench/oltp_write_only.lua run > mysql-benchmarking/run_64.log
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)

Running the test with following options:
Number of threads: 64
Report intermediate results every 5 second(s)
Initializing random number generator from current time

Initializing worker threads…

DEBUG: Worker thread (#0) started
DEBUG: Worker thread (#1) started
...
DEBUG: Worker thread (#60) started
DEBUG: Worker thread (#61) started
DEBUG: Worker thread (#62) started
DEBUG: Worker thread (#63) started
Failed to prepare query "BEGIN" (1295: This command is not supported in the prepared statement protocol yet), using emulation
(last message repeated 63 times)
FATAL: mysql_stmt_prepare() failed
FATAL: MySQL error: 1461 "Can't create more than max_prepared_stmt_count statements (current value: 16382)"
(last message repeated 1 times)
FATAL: mysql_stmt_prepare() failed
FATAL: MySQL error: 1461 "Can't create more than max_prepared_stmt_count statements (current value: 16382)"
(last message repeated 1 times)
FATAL: mysql_stmt_prepare() failed
(last message repeated 1 times)
FATAL: mysql_stmt_prepare() failed
(last message repeated 1 times)
FATAL: `thread_init' function failed: /usr/share/sysbench/oltp_common.lua:284: SQL API error

...

FATAL: Thread initialization failed!
Error in my_thread_global_end(): 64 threads didn't exit

great success ! We see the actual underlying issue now.

1461 "Can't create more than max_prepared_stmt_count statements (current value: 16382)"

Further reading documentation about max_prepared_stmt_count

This variable limits the total number of prepared statements in the server. It can be used in environments where there is the potential for denial-of-service attacks based on running the server out of memory by preparing huge numbers of statements. If the value is set lower than the current number of prepared statements, existing statements are not affected and can be used, but no new statements can be prepared until the current number drops below the limit. Setting the value to 0 disables prepared statements.

Reviewing current configuration

[root@benchmark ~]# mysql -hmysql-benchmarking-instance -e "select @@global.max_prepared_stmt_count;"
+----------------------------------+
| @@global.max_prepared_stmt_count |
+----------------------------------+
| 16382                            |
+----------------------------------+

The Fix for Error in my_thread_global_end()

The verbose mode showed us the reason for the failure. The write traffic was causing benchmark to terminate as it was crossing the max prepared statement count for higher concurrency. I adjusted the max_prepared_stmt_count to a higher value “1048570” and restarted the journey of MySQL benchmarking.

[root@benchmark ~]# mysql -hmysql-benchmarking-instance -e "select @@global.max_prepared_stmt_count;"
+----------------------------------+
| @@global.max_prepared_stmt_count |
+----------------------------------+
| 1048570                          |
+----------------------------------+

Restarted the MySQL Behchmarking using sysbench and this time it completed successfully.

The solution lies in adjusting the max_prepared_stmt_count variable in your MySQL configuration file. Simply increase this value to accommodate the anticipated number of statements used by sysbench.

Conclusion

Debugging logs and raising verbosity allows us to troubleshoot the issues, rightly what helped us in this situation. Don’t blindly trust default settings. Adapt system variables like max_prepared_stmt_count to your specific requirements. Debugging common errors like this one allows you to smoother benchmarking journey. Happy Benchmarking!

Leave a Reply

Your email address will not be published. Required fields are marked *