понедельник, 19 декабря 2016 г.

How to measure postgresql performance

I have three different servers: VPS with one core cpu, desktop pc and i7 server. I run one sql request and got such execution time:

explain analyze select now();

VPS
 Result  (cost=0.00..0.01 rows=1 width=8) (actual time=0.083..0.084 rows=1 loops=1)
 Planning time: 0.024 - 0.450 ms
 Execution time: 0.021 - 0.295 ms

Desktop
 Result  (cost=0.00..0.01 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=1)
 Planning time: 0.014 ms
 Execution time: 0.038 ms

Server
"Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)"
"Planning time: 0.003 ms"
"Execution time: 0.005 ms"

Seems good for "quick test"

пятница, 15 июля 2016 г.

Mass file renaming by regexp in linux

Good bash script when you want only take part of filename using regexp for renaming

#!/bin/bash

for filename in *.m4a; do
  newFilename=$(echo $filename | \
  sed -r 's#^(.*) - (.*)-(.*).m4a$#\2.m4a#')
  mv "$filename" "$newFilename"
done

Also, you can use rename command
rename s/.mp4$/.m4a/ *.mp4

Memcached info stats

Two good tools to see data of memcached

First of all - telnet

telnet localhost 11211
and type stats

Another good tool is memcached-tool

Just type in without parameters for sample usage

воскресенье, 20 марта 2016 г.

Обновление postgres до 9.5 с 9.4 в Убунту 15.10


Недавно боевые сервера обновили постгрес до 9.5 и даже с помощью pgadmin3 не получается на них зайти, т.к. локально всё еще 9.4

Но для начала сделаем бекап!
sudo -u postgres pg_dumpall > db-9.4.backup

Поэтому проще обновиться локально. Но как? Если в репозитории убунту новая версия базы появится только в 16.04? Подключим сторонние репозитории.

Добавляем репозиторий http://apt.postgresql.org/pub/repos/apt/ В README написано как.

И устанавливаем postgresql-9.5
sudo apt-get install postgresql-9.5

Заходим под пользователем в консоль, чтобы не было проблем с правами.
sudo -iu postgres

Сразу же удалим тот кластер, что создался при установке 9.5
pg_dropcluster 9.5 main --stop

И пересоздадим его на основе текущего - от версии 9.4
pg_upgradecluster 9.4 main

И ждём. Ждём. Готово! Проверьте что всё работает и удаляйте старую версию
pg_dropcluster 9.4 main

И также можно удалить бекап файл
rm db-9.4.backup

вторник, 15 марта 2016 г.

Symfony3 memcached config

When you get that exception after searching memcached config on stackoverflow and other blog article sites:

The reserved indicator "@" cannot start a plain scalar; you need to quote the scalar at line ... (near "- [ setMemcached, [ @memcached ]]").

So you should just quote "@memcached"! It's a new feature for yaml in Symfony3

So current good config I am using now:

parameters:
  memcached.servers:
      - { host: 127.0.0.1, port: 11211 }

services:
    memcached:
        class: Memcached
        calls:
            - [ addServers, [ %memcached.servers% ]]
    doctrine.cache.memcached:
        class: Doctrine\Common\Cache\MemcachedCache
        calls:
            - [ setMemcached, [ "@memcached" ]]

 And for doctrine caches:
doctrine:
  orm:
    metadata_cache_driver:
      type: service
      id: doctrine.cache.memcached
    result_cache_driver:
      type: service
      id: doctrine.cache.memcached
    query_cache_driver:
      type: service
      id: doctrine.cache.memcached

пятница, 19 февраля 2016 г.

Бенчмарк базы без баунсера. Только селекты. Начало

Идём по плану. Создали таблицу на 100к записей. Для pgbench

  1. Тестим в 1/4/8/16/32 селектов.
    • 1 - 1600 (-10) тпс - 1680
    • 4 - 7300 (-100) тпс - 7300
    • 8 - 17250 (-100) тпс - 17300
    • 16 - 26500 (-300) тпс - 26700
    • 32 - 28000 (-500) тпс - 28000
  2. Тестим в 1/4/8/16/32 селектов с новым коннектом
    • 1 - 120 / 940 тпс - 120 / 945
    • 4 - 133 / 11200 тпс - 133 / 11220
    • 8 - 135 / 11200 тпс - 134 / 11300
    • 16 - 133 / 10700 тпс - 133 / 11270
    • 32 - 133 / 10500 тпс - 132 / 10660
  3. Тестим в 1/4/8/16/32 селектов prepared statements
    • 1 - 1714 (-10) тпс - 1680
    • 4 - 7400 (-100) тпс - 7600
    • 8 - 18000 (-100) тпс - 18000
    • 16 - 27500 (-300) тпс - 27500
    • 32 - 28500 (-500) тпс - 27800
  4. Тестим в 1/4/8/16/32 селектов prepared statements с новым коннектом.
    • Не работает 

Выводы

На что можно обратить внимание?
  • prepared statements - ни разу не медленные! Может тут решает то, что всё делается не из скрипта (задержки между вызовами минимальны)
  • Новые коннекты создавать реально очень дорого - лишь 133 селекта в секунду на всех.
  • Теперь подключим баунсер и ожидаем получить что в групп 1 и 3 результаты немного упадут, а в группе 2 - вырастут!

вторник, 16 февраля 2016 г.

Системные вызовы при коннекте к БД Postgres из PHP

Symfony

1455554851.464383 sendto(6, "P\0\0\0z\0SELECT t0.name AS name_1, t0.number AS number_2, t0.id AS id_3 FROM bench_data t0 WHERE t0.num"..., 168, MSG_NOSIGNAL, NULL, 0) = 168 <0.000023>
1455554851.464435 poll([{fd=6, events=POLLIN|POLLERR}], 1, 4294967295) = 1 ([{fd=6, revents=POLLIN}]) <0.000278>
1455554851.464744 recvfrom(6, "1\0\0\0\0042\0\0\0\4T\0\0\0Q\0\3name_1\0\0\0bB\0\2\0\0\4\23\377\377\0\0\1\3\0\0number_2\0\0\0bB\0\3\0\0\0\27\0\4\377\377\377\377\0\0id_3\0\0\0bB\0\1\0\0\0\27\0\4\377\377\377\377\0\0D\0\0\0006\0\3\0"..., 16384, 0, NULL, NULL) = 167 <0.000010>

Yii

1455554340.049263 sendto(6, "P\0\0\0Ipdo_stmt_00000001\0SELECT * FROM \"bench_data\" WHERE \"number\"=$1\0\0\1\0\0\0\0S\0\0\0\4", 79, MSG_NOSIGNAL, NULL, 0) = 79 <0.000040>
1455554340.049454 poll([{fd=6, events=POLLIN|POLLERR}], 1, 4294967295) = 1 ([{fd=6, revents=POLLIN}]) <0.000061>
1455554340.049617 recvfrom(6, "1\0\0\0\4Z\0\0\0\5I", 16384, 0, NULL, NULL) = 11 <0.000087>

pgbench

1455559601.087593 sendto(12, "T\0\0\0!\0\1abalance\0\0\0b\240\0\3\0\0\0\27\0\4\377\377\377\377\0\0D\0\0\0\v\0\1\0\0\0\0010C\0\0\0\rSELECT 1\0Z\0\0\0\5I", 66, 0, NULL, 0) = 66 <0.000104>
1455559601.087742 recvfrom(12, "Q\0\0\0\20DISCARD ALL\0", 8192, 0, NULL, NULL) = 17 <0.000375>

Выводы

В пых коннекте вставлен системный вызов poll для ожидания завершения работы сокета. Наверно поэтому PDO коннекторы работают хуже чистого подключения. И еще у pgbench используется другой сокет (id = 12), в то время как yii и symfony используют один и тот же (id = 6)

понедельник, 15 февраля 2016 г.

Низкоуровневая отладка процесса в Linux с помощью strace

Начал читать статью http://www.speedemy.com/troubleshooting-web-application-performance-issues/ и уже буря эмоций!

Новый ключ к пониманию работы приложения и производительности!

Например подключаюсь к php-fpm и стартую процесс

ps aux | grep php
www-data  1900  0.0  0.5 340476 32840 ?    S    февр.14   0:00 php-fpm: pool www                                                           
www-data  1901  0.0  0.6 340492 36104 ?    S    февр.14   0:00 php-fpm: pool www


sudo strace -p 1900 -tttT -s200

И вуаля!

recvfrom(9, "VALUE NotOwlnewPermissionsUser64"..., 8196, MSG_NOSIGNAL, NULL, NULL) = 531
sendto(9, "get NotOwlnewPermissionsUser6452"..., 44, MSG_NOSIGNAL, NULL, 0) = 44
recvfrom(9, "VALUE NotOwlnewPermissionsUser64"..., 8196, MSG_NOSIGNAL, NULL, NULL) = 531
sendto(9, "get NotOwlnewPermissionsUser6452"..., 44, MSG_NOSIGNAL, NULL, 0) = 44
recvfrom(9, "VALUE NotOwlnewPermissionsUser64"..., 8196, MSG_NOSIGNAL, NULL, NULL) = 531
sendto(9, "get NotOwlnewPermissionsUser6452"..., 44, MSG_NOSIGNAL, NULL, 0) = 44
recvfrom(9, "VALUE NotOwlnewPermissionsUser64"..., 8196, MSG_NOSIGNAL, NULL, NULL) = 531


recvfrom(5, "\1\5\0\1\0\0\0\0", 8, 0, NULL, NULL) = 8
close(5)                                = 0
munmap(0x7f5816a00000, 2097152)         = 0
setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}}, NULL) = 0
accept(0, ^CProcess 1900 detached
 <detached ...>

Все системные вызовы на ладони!

суббота, 6 февраля 2016 г.

Сводка базовых итогов бенчмарка

Всё теперь происходит на пхп7. Раз уж под него вышел профилировщик.

Симфони3 без базы

Concurrency Level:      1
Time taken for tests:   4.300 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      406000 bytes
HTML transferred:       198000 bytes
Requests per second:    232.57 [#/sec] (mean)
Time per request:       4.300 [ms] (mean)
Time per request:       4.300 [ms] (mean, across all concurrent requests)
Transfer rate:          92.21 [Kbytes/sec] received


Concurrency Level:      50
Time taken for tests:   12.224 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4060000 bytes
HTML transferred:       1980000 bytes
Requests per second:    818.05 [#/sec] (mean)
Time per request:       61.121 [ms] (mean)
Time per request:       1.222 [ms] (mean, across all concurrent requests)
Transfer rate:          324.34 [Kbytes/sec] received





Уии2 без базы

Concurrency Level:      1
Time taken for tests:   1.856 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      336000 bytes
HTML transferred:       200000 bytes
Requests per second:    538.66 [#/sec] (mean)
Time per request:       1.856 [ms] (mean)
Time per request:       1.856 [ms] (mean, across all concurrent requests)
Transfer rate:          176.75 [Kbytes/sec] received



Concurrency Level:      50
Time taken for tests:   3.366 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3360000 bytes
HTML transferred:       2000000 bytes
Requests per second:    2970.70 [#/sec] (mean)
Time per request:       16.831 [ms] (mean)
Time per request:       0.337 [ms] (mean, across all concurrent requests)
Transfer rate:          974.76 [Kbytes/sec] received



Цепляемся через через баунсер

pgbench -S -U postgres  -p6432 -U tmp -C -c1 -T 10 -h 192.168.1.103 tmp
latency average: 21.692 ms
tps = 46.032208 (including connections establishing)
tps = 52.081821 (excluding connections establishing)

В 50 потоков. Это базовые цифры.
latency average: 541.126 ms
tps = 87.958383 (including connections establishing)
tps = 97.724345 (excluding connections establishing)


Теперь тоже на симфони3 - простые селекты

Concurrency Level:      1
Time taken for tests:   6.507 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      469000 bytes
HTML transferred:       261000 bytes
Requests per second:    153.67 [#/sec] (mean)
Time per request:       6.507 [ms] (mean)
Time per request:       6.507 [ms] (mean, across all concurrent requests)
Transfer rate:          70.38 [Kbytes/sec] received




Concurrency Level:      50
Time taken for tests:   20.924 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4690000 bytes
HTML transferred:       2610000 bytes
Requests per second:    477.92 [#/sec] (mean)
Time per request:       104.621 [ms] (mean)
Time per request:       2.092 [ms] (mean, across all concurrent requests)
Transfer rate:          218.89 [Kbytes/sec] received


Теперь тоже на уии2

Concurrency Level:      1
Time taken for tests:   6.421 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      398000 bytes
HTML transferred:       262000 bytes
Requests per second:    155.74 [#/sec] (mean)
Time per request:       6.421 [ms] (mean)
Time per request:       6.421 [ms] (mean, across all concurrent requests)
Transfer rate:          60.53 [Kbytes/sec] received


Concurrency Level:      50
Time taken for tests:   8.837 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3980000 bytes
HTML transferred:       2620000 bytes
Requests per second:    1131.63 [#/sec] (mean)
Time per request:       44.184 [ms] (mean)
Time per request:       0.884 [ms] (mean, across all concurrent requests)
Transfer rate:          439.83 [Kbytes/sec] received

понедельник, 1 февраля 2016 г.

pm.max_children - вот что еще нужно!

Ну конечно. Еще один важный параметр - сколько у нас php-fpm потоков для обработки запросов. По умолчанию - 5. Всего лишь 5. Это значит, что запросы на обработку php запросов будут вставать в очередь.


Concurrency Level:      50
Time taken for tests:   25.787 seconds
Complete requests:      10000
Requests per second:    387.80 [#/sec] (mean)
Time per request:       128.933 [ms] (mean)
Time per request:       2.579 [ms] (mean, across all concurrent requests)
Transfer rate:          153.76 [Kbytes/sec] received


Поднимем же и это число до 50 и проверим и его на скорость:
Concurrency Level:      50
Time taken for tests:   27.193 seconds
Complete requests:      10000
Requests per second:    367.75 [#/sec] (mean)
Time per request:       135.964 [ms] (mean)
Time per request:       2.719 [ms] (mean, across all concurrent requests)
Transfer rate:          145.81 [Kbytes/sec] received

На самом деле стало чутка хуже, т.к. нагрузка на проц возросла сильнее и переключение между потоками создало дополнительную нагрузку. Т.е. хорошо иметь быстрые запросы, чтобы они сильно не успевали загрузить систему. Поэтому вернёмся к тесту pgbouncer с новыми данными и попробуем нагрузить базу по полной!

воскресенье, 31 января 2016 г.

Бенч symfony3 с базой данных

Обновим наше приложение - на получение записи из базы.

Итого получим. Без базы как обычно (50 юзеров)
Concurrency Level:      50
Time taken for tests:   27.157 seconds
Complete requests:      10000
Failed requests:        0
Requests per second:    368.23 [#/sec] (mean)
Time per request:       135.786 [ms] (mean)


С базой уже
Concurrency Level:      50
Time taken for tests:   63.509 seconds
Complete requests:      10000
Failed requests:        0
Requests per second:    157.46 [#/sec] (mean)
Time per request:       317.547 [ms] (mean)
Time per request:       6.351 [ms] (mean, across all concurrent requests)
Transfer rate:          72.12 [Kbytes/sec] received

Это ужасно. Одно приложение, которое коннектится на одну базу, без баунсера.

Добавим баунсер
Concurrency Level:      50
Time taken for tests:   40.391 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4690000 bytes
HTML transferred:       2610000 bytes
Requests per second:    247.58 [#/sec] (mean)
Time per request:       201.957 [ms] (mean)
Time per request:       4.039 [ms] (mean, across all concurrent requests)
Transfer rate:          113.39 [Kbytes/sec] received

Стало быстрее, но всё равно очень медленно. pg_stat_activity не выдаёт того, что база работает на полную. В отличие от pgbench запросов

Если в одного юзера только селекты база отдаёт. Каждый запрос - одно соединение (-C):
tps = 470.757538 (including connections establishing)
tps = 900.448771 (excluding connections establishing)

Для 50 пользователей это будет (только селекты -S) и новые коннекты (-C)
tps = 1401.415031 (including connections establishing)
tps = 39028.763458 (excluding connections establishing)

На этом, пожалуй и закончим. Слишком много новых вопросов появилось при работе с базой данных. И с параллельными запросами.

пятница, 29 января 2016 г.

Потестируем pbouncer. Сессионный режим

Начнём прогрев. От чистой базы однопоточный режим выдаёт 112тпс. Отлично

Вернёмся к нашим предыдущим бенчмаркам. Очень неравномерные значения.
pgbench -c 80 -U postgres -T 30

1000-1400 тпс выдало. Повторить этот результат даже не удалось. Всё время грузился диск.

Теперь тоже с параметром -С - чтобы создавались каждый раз новый подключения.
latency average: 640.854 ms
tps = 124.538621 (including connections establishing)
tps = 5205.394150 (excluding connections establishing)
Очень мало. Очень!

Итак. Даём начальные данные.
Число коннектов активных в постгрес - 100
Число активных коннектов в баунсере - 80
Режим баунсера - сессионный.

Команда маленько поменяется
pgbench -U postgres -p6432 -U tmp -T 10
115 тпс! Прекрасно!

Теперь добавим юзеров - в 80 коннектов
1000-1300тпс. Наверно нелпохо. Т.к. всё очень скачет

Самое важное - попробуем теперь каждый раз создавать новый коннект!
tps = 598.120886 (including connections establishing)
tps = 1282.184457 (excluding connections establishing)

В целом неплохо. Как раз результат такой же, только коннекты теперь в приложении можно открывать/закрывать как новые. Плохо только что статистика показывает большой статус по простаиванию.

Попробуем 200 коннектов!
latency average: 197.485 ms
tps = 1004.205619 (including connections establishing)
tps = 1011.058380 (excluding connections establishing)

И это прекрасно! Имея всего 80 коннектов максимально доступных в постгрес мы можем обслуживать и 200 клиентов!
С установлением нового коннекта
latency average: 352.464 ms
tps = 562.867521 (including connections establishing)
tps = 1095.836196 (excluding connections establishing)

Подготовим инфу для селект запросов для дальнейшего теста веб приложения.
400-600 селектов через баунсер в один поток

1700-1800 селектов через баунсер в 50 потоков
latency average: 26.319 ms
tps = 1829.153870 (including connections establishing)
tps = 1838.549638 (excluding connections establishing)

среда, 27 января 2016 г.

symfony2, yii2 и теперь rails. Часть 3.

Сейчас после установки назад php-5.6 (чтобы работал blackfire) и возврата симфонии к дефолтной конфигурации (вернул доктрину и твиг) имеем следующий итог. Запомним эти цифры для дальнейших исследований.

symfony2
Concurrency Level:      50
Time taken for tests:   27.298 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4050000 bytes
HTML transferred:       1970000 bytes
Requests per second:    366.33 [#/sec] (mean)
Time per request:       136.488 [ms] (mean)
Time per request:       2.730 [ms] (mean, across all concurrent requests)
Transfer rate:          144.89 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0      10
Processing:    17  136   6.5    136     161
Waiting:       17  136   6.5    136     161
Total:         17  136   6.5    136     161

Percentage of the requests served within a certain time (ms)
  50%    136
  66%    138
  75%    139
  80%    140
  90%    143
  95%    145
  98%    148
  99%    150
 100%    161 (longest request)


yii2
Concurrency Level:      50
Time taken for tests:   7.543 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3350000 bytes
HTML transferred:       1990000 bytes
Requests per second:    1325.71 [#/sec] (mean)
Time per request:       37.716 [ms] (mean)
Time per request:       0.754 [ms] (mean, across all concurrent requests)
Transfer rate:          433.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     7   37   2.5     37      47
Waiting:        7   37   2.5     37      47
Total:          8   38   2.5     37      48

Percentage of the requests served within a certain time (ms)
  50%     37
  66%     38
  75%     38
  80%     39
  90%     41
  95%     43
  98%     44
  99%     45
 100%     48 (longest request)


И встречаем нового игрока - rails!
Concurrency Level:      50
Time taken for tests:   6.809 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      6230000 bytes
HTML transferred:       1400000 bytes
Requests per second:    1468.59 [#/sec] (mean)
Time per request:       34.046 [ms] (mean)
Time per request:       0.681 [ms] (mean, across all concurrent requests)
Transfer rate:          893.49 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       2
Processing:    12   34   2.7     33      57
Waiting:       12   34   2.6     33      52
Total:         12   34   2.7     34      57

Percentage of the requests served within a certain time (ms)
  50%     34
  66%     35
  75%     35
  80%     36
  90%     37
  95%     39
  98%     41
  99%     43
 100%     57 (longest request)

Явный победитель! - rails

Конечно вся эта синтетика - далека от реальностей. Но чем легко обёртка для задач - тем лучше. Следующий этап - подключим базу данных (постгрес + баунсер) и посмотрим как изменится время обработки запроса.

суббота, 23 января 2016 г.

Бенчмарк symfony3 vs yii2. Часть 2. php7

Выяснив с помощью blackfire, что большую часть времени занимает подключение файлов, попробуем всё тоже самое на php7, тем более - он сильно оптимизирован. Аж в 2 раза!

Протестим скорости в один поток для начала
ab -n 10000 %url%
Symfony3
Concurrency Level:      1
Time taken for tests:   53.361 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4140000 bytes
HTML transferred:       1970000 bytes
Requests per second:    187.40 [#/sec] (mean)
Time per request:       5.336 [ms] (mean)
Time per request:       5.336 [ms] (mean, across all concurrent requests)
Transfer rate:          75.77 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    3  47.5      0    1001
Processing:     2    3   0.2      3       9
Waiting:        2    3   0.2      3       9
Total:          3    5  47.6      3    1004

Percentage of the requests served within a certain time (ms)
  50%      3
  66%      3
  75%      3
  80%      3
  90%      3
  95%      3
  98%      3
  99%      3
 100%   1004 (longest request)


Результаты yii2:
Concurrency Level:      1
Time taken for tests:   21.935 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3440000 bytes
HTML transferred:       1990000 bytes
Requests per second:    455.88 [#/sec] (mean)
Time per request:       2.194 [ms] (mean)
Time per request:       2.194 [ms] (mean, across all concurrent requests)
Transfer rate:          153.15 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1  17.3      0    1000
Processing:     1    2   0.1      2       3
Waiting:        1    2   0.1      2       3
Total:          2    2  17.3      2    1002

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      2
  95%      2
  98%      2
  99%      2
 100%   1002 (longest request)


Теперь нагрузим в 50 потоков
Симфони:
Concurrency Level:      50
Time taken for tests:   9.383 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4140000 bytes
HTML transferred:       1970000 bytes
Requests per second:    1065.72 [#/sec] (mean)
Time per request:       46.917 [ms] (mean)
Time per request:       0.938 [ms] (mean, across all concurrent requests)
Transfer rate:          430.87 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     5   47   3.4     46      70
Waiting:        5   47   3.4     46      70
Total:          6   47   3.4     46      70

Percentage of the requests served within a certain time (ms)
  50%     46
  66%     47
  75%     47
  80%     48
  90%     50
  95%     55
  98%     57
  99%     57
 100%     70 (longest request)

Тоже для yii
Concurrency Level:      50
Time taken for tests:   3.116 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3440000 bytes
HTML transferred:       1990000 bytes
Requests per second:    3209.72 [#/sec] (mean)
Time per request:       15.578 [ms] (mean)
Time per request:       0.312 [ms] (mean, across all concurrent requests)
Transfer rate:          1078.27 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       2
Processing:     4   15   1.9     15      35
Waiting:        4   15   1.9     15      35
Total:          4   16   1.9     15      35

Percentage of the requests served within a certain time (ms)
  50%     15
  66%     15
  75%     16
  80%     16
  90%     16
  95%     17
  98%     23
  99%     27
 100%     35 (longest request)


Получаем что при хорошей такой нагрузке php7 даёт такие результаты
Симфони 5.6,   23.8 с на всё время теста и 120мс на 1 запрос
Симфони 7       9.3 с, 47мс
Yii 5.6                7.7с, 38мс
Yii 7                   3.2с, 15мс

Уии на php5 быстрее симфони3 на php7. (на php7 немного другой набор расширений)
По потребляемой памят
С5.6 - 2486184
С7    - 1955816
У5.6 - 950000
У7    - 1073216

Но всё это - чистая синтетика - простое echo. Надо сравнить с примером, когда будет запрос в базу или другой сервис (кэш). Продолжение следует

среда, 20 января 2016 г.

Бенчмарк symfony3 vs yii2. Часть 1

Создадим дефолтное приложение которое выводит случайное число от 10 до 99 (чтобы создать динамику и исключить влияние кэша)

https://github.com/phan7om/s3bench
https://github.com/phan7om/yii2bench

Тестировать будем с помощью ab

Дефолтная конфигурация - php.ini (prod), nginx (c дефолтными настройками), php-fpm (дефолт). Композер установленный через install без оптимизаций.

ab -n1000 http://192.168.1.101/
Concurrency Level:      1
Time taken for tests:   7.607 seconds
Complete requests:      1000
Failed requests:        907
   (Connect: 0, Receive: 0, Length: 907, Exceptions: 0)
Total transferred:      387916 bytes
HTML transferred:       170916 bytes
Requests per second:    131.46 [#/sec] (mean)
Time per request:       7.607 [ms] (mean)
Time per request:       7.607 [ms] (mean, across all concurrent requests)
Transfer rate:          49.80 [Kbytes/sec] received

Всё хорошо. Сразу в 50 потоков попробуем и подольше
ab -c50 -n10000 http://192.168.1.101/

Concurrency Level:      50
Time taken for tests:   25.756 seconds
Complete requests:      10000
Failed requests:        965
   (Connect: 0, Receive: 0, Length: 965, Exceptions: 0)
Total transferred:      3879215 bytes
HTML transferred:       1709215 bytes
Requests per second:    388.26 [#/sec] (mean)
Time per request:       128.779 [ms] (mean)
Time per request:       2.576 [ms] (mean, across all concurrent requests)
Transfer rate:          147.09 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       7
Processing:    10  128   6.4    128     160
Waiting:       10  128   6.4    128     160
Total:         10  128   6.4    128     163

Percentage of the requests served within a certain time (ms)
  50%    128
  66%    130
  75%    131
  80%    132
  90%    134
  95%    137
  98%    140
  99%    142
 100%    163 (longest request)

nginx содержит настройку worker_processes auto; поэтому число воркеров было дефолтным - 4 (по процессу на ядро)

Оптимизируем композер, чтобы проверить влияние.
SYMFONY_ENV=prod composer install --no-dev --optimize-autloader

Concurrency Level:      50
Time taken for tests:   25.224 seconds
Complete requests:      10000
Failed requests:        989
   (Connect: 0, Receive: 0, Length: 989, Exceptions: 0)
Total transferred:      3879149 bytes
HTML transferred:       1709149 bytes
Requests per second:    396.45 [#/sec] (mean)
Time per request:       126.118 [ms] (mean)
Time per request:       2.522 [ms] (mean, across all concurrent requests)
Transfer rate:          150.19 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       7
Processing:     9  126   6.4    126     158
Waiting:        9  126   6.4    125     158
Total:         10  126   6.4    126     158

Percentage of the requests served within a certain time (ms)
  50%    126
  66%    127
  75%    128
  80%    129
  90%    131
  95%    134
  98%    138
  99%    140
 100%    158 (longest request)

Оптимизация композера не сильно помогла. Может правда стали меньше памяти потреблять.

AppCache
Concurrency Level:      50
Time taken for tests:   27.139 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3880000 bytes
HTML transferred:       1710000 bytes
Requests per second:    368.48 [#/sec] (mean)
Time per request:       135.694 [ms] (mean)
Time per request:       2.714 [ms] (mean, across all concurrent requests)
Transfer rate:          139.62 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0      10
Processing:    10  135   7.3    135     169
Waiting:       10  135   7.3    135     169
Total:         10  135   7.3    135     170

Percentage of the requests served within a certain time (ms)
  50%    135
  66%    136
  75%    138
  80%    138
  90%    142
  95%    145
  98%    150
  99%    158
 100%    170 (longest request)

Стало только хуже. Вывод - без этой обёртки работает быстрее! По крайней мере на простых запросах.

Заюзаем роутинг симфони и будем учитывать эти параметры при расчете
Также выведем потребляемую память. Получим такие цифры
Document Path:          /random/10/99
Document Length:        197 bytes

Concurrency Level:      50
Time taken for tests:   25.613 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4140000 bytes
HTML transferred:       1970000 bytes
Requests per second:    390.42 [#/sec] (mean)
Time per request:       128.066 [ms] (mean)
Time per request:       2.561 [ms] (mean, across all concurrent requests)
Transfer rate:          157.85 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       7
Processing:     9  127   7.8    127     158
Waiting:        9  127   7.8    127     158
Total:         10  128   7.8    127     158

Percentage of the requests served within a certain time (ms)
  50%    127
  66%    129
  75%    130
  80%    131
  90%    135
  95%    139
  98%    150
  99%    156
 100%    158 (longest request)

Используемая память - Memory usage: 2628064

Выкидываем твиг и доктрину. Memory usage: 2486184
Идёт ускорение
Concurrency Level:      50
Time taken for tests:   21.727 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4140000 bytes
HTML transferred:       1970000 bytes
Requests per second:    460.25 [#/sec] (mean)
Time per request:       108.636 [ms] (mean)
Time per request:       2.173 [ms] (mean, across all concurrent requests)
Transfer rate:          186.08 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     7  108   6.7    108     136
Waiting:        7  108   6.7    108     136
Total:          8  108   6.7    108     136

Percentage of the requests served within a certain time (ms)
  50%    108
  66%    110
  75%    111
  80%    111
  90%    114
  95%    118
  98%    131
  99%    132
 100%    136 (longest request)


Итак. Встречайте yii2
Concurrency Level:      50
Time taken for tests:   7.708 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      3440000 bytes
HTML transferred:       1990000 bytes
Requests per second:    1297.32 [#/sec] (mean)
Time per request:       38.541 [ms] (mean)
Time per request:       0.771 [ms] (mean, across all concurrent requests)
Transfer rate:          435.82 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     5   38   2.2     38      48
Waiting:        5   38   2.2     38      48
Total:          5   38   2.2     38      48

Percentage of the requests served within a certain time (ms)
  50%     38
  66%     39
  75%     39
  80%     39
  90%     41
  95%     43
  98%     44
  99%     45
 100%     48 (longest request)

Усилим оптимизацию. Внесём правки в php.ini
realpath_cache_size = 4096k


А также следующие команды
SYMFONY_ENV=prod composer install --no-dev --optimize-autoloader
SYMFONY_ENV=prod composer dump-autoload --optimize
php bin/console cache:clear -e=prod --no-debug

И в итоге получим
Concurrency Level:      50
Time taken for tests:   23.838 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      4140000 bytes
HTML transferred:       1970000 bytes
Requests per second:    419.49 [#/sec] (mean)
Time per request:       119.191 [ms] (mean)
Time per request:       2.384 [ms] (mean, across all concurrent requests)
Transfer rate:          169.60 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     9  119   7.1    118     150
Waiting:        9  119   7.1    118     150
Total:         10  119   7.0    118     150

Percentage of the requests served within a certain time (ms)
  50%    118
  66%    120
  75%    121
  80%    122
  90%    124
  95%    128
  98%    139
  99%    146
 100%    150 (longest request)

Уже быстрее. Но всё же не настолько. Если смотреть на профилировщик, то окажется что основное, чем занят symfony2 - это подгрузка файлов (классов) - их намного больше чем в yii2.

Как бы 1000 запросов в 50 потоков обрабатываются 23 секунды или 8 - есть разница.

воскресенье, 10 января 2016 г.

postgres бенчмарки. часть 3. железо

Т.к. постгрес каждый запрос выполняем на отдельном цпу (без распараллеливания) то очень важно для системы, работающей с постгрес, чтобы эффективность каждого ядра + работа с памятью была максимальной.

Есть хороший бенчмарк, написанный для этих целей - http://github.com/gregs1104/stream-scaling

Чтобы бенчмарк был более достверный - надо отключить пониженное энергопотребление процессора и динамическую частоту.

На системе с Intel(R) Core(TM) i3-4030U CPU @ 1.90GHz - 4 ядра:

Function    Best Rate MB/s  Avg time     Min time     Max time
Copy:           11128.2     0.015148     0.014378     0.016843
Scale:           9838.3     0.017435     0.016263     0.022605
Add:             9520.8     0.026703     0.025208     0.031915
Triad:           8808.9     0.028463     0.027245     0.029689

Number of Threads requested = 2
Function    Best Rate MB/s  Avg time     Min time     Max time
Triad:          10690.4     0.026216     0.022450     0.030911

Number of Threads requested = 3
Function    Best Rate MB/s  Avg time     Min time     Max time
Triad:           9466.7     0.026791     0.025352     0.030185

Number of Threads requested = 4
Function    Best Rate MB/s  Avg time     Min time     Max time
Triad:          10119.8     0.024579     0.023716     0.027354



Вот данные с системы на которой основные бенчмарки проверяются:

Intel(R) Core(TM) i5 CPU         750  @ 2.67GHz
Function    Best Rate MB/s  Avg time     Min time     Max time
Copy:            6894.2     0.037242     0.036641     0.038797
Scale:           8803.7     0.028890     0.028694     0.029372
Add:             8344.5     0.045766     0.045409     0.047154
Triad:           7644.4     0.050011     0.049568     0.052200

Number of Threads requested = 2
Function    Best Rate MB/s  Avg time     Min time     Max time
Triad:           8180.4     0.047172     0.046320     0.049512

Number of Threads requested = 3
Function    Best Rate MB/s  Avg time     Min time     Max time
Triad:           7354.3     0.055346     0.051523     0.060877

Number of Threads requested = 4
Function    Best Rate MB/s  Avg time     Min time     Max time
Triad:           7282.7     0.054480     0.052030     0.059323



Современные системы работают с памятью лучше.


В первом случае частота памяти 1600 MHz, во втором - 1333 MHz


Диски
Т.к. постгрес работает с блоками по 8кб - замерим работу диск с данными, которые вдвое превышают оперативу
blocks = 250,000 * (gigabytes of RAM) = 1750000  (для 7gb)
time sh -c "dd if=/dev/zero of=bigfile bs=8k count=1750000 && sync"
time dd if=bigfile of=/dev/null bs=8k

hdd
time sh -c "dd if=/dev/zero of=bigfile bs=8k count=1750000 && sync"
1750000+0 записей получено
1750000+0 записей отправлено
скопировано 14336000000 байт (14 GB), 254,593 c, 56,3 MB/c

real 4m29.297s
user 0m0.284s
sys 0m10.948s

На чтение
time dd if=bigfile of=/dev/null bs=8k
1750000+0 записей получено
1750000+0 записей отправлено
скопировано 14336000000 байт (14 GB), 262,622 c, 54,6 MB/c

real 4m22.634s
user 0m0.592s
sys 0m15.396s

sudo hdparm -tT /dev/sda
/dev/sda:
 Timing cached reads:   19278 MB in  2.00 seconds = 9647.50 MB/sec
 Timing buffered disk reads: 272 MB in  3.01 seconds =  90.22 MB/sec

Скорость памяти можно измерять с помощью memtest86+

postgres бенчмарки. часть 2

Создадим таблицу помощнее
pgbench -i -s 30 -h 192.168.1.103 -U postgres tmp

На этот раз она занимает 456М

И пройдёмся теми же тестами
110тпс для одного клиента

pgbench -c 80 -U postgres -T 30 -h 192.168.1.103 tmp
При 80 клиентах получается 320тпс

Уже заметна нагрузка на базу в лице checkpoint process - база нахватывается транзакций, исполняет их и сохраняет, создавая нагрузку на диск. (в конце статьи поборем эту беду)

Локально получалось и до 420тпс разгонять. Возможно было удачное попадание в чекпойнт.

Таблица таже. Попробуем добавить --foreign-keys
300-320 tps

И без них или чуть хуже (?) или столько же

 -j 4 - в 4 потока. В пределах погрешности - 427
pgbench -c 80 -j4 -U postgres -T 30 -h 192.168.1.103 tmp
scaling factor: 30
query mode: simple
number of clients: 80
number of threads: 4
duration: 30 s
number of transactions actually processed: 12812
latency average: 187.324 ms
tps = 425.185222 (including connections establishing)
tps = 427.432431 (excluding connections establishing)


Если делать в одного клиента - нагрузка на сеть получается равномерной
Нашел интересную вещь - протокол

Теперь нужна нормальная (большая база) для тестов похожи на среднюю нагрузку
pgbench -i -s 200 -h 192.168.1.103 -U postgres tmp

Это база на 3гб
Классический тест
pgbench -c 80 -U postgres -T 30 -h 192.168.1.103 tmp
Делает большой разброс от 180 до 280 тпс.

В один коннект
93тпс. Видно что нагрузка просела.

Протестим увеличение work_mem
Непонятно. Всё также
200-270тпс

Самое время увеличить shared_buffers. 2гб в самый раз!
И сразу 200-290тпс

Всё упирается в чекпойнты. С 3 поднимем до 10
И сразу 290-337. Т.е. когда часто идёт запись есть смысл увеличивать число сегментов.

А теперь всё увеличим!
500! 500! Карл!
Повторно - 300.
Соло - 113-115 что несколько выше

Если при тестах видно что упирается всё в сегменты, то надо увеличивать число. При этом логи постгреса сами подскажут что нужно это число увеличить! Грепайте по HINT
После увеличения сегментов много пользовательский тест показал
pgbench -c 100 -U postgres -T 30 -h 192.168.1.103 tmp
starting vacuum...end.
transaction type: TPC-B (sort of)
scaling factor: 200
query mode: simple
number of clients: 100
number of threads: 1
duration: 30 s
number of transactions actually processed: 48504
latency average: 61.851 ms
tps = 1597.936361 (including connections establishing)
tps = 1638.000089 (excluding connections establishing)

Огонь!

Проверим только селекты
pgbench -S -c 100 -U postgres -T 30 -h 192.168.1.103 tmp
starting vacuum...end.
transaction type: SELECT only
scaling factor: 200
query mode: simple
number of clients: 100
number of threads: 1
duration: 30 s
number of transactions actually processed: 93766
latency average: 31.995 ms
tps = 3100.100112 (including connections establishing)
tps = 3179.048805 (excluding connections establishing)

Это при 100 клиентах. Для одного клиента нам тоже важно
 pgbench -S -U postgres -T 30 -h 192.168.1.103 tmp
starting vacuum...end.
transaction type: SELECT only
scaling factor: 200
query mode: simple
number of clients: 1
number of threads: 1
duration: 30 s
number of transactions actually processed: 48013
latency average: 0.625 ms
tps = 1600.395937 (including connections establishing)
tps = 1600.801624 (excluding connections establishing)

1600 записей можно читать для одного клиента

суббота, 2 января 2016 г.

postgres бенчмарки. часть 1

Начинаем с установки на систему - Ubuntu-15.10 - десктоп эдишн 64.
Устанавливаем все обновления.
Измеряем начальные настройки postgresql-9.4
Коротко о железе - диск hdd, 8gb ram, i5-750 цпу.

Измерять будет с удаленного ноутбука по сети.
shared_buffers = 8MB
work_mem = 4MB

Инициализируем БД
pgbench -i -s 10 -h 192.168.1.103 -U postgres tmp

Размер базы 166мб

Тестим через wifi
pgbench -U postgres -T 10 -h 192.168.1.103 tmp


scaling factor: 10
query mode: simple
number of clients: 1
number of threads: 1
duration: 10 s
number of transactions actually processed: 555
latency average: 18.018 ms

Итог: 53-55  tps

Тестим локально:
112 tps

Тестим через 10mb ethernet
110tps
Вывод - соединение с сервером решает. Надо тестить через эзернет.

Если будем создавать новый коннект на каждое соединение - то будет всё плохо
tps = 39.143242 (including connections establishing)
tps = 72.343396 (excluding connections establishing)

Поставим число клиентов в 2   -c 2
tps = 115.960384 (including connections establishing)
tps = 116.221777 (excluding connections establishing)

Переходим на T 20
Если клиентов 8, то
transaction type: TPC-B (sort of)
scaling factor: 10
query mode: simple
number of clients: 8
number of threads: 1
duration: 20 s
number of transactions actually processed: 4877
latency average: 32.807 ms
tps = 243.586452 (including connections establishing)
tps = 244.582132 (excluding connections establishing)

При 16 коннектах 300-310 tps. Локально 400
При 32 коннектах 360.

pgbench -c 64 -U postgres -T 20 -h 192.168.1.103 tmp
tps = 365.203169 (including connections establishing)
tps = 377.551772 (excluding connections establishing)

Много соединений и процессов. Загружаются все ядра
Финальный длинный тест
 pgbench -c 100 -U postgres -T 60 -h 192.168.1.103 tmp
starting vacuum...end.
transaction type: TPC-B (sort of)
scaling factor: 10
query mode: simple
number of clients: 100
number of threads: 1
duration: 60 s
number of transactions actually processed: 22175
latency average: 270.575 ms
tps = 357.247713 (including connections establishing)
tps = 363.024830 (excluding connections establishing)

Бывает, разгоняется до 400.
При этом странно, что сеть держится непостоянно - идёт ровно и сбрасывается.

Пока на этих цифрах можно остановиться

Вообще есть теоритеческий предел. Один клиент может при обороте диска 7200 rpm сделать... 7200/60 = 120 оборотов диска в секунду
Т.к. каждый инсёрт сопровождается сбросом то в самых идеальных условиях максимум, что может показать  система - это 120 tps.

Если много клиентов одновременно пишут, то обращение к диску может содержать сброс нескольких транзакций и tps вырастет. Что и было показано выше. Вот почему ssd значительно повышает tps вставок.