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

[6.x/7.x] broadcast() method causes memory leak #33952

Closed
rennokki opened this issue Aug 20, 2020 · 18 comments
Closed

[6.x/7.x] broadcast() method causes memory leak #33952

rennokki opened this issue Aug 20, 2020 · 18 comments
Labels

Comments

@rennokki
Copy link
Contributor

rennokki commented Aug 20, 2020

Like the title says, I ran into a discussion about some memory leaks for beyondcode/laravel-websockets here: beyondcode/laravel-websockets#325

The basic truth is that after some testing, I found out that running broadcast(...) will severely increase the memory for a ReactPHP loop, for instance.

To replicate this:

  • create a new Laravel project
  • composer require laravel/websockets:"dev-2.x-memory-leak"
  • copy the migrations: php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
  • run them: php artisan migrate
  • get to the root of the project and run php artisan websockets:serve --statistics-interval=1
  • open an artisan server with php artisan serve
  • Go to http://127.0.0.1:8000/laravel-websockets
  • Click on Connect
  • Watch the memory increase in the console that ran websockets:serve

As explained in beyondcode/laravel-websockets#325 (comment) and beyondcode/laravel-websockets#325 (comment), the problem starts from a broadcast() that causes the leakage.

I have tested even the code within the event. Running broadcast() caused the memory leaks.

@taylorotwell
Copy link
Member

What driver is broadcast using? Redis?

@taylorotwell
Copy link
Member

It would need to be tracked down if this is something that actually happens in Laravel. It could be in the Redis library you are using, etc.

@rennokki
Copy link
Contributor Author

It's using the native Redis broadcast driver from Laravel.

@taylorotwell
Copy link
Member

Predis or phpredis?

@rennokki
Copy link
Contributor Author

I think predis, if that's the one that is set by default within homestead

@GrahamCampbell
Copy link
Member

Can you please find out the actual driver, with 100% certainty.

@rennokki
Copy link
Contributor Author

Predis.

@rennokki
Copy link
Contributor Author

@GrahamCampbell @taylorotwell For 2.0.0-beta.8 and afterward, I have removed the broadcast() method from the code to avoid memory leaking while testing for 2.0, so make sure you get the 2.0.0-beta.7 only.

@GrahamCampbell
Copy link
Member

And the issue only occurs with predis, or also with phpredis? phpredis is the recommended driver, with up to 7x better performance.

@rennokki
Copy link
Contributor Author

rennokki commented Aug 22, 2020

So, to give you the full console output for each driver:

PHPRedis:

Click for logs
➜  code php artisan websockets:serve --statistics-interval=1
"Using client: phpredis"
Starting the WebSocket server on port 6001...
Using: 18.32 MB
Saving statistics...
Using: 18.34 MB
Saving statistics...
Using: 18.34 MB
Saving statistics...
Using: 18.34 MB
Saving statistics...
Using: 18.34 MB
[ HERE I HAVE INITIATED A NEW CONNECTION; UNTIL AT THIS POINT, THE broadcast() DID NOT GET CALLED BECAUSE THERE WERE NO CONNECTED USERS ]
Using: 19.88 MB
Saving statistics...
Using: 19.98 MB
Saving statistics...
Using: 20.09 MB
Saving statistics...
Using: 20.19 MB
Saving statistics...
Using: 20.3 MB
Saving statistics...
Using: 20.4 MB
Saving statistics...
[ HERE I HAVE DISCONNECTED FROM THE WEBSOCKETS SERVER ]
Using: 20.51 MB
Saving statistics...
Using: 20.62 MB
Saving statistics...
Using: 20.72 MB
Saving statistics...
Using: 20.83 MB
Saving statistics...
Using: 20.95 MB
Saving statistics...
Using: 21.06 MB
Saving statistics...
Using: 21.16 MB
Saving statistics...
Using: 21.27 MB
Saving statistics...
Using: 21.37 MB

Predis:

Click for logs
➜  code php artisan websockets:serve --statistics-interval=1
"Using client: predis"
Starting the WebSocket server on port 6001...
Using: 18.64 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
Saving statistics...
Using: 18.66 MB
[ HERE I HAVE INITIATED A NEW CONNECTION; UNTIL AT THIS POINT, THE broadcast() DID NOT GET CALLED BECAUSE THERE WERE NO CONNECTED USERS ]
Using: 20.2 MB
Saving statistics...
Using: 20.3 MB
Saving statistics...
Using: 20.41 MB
Saving statistics...
Using: 20.51 MB
Saving statistics...
Using: 20.62 MB
Saving statistics...
Using: 20.72 MB
Saving statistics...
Using: 20.83 MB
Saving statistics...
Using: 20.94 MB
Saving statistics...
Using: 21.04 MB
Saving statistics...
Using: 21.15 MB
Saving statistics...
Using: 21.27 MB
Saving statistics...
[ HERE I HAVE DISCONNECTED FROM THE WEBSOCKETS SERVER ]
Using: 21.34 MB
Saving statistics...
Using: 21.45 MB
Saving statistics...
Using: 21.55 MB
Saving statistics...
Using: 21.66 MB
Saving statistics...
Using: 21.76 MB
Saving statistics...
Using: 21.87 MB
Saving statistics...
Using: 21.97 MB
Saving statistics...
Using: 22.08 MB
Saving statistics...
Using: 22.18 MB
Saving statistics...
Using: 22.29 MB
Saving statistics...
Using: 22.4 MB
Saving statistics...
Using: 22.5 MB
Saving statistics...
Using: 22.61 MB
Saving statistics...

So it doesn't depend on which driver is used.

@GrahamCampbell
Copy link
Member

Thanks.

@rennokki
Copy link
Contributor Author

rennokki commented Aug 23, 2020

@taylorotwell @GrahamCampbell I can confirm this memory leak happens even on the sync driver (so no queues involved). Either the ShouldBroadcastNow contract does not change the game at all.

@rennokki
Copy link
Contributor Author

I have pointed out in beyondcode/laravel-websockets#325 (comment) that a controller also caused the issue, eventually moving on in beyondcode/laravel-websockets#325 (comment) to find out the issue is because of the broadcasting dispatch.

The package got a dev-2.x-memory-leak version in composer where just the broadcast() method causes the memory leak.

@rennokki
Copy link
Contributor Author

rennokki commented Aug 24, 2020

The issue seems to be caused by the new StatisticsUpdated(...) bit, where StatisticsUpdated is an event class.

Calling broadcast(null); triggers no memory leak.

@mo3000
Copy link

mo3000 commented Sep 1, 2020

I followed the instructions step by step to reproduce this. After digging a while, I found out that in /facade/ignition/src/IgnitionServiceProvider.php, function boot():

    public function boot()
    {
    ...
    
//        $this->app->make(QueryRecorder::class)->register();
//        $this->app->make(LogRecorder::class)->register();
//        $this->app->make(DumpRecorder::class)->register();
    }

comment out these three lines make the memory leak go away, and the websocket part works well.
So it sounds like not a bug of "broadcast()".

@taylorotwell
Copy link
Member

See above.

@mpskovvang
Copy link
Contributor

mpskovvang commented Sep 16, 2020

If the memory leak is caused by running SQL queries with many bindings, a fix is to set reporting.maximum_number_of_collected_queries to 0 in config/flare.php.

@rennokki
Copy link
Contributor Author

rennokki commented Dec 1, 2020

@mpskovvang Makes sense! I have informed the package users that had the respective issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants