리눅스 공유 메모리
리눅스 공유 메모리는 아주 특별하고 중요합니다. 튜닝하는데 있어서 매우 중요한 요소이기 때문입니다. PostgreSQL 를 세팅할때에도 반드시 해줘야 하는 것이기에 정확하게 무엇인지 짚고 넘어가고자 아는 선에 적습니다.
페이지(Page)
가장 먼저 이야기할 것이 바로 페이지(Page) 입니다. 리눅스 시스템은 메모리를 가상으로 만들어 관리합니다. 웃기게도 리눅스 시스템에서 동작하는 프로그램들은 자신들이 시스템의 모든 메모리를 사용할 수 있다, 아니 그보다 더 많은 메모리를 사용할 수 있다라고 착각을 합니다. 이는 리눅스 시스템이 메모리를 가상화해서 프로그램들에게 보여주기 때문입니다.
문제는 리눅스 시스템은 가상화된 메모리들을 페이지(Page)라는 단위로 쪼개서 관리합니다. 특정 크기를 정해서 페이지단위로 나뉘어 관리를 하는데 이렇게 해야지만이 가상화를 하기에 훨씬 쉽고 운영체제를 제작하는데 손이 덜 간다고 합니다.
그런데 이 페이지는 크기를 가지고 있으며 이를 확인하는 방법은 다음과 같습니다.
1 2 |
]# getconf PAGESIZE 4096 |
단위는 bytes 여서 정확하게 4kb 가 됩니다.
이게 무척이나 중요한 것이 PostgreSQL 데이터베이스 세스템에서 Shared_Buffer 값을 계산할때에 페이지 크기를 알아야 합니다.
공유 메모리(Shared Memory)
리눅스 시스템은 놀랍게도 공유메모리(Shared Memory)를 제공합니다. 이게 정말로 뚱딴지 같은 소리인데 왜냐하면 이 공유 메모리는 프로세스간에 서로 공유하기위해서 메모리이기 때문입니다.
프로세스는 자신만의 메모리를 필요로 합니다. 그것으로 끝입니다. 하나의 프로세스가 다른 프로세스의 메모리에 자료를 가져가면 그건 잘못된 것이고 절대로 그렇게 동작하지도 않습니다. 그런데 프로세스 사이에 자료를 공유하고 싶을때 어떻게 해야 할까요?
이럴때 바로 공유 메모리를 사용합니다. 공유 메모리의 특징은 다음과 같습니다.
- 공유메모리는 최초로 공유 메모리를 만드는 프로세스에 의해서 만들어 집니다. 이렇게 만들어진 메모리는 커널이 관리해 줍니다.
- 한번 만들어진 공유 메모리 공간은 직접 삭제를 하거나 리눅스 시스템이 재부팅을 하거나 해야지만 없어집니다. 모든 프로세스가 더 이상 공유 메모리를 사용하지 않는다고 자동 삭제되는 일은 결코 없습니다.
뭔가 대단히 있어보이는 듯한데, 한마디로 정의 하면
프로세스간에 데이터를 공유하고자 할때 사용하는 메모리로 커널에 의해서 관리 되어진다.
입니다. 참 쉽조잉~
그런데, 이 공유 메모리는 아주 많이 사용되어지기 때문에 이 공유메모리 양을 얼마로 해주냐가 리눅스 튜닝의 시작입니다. 실제로 커널 파라메터에 다음과 같은게 있습니다.
1 |
kernel.shmmax = 4294967296 |
많이들 하는 튜닝입니다. 최대 공유 메모리를 얼마나 할 것인가 하는 겁니다.
공유 메모리는 최소(SHMMNI), 최대(SHMAX), 그리고 시스템을 통틀어 모든 공유 메모리 세그먼트의 총합(SHMALL) 로 구분이 되는데 이들의 최대 용량(제한 용량)은 다음과 같이 확인할 수 있습니다.
1 2 3 4 5 6 7 |
]# ipcs -lm ------ Shared Memory Limits -------- max number of segments = 4096 <--- SHMMAX max seg size (kbytes) = 67108864 max total shared memory (kbytes) = 17179869184 <---- SHMALL min seg size (bytes) = 1 |
그런데, 여기서 주의해야 할 것이 있습니다. 커널은 이값을 지정할때에 shmmax 는 ‘bytes’ 단위이고 shmall 은 ‘pages’ 단위 입니다.
1 2 3 4 5 6 7 8 9 10 11 |
]# cat /proc/sys/kernel/shmmax 68719476736 ]# cat /proc/sys/kernel/shmall 4294967296 ]# ipcs -lm ------ Shared Memory Limits -------- max number of segments = 4096 max seg size (kbytes) = 67108864 max total shared memory (kbytes) = 17179869184 min seg size (bytes) = 1 |
위에 보시면 커널에 할당된 shmall 값과 ‘ipcs -lm’ 해서 나온 값이 다릅니다. 이는 단위의 차이로 인한 것으로 커널의 shmall 값은 page 단위이기 때문에 다음과 같이 계산하면 ‘ipcs -lm’가 똑같아 집니다.
1 2 |
(4294967296 * 4096)/1024 17179869184 |
SHMMAX 값은 새로운 메모리 영역을 할당할때, 그러니까 shmget() 함수를 호출할때에 사용가능한 최대 메모리 양을 말합니다. 다시 강조하면 shmget()함수를 이용할때입니다. 이는 단일 프로세스가 공유메모리를 호출하기 위한 최대 값이라는 이야기 입니다.
SHMALL 은 시스템을 통틀어 모든 프로세스가 사용 가능한 공유메모리 양입니다.
이게 왜 중요해?
대부분 데이터베이스 시스템을 다룰때에 이 부분이 문제가 됩니다. ORACLE, PosgreSQL의 경우에 바로 이 공유 메모리 설정이 작으면 설치가 진행이 안된다거나 서버가 구동된다하더라도 오류 메시를 내보내고 오류를 내는 경우가 많습니다.
어떻게 설정해야 잘 하는 것일까? 혹은 적절한 값은 무엇인가는 어떤 시스템을 다루느냐에 따라서 달라집니다. PostgreSQL 의 경우에 Shared_buffers 값이 있는데, 이 값은 PostgreSQL에서 데이터를 캐쉬하는데 얼마의 RAM을 사용할 것인지를 지정합니다. PostgreSQL의 경우에 Subprocess 모델 기반으로 각 프로세스별 데이터를 공유하기위해서는 바로 공유메모리가 필요하고 Shared_buffers 는 결국 공유 메모리 입니다. 따라서 운영체제에서 PostgreSQL이 요구하는 Shared_buffers 메모리 값보다 적은 공유 메모리를 설정하면 PostgreSQL이 동작하지 않습니다.
PostgreSQL 의 경우에 Shared_buffers 메모리는 32GB 경우에 8GB 를 Shared_buffers 로 권장하고 있습니다. Shared_buffers 메모리는 공유메모리이고 단일 프로그램이 사용할 것이 때문에 SHMMAX 는 최소 8GB로 해야 합니다.
최대 공유메모리는 32GB-4GB 정도해서 28GB를 SHMALL로 지정해줍니다. 정리를하면
1 2 |
shmmax=8589934592 (8GB) shmall=7340032 (32-2GB/4096) |
위와같이 지정할 수 있겠습니다.
공유 메모리 사용현황
공유메모리 사용현황은 ‘ipcs -a’ 명령어를 이용해서 확인할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
]# ipcs -a ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x0052e2c1 98304 postgres 600 32955408384 37 ------ Semaphore Arrays -------- key semid owner perms nsems 0x00000000 0 root 600 1 0x00000000 32769 root 600 1 0x0052e2c1 2654210 postgres 600 17 0x0052e2c2 2686979 postgres 600 17 0x0052e2c3 2719748 postgres 600 17 0x0052e2c4 2752517 postgres 600 17 0x0052e2c5 2785286 postgres 600 17 0x0052e2c6 2818055 postgres 600 17 0x0052e2c7 2850824 postgres 600 17 0x0052e2c8 2883593 postgres 600 17 ------ Message Queues -------- key msqid owner perms used-bytes messages |