Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126260 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 137A51A00BC for ; Fri, 31 Jan 2025 15:30:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1738337253; bh=1a0oDJ0Y3uQ1uP55Et/VhUwZk9ZfL0t+Is++8oHZlc0=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=P8ppiCtwJHCsWgqHKITHoE0bgrsFWDGFhZoHo+8ZOS/3O8lizTD42TujmgOzYjyRb g/Kxsl8IkWtF0I6uFdqWUvUasvaVl51X5DDPVTeIV9r30w9WrriJFHzeP6xVnxtssF reZK+LOAO0yyFig+6hc2Oq+cbBPsYzpaOFvvhR+nqx/MHMM8uxXYRifmZzl9Y/pSzW f3EgwOUaCzOV6x6+T40SvejkIS+UtmJQ7c5bvdn0Qefe6zY48Nk+AS1op3ajJSjCKN 1SHfCm70lcYyPYK1KB+CX8FRm5eORRALEOHx7WYGW1bX6YriHeN62l4J4zlK30Zx6j dQVoc9Y6E5+KA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 6F73418007E for ; Fri, 31 Jan 2025 15:27:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: * X-Spam-Status: No, score=2.0 required=5.0 tests=BAYES_50,DMARC_NONE, FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-oa1-f45.google.com (mail-oa1-f45.google.com [209.85.160.45]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 31 Jan 2025 15:27:32 +0000 (UTC) Received: by mail-oa1-f45.google.com with SMTP id 586e51a60fabf-29fe83208a4so1048416fac.0 for ; Fri, 31 Jan 2025 07:30:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738337419; x=1738942219; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=1a0oDJ0Y3uQ1uP55Et/VhUwZk9ZfL0t+Is++8oHZlc0=; b=rX9LdiYgHaLjhf+5E7jd4QH1xZ5z3n2doMmdHz1tOkEE++3Ky9DLovmp9fAS9AcxQ0 qmoyO8hbpYUNBRGMuKAvvb+Eg+fOYyAuRt/IIaJh21NBfeXfx+4s6IhBYARTr/Lh3Y9N DjTLHKzgb39eiv6V6EY1xT9n/mCSeEjXcfmgshEsksqT+lBm0btpdMBoUBI3SAPLrZVh hplb3H76P+lcCKRTnMlyDTKvQEGtY33dImjeD+ZLkBUuOAvOV6NUyK3Q3xd9fsYjCadv HmFpz+krG2hM7CQNMbb89EhYeFORD/NVtAj2QgJFXPpcnc7w/u2ykcZ5ol6S9Q8HDtmG DtLA== X-Gm-Message-State: AOJu0YyZSAfRgiCf0LqY3YR+qmSAInanRt9H1A/Y9Q+BfTFlod68Myi1 PPV3AkewLUlt3+MPHnL0WyvcFSukQuVIFbFhgTxCZKIggSgw2IbxVh46gSg+qUJkCYE2CzYSUvV gTguuLI2lYJRtA2EojT53rvyFT+d5ECof X-Gm-Gg: ASbGncu31bS3f3JMw9aR3ZugGiOM1a6mi5UF0FQEeNJb2V3SSfsdDuGnc+uI4+n8q8s TNQrvi0zxLTx94Nb2GfHwKVJc8cSDTQxBMHuDTjbKaO5B/qQfDecf31RjvSGAas2GmM+yv46M X-Google-Smtp-Source: AGHT+IEEyPvMj9hG2jEoIlZVCCNZOn9L8EIpGXIb72G/Y6OJ4qZvZXksTENwQyoIAdtSvdOwdAzJwu2+q79xntIgUBc= X-Received: by 2002:a05:6871:4f08:b0:2a7:5ce8:820f with SMTP id 586e51a60fabf-2b34ff203admr5468682fac.9.1738337418871; Fri, 31 Jan 2025 07:30:18 -0800 (PST) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Fri, 31 Jan 2025 16:30:07 +0100 X-Gm-Features: AWEUYZn9nPvZdaA9IkiSsDTezAyVyuGm1PiI-KTEpt2eC0f2sZxImgjaYVuzOpc Message-ID: Subject: Re: [PHP-DEV] [RFC] Introducing pm.max_memory for PHP-FPM To: Arkadiy Kulev Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000005a0f9f062d0238e1" From: bukka@php.net (Jakub Zelenka) --0000000000005a0f9f062d0238e1 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Jan 31, 2025 at 4:06=E2=80=AFPM Arkadiy Kulev wr= ote: > Hi! > > >> This wouldn't really work because FPM does not control the script during >>>> execution and would have to check it out after each allocation which i= s not >>>> really viable. >>>> >>> >>>> >>> Thanks for the feedback! I agree that monitoring memory usage after eac= h >>> allocation would be infeasible. However, my suggestion was actually to >>> check memory usage *only once per request*, specifically at request >>> shutdown, when FPM regains control and before assigning another request= to >>> that worker. >>> >> >>> >> I think that would require a different name because it would not reflect >> max memory usage in any way - it would be measured at the time when the >> memory usage is lowest. We could maybe set some options that would measu= re >> the maximum of increase of memory between requests - I mean difference >> between lowest memory usage (most likely after the first request) and th= en >> compare against current usage after the latest request and set limit on >> this difference. Not sure about the name for that. Maybe something like >> pm.max_memory_increase or something like that. >> > > I see where you=E2=80=99re coming from, but I believe measuring memory = =E2=80=9Cdelta=E2=80=9D or > =E2=80=9Cincrease=E2=80=9D could be confusing for end users. In practice,= admins and > developers often glance at tools like top or ps to see *current* memory > usage for each FPM worker, spot outliers, and then set a threshold > accordingly. > > If we start talking about =E2=80=9Clowest usage=E2=80=9D vs. =E2=80=9Ccur= rent usage=E2=80=9D and a =E2=80=9Cmax > increase,=E2=80=9D that becomes much harder to translate to real-world > monitoring=E2=80=94and it=E2=80=99s non-intuitive compared to simply read= ing the value > right off top and setting a limit. So, from a usability standpoint, I > think a direct measurement of resident memory (as people see in common > system tools) would be the most straightforward and least confusing. > It's probably less confusing than setting pm.max_memory to some value and then see that the process allocates much more. We could potentially call it pm.max_idle_memory or something that clearly shows that it's not a total max memory. > Just to be clear, "memory_limit" helps kill runaway scripts mid-request. >>> By contrast, the newly proposed pm.max_memory is meant to catch process= es >>> with a slow leak across multiple requests. We only need to check at the= end >>> of each request, which is presumably when the worker returns control to= FPM. >>> >> >> There is one thing to note that memory_limit actually measure only memor= y >> allocated through the per request php memory allocator so it's not actua= lly >> limit on total usage including the standard allocator memory usage. So >> there would be still a use case for total limit using cgroups but I agre= e >> that the more important use is to catch slow leaks which the above shoul= d >> help with in a better way than pm.max_requests. >> > > You=E2=80=99re absolutely right that cgroups handle total memory usage=E2= =80=94including > memory outside the PHP allocator=E2=80=94more accurately. But as I=E2=80= =99ve mentioned > before, relying on cgroups to limit memory typically means an OOM kill th= at > can happen at *any* moment, often right in the middle of a request. > That=E2=80=99s precisely what I=E2=80=99m trying to avoid. > The whole idea behind pm.max_memory is to allow a *graceful* check *after= * > each request completes, so we can recycle the worker before starting a ne= w > request. That way, no request gets abruptly killed. cgroups don=E2=80=99t= really > accommodate that scenario=E2=80=94they=E2=80=99re great for overall resou= rce control but > not for per-request, child-level recycling within FPM. > Yeah it should really be the last resort. Agreed that for this particular case, the solution above would be better. Regards, Jakub --0000000000005a0f9f062d0238e1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


On Fri, Jan 31,= 2025 at 4:06=E2=80=AFPM Arkadiy Kulev <eth@ethaniel.com> wrote:
Hi!
=C2=A0
This wouldn't really work because FPM does not control the script dur= ing execution and would have to check it out after each allocation which is= not really viable.
=
=C2=A0
=
Thanks for the feed= back! I agree that monitoring memory usage after each allocation would be i= nfeasible. However, my suggestion was actually to check memory usage onl= y once per request, specifically at request shutdown, when FPM regains = control and before assigning another request to that worker.=C2=A0=C2=A0
=C2=A0
=
=
I think that would require= a different name because it would not reflect max memory usage in any way = - it would be measured at the time when the memory usage is lowest. We coul= d maybe set some options that would measure the maximum of increase of memo= ry between requests - I mean difference between lowest memory usage (most l= ikely after the first request) and then compare against current usage after= the latest request and set limit on this difference. Not sure about the na= me for that. Maybe something like pm.max_memory_increase or something like = that.
=C2=A0
I see where = you=E2=80=99re coming from, but I believe measuring memory =E2=80=9Cdelta= =E2=80=9D or =E2=80=9Cincrease=E2=80=9D could be confusing for end users. I= n practice, admins and developers often glance at tools like=C2=A0top= =C2=A0or=C2=A0ps=C2=A0to see=C2=A0current=C2= =A0memory usage for each FPM worker, spot outliers, and then set a threshol= d accordingly.

If we start talking about =E2=80=9Clowest usage= =E2=80=9D vs. =E2=80=9Ccurrent usage=E2=80=9D and a =E2=80=9Cmax increase,= =E2=80=9D that becomes much harder to translate to real-world monitoring=E2= =80=94and it=E2=80=99s non-intuitive compared to simply reading the value r= ight off=C2=A0top=C2=A0and setting a limit. So, from a usabili= ty standpoint, I think a direct measurement of resident memory (as people s= ee in common system tools) would be the most straightforward and least conf= using.

It's probably less = confusing than setting pm.max_memory to some value and then see that the pr= ocess allocates much more. We could potentially call it pm.max_idle_memory = or something that clearly shows that it's not a total max memory.
=
=C2=A0
Just to be clear, "memory_limit" helps = kill runaway scripts mid-request. By contrast, the newly proposed pm.max_me= mory is meant to catch processes with a slow leak across multiple requests.= We only need to check at the end of each request, which is presumably when= the worker returns control to FPM.

=
There is one thing to note that memory_limit actually measure on= ly memory allocated through the per request php memory allocator so it'= s not actually limit on total usage including the standard allocator memory= usage. So there would be still a use case for total limit using cgroups bu= t I agree that the more important use is to catch slow leaks which the abov= e should help with in a better way than pm.max_requests.
<= /blockquote>

You=E2=80=99re absolutely right that cgroups handle= total memory usage=E2=80=94including memory outside the PHP allocator=E2= =80=94more accurately. But as I=E2=80=99ve mentioned before, relying on cgr= oups to limit memory typically means an OOM kill that can happen at any= moment, often right in the middle of a request. That=E2=80=99s precis= ely what I=E2=80=99m trying to avoid.

The whole idea behind pm.max= _memory is to allow a graceful check after= each request completes, so we can recycle the worker before starting a new= request. That way, no request gets abruptly killed. cgroups don=E2=80=99t = really accommodate that scenario=E2=80=94they=E2=80=99re great for overall = resource control but not for per-request, child-level recycling within FPM.= =C2=A0

Yeah it should rea= lly be the last resort. Agreed that for this particular case, the solution = above would be better.

Regards,

Jakub
--0000000000005a0f9f062d0238e1--