Configure CGroup for LAMP stack

by Anish

Posted on Tuesday December 10/2019

CGroup were introduced into the kernel by Google in 2006 and it's stands for Control Groups

Cgroups allow you to allocate these subsystem resources among user-defined groups of tasks (processes) running on a system

  • cpu: Uses the scheduler to provide cgroup tasks access to the CPU.
  • blkio: Sets limits on input/output access to and from block devices such as physical drives
  • cpuacct: Generates automatic reports on CPU resources used by tasks in a cgroup
  • cpuset: Assigns individual CPUs and memory nodes to tasks in a cgroup
  • devices: Allows or denies access to devices by tasks in a cgroup
  • freezer: Suspends or resumes tasks in a cgroup
  • perf_event: Identifies cgroup membership of tasks and can be used for performance analysis
  • net_cls: Tags network packets with a class identifier
  • memory: Sets limits on memory use by tasks in a cgroup and generates automatic reports on memory resources used by those tasks

CGroup for LAMP

For example, let's say we wanted to assign or isolate the resources of an application, for the same purpose we will create two cgroup one for application and other for operating system itself.

cgroup lamp stack

Let's extend the scenario to more practical one imagine you have a LAMP stack, you have to manage the cpu, memory, disk and network bandwidth, for your LAMP application.

LAMP stack (Linux, Apache, MariaDB/MYSQL and PHP)

and your cloud/VM has 4GB of Memory and you have to limit the following configuration in the CGgroup

  • Form httpd service ( httpd.service): 30% of CPU, 1G of memory,
  • PHP service (here php-fpm.service): 20% of CPU, 1G of memory,
  • MariaDB service (here mariadb.service): 50% of CPU, 1G of memory.

and you have left 1G of memory for the operating system itself.

Without CGroup processes will share the server power and the memory as they need.

with CGroup the httpd service: will have CPUShares=3072 (3x 1024); and MemoryLimit=1G, and to configure in httpd service using systemctl

[anish@localhost ~]$ sudo systemctl set-property httpd CPUShares=3072
[anish@localhost ~]$ sudo systemctl set-property httpd  MemoryLimit=1G
[anish@localhost ~]$ sudo systemctl daemon-reload
[anish@localhost ~]$ sudo systemctl show -p CPUShares,MemoryLimit httpd

The httpd status shows CGroup configured with 1GB limit

[anish@localhost ~]$ systemctl status httpd
 httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/httpd.service.d
           50-CPUShares.conf, 50-MemoryLimit.conf
   Active: active (running) since Tue 2019-12-10 02:13:24 EST; 6min ago
     Docs: man:httpd(8)
 Main PID: 1551 (httpd)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
    Tasks: 6
   Memory: 2.7M (limit: 1.0G)
   CGroup: /system.slice/httpd.service
           1551 /usr/sbin/httpd -DFOREGROUND
           1552 /usr/sbin/httpd -DFOREGROUND
           1553 /usr/sbin/httpd -DFOREGROUND

The drop-ins files

[anish@localhost ~]$ cat /etc/systemd/system/httpd.service.d/50-CPUShares.conf 
[anish@localhost ~]$ cat /etc/systemd/system/httpd.service.d/50-MemoryLimit.conf 

If you want the httpd service to display the amount of memory currently used through the systemd-cgtop command, you need to activate accounting by MemoryAccounting=true

[anish@localhost ~]$ sudo systemctl set-property httpd  MemoryAccounting=true 
[anish@localhost ~]$ sudo systemctl daemon-reload; sudo systemctl restart httpd

and then

[anish@localhost ~]$ systemd-cgtop


CGroup configuration for mariadb service: CPUShares=5120 (5 x 1024); MemoryLimit=1G and write below 2MB/s onto the /dev/vdb partition

[anish@localhost ~]$ sudo systemctl set-property mariadb CPUShares=5120
[anish@localhost ~]$ sudo systemctl set-property mariadb  MemoryLimit=1G
[anish@localhost ~]$ sudo systemctl set-property mariadb.service BlockIOWriteBandwidth="/dev/vdb 2M"
[anish@localhost ~]$ sudo systemctl daemon-reload
[anish@localhost ~]$ sudo systemctl restart mariadb

The mariadb status shows CGroup configured with 1GB limit and with required BlockIOWriteBandwidth and CPUShares

[anish@localhost ~]$ systemctl status mariadb
 mariadb.service - MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/mariadb.service.d
           50-BlockIOWriteBandwidth.conf, 50-CPUShares.conf, 50-MemoryLimit.conf
   Active: active (running) since Tue 2019-12-10 02:47:14 EST; 28s ago
  Process: 2371 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=0/SUCCESS)
  Process: 2335 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCESS)
 Main PID: 2370 (mysqld_safe)
    Tasks: 20
   Memory: 74.4M (limit: 1.0G)
   CGroup: /system.slice/mariadb.service
           2370 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
           2532 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/

CGroup Fundamentals

Installation on rhel7/8 and centos Like system,

if you are using systemd the systemd uses CGroups libcgroup package and is installed by default

$ yum -y install libcgroup libcgroup-tools
$ systemctl start cgroup
$ systemctl enable cgroup

lscgroup list all cgroups

[root@localhost ~]# lscgroup

lssubsys - list hierarchies containing given subsystem

[root@localhost ~]# lssubsys

limiting memory usage

This example shows how a new cgroup is created assiged a user to it and set some memmory limits

[root@localhost ~]# adduser testing

cgcreate will create a new directory within the mounted memory cgroup with assiged username

[root@localhost ~]# cgcreate -a testing -g memory,cpu:testing

For testing set 256MB of memory limit in this cgroup testing

[root@localhost ~]# echo 268435456 > /sys/fs/cgroup/memory/testing/memory.limit_in_bytes

Validate the memory.limit_in_bytes

[root@localhost ~]# cat /sys/fs/cgroup/memory/testing/memory.limit_in_bytes

Switch to newly created user

[root@localhost ~]# su - testing

run stress with the -m option to consume memory and see what happens

[testing@localhost ~]$ stress -m 2 --vm-bytes 800M --vm-keep
stress: info: [2678] dispatching hogs: 0 cpu, 0 io, 2 vm, 0 hdd
stress: FAIL: [2678] (415) <-- worker 2679 got signal 9
stress: WARN: [2678] (417) now reaping child worker processes
stress: FAIL: [2678] (451) failed run completed in 1s

The Application just crash because of memory.oom_control

[testing@localhost ~]$  cat /sys/fs/cgroup/memory/testing/memory.oom_control
oom_kill_disable 0
under_oom 0

Next Reading : Overview of Linux Namespace

Thanku for reading !!! Give a Share for Support

Your Support Matters!

Instead of directly asking for donations, I'm thrilled to offer you all nine of my books for just $9 on leanpub By grabbing this bundle you not only help cover my coffee, beer, and Amazon bills but also play a crucial role in advancing and refining this project. Your contribution is indispensable, and I'm genuinely grateful for your involvement in this journey!

Any private key value that you enter or we generate is not stored on this site, this tool is provided via an HTTPS URL to ensure that private keys cannot be stolen, for extra security run this software on your network, no cloud dependency

python Cryptography Topics
For Coffee/ Beer/ Amazon Bill and further development of the project Support by Purchasing, The Modern Cryptography CookBook for Just $9 Coupon Price

Kubernetes for DevOps

Hello Dockerfile

Cryptography for Python Developers

Cryptography for JavaScript Developers

Go lang ryptography for Developers