swooletw / laravel-swoole

High performance HTTP server based on Swoole. Speed up your Laravel or Lumen applications.
MIT License
4.04k stars 388 forks source link

Redis connection become a zombie after using Cache class #365

Closed abdulnewswav closed 2 years ago

abdulnewswav commented 4 years ago

Make sure you read Issues Guideline and answer these questions before submitting your issue. Thanks! (Any non-English issues will be closed immediately.)

  1. Please provide your PHP and Swoole version. (php -v and php --ri swoole) PHP 7.3.13 (cli) Swoole 4.4.14

  2. Please provide your Laravel/Lumen version.

Lumen 5.7 and 5.8

  1. Which release version of this package are you using? 2.6

  2. What did you do? If possible, provide a recipe for reproducing the error. Call any api that use Cache::xxx, driver should be redis, predis in my case illuminate/redis predis:1.1.1

  3. What did you expect to see? redis connection get close after api call, or having pool of redis connections

  4. What did you see instead? I see X redis connection still established and opened after having X api calls uses Cache class

abdulnewswav commented 4 years ago

Oh is not just about Redis Connection, also HTTP connections from Guzzle will become zombie connections

codercms commented 4 years ago

@abdulnewswav No, they are not zombie connections, it is one of a long-running (long-live) application's advantages. Establishing redis/database connection on each request will slow down your application. When you started your application and it used database or cache methods at least once, then connection will be established at once and application will reuse it for all next requests. If you want to manully close a connection after each request you can use middleware for this case - https://laravel.com/docs/6.x/middleware#terminable-middleware. For example: You can close database connection by calling DB::connection('your_connection_name')->disconnect();

abdulnewswav commented 4 years ago

@codercms I don't think is working in this way, after I made some debugging I noticed that for every request it will create new socket connection to Redis server, until Redis server get it max of allowed connections I hope it was using a pool of connections, but that would be a bit hard, also this lib doesn't support mysql connections pool yet The only options I got is to create my own sub class of Cache class and add a destructor to close Redis connection and making that object reset for every request

codercms commented 4 years ago

@abdulnewswav i think there is some mistake in your application's code. Just tested my app (12 workers) under AB with concurrency about 1000. And i have checked my connections list during testing (redis-cli SHOW CLIENTS), it shown exactly 12 connections + 1 (my connection to redis-cli). Do you have following lines in your swoole_http.php config file in the "pre_resolved" section?

        'cache',
        'cache.store',

And please check "instances" and "providers" sections, maybe you're resetting the cache on every request.

codercms commented 4 years ago

@abdulnewswav regarding the connection pool. You don't actually need a connection pool if you're using a synchronous database driver, because it blocks the entire thread in a worker process. However this package has something regarding Coroutine-based MySQL client - https://github.com/swooletw/laravel-swoole/blob/master/src/HttpServiceProvider.php#L215, but i'm not sure how it works with concurrent coroutines. I can't find any code that prevents connection usage by another concurrent coroutine while first coroutine is still in transaction.

But you can implement your own connection pool. By the way, I have reached better performance with only 1-2 connections in the pool, but with increased workers number. But in your app results may be diffrent. I implemented my own CP here - https://github.com/codercms/laravel-pg-conn-pool You can do simmilar thing for your app.

P.S. You don't need to compile "special" pdo extension for PHP, if you're not using Postgres. pdo_mysql can be hooked by Swoole at runtime.

Swoole\Runtime::enableCoroutine(); // this will prevent pdo_mysql from blocking your worker thread

Read more here: