PHP، در ایجاد انواع برنامه‌ها دخالت دارد و جزو زبان‌هایی است که به طور گسترده در شبکه اینترنت مستقر شده است.

با این حال، زبان PHP در برخی حالات به ویژه در مورد سیستم‌های حساس به زمان، زبان کارآمدی شناخته نمی‌شود. به همین دلیل است که برای چنین کاربردهای خاص، تکنولوژی‌هایی مانند Node ،Go و Elixir ارائه شده است.

 

با این همه، بهینه‌سازی‌های زیادی وجود دارد که به منظور بهبود عملکرد PHP در سرور شما قابل اعمال است.

 

این مطلب نیز ممکن است برای شما مفید باشد: PHP چیست؟

 

در این مقاله، برروی گزینه php-fpm متمرکز شده است، که در صورت استفاده از Nginx، یک روش طبیعی برای پیکربندی در سرور شما است.

قبل از پرداختن به این روش، در ابتدا در مورد php-fpm شرح مختصری داده می‌شود.

 

php-fpm چیست؟

زمانی که مرورگر درخواستی را به یک سرور اجرا کننده PHP ارسال می‌کند، این PHP نیست که برقرار کننده ارتباط است؛ بلکه، سرور HTTP است که عمدتاً Apache یا Nginx است. این سرورهای وب هستند که باید تصمیم بگیرند كه چگونه به PHP متصل شده و نوع درخواست، داده‌ها و هدرها را به آن منتقل كنند.

این چرخه درخواست-پاسخ در تصویر زیر نشان داده شده است.

 

در برنامه‌های جدید PHP، بخش “find file” در تصویر بالا، همان index.php است و سرور بگونه‌ای پیکربندی شده است که کلیه درخواست‌ها را به آن واگذار کند.

چنانچه Apache را وب سرور انتخابی در نظر بگیریم، PHP یک ماژول داخل سرور خواهد بود؛ بدین صورت، هر زمان درخواستی دریافت شود، سرور فرآیند جدیدی را آغاز می‌کند که بصورت خودکار شامل PHP است. این روش mod_php نامیده می‌شود که اختصار عبارت “php as a module” است. این رویکرد در ابتدا دارای محدودیت‌های زیادی بود که Nginx با استفاده از php-fpm بر آن‌ها غلبه کرد.

در php-fpm، مسئولیت مدیریت PHP وابسته به فرآیندهای مربوط به برنامه PHP در سرور است. به عبارت دیگر، سرور وب (در اینجا Nginx)، اهمیتی نمی‌دهد که PHP کجاست و چگونه بارگذاری می‌شود؛ بلکه تنها برای آن مهم است که چگونه داده‌ها را برای آن ارسال کرده و یا از آن دریافت نماید.

 

چنانچه تنظیمات Nginx را انجام داده باشید، به چنین چیزی برخورد خواهید کرد:

location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

از بین کدهای بالا، خط مورد نظر ما این است:

fastcgi_pass unix:/run/php/php7.2-fpm.sock;

که در آن به Nginx گفته می‌شود، از طریق سوکتی به نام php7.2-fpm.sock با فرآیند PHP ارتباط برقرار کند. بنابراین، به ازای هر درخواست، Nginx داده‌ها را درون این فایل نوشته و با دریافت خروجی، آن را به مرورگر برمی‌گرداند.

 

براساس آنچه در این بخش بیان شد، می‌توان به طور خلاصه گفت:

  • PHP، درخواست‌های ارسال شده توسط مرورگرها را به طور مستقیم دریافت نمی‌کند؛ بلکه وب سرورهایی مانند Nginx ابتدا آن‌ها را دریافت می‌نمایند.
  • وب سرور می‌داند، چگونه به فرایند PHP متصل شده و تمام داده‌های درخواست را برای PHP  بفرستد.
  • هنگامی‌که PHP کار خود را انجام داد، پاسخ را به وب سرور ارسال کرده و سرور آن را برای کلاینت (در بیشتر موارد مرورگر) ارسال می‌نماید.

 

نحوه عملکرد PHP و Nginx در تصویر زیر آمده است:

 

بخش “FPM” در کنار PHP، مخفف عبارت “Fast Process Manager” است که وظیفه ایجاد، کنترل و توقف فرایندهای PHP را به عهده دارد. این مدیر فرآیند است که سرور وب درخواست‌ها را به آن‌ها منتقل می‌کند.

 

دلیل نیاز به بهینه‌سازی php-fpm

چنانچه php-fpm با تنظیمات شما خوب عمل می‌کند و شما نیز آن را برای موارد اختصاصی استفاده نمی‌کنید، بهتر است از تنظیمات پیش فرض استفاده نمایید. اما اگر می‌خواهید فراتر از یک دستگاه واحد عمل نماید، باید آن را بهینه‌سازی کنید.

نکته دیگری که باید بدانیم این است که Nginx برای مدیریت انتقال‌های سنگین ساخته شده است. علاوه‌براین، این قابلیت را دارد که هزاران اتصال را از طریق آن همزمان انجام دهید. با این حال، اگر بهینه‌سازی را برروی تنظیمات PHP خود اعمال نکنید، منابع خود را هدر داده‌اید؛ زیرا Nginx در هر حال باید منتظر اجرای کامل فرآیندهای PHP بماند. در نتیجه تمام مزایایی را که Nginx برای ارائه آن‌ها ساخته شده است، از دست خواهید داد.

در بخش بعدی چگونگی بهینه‌سازی php-fpm شرح داده شده است.

 

نحوه بهینه‌سازی PHP-FPM

مسیر فایل پیکربندی php-fpm ممکن است در سرورهای مختلف متفاوت باشد. بنابراین برای یافتن آن مسیر باید مقداری جستجو کنید. در UNIX می‌توانید از دستور find استفاده نمایید.

در اینجا، مسیر فایل بصورت etc/php/7.2/fpm/php-fpm.conf/ است که مربوط به نسخه  PHP 7.2 در اوبونتو است.

آنچه در چند سطر اول این فایل مشاهده می‌کنید، بدین صورت خواهد بود:

 ;;;;;;;;;;;;;;;;;;;;;
; FPM Configuration ;
;;;;;;;;;;;;;;;;;;;;;

; All relative paths in this configuration file are relative to PHP's install
; prefix (/usr). This prefix can be dynamically changed by using the
; '-p' argument from the command line.

;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;

[global]
; Pid file
; Note: the default prefix is /var
; Default Value: none
pid = /run/php/php7.2-fpm.pid

; Error log file
; If it's set to "syslog", log is sent to syslogd instead of being written
; into a local file.
; Note: the default prefix is /var
; Default Value: log/php-fpm.log
error_log = /var/log/php7.2-fpm.log

 

خط pid = /run/php/php7.2-fpm.pid می‌گوید کدام فایل شامل شناسه فرایند php-fpm است.

همچنین قابل مشاهده است که مسیر var/log/php7.2-fpm.log مکانی است که گزارش‌های php-fpm باید ذخیره شوند.

در داخل این فایل، سه متغیر دیگر به صورت زیر اضافه کنید:

emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s

دو تنظیم اول جنبه احتیاطی داشته و به فرآیند php-fpm می‌گویند که اگر ده فرآیند فرزند طی یک دقیقه شکست خورد، فرآیند اصلی php-fpm باید خودش مجدداً راه‌اندازی شود.

اگرچه این متغیر ممکن است غیر ضروری به نظر برسد؛ ولیکن بدین صورت نیست. چراکه PHP یک فرایند کوتاه مدت است که باعث نشت حافظه می‌شود؛ بنابراین راه‌اندازی مجدد فرآیند اصلی در موارد شکست‌های زیاد می‌تواند بسیاری از مشکلات را برطرف کند.

 

گزینه سوم یعنی process_control_timeout، به فرآیندهای فرزند می‌گوید؛ قبل از اجرای سیگنال دریافتی از فرآیند پدر، مدت زمانی را صبر کنند. این گزینه در مواردی مفید است که فرآیندهای فرزند در وسط کار باشند و فرآیند پدر به‌عنوان‌مثال یک سیگنال KILL ارسال می‌کند. در این صورت با گذشت ده ثانیه، آن‌ها شانس بهتری برای به پایان رساندن وظایف خود خواهند داشت.

اما این تمام چیزی نیست که برای پیکربندی php-fpm نیاز است! به این دلیل که برای ارائه درخواست‌های وب، php-fpm یک مجموعه جدید از فرآیندها ایجاد می‌کند که پیکربندی جداگانه‌ای خواهند داشت. در اینجا، نام این مجموعه www و فایل مورد نیاز برای ویرایش etc/php/7.2/fpm/pool.d/www.conf/ است.

بیایید ببینیم این فایل به چه صورت شروع می‌شود:

; Start a new pool named 'www'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('www' here)
[www]

; Per pool prefix
; It only applies on the following directives:
; - 'access.log'
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
; When not set, the global prefix (or /usr) applies instead.
; Note: This directive can also be relative to the global prefix.
; Default Value: none
;prefix = /path/to/pools/$pool

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
user = www-data
group = www-data

با نگاهی گذرا به انتهای قطعه کد بالا، این سوال پاسخ داده می‌شود که چرا فرآیند سرور به صورت www-data اجرا می‌شود.

اگر هنگام تنظیم وب سایت خود با مشکل مجوز فایل روبرو شدید، احتمالاً مالک یا گروه دایرکتوری را به www-data تغییر داده‌اید. بنابراین به فرایند PHP اجازه می‌دهید تا بتواند در فایل‌های گزارش بنویسد، اسناد را بارگذاری نماید و ... .

 

در انتها، به مدیریت فرآیند (PM) می‌رسیم. به طور کلی، پیش فرض‌های این بخش را به صورت زیر مشاهده خواهید کرد:

pm = dynamic
pm.max_children = 5
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 200

 

همانطور که در مستند زیر بیان شده است، pm می‌تواند سه مقدار بگیرد که در ادامه شرح داده‌ایم:

 ; Choose how the process manager will control the number of child processes.
; Possible Values:
;   static  - a fixed number (pm.max_children) of child processes;
;   dynamic - the number of child processes are set dynamically based on the
;             following directives. With this process management, there will be
;             always at least 1 children.
;             pm.max_children      - the maximum number of children that can
;                                    be alive at the same time.
;             pm.start_servers     - the number of children created on startup.
;             pm.min_spare_servers - the minimum number of children in 'idle'
;                                    state (waiting to process). If the number
;                                    of 'idle' processes is less than this
;                                    number then some children will be created.
;             pm.max_spare_servers - the maximum number of children in 'idle'
;                                    state (waiting to process). If the number
;                                    of 'idle' processes is greater than this
;                                    number then some children will be killed.
;  ondemand - no children are created at startup. Children will be forked when
;             new requests will connect. The following parameter are used:
;             pm.max_children           - the maximum number of children that
;                                         can be alive at the same time.
;             pm.process_idle_timeout   - The number of seconds after which
;                                         an idle process will be killed.
; Note: This value is mandatory.

 

static: تعداد مشخصی از فرایندهای PHP را تعیین می‌نماید که باید زنده نگه داشته شوند.

Dynamic: حداقل و حداکثر تعداد فرایندهای PHP را تعیین می‌نماید که باید در هر زمان زنده نگه داشته شوند.

Ondemand: فرایندها را براساس تقاضا ایجاد و تخریب می‌کند.

 

اکنون این سوال در ذهن ایجاد می‌شود که هر کدام از این حالت‌ها در چه زمانی باید استفاده شوند؟

به زبان ساده، اگر وب سایتی با ترافیک کم دارید، تنظیمات “dynamic” منجر به تلف شدن منابع می‌شود. با فرض اینکه pm.min_spare_servers را روی 3 تنظیم کرده باشید، حتی زمانی که ترافیکی در وب سایت وجود نداشته باشد، سه فرآیند PHP ایجاد و نگه داری می‌شوند. بنابراین در چنین مواردی، “ondemand” گزینه بهتری است چراکه به سیستم اجازه می‌دهد تصمیم بگیرد که چه زمانی فرایندهای جدیدی را راه‌اندازی کند.

از طرف دیگر، وب سایت‌هایی که میزان زیادی از ترافیک را کنترل می‌کنند یا باید به سرعت پاسخ دهند، “dynamic” برای آن‌ها مناسب است. چراکه ایجاد یک فرآیند جدید PHP، منجر به سربار اضافی می‌شود که به بهترین وجه از آن جلوگیری می‌شود.

استفاده از pm = static تعداد فرایندهای فرزند را بصورت دقیق مشخص می‌کند و اجازه می‌دهد حداکثر منابع سیستم به منظور پاسخ به درخواست‌ها نسبت به مدیریت PHP مورد استفاده قرار گیرند. اگر این روش را انتخاب کرده‌اید، مراقب باشید که دستورالعمل‌ها و مشکلات خاص خود را دارد که نیازمند تحقیقات بیشتری در این زمینه است.

با همه این‌ها، اگر نمی‌خواهید برای بهینه‌سازی سرورهای PHP خود وقت بگذارید، بهتر است از یک پلتفرم قابل اعتماد مانند Kinsta استفاده نمایید که از امنیت بهینه‌سازی عملکرد مراقبت می‌کند.

 

 

منبع:

geekflare