暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL使用Linux cgroup2控制资源消耗

yanzongshuaiDBA 2024-06-11
99
PostgreSQL使用Linux cgroup2控制资源消耗
多租户和共host是一个挑战性问题。运行多个PG实例可以帮助减少内部竞争点(可伸缩性问题)。然而,一个租户的load可能会影响其他tenets,即所谓的“Noisy Neighbor”效应。幸运的是Linux允许用户通过每个程序使用cgroups来控制资源消耗。Cgroup2替代了cgroup1,处理了版本1几乎所有的限制。
Linux的5.2.0及其之后版本的内核可以使用cgroup2。实际上,2022年及其之后的Linxu分支的及其很可能已经准备好了cgroup2。
检查Linux是cgroup1还是cgroup2,可以通过cgroup mount的个数进行检查:
    $ grep -c cgroup /proc/mounts
    1
    复制
    如果count值是1,那么就是cgroup2。因为cgroup2有一个统一单层次结构。如果是cgroup1,那么会看到多个mounts值。
    如果Linux内核比较新并且仍旧使用cgroup1,那么可以使用boot参数:“systemd.unified_cgroup_hierarchy=1”。Redhat/OEL系统中,可以执行下面命令添加这个参数:
      sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
      复制
      通常情况下将这个作为引导选项添加到内核参数中:
        $ cat /etc/default/grub

        GRUB_CMDLINE_LINUX="xxxxxx systemd.unified_cgroup_hierarchy=1"

        复制
        需要重启机器生效。重启后可以验证:
          $ sudo mount -l | grep cgroup
          cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,seclabel,nsdelegate)
          复制
          请确保是cgroup2。现在我们检查这个虚拟文件系统,以便很好地理解:
            [jobinaugustine@localhost ~]$ ls -l /sys/fs/cgroup/
            total 0
            -r--r--r--. 1 root root 0 May 27 02:10 cgroup.controllers
            -rw-r--r--. 1 root root 0 May 27 02:10 cgroup.max.depth
            -rw-r--r--. 1 root root 0 May 27 02:10 cgroup.max.descendants
            -rw-r--r--. 1 root root 0 May 27 02:10 cgroup.procs
            -r--r--r--. 1 root root 0 May 27 02:10 cgroup.stat
            -rw-r--r--. 1 root root 0 May 27 02:10 cgroup.subtree_control
            -rw-r--r--. 1 root root 0 May 27 02:10 cgroup.threads
            -rw-r--r--. 1 root root 0 May 27 02:10 cpu.pressure
            -r--r--r--. 1 root root 0 May 27 02:10 cpuset.cpus.effective
            -r--r--r--. 1 root root 0 May 27 02:10 cpuset.mems.effective
            -r--r--r--. 1 root root 0 May 27 02:10 cpu.stat
            drwxr-xr-x. 2 root root 0 May 27 02:10 init.scope
            -rw-r--r--. 1 root root 0 May 27 02:10 io.pressure
            -r--r--r--. 1 root root 0 May 27 02:10 io.stat
            drwxr-xr-x. 2 root root 0 May 27 02:10 machine.slice
            -r--r--r--. 1 root root 0 May 27 02:10 memory.numa_stat
            -rw-r--r--. 1 root root 0 May 27 02:10 memory.pressure
            -r--r--r--. 1 root root 0 May 27 02:10 memory.stat
            -r--r--r--. 1 root root 0 May 27 02:10 misc.capacity
            drwxr-xr-x. 107 root root 0 May 27 02:10 system.slice
            drwxr-xr-x. 3 root root 0 May 27 02:16 user.slice
            复制
            这个是root control group。所有的slices都在这个下面。可以看到“system.slice”和“user.slice”,他们都是作为一个目录,因为他们是下一层级。
            可以检查下哪些是可用的cgroup controller:
              [jobinaugustine@localhost ~]$ cat /sys/fs/cgroup/cgroup.controllers
              cpuset cpu io memory hugetlb pids rdma misc
              复制

              1、实践

              创建一个slice

              当有多个实例时,为每个PG实例都创建一个独立的slice是一个不错的主意。允许我们从高级别控制资源的整个消耗。
              假设想要限制所有PG服务使用不超过机器CPU的25%:
              1)创建一个slice
                sudo systemctl edit --force postgres.slice
                复制
                2)为了演示,添加下面配置
                  [Unit]
                  Description=PostgreSQL Slice
                  Before=slices.target
                  [Slice]
                  MemoryAccounting=true
                  MemoryLimit=2048M
                  CPUAccounting=true
                  CPUQuota=25%
                  TasksMax=4096
                  复制
                  3)保存后重新加载
                    sudo systemctl daemon-reload
                    复制
                    4)检查slice的状态
                    sudo systemctl status postgres.slice

                    更改PG服务

                    1)我们可以使用PG服务中创建的slice,编辑:
                      $ sudo systemctl edit --full postgresql-16
                      复制
                      2)添加slice配置,例如Slice=postgres.slice:
                        ...
                        [Service]
                        Type=notify
                        User=postgres
                        Group=postgres
                        Slice=postgres.slice
                        ...
                        复制
                        3)保存并退出编辑。需要重启PG服务。重启时,PG会在新的slice下运行:
                          $ systemd-cgls | grep post
                          ├─postgres.slice
                          │ └─postgresql-16.service
                          │ ├─3760 /usr/pgsql-16/bin/postgres -D /var/lib/pgsql/16/data/
                          │ ├─3761 postgres: logger
                          │ ├─3762 postgres: checkpointer
                          │ ├─3763 postgres: background writer
                          │ ├─3765 postgres: walwriter
                          │ ├─3766 postgres: autovacuum launcher
                          │ └─3767 postgres: logical replication launcher
                          │ └─3770 grep --color=auto post
                          复制
                          4)服务状态中也会看到同样的信息

                          验证

                          尝试在一个CPU机器上并行多个会话,运行一个benchmark执行一个厚重的负载。不管我尝试了什么,Linux都限制了PG不超过slice指定的限制:

                          如果我们将PG的所有进程的CPU利用率都加起来,我们会看到2.3*4+2*7+1.7 = 24.9
                          同样的负载下不进行任何cgroup限制,会带来100%的利用率(0% idle):

                          Cgroup slice限制了负载,这符合预期。我们可以在一个slice中弄多个服务,这是下一个层级。systemd-cgtop可以展示slice-wise和单独的service-wise利用率:

                          系统级别的控制

                          Cgroup2非常有用,可选项更多。例如,你可能不想为PG服务创建单独的slice,特别当该机器上仅有一个PG实例时。默认情况下,PG和所有服务都作为“system.slice”的一部分。这种场景下,最简单的方式是在service级别指定cgroup限制,而不是slice级别:
                            sudo systemctl edit --full postgresql-16
                            复制
                            添加:
                              ...
                              [Service]
                              User=postgres
                              Group=postgres
                              CPUAccounting=true
                              CPUQuota=25%
                              ...
                              复制
                              重启后生效。

                              2、总结

                              Control group在docker和kubernetes中广泛使用。它们是限制机器上资源消耗的有效方法之一。Cgroup2使得使用更加便捷。使用场景:
                              1)更好的多租户环境
                              可以通过防止租户争夺同一套资源来防止“Noisy Neighbor”效应。
                              2)同一台机器上部署数据库服务和应用服务
                              绝大多数应用都是CPU密集型,数据库服务大多是内存/IO密集型。因此某些场景可以将他们部署在同台机器上。实际上我们看到许多情况下网络是潜在威胁,另一个优势是我们不必向网络公开数据库服务端口。
                              3)保护系统不受滥用、服务拒绝攻击
                              当系统重负载时,可能造成机器上运行的所有程序失去响应。这种情况往往会导致HA框架异常。对资源的良好控制可以防止这种情况发生。

                              3、原文

                              https://www.percona.com/blog/controlling-resource-consumption-on-a-postgresql-server-using-linux-cgroup2/

                              文章转载自yanzongshuaiDBA,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                              评论