[MDEV-16446] create temporary table engine=memory does not release memory and tmp space Created: 2018-06-08 Updated: 2020-08-25 Resolved: 2018-07-12 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Server |
| Affects Version/s: | 10.2.15 |
| Fix Version/s: | 10.2.15 |
| Type: | Bug | Priority: | Major |
| Reporter: | Rick Pizzi | Assignee: | Axel Schwenke |
| Resolution: | Not a Bug | Votes: | 1 |
| Labels: | None | ||
| Attachments: |
|
| Description |
|
A workload that uses a lot in-memory temporary tables makes the mysqld process grow until it fills all the avaialble system memory and eventually the process is killed by OOM killer. While verifying this in my lab, I also found that the above statement is also using the ibtmp1 tablespace, and makes it grow enormously (it filled my disk during the test run). According to the documentation, the memory allocated by CREATE TEMPORARY TABLE .. ENGINE=MEMORY should be released when the session is terminated, however, this doesn't seem to be the case. Also, the enormous growth of the temporary innodb tablespace is kind of unexpected - only way to reclaim this space is to restart MariaDB. How to reproduce:
I am attaching the LUA file to this ticket. While this runs, you can monitor mysqld footprint and ibtmp1 growth with:
Please note:
|
| Comments |
| Comment by Elena Stepanova [ 2018-06-25 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
axel, Could you please check it quickly and if it reproduces, preserve the setup and pass it over to serg (for futher assignment). The important part is the setup, because whoever ends up fixing it, will most likely need to be able to reproduce it again, and I don't have a shareable machine which can meaningfully run 48 threads. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-11 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
I cannot reproduce the claims made in this ticket. Instead I find several flaws in the test method:
I have fixed the CREATE TABLE statement and shortened the execution time of the test to 2 minutes. I used
to write memory statistics to the error log. I did this 4 times:
The reason for 4. is that the cleaning up of 48 session contexts (including dropping temporary tables) is not immediate, but takes some time. If one would watch closer, one could see the memory usage falling steadily between 3. and 4. Here are the 4 samples (edited for readability)
Observations:
I tested that with MariaDB 10.2.15 (as given in the ticket) and also with most recent MariaDB 10.3.8 and the results are the same. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-11 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
attached a fixed version create_temporary_fixed.lua | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-11 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Finally: I attached create_temporary_proper.lua | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Sorry for having crafted a broken LUA script, and thanks for the analysis. Also, not clear to me, are you saying we can bring down the server by creating a number Why is creating a temporary table on disk using memory? Still this means a loop of "create temporary table" in a session can bring down the server. Anyway I will try to reproduce properly our problem and reopen the ticket if I succeed... | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Rick, it is true that there is no limit on the total amount of memory that could be spent on MEMORY tables - be it temporary or resident tables. The max_heap_table_size limit is per table. If a user is allowed to create an arbitrary number of such tables, he can fill any amount of memory. I'm not sure what the exact problem of your customer is. It could be some application flaw that creates (too) many temporary tables. Or it could be a broken connection pool (PHP's pconnect() was notorious for that) that doesn't clean up connections that go back into the pool. The only safe way is IMHO to put a DROP TABLE statement for each CREATE TEMPORARY TABLE in the application code and make sure it is executed even in case of errors (using exception handling or whatever the app language offers). | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
I think there must be some kind of memory leak. I'll be back if I can reproduce it in my lab. RIck | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
A temporary InnoDB table (the default when neither default_storage_engine nor default_tmp_storage_engine is set) will be created in an InnoDB tablespace and will use some memory in InnoDB buffers. The InnoDB buffer pool will not grow beyond the configured size, but the data dictionary may. It's however relatively small and unlikely to fill all RAM. But if the buffer pool size was made too big from the beginning (but never used under normal circumstances) then it might as well bring down the machine. Again: there is not enough information for a detailed analysis. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
"mysqladmin debug" could be helpful to find where the memory is spent. Output from "ps" is not helpful at all. If an application creates unlimited number of temporary tables and never cleans them up, then this is the leak. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Oh, one more thing. Replicating temporary tables is often a bad idea. From the application side it's often unnecessary to replicate such tables. Or to put it the other way: it's only necessary when the temporary table is later used to fill rows into a persistent table. I.e.
But in most cases the temporary table is only used for aggregation and then none of the temporary table operations needs to be executed on the slave. In the past I handled that in the application code, using a separate database for such temporary tables and a replication filter. A unique prefix on the table name would also do. And of course: using row-based logging, temporary tables won't be replicated at all. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Not replicated. they are running this on the slave directly, the flow should be (I have to recheck as it . connect
| |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
OK, I have checked the customer again and: 1) this happens also on galera nodes The mysqladmin debug reports obviously incorrect values: Running threads: 42 Cached threads: 101 Stack size: 299008 Key caches: handler status: Table status: Alarm status: Memory status: | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
More details:
| |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
reopened on request of reporter | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Thanks. I am still trying to reproduce in lab but so far haven't found a way. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Also I think there is a bug around counters in the memory stats inside the server (mysqladmin debug command), perhaps some counters should be 8 bytes instead of 4 | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rick Pizzi [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
I have rechecked the workload of the customer - and found that, in fact, they are leaking one temp table at every iteration of their application. This explains the memory leak! Thanks for your support and apologies for the wrong LUA code posted above. | |||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Axel Schwenke [ 2018-07-12 ] | |||||||||||||||||||||||||||||||||||||||||||||||||
|
The leak is in the application, not MariaDB. |