Получи случайную криптовалюту за регистрацию!

Beer::PHP 🍺

Логотип телеграм канала @beerphp — Beer::PHP 🍺 B
Логотип телеграм канала @beerphp — Beer::PHP 🍺
Адрес канала: @beerphp
Категории: Технологии , Образование
Язык: Русский
Количество подписчиков: 3.05K
Описание канала:

Здесь публикуются короткие заметки о PHP, Linux, Unit Testing, DB, OOP, etc., выдержки из статей, книг, видео, курсов и других материалов.
Теперь тебе больше не нужно перерывать тонны информации ;)
@genkovich — написать автору канала.

Рейтинги и Отзывы

3.33

3 отзыва

Оценить канал beerphp и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

1

4 звезд

0

3 звезд

1

2 звезд

1

1 звезд

0


Последние сообщения 2

2021-12-21 10:00:46 Опросник по итогам года

В преддверии нового года самое время подвести итоги и в нашем php-комьюнити. Для этого, как и в прошлом году, был составлен очень простой опросник, заполнение которого займет меньше 2 минут и 46 секунд времени

Ребята проводят опрос уже второй год и вот такие результаты были по итогам 2020.

Каждый, кто дойдёт до конца, имеет возможность принять участие в розыгрыше ништяков от партнёров опроса. Так что не ленись и заполняй опросник прямо сейчас ;)

P.S. Если этот канал был полезен, не забудь отметить, что читал его в этом году, мелочь, а мне будет приятно
1.8K viewsКирилл Сулимовский, 07:00
Открыть/Комментировать
2021-12-08 15:00:46
В Новый год — с новой профессией в IT!

Проверь свои знания на NIX Online Edu Testing

Купить подарки, поставить елку. Чего-то не хватает в праздничном списке… Точно! Подготовиться к карьере в IT!
Для этого приглашаем тебя поучаствовать в онлайн-тестировании по одной из 17-ти программ обучения. Выполни тест и узнай уровень своей подготовки.

Когда:
с 3 по 24 декабря
Где: онлайн с любого удобного тебе гаджета

Хочешь освоить самую актуальную профессию в IT? Эксперты NIX помогут тебе.

В Корпоративном центре обучения NIX есть 17 учебных программ. В зависимости от направления ты будешь учиться офлайн в Харькове или онлайн. Ты получишь базовые знания по фронтенд и бэкенд-разработке, по бизнес-анализу и в сфере облачных технологий. После обучения ты сможешь уверенно начать карьеру в IT и попробовать себя на позиции Junior-специалиста в команде NIX!

Отличный старт для нового года, правда? ;)

Теперь дело за малым — переходи по ссылке, выбирай понравившуюся программу обучения и проходи онлайн-тестирование.
1.5K viewsКирилл Сулимовский, 12:00
Открыть/Комментировать
2021-12-02 10:00:22 Настройка PHP-FPM (part 3)

Ранее мы рассмотрели 2 стратегии запуска дочерних процессов процессов и проговорили об основах работы самого fpm.

Итак третья стратегия:

Ondemand — на старте у вас есть 0 (ноль, зеро) рабочих процессов. Процессы создаются когда появляются новые запросы. Такая стратегия подойдет для проекта с низким трафиком и ограниченным ресурсом. С одной стороны у вас не будет запущено лишних процессов, с другой клиентам придётся немного подождать, пока fpm создаст для них процесс.

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

Для настройки этого режима используется 2 параметра — уже хорошо известный нам pm.max_children и pm.process_idle_timeout. Второй параметр устанавливает время через которое нужно убить ваш дочерний процесс, если тот свободен и простаивает. Маленькое значение конечно поможет вам быстро высвободить память, но если у вас есть скачки трафика, то лучше заменить стандартные 10 секунда на несколько минут, а может и несколько десятков минут.

И еще несколько полезных параметров:

Как же подобрать оптимальное значение pm.max_children в процессе использования? Для этого можно посмотреть статистику в реальном времени воспользовавшись параметром pm.status_path, который задаст адрес для просмотра страницы. Сколько процессов запущено, сколько из них находится в ожидании, а также какая длина очереди ожидающих выполнения запросов и всё что вас интересует — можно здесь найти. Данные значения можно отображать в xml, json, html, что может быть полезно в разных ситуациях (например если вы собираете данные с помощью prometeus).

Раз уж начал, то стоит и упомянуть и ping.path, в которой также можно указать адрес страницы. С её помощью можно убедиться, что FPM жив и отвечает. Вам будет отдаваться ответ с кодом 200, а контент страницы можно задать в ping.response, по умолчанию увидите pong. Почему не использовать status page? Просто потому, что этот вариант требует меньшего ресурса и его можно чаще опрашивать т.к. ему не нужно проводить дополнительных манипуляций.

Как помочь освободить память?

pm.max_requests — это максимальное количество запросов, которое обработает дочерний процесс, прежде чем будет уничтожен. Принудительное уничтожение процесса позволяет избежать ситуации в которой память дочернего процесса "разбухнет" по причине утечек (т.к процесс продолжает работу после от запроса к запросу). С другой стороны, слишком маленькое значение приведет к частым перезапускам, что приведет к потерям в производительности. По умолчанию стоит 0, но стоит с ним поиграться. Для стратегии static под большими нагрузками я бы начал со значения в 50000, ведь мы специально её выбрали, чтобы не тратить ресурсы на работу с процессами. Для dynamic и ondemand нужно выбирать меньшее значение.

request_terminate_timeout — устанавливает максимальное время выполнения дочернего процесса, прежде чем он будет уничтожен. Это позволяет избегать долгих запросов, если по какой-либо причине было изменено значение max_execution_time в настройках интерпретатора. Значение стоит установить исходя из логики обрабатываемых приложений, скажем 60s (1 минута).

Также достаточно полезным инструментом для анализа может быть slowlog.

request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slowlog-site.log

Таким образом мы указали файл, в который будет писаться журнал всех запросов, которые выполнялись дольше 5 секунд. Не забудьте — память на сервере не резиновая :)

Ну что, с циклом статей по PHP-FPM будем заканчивать. Не забывайте следить за показателями на своём серваке, анализировать и настраивать на основе именно вашей нагрузки.

#php #server #middle #source
1.3K viewsКирилл Сулимовский, 07:00
Открыть/Комментировать
2021-11-25 19:16:18 Релиз PHP 8.1, запуск PHP Foundation и истории переезда на 8.0

Для тех кто не в курсе, ребята подрубили крутой стрим в котором обсудят апдейты релиза и PHP Foundation, а также поделятся опытом и советами о том как переезжали на PHP 8.0.

Короче должно быть круто, подключайтесь!



1.6K viewsКирилл Сулимовский, 16:16
Открыть/Комментировать
2021-11-24 10:00:58 Настройка PHP-FPM (part 2)

Окей, вот мы переходим к самому интересному, по моему мнению, разделу: управление процессами.

С помощью параметра pm можно настроить стратегию запуска дочерних процессов. Всего есть 3 режима работы.

Static — гарантирует, что обработка запросов всегда доступна фиксированному количеству дочерних процессов (кол-во которых устанавливается с помощью pm.max_children). При такой схеме кол-во дочерних процессов не меняется, а значит они всегда занимают определенный объем ОЗУ и в случае пиковых нагрузок у вас могут быть сложности (клиенты будут становиться в очередь). С другой стороны — запросам не нужно ждать запуска новых процессов, а значит на это не тратятся дополнительные ресурсы, что делает static самым быстрым подходом. Такую стратегию лучше использовать когда у вас постоянная высокая нагрузка и большой объём оперативной памяти.

pm.max_children — очень важный параметр, который работает для всех трёх режимов, означает максимально возможное количество дочерних процессов, если значение будет слишком маленьким, то при возрастании нагрузки, лимит исчерпается и ваш сайт начнёт тупить, если слишком большим - исчерпается оперативная память и что-то упадёт;

Как посчитать значение pm.max_children?

Один из способов — от оперативной памяти. Безопаснее всего когда ваш fpm работает изолировано, например в контейнере, и ему выделен определенный ресурс. В противном случае высока вероятность что-то не учесть, а конкурирующие процессы будут недовольны таким положением дел.

Для этого определяем сколько памяти кушает каждый наш процесс (найдите для вашей ОС, вот пример для Ubuntu):

ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'

Например я получил, что в среднем один процесс кушает 60 МБайт. Допустим у меня на серваке всего 16 ГБайт, 8 из них уже использует БД (кеши и прочее), еще 2 другие приложения, остаётся 6. Какой-то запас необходимо оставить, итого 4 ГБ / 60 МБ = 66 процессов.

От себя рекомендую получившееся число изначально разделить еще на 2 и двигаться дальше от этой отправной точки эмпирическим путём, внимательно наблюдая за метриками сервера.

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

Помимо pm.max_children в настройке этой стратегии принимают участие еще 3 параметра:

pm.start_servers — количество процессов, запускаемых при старте PHP-FPM. Видел 2 рекомендации по подсчёту: Значение равно кол-ву ядер (но не нашел информации где это обоснованно) или 25% от pm.max_children, который считается также, как для static.

pm.min_spare_servers — минимальное количество бездействующих дочерних процессов. Чтобы новый процесс не создавался прямо в момент подключения нового клиента — PHP-FPM создаёт процессы заранее. Например на старте у нас было 10 процессов, и значение min_spare_servers мы установили равным 10. Пришел клиент и сразу подключился к одному из поднятых процессов, а в это время заботливый FPM создаёт еще один 11й процесс, чтобы бездействующих снова стало 10. Когда общее кол-во процессов упирается в pm.max_children, то новые свободные процессы не создаются (что логично). Также рекомендуют брать значение 25% от pm.max_children.

pm.max_spare_servers — максимальное количество бездействующих дочерних процессов. При падении нагрузки, PHP-FPM будет убивать лишние процессы высвобождая ресурсы. Если значение свободных процессов больше, чем pm.max_spare_servers, то главному процессу будет отправлен SIGCHLD, чтобы он сократил кол-во дочерних процессов и они всегда находились в пределе между pm.min_spare_servers и pm.max_spare_servers. Считают как 75% от pm.max_children.

Как вы уже догадались, вас ждёт 3я часть из данного цикла. Если вам есть что добавить — обязательно пишите мне лично или добавляйтесь в наш уютный чатик :)

#php #server #middle #source
1.1K viewsКирилл Сулимовский, 07:00
Открыть/Комментировать
2021-11-18 10:00:48 Настройка PHP-FPM (part 1)

Ну что, вы просто не оставили мне выбора, почти 400 , круто! Сразу оговорюсь, что материал, который здесь приведен — очень сухая и субъективная выжимка, потому как материала слишком много (и уже получилось несколько частей), но я не стал углубляться в дебри. Постарался сделать так, чтобы было понятно откуда ноги растут и куда копать, если что.

Давайте по порядку. В конфигурации нас будут интересовать 2 места:

• основной файл конфигурации /etc/php/(версия)/fpm/php-fpm.conf
• и файлы пулов /etc/php/(версия)/fpm/pool.d/

С понятием Pool вы будете сталкиваться достаточно часто. Pool – это группа процессов, выделенная для обработки запросов, поступающих на определённый порт или unix-socket. В PHP-FPM возможно настраивать (и использовать) сразу несколько пулов, для решения разных, отдельных задач.

Разделение приложений по пулам позволяет предотвратить ситуацию, когда один высоконагруженный сервис постоянно держит занятыми процессы-обработчики, не давая нормально работать другим, более лёгким приложениям

Для того чтобы создать несколько отдельных пулов, внутри директории pool.d следует создать отдельный файл под каждый пул. Сразу скажу, что настройки в этих файлах будут иметь приоритет выше, чем те, что в php.ini. По умолчанию у нас описан пул в файле www.conf. Открыв его мы сразу видим [www], это и есть наше имя пула. В зависимости от потребностей вы можете создать пул с любым именем. Например вы можете настроить отдельными пулами [backend] и [frontend]. Имя пула должно быть в самом верху в квадратных скобках.

На что следует обратить внимание, это то как проходят данные от веб-сервера к вашим php процессам. Это отражено в директиве listen:

listen = /var/run/php8-fpm.sock

По факту, таким образом в нашей операционной системе мы задаём адрес (socket или host:port) , который будет принимать FastCGI-запросы. И затем уже в нашем nginx конфиге мы указываем по какому адресу нам стоит обращаться, а следовательно какой пулл с какими настройками будет использован:

### nginx config ###

location ~ \.php$ {
...
fastcgi_pass unix:/var/run/php8-fpm.sock;
...
}

Коротко про права доступа: Чтобы кто попало не писал в наш сокет - запрещаем это делать путём указания прав доступа к нему. Для этого предназначены строчки listen.owner, listen.group и listen.mode. По умолчанию стоит группа и пользователь www-data (как у вашего веб-сервера) и права 0660, что означает, что владелец и пользователь могут читать и редактировать, а все остальные не могут делать ничего.

Помните в прошлом посте был пример про "очередь", в которой будет ожидать наш запрос, если он еще не обрабатывается каким-то процессом?

Так вот, параметр listen.backlog отвечает за размер очереди одновременно ожидающих подключений к нашему сокету. В зависимости от версии и операционной системы вы можете увидеть значение по умолчанию 511, 128, 65535, -1 (подразумевая неограниченно, но это не так) и т.д.

Какое значение установить? Зависит от задачи которую вы решаете:

Если значение слишком большое, а php-fpm не успевает обрабатывать все запросы, то nginx дождется тайм-аута и отключится, выкинув 504 ошибку.

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

Лучший метод расчета — определить размер в соответствии с QPS (query per second) у вашего production сервера, накинуть 30-50%, и убедиться, что железо справляется с таким кол-вом запросов. Тогда во время пиковой нагрузки (черная пятница/новый год) вы конечно рискуете, что некоторые из пользователей отвалятся получая 502, но не потеряете всех из-за зависшего железа.

Думаю на сегодня достаточно, в следующей части рассмотрим настройки самого Process Manager (pm), узнаем, какие стратегии лучше использовать для решения различных задач. Если у вас есть вопросы — их можно обсудить со мной и другими подписчиками в нашем чатике.

#php #server #middle #source
1.4K viewsКирилл Сулимовский, 07:00
Открыть/Комментировать
2021-11-17 13:00:26
PHP Jobs

Тем временем спешу поделиться с вами прикольным каналом, который только появился на просторах ТГ. Если вдруг вы находитесь в поиске подходящей работы, на любую позицию от Junior до CTO, то вам следует обратить внимание на канал PHP JOBS.

Подписывайтесь и получайте информацию о свежих и актуальных вакансиях по вашему профилю :)
1.4K viewsКирилл Сулимовский, 10:00
Открыть/Комментировать
2021-11-10 10:01:01 Fluent interface. Evil or not?

Ну а пока я готовлю материал по теме настройки fpm (оказалось не очень просто вместить его в небольшой и понятный пост), решил поднять довольно старую тему, о которой не так уж много сказано.

Прежде всего давайте синхронизируемся что же такое fluent interface?

Каждый из вас наверняка видел конструкцию наподобие:

$example = Example::create()->addFoo()->deleteBar()->build();

А добиться этого можно с помощью вот такого нехитрого фокуса [pic | code ]. При такой реализации мы сможем добавлять в массив строки не вызывая каждый раз переменную [pic | code ].

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

Первая проблема — подобные конструкции начинают вставлять везде, где только можно. Возьмём пример с какой-нибудь сущностью Order. Предположим у вас есть сеттеры (об этом зле у нас будет отдельный разговор, но потом. Пока предположим, что у вас они есть) setId(), setTitle(), setDescription(). Всё выглядит достаточно удобно, в сущности всего 3 метода, мы можем вызывать их цепочкой. Однако, представим, что нам нужно добавить информацию о доставке setCountry(), setCity(), setAddress().

Что мы делаем? Правильно, мы берем и просто добавляем еще 3 метода, потому что нам хочется вызывать их цепочкой. Затем мы хотим добавить инфу о получателе и добавляем еще 5 методов, инфу о скидках — еще 4 и т.д. В итоге наша сущность раздувается до нереальных размеров, данные никак не разбиты на логические (бизнесовые) куски (смотри whole objects).

К нам приходит менеджер и говорит — "Нельзя, чтобы описание товара было заполнено без тайтла, а адрес не должен быть указан без страны и города". И тут начинается веселье, в котором в сеттеры добавляются проверки, а у нашего fluent interface появляется необходимость вызывать методы в определенной очереди, которая совсем не очевидна другому разработчику. Чем больше правил — тем больше хаоса, рано или поздно кто-то таки выстрелит себе в ногу.

Второе — декорирование. Давайте представим, что мы хотим расширить наш класс Example и добавить логирование [pic | code ]. На первый взгляд всё выглядит логично, но сколько раз вызовется логгер? Один(!). А всё потому, что нашу обёртку теперь тоже нужно сделать "текучей", что тоже не сразу очевидно и часто бывает местом для багов.

Третье — их сложнее мокать. Не секрет, что мокая объект мы создаем Null Object, где все методы являются заглушками. Чтобы протестировать логику и случайно не оборвать нашу цепочку — нам придётся описывать КАЖДЫЙ метод (а напомню, что в примере с Order их больше 20) примерно такой конструкцией, даже если на самом деле его вызов ни на что не влияет в нашем тесте.

$example
->expects($this->any())
->method('addBar')
->willReturnSelf();

Если копнуть еще глубже, то можно найти проблемы с обратной совместимостью, нарушением инкапсуляции, сложностью с отслеживанием изменений, однако не всё так плохо.

Есть места, где использование данного похода достаточно хорошо себя показывает и это билдеры (в множестве их проявлений):

$queryBuilder
->select('u')
->from('User u')
->where('u.id = :identifier')
->orderBy('u.name', 'ASC')
->setParameter('identifier', 100);


Так зло или нет?!

Сам по себе данный подход ни в коем случае не является абсолютным злом, однако, прежде чем его использовать вам следует хорошо подумать:
1. Не создаёте ли вы себе дополнительных проблем?
2. В какой момент и что пошло не так, если в Entity вам нужно засэтить десяток полей?
3. Точно ли всё очевидно?

Хорошо и правильно, если данный подход вы используете с умом, там где это уместно. Тогда fluent interface действительно сделает ваш код лаконичнее, а не породит несколько мест для новых багов.

#php #junior #source
977 viewsКирилл Сулимовский, 07:01
Открыть/Комментировать
2021-10-27 09:00:27 CGI, FastCGI, php-fpm

Уверен, многие из вас видели эти аббревиатуры, но, как оказалось, не все знают, как они связаны и что обозначают. Конечно, эта тема может быть более актуальна тем, кто занимается настройкой ПО (типа DevOps), но считаю, что хотя-бы общее представление должно быть у всех, кто так или иначе занимается разработкой на PHP, потому решил поверхностно описать эти вопросы.

CGI

Common Gateway Interface
— это стандарт (протокол, спецификация, соглашение, набор правил), который описывает, как веб-сервер должен запускать скрипты (в т.ч. PHP, а также другие программы), как должен передавать им параметры HTTP-запроса и как скрипты должны передавать результаты своей работы веб-серверу. То есть CGI был разработан для того, чтобы расширить возможности веб-сервера и дать возможность создания и обработки динамического контента.

FastCGI

По факту это дальнейшее развитие технологии CGI, является более производительным и безопасным. В чем же главное отличие?
В CGI-режиме на каждый запрос создается отдельный процесс, "умирающий" после окончания обработки. В FastCGI процесс работает в качестве демона, то есть один и тот же процесс обрабатывает различные HTTP запросы один за другим. PHP из коробки умеет работать и в FastCGI режиме.

PHP-FPM

F
astCGI Process Manager — альтернативная реализация PHP FastCGI, которая позволяет вам достаточно гибко настраивать те самые процессы, о которых я писал выше.

Как это работает?

Представим, что в наше приложение одновременно приходит 50 клиентов. Сначала они обращаются в наш NGINX, который по факту пробрасывает запросы сквозь себя на PHP-FPM (за исключением запросов за статическими ресурсами/файлами), а дальше PHP-FPM пытается обработать все запросы с помощью своих процессов (воркеров).

Допустим у нас запущено 5 воркеров, как на картинке. В таком случае во время одновременного запроса первые 5 клиентов будут обрабатываться сразу, а остальные 45 становятся в очередь и ждут, когда первые 5 закончат обработку. PHP-FPM позволяет задавать настройки в зависимости от ваших потребностей, будь то динамическое увеличение воркеров для того чтобы клиенты не ждали в очереди или экономия ресурсов с целью ускорения обработки запросов со статическим кол-вом воркеров.

Если интересно более подробно почитать про настройку php-fpm, то ставь . Надеюсь стало немного понятнее и теперь никто не будет впадать в ступор при виде этих аббревиатур.

#php #server #source
1.7K viewsКирилл Сулимовский, 06:00
Открыть/Комментировать
2021-10-07 09:00:17 DRY (Don't Repeat Yourself)

Буквально сегодня сидел и смотрел на пачку похожих классов, код которых на 98,2% одинаков. Очень сильно подмывало схлопнуть это всё, но как правильно это сделать? Давайте разберемся подробнее.

Многие считают, что DRY запрещает дублировать код, но это не так. Вся суть таится немного глубже. Давайте разберемся с определением:

"Каждая часть знания должна иметь единственное, непротиворечивое и авторитетное представление в рамках системы"

Вся тайна кроется как раз в определении "часть знания". Что же это такое?

Речь идёт не о написанном коде, а о знаниях в "предметной области" или "бизнес правилах". Давайте рассмотрим пример { pic | gist }

В данном случае код выглядит одинаково, однако, это может продиктовано абсолютно разными требованиями бизнеса:

Мы ограничиваем корзину тремя единицами товара из-за высокого спроса, а нам выгодно продать его как можно большему кол-ву покупателей.
В то же время мы ограничиваем доставку тремя единицами, потому что наш транспорт физически не может вместить большего объема.

Подсознательно нам хочется взять и вынести дублирующийся код в один источник, но что если какое-то из правил изменится? Например мы купили новый транспорт для доставки и теперь можем доставлять до 10 единиц товара?

Очень важно, чтобы у вашего кода могла быть только "одна причина для изменения" (прямо как в SRP), ведь правила вашего бизнеса в одной предметной области могут (и должны) меняться независимо от другой.

Когда-то М. Фаулер популяризировал так называемое Rule of three. Звучит примерно так: "Два экземпляра аналогичного кода не требуют рефакторинга, но, когда аналогичный код используется три раза, его следует извлечь в новую процедуру." Это правило, в первую очередь, отлично помогает избежать преждевременного обобщения, когда с виду похожие вещи имеют разные зоны ответственности и потому не являются дублированием.

DRY — это принцип, однако принципы — не правила. Они лишь инструменты, помогающие идти в правильном направлении. Очевидно, что не стоит везде повторять бизнес-логику, но также не нужно и объединять всё подряд. Необходимо искать баланс, который зависит от текущей ситуации.

#php #junior #source
1.9K viewsКирилл Сулимовский, edited  06:00
Открыть/Комментировать