Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible goroutine leak in metricbeat sql module when database is not available #25840

Closed
simioa opened this issue May 25, 2021 · 2 comments · Fixed by #26607
Closed

Possible goroutine leak in metricbeat sql module when database is not available #25840

simioa opened this issue May 25, 2021 · 2 comments · Fixed by #26607
Assignees
Labels
Team:Integrations Label for the Integrations team

Comments

@simioa
Copy link

simioa commented May 25, 2021

Hello,

we're using the metricbeat sql module to gather some metrics. During Downtime of our Database, I observed slowly increasing memory consumption from metricbeat.
I tried to reproduce this with the following metricbeat config with a non-existent Database:

  • Steps to Reproduce:
  1. Create SQL Config pointing to a non-existent Database
    Using example config from the metricbeat reference:
metricbeat.modules:
- module: sql
  metricsets:
    - query
  period: 10s
  hosts: ["root:root@tcp(localhost:3306)/ps"]

  driver: "mysql"
  sql_query: "SHOW GLOBAL STATUS LIKE 'Innodb_system%'"
  sql_response_format: variables
  1. Let it run for a few minutes/hours - While metricbeat was running, I could see a steady increase in memory consumption from metricbeat.

I restarted metricbeat with the httpprof parameter and could observe that many database/sql.(*DB).connectionOpener goroutines are being created.

goroutine profile: total 10395
10305 @ 0x1f2cd25 0x1f3ce8f 0x39018d5 0x1f63e41
#	0x39018d4	database/sql.(*DB).connectionOpener+0xf4	/usr/local/go/src/database/sql/sql.go:1126 

With debug=2

goroutine 2004 [select, 14 minutes]:
database/sql.(*DB).connectionOpener(0xc000df6dd0, 0x5fa9520, 0xc00096b940)
	/usr/local/go/src/database/sql/sql.go:1126 +0xf5
created by database/sql.OpenDB
	/usr/local/go/src/database/sql/sql.go:740 +0x12a

After some debugging I think I figured out what happens.

In

err = dbx.Ping()
if err != nil {
return nil, errors.Wrap(err, "testing connection")
}
there is a check to test if the connection to the database works and if not, returns an error - but in case there is an error, the Database Object is never closed and leaking the goroutine.

To test my assumption, I replaced the code

if err != nil {
    return nil, errors.Wrap(err, "testing connection")
}

with

if err != nil {
	if dbx != nil {
		dbx.Close()
	}
	return nil, errors.Wrap(err, "testing connection")
}

After replacing the code, I could not observe further memory growth or goroutine creations.

Can you please check if my assumption is correct or if this is even a bug?

@botelastic botelastic bot added the needs_team Indicates that the issue/PR needs a Team:* label label May 25, 2021
@jsoriano jsoriano added the Team:Integrations Label for the Integrations team label Jun 23, 2021
@elasticmachine
Copy link
Collaborator

Pinging @elastic/integrations (Team:Integrations)

@botelastic botelastic bot removed the needs_team Indicates that the issue/PR needs a Team:* label label Jun 23, 2021
@jsoriano
Copy link
Member

@simioa thanks for reporting this! I think you are right, NewDBClient should close the connection if it fails to ping. Would you like to open a PR with your fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Team:Integrations Label for the Integrations team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants