- Модификация параметров ядра Linux (семафоры)
- Шаг 1. Выполним команду ipcs -l для отображения текущих параметров параметров ядра:
- Шаг 2. Проанализируйте вывод команды, чтобы определить, нужно ли изменять параметры ядра или нет, путем сравнения текущих значений с установленными минимальными настройками в следующей таблице.
- How does limits on the shared memory work on Linux
- 2 Answers 2
- Linux — Shared Memory (SHM) (/dev/shm)
- Articles Related
- Management
- File structure
- How to check its size ?
- Limit
- Parameters
- shmmax
- segments
- Process
- top
Модификация параметров ядра Linux (семафоры)
Семафор — самый часто употребляемый метод для синхронизации потоков и для контролирования одновременного доступа множеством потоков/процессов к общей памяти.
Семафор — это объект IPC, управляющий доступом к общим ресурсам (устройствам). Семафоры не позволяют одному процессу захватить устройство до тех пор, пока с этим устройством работает другой процесс. Семафор может находиться в двух положениях: 0 (устройство занято) и 1 (устройство свободно).
Одиночный семафор используется редко, практически никогда. Для контроля доступа к ресурсам обычно используются множества семафоров, даже если это множество состоит всего из одного семафора. К примеру, допустим у нас есть три принтера. Когда мы посылаем задание на печать, диспетчер печати просматривает множество семафоров принтеров и выясняет, есть ли свободный принтер. Если да, то он начинает печатать наше задание, если же нет, диспетчер ставит задание в очередь печати.
Еще один пример использования семафоров — это счетчики ресурсов. Представим, что вместо принтера есть некий контроллер, позволяющий выполнять 100 заданий одновременно. Когда он свободен, значение семафора равно 100. По мере поступления заданий диспетчер контроллера уменьшает значение семафора на 1, а по мере их выполнения увеличивает на 1. Когда значение достигает 0, новое задание ставится в очередь до освобождения контроллера.
Оптимизируем работу ядра на серверах с большим размером ОЗУ в ситуациях повышенной сетевой и дисковой нагрузки.
В моем примере рассмотрен сервер с 128Gb ОЗУ и 10Gb подключением.
Шаг 1. Выполним команду ipcs -l для отображения текущих параметров параметров ядра:
—— Messages Limits ———
max queues system wide = 32768
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384
—— Shared Memory Limits ———
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398442373116
min seg size (bytes) = 1
—— Semaphore Limits ———
max number of arrays = 128
max semaphores per array = 250
max semaphores system wide = 32000
max ops per semop call = 32
semaphore max value = 32767
Шаг 2. Проанализируйте вывод команды, чтобы определить, нужно ли изменять параметры ядра или нет, путем сравнения текущих значений с установленными минимальными настройками в следующей таблице.
IPC kernel parameter | Enforced minimum setting |
---|---|
kernel.shmmni (SHMMNI) | 256 * (size of RAM in GB) |
kernel.shmmax (SHMMAX) | (size of RAM in bytes) |
kernel.shmall (SHMALL) | 2 * (size of RAM in the default system page size) |
kernel.sem (SEMMNI) | 256 * (size of RAM in GB) |
kernel.sem (SEMMSL) | 250 |
kernel.sem (SEMMNS) | 256 000 |
kernel.sem (SEMOPM) | 32 |
kernel.msgmni (MSGMNI) | 1 024 * (size of RAM in GB) |
kernel.msgmax (MSGMAX) | 65 536 |
kernel.msgmnb (MSGMNB) | 65 536 |
SHMALL ограничивает общий объем виртуальной совместной памяти, которая может быть выделена системе. Каждый сервер данных эффективно управляет тем объемом системной памяти, который он использует; ее называют также переданная память (committed memory). Сервер данных выделяет больше виртуальной памяти, чем ему передано, чтобы поддерживать предварительное выделение памяти и динамическое управление памятью. Предварительное выделение памяти повышает производительность. Динамическое управление памятью — это процесс увеличения и сокращения действительного использования памяти в отдельных областях виртуальной памяти совместного использования. Для поддержки предварительного выделения памяти и динамического управления памятью серверам данных часто необходимо выделять в системе больший объем виртуальной памяти совместного использования, чем физический объем оперативной памяти. Но для ядра это значение задается как число страниц.
Производительность нагрузки может увеличиться в случае большего предельного размера очереди сообщений, который задается в байтах параметром MSGMNB. Использование памяти очередью сообщений можно просмотреть, введя команду ipcs -q . Если очереди сообщений уже достигли предельного размера или близки к нему при операциях загрузки, рассмотрите возможность увеличения предельного размера очереди сообщений.
$ ipcs -l
—— Messages Limits ———
max queues system wide = 131072 // MSGMNI
max size of message (bytes) = 65536 // MSGMAX
default max size of queue (bytes) = 65536 // MSGMNB
—— Shared Memory Limits ———
max number of segments = 32768 // SHMMNI
max seg size (kbytes) = 134217728 // SHMMAX
max total shared memory (kbytes) = 524288 // SHMALL
min seg size (bytes) = 1
—— Semaphore Limits ———
max number of arrays = 32768 // SEMMNI
max semaphores per array = 250 // SEMMSL
max semaphores system wide = 8192000 // SEMMNS
max ops per semop call = 100 // SEMOPM
semaphore max value = 32767
В первом разделе, Shared Memory Limits (Предельные значения для совместно используемой памяти), предельное значение SHMMAX — это максимальный размер сегмента совместно используемой памяти в системе Linux. Предельное значение SHMALL — это максимальное выделение страниц совместно используемой памяти в системе.
Рекомендуется задать для SHMMAX значение, численно равное объему физической памяти в системе. Однако минимально необходимое в системах x86 значение равно 268435456 (256 Мбайт), а в 64-битных системах — 1073741824 (1 Гбайт).
Следующий раздел описывает количество семафоров, доступных для операционной системы. Параметр ядра sem состоит из четырех элементов: SEMMSL, SEMMNS, SEMOPM и SEMMNI. Значение SEMMNS равно произведению SEMMSL на SEMMNI. Для менеджера данных требуется соответственным образом увеличить число массивов (SEMMNI). Обычно значение SEMMNI должно быть вдвое больше максимального разрешенного числа ожидаемых в системе агентов, умноженного на число логических разделов на компьютере сервера данных плюс число соединений локальных программ с компьютером сервера данных.
Параметр MSGMNI влияет на число агентов, которые можно запустить.
Параметр MSGMAX влияет на размер сообщения, которое можно поместить в очередь, а параметр MSGMNB влияет на размер очереди.
Для параметра MSGMAX нужно задать значение 64 Кбайта (то есть 65536 байт), а значение MSGMNB нужно увеличить до 65536.
Измените параметры ядра, которые требуется изменить, отредактировав файл /etc/sysctl.d/01-kernel.conf . Если этот файл не существует, создайте его.
Ниже показаны примеры строк, которые нужно поместить в этот файл:
kernel.shmmni = 32768
kernel.shmmax = 137438953472
kernel.shmall = 131072
#kernel.sem=
kernel.sem = 250 8192000 100 32768
kernel.msgmni = 131072
kernel.msgmax = 65536
kernel.msgmnb = 65536
Для применения изменений выполните команду sysctl -p /etc/sysctl.d/01-kernel.conf .
Используемый материал
How does limits on the shared memory work on Linux
specifies the maximum amount of pages that can be allocated. Considering this number as x and the page size as p. I assume that «x * p» bytes is the limit on the system wide shared memory. Now I wrote a small program to create a shared memory segment and i attached to that shared memory segment twice as below
shm_id = shmget(IPC_PRIVATE, 4*sizeof(int), IPC_CREAT | 0666); if (shm_id < 0) < printf("shmget error\n"); exit(1); >printf("\n The shared memory created is %d",shm_id); ptr = shmat(shm_id,NULL,0); ptr_info = shmat(shm_id,NULL,0);
In the above program ptr and ptr_info were different. So the shared memory is mapped to 2 virtual addresses in my process address space. When I do an ipcs it looks like this
. 0x00000000 1638416 sun 666 16000000 2 .
Now coming to the shmall limit x * p noted above in my question. Is this limit applicable on the sum of all the virtual memory allocated for every shared memory segment? or does this limit apply on the physical memory? Physical memory is only one here (shared memory) and from the program above when I do 2 shmat ‘s there is twice the amount of memory allocated in my process address space. So this limit will hit soon if do continuous shmat ‘s on a single shared memory segment?
2 Answers 2
The limit only applies to physical memory, that is the real shared memory allocated for all segments, because shmat() just maps that allocated segment into process address space.
You can trace it in the kernel, there is only one place where this limit is checked — in the newseg() function that allocates new segments ( ns->shm_ctlall comparison). shmat() implementation is busy with a lot of stuff, but doesn’t care at all about shmall limit, so you can map one segment as many times as you want to (well, address space is also limited, but in practice you rarely care about this limit).
You can also try some test from userspace with a simple program like this one:
#define _GNU_SOURCE #include #include #include #include #include #include #include unsigned long int get_shmall() < FILE *f = NULL; char buf[512]; unsigned long int value = 0; if ((f = fopen("/proc/sys/kernel/shmall", "r")) != NULL) < if (fgets(buf, sizeof(buf), f) != NULL) value = strtoul(buf, NULL, 10); // no proper checks fclose(f); // no return value check >return value; > int set_shmall(unsigned long int value) < FILE *f = NULL; char buf[512]; int retval = 0; if ((f = fopen("/proc/sys/kernel/shmall", "w")) != NULL) < if (snprintf(buf, sizeof(buf), "%lu\n", value) >= sizeof(buf) || fwrite(buf, 1, strlen(buf), f) != strlen(buf)) retval = -1; fclose(f); // fingers crossed > else retval = -1; return retval; > int main() < int shm_id1 = -1, shm_id2 = -1; unsigned long int shmall = 0, shmused, newshmall; void *ptr1, *ptr2; struct shm_info shminf; if ((shmall = get_shmall()) == 0) < printf("can't get shmall\n"); goto out; >printf("original shmall: %lu pages\n", shmall); if (shmctl(0, SHM_INFO, (struct shmid_ds *)&shminf) < 0) < printf("can't get SHM_INFO\n"); goto out; >shmused = shminf.shm_tot * getpagesize(); printf("shmused: %lu pages (%lu bytes)\n", shminf.shm_tot, shmused); newshmall = shminf.shm_tot + 1; if (set_shmall(newshmall) != 0) < printf("can't set shmall\n"); goto out; >if (get_shmall() != newshmall) < printf("something went wrong with shmall setting\n"); goto out; >printf("new shmall: %lu pages (%lu bytes)\n", newshmall, newshmall * getpagesize()); printf("shmget() for %u bytes: ", (unsigned int) getpagesize()); shm_id1 = shmget(IPC_PRIVATE, (size_t)getpagesize(), IPC_CREAT | 0666); if (shm_id1 < 0) < printf("failed: %s\n", strerror(errno)); goto out; >printf("ok\nshmat 1: "); ptr1 = shmat(shm_id1, NULL, 0); if (ptr1 == 0) < printf("failed\n"); goto out; >printf("ok\nshmat 2: "); ptr2 = shmat(shm_id1, NULL, 0); if (ptr2 == 0) < printf("failed\n"); goto out; >printf("ok\n"); if (ptr1 == ptr2) < printf("ptr1 and ptr2 are the same with shm_id1\n"); goto out; >printf("shmget() for %u bytes: ", (unsigned int) getpagesize()); shm_id2 = shmget(IPC_PRIVATE, (size_t)getpagesize(), IPC_CREAT | 0666); if (shm_id2 < 0) printf("failed: %s\n", strerror(errno)); else printf("ok, although it's wrong\n"); out: if (shmall != 0 && set_shmall(shmall) != 0) printf("failed to restrore shmall\n"); if (shm_id1 >= 0 && shmctl(shm_id1, IPC_RMID, NULL) < 0) printf("failed to remove shm_id1\n"); if (shm_id2 >= 0 && shmctl(shm_id2, IPC_RMID, NULL)
What is does is it sets the shmall limit just one page above what is currently used by the system, then tries to get page-sized new segment and map it twice (all successfully), then tries to get one more page-sized segment and fails to do that (execute the program as superuser because it writes to /proc/sys/kernel/shmall ):
$ sudo ./a.out original shmall: 18446744073708503040 pages shmused: 21053 pages (86233088 bytes) new shmall: 21054 pages (86237184 bytes) shmget() for 4096 bytes: ok shmat 1: ok shmat 2: ok shmget() for 4096 bytes: failed: No space left on device
Linux — Shared Memory (SHM) (/dev/shm)
The shared memory system can also be used to set permissions on memory.
There are two different types of shared memory implementations:
Articles Related
Management
By default, your operating system includes an entry in /etc/fstab to mount /dev/shm .
File structure
shm / shmfs is also known as tmpfs.
tmpfs means temporary file storage facility. It is intended to appear as a mounted file system, but one which uses virtual memory instead of a persistent storage device.
How to check its size ?
To check the size of the shared memory file system, enter the following command:
Limit
To determine current shared memory limits you can use the ipcs command.
------ Shared Memory Limits -------- max number of segments = 4096 max seg size (kbytes) = 1073741824 max total shared memory (kbytes) = 17179869184 min seg size (bytes) = 1
Parameters
shmmax
shmmax define the Maximum size (in bytes) for a shared memory segment.
We gan get the parameters limit by using the proc Filesystem such as:
shmall total shared memory avail: 2097152
segments
------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x45110010 1774485506 oracle 660 1048576 2 0x00000000 3112963 oracle 660 67108864 51 0x00000000 3145732 oracle 660 1543503872 51 0x910ac490 3178501 oracle 660 2097152 51 0x6611c0d9 1774518278 oracle 660 126921994088 1 locked 0x6711c0d9 1774551047 oracle 660 33554432 1 0x1111c0df 1775206408 oracle 660 273722634328 2 locked 0x1211c0df 1775239177 oracle 660 33554432 2
Process
------ Shared Memory Creator/Last-op -------- shmid owner cpid lpid 1774485506 oracle 30581 11420 3112963 oracle 24249 11377 3145732 oracle 24249 11377 3178501 oracle 24249 11377 1774518278 oracle 30572 11420 1774551047 oracle 30572 11420
lpid is the process ID of the last job to attach or detach from the shared memory segment or change the semaphore value.
top
The amount of shared memory used by a task. It simply reflects mem- ory that could be potentially shared with other processes.