systemd로 시작된 서비스에 대해 구성된 모든 메모리 제한을 식별하는 방법은 무엇입니까?

systemd로 시작된 서비스에 대해 구성된 모든 메모리 제한을 식별하는 방법은 무엇입니까?

Postgres에 새로운 조정을 적용하려는 버그를 추적하고 있습니다.

정확한 오류는 다음과 같습니다.

2018-11-07 22:14:49 EST [7099]: [1-1] FATAL:  could not map anonymous shared memory: Cannot allocate memory
2018-11-07 22:14:49 EST [7099]: [2-1] HINT:  This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently 35301089280 bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.

나는 이 오류에 대해 잘 알고 있습니다. Postgres의 다양한 인스턴스를 조정하는 것은 나와 함께 일하는 엔지니어의 월별 작업입니다. 해결책은 Postgres 조정이나 shmall및 와 같은 관리 설정을 롤백하는 것입니다 ulimit.

이 경우 우리는 다른 사람이 만든 postgres 설치를 적용하고 있으며 수년간 실행하고 업그레이드하면서 몇 가지 결함이 있습니다. 이 설치는 CentOS 5 설치로 시작되었으며 현재 CentOS 7에 설치 중입니다. CentOS 5의 이전 SysV 설치에는 다음을 포함한 다양한 메모리 제한 제어가 적용되었습니다.

  • /etc/sysconfig/postgresql.d/ulimit.sh
  • /etc/sysconfig/postgresql.d/memory-cap
  • shmmax및 설정은 매우 보수적입니다.shmall
  • 구성 파일을 변경하여 의도적으로 특정 값을 강제하는 다른 공급업체 또는 시스템 관리자의 스크립트
  • /etc/sysctl.conf

CentOS 5에서 CentOS 7로 업그레이드한 이후 SysV에서 SystemD로 변경할 때 적용되는 메모리 제한에 대한 추가 제어 기능이 있는 것으로 보입니다.

예를 들어 다음과 같이 systemctl cat postgresql.service표시됩니다.

# /usr/lib/systemd/system/postgresql.service
[Unit]
Description=PostgreSQL database server
After=network.target

[Service]
Type=forking
User=postgres
Group=postgres
Environment=PGPORT=5432
Environment=PGDATA=/opt/pgsql/data
OOMScoreAdjust=-1000
LimitSTACK=16384
ExecStart=/opt/pgsql/bin/pg_ctl start -D ${PGDATA} -s -o "-p ${PGPORT}" -w -l ${PGDATA}/serverlog
ExecStop=/opt/pgsql/bin/pg_ctl stop -D ${PGDATA} -s -m fast
ExecReload=/opt/pgsql/bin/pg_ctl reload -D ${PGDATA} -s
TimeoutSec=300

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/postgresql.service.d/memory-cap.conf
#
# THIS FILE IS AUTO-GENERATED by /opt/pgsql/bin/tune.sh
# DO NOT MODIFY, it will be overwritten on next postgres startup.
# If you need to make a change, then disable the tuner:
#
# ln -s /dev/null /etc/systemd/system/postgresql.service.d/tune.conf
#

[Service]
LimitAS=12884901888
# /etc/systemd/system/postgresql.service.d/tune.conf
# /usr/lib/systemd/system/postgresql.service.d/use-system-timezone.conf
# Disable automatically setting the timezone by masking this drop-in file:
# ln -s /dev/null /etc/systemd/system/postgresql.service.d/use-system-timezone.conf
# Then you need to:
# systemctl daemon-reload
[Service]
ExecStartPre=/opt/pgsql/bin/use-system-timezone.sh

이제 실제 질문으로 돌아가겠습니다. 커널 설정, 사용자별 제한 및 서비스 구성에는 분명히 여러 계층이 있으며 각 계층은 shmmax, shmall, 및 관련 설정에 ulimit제한을 가할 수 있습니다.SystemD 서비스가 시작될 때 실제로 적용되는 제한을 구성 또는 런타임에서 어떻게 확인할 수 있습니까?

런타임에 제한이 무엇인지 확인할 수 있으면 grep파일과 스크립트 구성을 시작하여 해당 제한이 설정된 위치를 찾을 수 있습니다. 이 값을 찾으면 필요에 따라 값을 설정할 수 있습니다. SystemD 또는 내 postgres 프로세스가 서비스로 시작될 때 명백한 설정을 등록 취소하도록 하는 플래그가 있었으면 좋겠습니다.

이러한 값을 어떻게 설정해야 하는지에 만족합니다. 이러한 값을 강제하거나 재정의할 수 있는 레이어가 너무 많습니다. 어떤 구성 위치를 터치해야 하는지 알고 싶습니다.

제가 보기에는 LimitFOO값이 , sysctl -w kernel.shmfoo와 다른 SystemD 설정과 같은 상황에 처할 수도 있다는 것입니다 /etc/someconfig/serviceuser/limit.foo. 실행 중인 서비스를 조정하기 위해 올바르게 변경하고 설정할 수 있도록 실제로 사용되거나 적용되는 제한을 확인해야 합니다.

답변1

귀하의 질문에서 지적했듯이 게임에는 몇 가지 제한 사항이 있습니다.

  1. System V IPC shmallshmmax
  2. 이것RLIMIT개(종종 ulimit셸의 명령으로 설정하고 확인하므로 해당 이름으로 알 수도 있습니다.)
  3. cgroup 제한(귀하의 경우 특히 메모리 cgroup)은 최신 커널의 프로세스 그룹에 제한을 적용하는 새로운 방법입니다.

systemd는 특히 제한 및 청구를 위한 기본 메커니즘으로 cgroup을 사용하여 후자 두 가지를 관리합니다. System V IPC에 대한 약간의 제한된 지원이 있지만 실제로는 제한 사항이 아닙니다.

이 세 가지 개별 개념을 분석하고 systemd와 관련하여 각 개념의 한계를 조사하고 조정하는 방법을 살펴보겠습니다.

시스템 V 산업용 컴퓨터

systemd는 System V IPC를 약간 지원합니다(예:서비스 중단 시 IPC 정리,자체 IPC 네임스페이스에서 서비스 실행또는/tmp개별 서비스에 대한 비공개 tmpfs 설치(shm에서 지원)), 그러나 대부분의 경우 System V IPC 제한을 추가로 관리하거나 이에 대한 회계 처리를 수행하지 않습니다.

따라서 System V IPC의 제한은 완전히 관리되므로 sysctl다음 명령을 사용하여 이러한 제한을 확인할 수 있습니다.

$ sysctl kernel.shmmax kernel.shmall kernel.shmmni
kernel.shmmax = 18446744073692774399
kernel.shmall = 18446744073692774399
kernel.shmmni = 4096

로 조정하세요 sysctl -w.

systemd는 다음을 포함하므로 이러한 제한 설정에만 관여합니다.systemd-sysctl.service/etc/sysctl.conf및 에서 오는 항목을 설정하는 역할을 담당합니다 /etc/sysctl.d/*.conf. 그러나 그 이상으로 sysctl이러한 제한에 대한 직접적인 커널 정보를 제공합니다.

RLIMIT(한계)

이러한 제한은 프로세스별로 설정되고 하위 프로세스에 상속됩니다. 따라서 일반적으로 프로세스 트리 전체에서 동일하지만 반드시 그런 것은 아닙니다.

systemd를 사용하면 서비스별 설정을 통해 서비스가 시작될 때 구성된 대로 제한을 설정할 수 있습니다.

LimitSTACK=이는 귀하 LimitAS=의 질문에서 이미 언급 한 것과 같은 지시어로 구성됩니다 . RLIMIT의 전체 목록을 볼 수 있습니다.systemd 매뉴얼 페이지에서, 이는 또한 이를 친숙한 명령과 ulimit연관시킵니다 .

systemctl showsystemd에서 장치의 내부 상태를 덤프하는 이 명령을 사용하여 실행 중인 장치의 현재 제한을 확인할 수 있습니다 .

예를 들어:

$ systemctl show postgresql.service | grep ^Limit
LimitSTACK=16384
LimitSTACKSoft=16384
LimitAS=12884901888
LimitASSoft=12884901888
... (other RLIMITs omitted for terseness) ...

커널이 생각하는 한계가 무엇인지 확인할 수도 있습니다. /proc/$pid/limits(이러한 한계는 프로세스별로 적용되므로 개별 PID를 살펴봐야 한다는 점을 기억하세요.)

예를 들어:

$ cat /proc/12345/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max stack size            16384                16384                bytes     
Max address space         12884901888          12884901888          bytes     
... (other RLIMITs omitted for terseness) ...

cgroup(메모리 cgroup)

마지막으로 cgroup은 서비스 관리, 제한 제공 및 회계를 위한 systemd의 기본 메커니즘입니다.

systemd에서 사용 가능하고 지원되는 cgroup(예: CPU, 메모리, IO, 작업 등)이 많이 있지만, 이 논의에서는 메모리 cgroup에 중점을 둘 것입니다(귀하의 질문과 관련된 제한 사항이므로 SysV IPC를 살펴보았습니다). RLIMIT에도 해당 메모리 제한이 있습니다.

RLIMIT와 마찬가지로 systemctl showcgroup을 사용하여 systemd에서 제공하는 메모리 통계를 볼 수도 있습니다.

$ systemctl show postgresql.service | grep ^Memory
MemoryCurrent=631328768
MemoryAccounting=yes
MemoryLow=0
MemoryHigh=infinity
MemoryMax=infinity
MemorySwapMax=infinity
MemoryLimit=infinity
MemoryDenyWriteExecute=yes

메모리 계산이 활성화되었지만( ) 제한이 설정되지 않은 것을 볼 수 있습니다 MemoryAccounting=yes(모두 로 설정됨 inifinity). 제한 목록은 시스템 및 커널 버전에 따라 다를 수 있습니다. 이는 커널 4.20-rc0의 시스템 239이며 "낮음"이 있습니다. ", "높음", "최대", "한도" 및 교환을 위한 별도의 한도가 있습니다.

MemoryCurrent=또 다른 흥미로운 점은 이 값을 통해 서비스가 얼마나 많은 메모리를 사용하고 있는지 알 수 있다는 것입니다 . 이는 커널 cgroup 정보에서 가져오며 서비스의 메모리 사용량에 대한 최신 측정값입니다.

systemctl status서비스를 사용할 때 다음 정보 도 볼 수 있습니다 .

$ systemctl status postgresql.service
● postgresql.service - PostgreSQL database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; vendor preset: disabled)
 Main PID: 12345 (postgresql)
    Tasks: 10 (limit: 4321)
   Memory: 602M
   CGroup: /system.slice/postgresql.service
           └─12345 /usr/lib/postgresql/postgresql

보시다시피 systemd는 Memory: 602Mcgroup 정보에서 가져온 메모리 사용량( )을 보고합니다. 또한 작업 계정이 (해당 cgroup을 통해) 활성화되어 있고 4321개의 최대 작업 제한 중 10개의 작업이 현재 서비스를 사용하고 있음을 보고하는 것을 볼 수 있습니다.

상태 출력에는 서비스 이름을 딴 기본 cgroup에 대한 정보도 포함되어 있으며(각 서비스는 자체 cgroup에서 실행됨) 이를 커널에서 직접 cgroup 제한 및 계정 정보를 확인하는 데 사용할 수 있습니다.

예를 들어:

$ cd /sys/fs/cgroup/memory/system.slice/postgresql.service/
$ cat memory.limit_in_bytes 
9223372036854771712
$ cat memory.usage_in_bytes 
631328768

(숫자 9223372036854771712는 2^63 - 4096, 이 경우에는 infinity64비트 카운터입니다.)

당신은 볼 수 있습니다메모리 cgroup에 대한 커널 문서이러한 한도 및 카운터에 대한 자세한 내용입니다. 커널에는 두 가지 버전의 cgroup(cgroup-v1 및 cgroup-v2)이 있으므로 시스템에서 cgroup-v2를 사용하는 경우 시스템에서 몇 가지 중요한 차이점을 발견할 수 있습니다. systemd는 둘 다(두 가지를 모두 사용하는 하이브리드 모델도 포함) 지원하므로 systemctl쿼리 제한 및 카운터는 커널에서 활성화된 cgroup 버전에 관계없이 일관된 보기를 제공해야 합니다.

관련 정보