Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Performance degradation with sessions. Laravel 8. Docker #23

Closed
apoldev opened this issue Nov 30, 2020 · 8 comments
Closed

Performance degradation with sessions. Laravel 8. Docker #23

apoldev opened this issue Nov 30, 2020 · 8 comments

Comments

@apoldev
Copy link

apoldev commented Nov 30, 2020

Hello.
I have a docker container with RoadrRunner and Laravel 8.16.1 by default. (clean install laravel new www)

I try it many times:
ab -n 1000 -c 100 "http://serverhost:8080/"

I notice a degradation of app performance:

3113.96 [#/sec]
....
1024.88 [#/sec]
539.06 [#/sec]
439.41 [#/sec]

If i remove in Http/Kernel.php in $middlewareGroups
these lines:

\Illuminate\Session\Middleware\StartSession::class, 
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class, 

then performance not degrade:

Requests per second:    2844.97 [#/sec] (mean)
Time per request:       35.150 [ms] (mean)
Time per request:       0.351 [ms] (mean, across all concurrent requests)

I suppose I need to reset the sessions? Only with the default config, roadrunner-laravel does not work.
How can I do it?

Dockerfile

FROM php:7.4-cli

#COPY opcache.ini /usr/local/etc/php/conf.d/opcache.ini

RUN apt-get update && apt-get install -y \
        curl \
  		vim \
  		libfreetype6-dev \
  		libjpeg62-turbo-dev \
  		libmcrypt-dev \
  		libpng-dev \
  		zlib1g-dev \
  		libxml2-dev \
  		libzip-dev \
  		libonig-dev \
  		graphviz \
  		libcurl4-openssl-dev \
  		pkg-config \
  		libpq-dev \
  		iputils-ping \
  		wget \
  		git

# Install PHP Extensions
RUN docker-php-ext-install -j$(nproc) iconv mbstring mysqli pdo_mysql zip \
    && docker-php-ext-install opcache \
    && docker-php-ext-enable opcache

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Download RoadRunner
ENV RR_VERSION 1.8.4
RUN mkdir /tmp/rr \
  && cd /tmp/rr \
  && echo "{\"require\":{\"spiral/roadrunner\":\"${RR_VERSION}\"}}" >> composer.json \
  && composer install --ignore-platform-reqs \
  && vendor/bin/rr get-binary -l /usr/local/bin \
  && rm -rf /tmp/rr

## Copy RoadRunner config
COPY config /etc/roadrunner

WORKDIR /var/www

CMD ["/usr/local/bin/rr", "serve", "-c", "/etc/roadrunner/.rr.yaml", "-w", "/var/www"]

docker-compose.yml

version: "3.7"
services:
  roadrunner:
    build: ./images/roadrunner
    container_name: "roadrunner"
    ports:
      - 8080:8080
    volumes:
      - ./www:/var/www:cached
      - ./configs/roadrunner:/etc/roadrunner:cached
    network_mode: "host"

.rr.yaml

env:
#APP_REFRESH: true

http:
  address: 0.0.0.0:8080
  workers:
    command: 'php /var/www/vendor/bin/rr-worker' # for windows: `php vendor/spiral/roadrunner-laravel/bin/rr-worker`
static:
  dir: 'public'

reload:
 interval: 1s
 patterns: [".php"]
 services:
   http:
     dirs: [""]
     recursive: true
@apoldev apoldev added the type:question Further information is requested label Nov 30, 2020
@tarampampam
Copy link
Collaborator

Hi @apoldev! What about memory usage during your ab tests?

@apoldev
Copy link
Author

apoldev commented Dec 1, 2020

Hello!

If i remove these three lines from $middlewareGroups:

Start. MEMORY USAGE
197MiB

After `ab` tests:
ab -c 100 -t 120  "http://remote_server:8080"

Time taken for tests:   17.783 seconds
Requests per second:    2811.70 [#/sec] (mean)
MEMORY USAGE  287.7MiB

WITH SESSION IN $middlewareGroups.

Start. MEMORY USAGE
197MiB

After ab tests:
ab -c 100 -t 120  "http://remote_server:8080"

Complete requests:      13926
Time taken for tests:   120.201 seconds
Requests per second:    115.86 [#/sec] (mean)
MEMORY USAGE:  398.9MiB

@tarampampam
Copy link
Collaborator

tarampampam commented Dec 2, 2020

Performance degradation confirmed.

My dockerfile:

FROM php:7.4.13-alpine

# Install PHP Extensions
RUN set -x \
    && docker-php-ext-install opcache \
    && docker-php-ext-enable opcache

# Download RoadRunner
COPY --from=spiralscout/roadrunner:1.9.0 /usr/bin/rr /usr/bin/rr

# Download Composer
COPY --from=composer:2.0.7 /usr/bin/composer /usr/bin/composer

# Install "clean" laravel
RUN composer create-project --prefer-dist --no-progress "laravel/laravel" /src "^8.4"

# Change working diretory to the laravel installation
WORKDIR /src

# Install RR bridge
RUN composer require --no-progress spiral/roadrunner-laravel "^3.4"

# Create simple RR config file
RUN echo -e \
"rpc:\n"\
"  enable: false\n"\
"http:\n"\
"  address: 0.0.0.0:8080\n"\
"  workers:\n"\
"    command: 'php ./vendor/bin/rr-worker'\n"\
"    pool:\n"\
"      numWorkers: 4\n"\
"      maxJobs: 0\n"\
"      allocateTimeout: 60\n"\
"      destroyTimeout: 60\n"\
"static:\n"\
"  dir: 'public'" > ./.rr.yaml

CMD rr -c /src/.rr.yaml serve -d

Build & run:

$ docker build --tag laravel-rr:local . && docker run --rm -p "8080:8080/tcp" laravel-rr:local

In separate terminal:

$ for i in {0..20}; do ab -n 1000 -c 100 "http://127.0.0.1:8080/" 2>&1 | grep 'per second:'; done
Requests per second:    1102.43 [#/sec] (mean)
Requests per second:    918.61 [#/sec] (mean)
Requests per second:    746.16 [#/sec] (mean)
Requests per second:    637.29 [#/sec] (mean)
Requests per second:    614.52 [#/sec] (mean)
Requests per second:    512.78 [#/sec] (mean)
Requests per second:    540.68 [#/sec] (mean)
Requests per second:    445.41 [#/sec] (mean)
Requests per second:    479.77 [#/sec] (mean)
Requests per second:    388.88 [#/sec] (mean)
Requests per second:    445.12 [#/sec] (mean)
Requests per second:    381.85 [#/sec] (mean)
Requests per second:    328.83 [#/sec] (mean)
Requests per second:    324.74 [#/sec] (mean)
Requests per second:    409.21 [#/sec] (mean)
Requests per second:    351.63 [#/sec] (mean)
Requests per second:    304.58 [#/sec] (mean)
Requests per second:    347.62 [#/sec] (mean)
Requests per second:    262.54 [#/sec] (mean)
Requests per second:    281.68 [#/sec] (mean)
Requests per second:    221.30 [#/sec] (mean)

screenshot

I need in some time for additional local tests. Thank for your report!

@tarampampam tarampampam added priority:high status:accepted and removed type:question Further information is requested labels Dec 2, 2020
@tarampampam
Copy link
Collaborator

With next config RR works better:

http:
  workers:
    pool:
      numWorkers: 16
      maxJobs: 64
      allocateTimeout: 60
      destroyTimeout: 60

screenshot

$ for i in {0..10}; do ab -n 1000 -c 100 "http://127.0.0.1:8080/" 2>&1 | grep 'per second:'; done
Requests per second:    1053.86 [#/sec] (mean)
Requests per second:    578.81 [#/sec] (mean)
Requests per second:    613.15 [#/sec] (mean)
Requests per second:    517.34 [#/sec] (mean)
Requests per second:    552.03 [#/sec] (mean)
Requests per second:    492.22 [#/sec] (mean)
Requests per second:    491.06 [#/sec] (mean)
Requests per second:    475.94 [#/sec] (mean)
Requests per second:    455.25 [#/sec] (mean)
Requests per second:    359.54 [#/sec] (mean)
Requests per second:    401.63 [#/sec] (mean)

@eldario
Copy link

eldario commented Dec 3, 2020

@apoldev

Hello, I will take part in this discussion.

Are you using the RoadRunner config (If you publish a vendor config, it is placed in ./config/roadrunner.php)?

Please, show it.

@jetexe
Copy link

jetexe commented Dec 4, 2020

Hello.

Default laravel session driver is file (.env.example, config).

Each time session starts, laravel calls garbage-collector (StartSession middleware). This operation is I/O bound for FileSessionHandler and degrade on large session list.

For tests i use "Apache jMeter" and "Apache ab", dockerfile from @tarampampam reply with configs:

http:
  workers:
    pool:
      numWorkers: 4 # I have only 4 threads on testing machine
      maxJobs: 64
      allocateTimeout: 60
      destroyTimeout: 60

jMeter tests was run in 50 parallel threads. Each thread does 5000 calls.

All graphics contains 90th percentile.

Default run:

$ docker run --rm -p "8080:8080/tcp" laravel-rr:local

изображение

$ for i in {0..20}; do ab -n 1000 -c 100 "http://127.0.0.1:8080/" 2>&1 | grep 'per second:'; done 
Requests per second:    714.26 [#/sec] (mean)
Requests per second:    676.30 [#/sec] (mean)
Requests per second:    650.93 [#/sec] (mean)
Requests per second:    619.68 [#/sec] (mean)
Requests per second:    581.30 [#/sec] (mean)
Requests per second:    587.99 [#/sec] (mean)
Requests per second:    493.58 [#/sec] (mean)
Requests per second:    577.38 [#/sec] (mean)
Requests per second:    480.70 [#/sec] (mean)
Requests per second:    486.99 [#/sec] (mean)
Requests per second:    506.49 [#/sec] (mean)
Requests per second:    422.18 [#/sec] (mean)
Requests per second:    419.97 [#/sec] (mean)
Requests per second:    410.45 [#/sec] (mean)
Requests per second:    400.14 [#/sec] (mean)
Requests per second:    458.22 [#/sec] (mean)
Requests per second:    412.70 [#/sec] (mean)
Requests per second:    419.72 [#/sec] (mean)
Requests per second:    518.80 [#/sec] (mean)
Requests per second:    388.01 [#/sec] (mean)
Requests per second:    347.34 [#/sec] (mean)

With array session driver:

$ docker run --rm -p "8080:8080/tcp" -e "SESSION_DRIVER=array"  laravel-rr:local

изображение

$ for i in {0..20}; do ab -n 1000 -c 100 "http://127.0.0.1:8080/" 2>&1 | grep 'per second:'; done 
Requests per second:    780.17 [#/sec] (mean)
Requests per second:    725.75 [#/sec] (mean)
Requests per second:    742.22 [#/sec] (mean)
Requests per second:    699.86 [#/sec] (mean)
Requests per second:    730.22 [#/sec] (mean)
Requests per second:    734.53 [#/sec] (mean)
Requests per second:    711.45 [#/sec] (mean)
Requests per second:    705.01 [#/sec] (mean)
Requests per second:    715.21 [#/sec] (mean)
Requests per second:    718.66 [#/sec] (mean)
Requests per second:    703.98 [#/sec] (mean)
Requests per second:    747.79 [#/sec] (mean)
Requests per second:    684.66 [#/sec] (mean)
Requests per second:    718.03 [#/sec] (mean)
Requests per second:    724.57 [#/sec] (mean)
Requests per second:    723.42 [#/sec] (mean)
Requests per second:    720.13 [#/sec] (mean)
Requests per second:    695.69 [#/sec] (mean)
Requests per second:    711.15 [#/sec] (mean)
Requests per second:    724.82 [#/sec] (mean)
Requests per second:    687.52 [#/sec] (mean)

Remove gc call from startSession middleware, using session.lottery config:

изображение

$ for i in {0..20}; do ab -n 1000 -c 100 "http://127.0.0.1:8080/" 2>&1 | grep 'per second:'; done                    
Requests per second:    699.82 [#/sec] (mean)
Requests per second:    661.41 [#/sec] (mean)
Requests per second:    603.76 [#/sec] (mean)
Requests per second:    597.45 [#/sec] (mean)
Requests per second:    702.27 [#/sec] (mean)
Requests per second:    658.57 [#/sec] (mean)
Requests per second:    659.56 [#/sec] (mean)
Requests per second:    726.27 [#/sec] (mean)
Requests per second:    738.47 [#/sec] (mean)
Requests per second:    724.43 [#/sec] (mean)
Requests per second:    669.35 [#/sec] (mean)
Requests per second:    705.24 [#/sec] (mean)
Requests per second:    704.70 [#/sec] (mean)
Requests per second:    695.04 [#/sec] (mean)
Requests per second:    710.15 [#/sec] (mean)
Requests per second:    683.25 [#/sec] (mean)
Requests per second:    695.19 [#/sec] (mean)
Requests per second:    704.88 [#/sec] (mean)
Requests per second:    679.48 [#/sec] (mean)
Requests per second:    680.28 [#/sec] (mean)
Requests per second:    734.98 [#/sec] (mean)

@tarampampam
Copy link
Collaborator

@jetexe - great thanks for your research!

@apoldev - in a two words - laravel uses file driver for sessions by default, and file implementation is very expensive for I/O. Also you should remember about RR http.workers.pool.maxJobs option - do not use 0. Can you confirm problem resolving?

@tarampampam tarampampam pinned this issue Dec 4, 2020
@apoldev
Copy link
Author

apoldev commented Dec 4, 2020

@tarampampam
Yes. Thanks for your research!
There is no more problem. Thanks

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

No branches or pull requests

4 participants