1# 容器配额(plimits) 2 3## 简介 4 5面对进程越来越多,应用环境越来越复杂的状况,需要对容器做限制,若不做限制,会发生资源浪费、争夺等。容器配额plimits(Process Limits)是内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对cpu,内存等资源实现精细化控制。plimits的接口通过plimitsfs的伪文件系统提供。通过操作文件对进程及进程资源进行分组管理,通过配置plimits组内限制器Plimiter限制进程组的memory、sched等资源的使用。 6 7## 基本概念 8 9- plimits:内核的一个特性,用于限制、记录和隔离一组进程的资源使用。 10- plimitsfs:plimits文件系统,向用户提供操作接口,实现plimits的创建,删除。向用户展示plimits的层级等。 11- plimiter:资源限制器的总称,一个子系统代表一类资源限制器,包含memory限制器、pids限制器、sched限制器。 12- sched限制器:限制plimits组内的所有进程,在时间周期内占用的cpu时间。 13- memory限制器:限制plimits组内所有进程的内存使用总和。 14- pids限制器:限制plimits组内能挂载的最大进程数。 15 16## 运行机制 17 18plimitsfs文件系统,在系统初始化阶段,初始化plimits目录挂载至proc目录下: 19 20``` 21├─proc 22│ ├─plimits 23│ │ ├─plimits.plimiter_add 24│ │ ├─plimits.plimiter_delete 25│ │ ├─plimits.procs 26│ │ ├─plimits.limiters 27│ │ ├─pids.max 28│ │ ├─sched.period 29│ │ ├─sched.quota 30│ │ ├─sched.stat 31│ │ ├─memory.failcnt 32│ │ ├─memory.limit 33│ │ ├─memory.peak 34│ │ ├─memory.usage 35│ │ ├─memory.oom_ctrl 36│ │ └─memory.stat 37``` 38 391. plimits分组: 40 41 **图1** plimits创建/删除 42 43 ![zh-cn_image_0000002324](figures/zh-cn_image_0000002324.png) 44 452. sched限制器: 46 47 **图2** sched限制器配置 48 49 ![zh-cn_image_000000252628](figures/zh-cn_image_000000232425.png) 50 513. memory限制器: 52 53 **图3** memory限制器配置 54 55 ![zh-cn_image_000000232426](figures/zh-cn_image_000000232426.png) 56 574. pids限制器: 58 59 **图4** Pids限制器配置 60 61 ![zh-cn_image_000000232428](figures/zh-cn_image_000000232428.png) 62 63 64## 开发指导 65 66 67### 接口说明 68 69LiteOS-A的plimits根目录在/proc/plimits下,其下的所有文件只有只读权限,不允许写操作。限制器文件设定值默认为最大值,通过读文件,可查看组内进程资源状态。 70通过mkdir创建plimitsA目录完成对进程资源分组,进而操作资源的分配限制。创建的plimitsA目录继承其父plimits目录。 71 721. plimitsA文件目录见下表: 73 74 | <div style="width:70px">权限</div> | 大小 | 用户 | 用户组 | 文件名 | 文件描述 | 75 | --------- | ---- | ---- | ------ | ---------------------- | --------- | 76 |-r--r--r-- | 0 | u:0 | g:0 | sched.stat | 每个线程上周期内使用的时间片信息,方便测试验证使用 | 77 |-rw-r--r-- | 0 | u:0 | g:0 | sched.quota | 组内所有进程在周期内使用时间片总和,单位:ns | 78 |-rw-r--r-- | 0 | u:0 | g:0 | sched.period | 时间片统计周期,单位:ns | 79 |-r--r--r-- | 0 | u:0 | g:0 | memory.stat | 统计内存使用的信息,单位:字节 | 80 |-r--r--r-- | 0 | u:0 | g:0 | memory.usage | 已使用内存份额,单位:字节 | 81 |-r--r--r-- | 0 | u:0 | g:0 | memory.peak | 内存历史使用峰值,单位:字节 | 82 |-rw-r--r-- | 0 | u:0 | g:0 | memory.limit | 内存使用限额,单位:字节 | 83 |-r--r--r-- | 0 | u:0 | g:0 | memory.failcnt | 记录超过限额内存分配失败的次数,单位:次 | 84 |-rw-r--r-- | 0 | u:0 | g:0 | pids.max | 组内允许挂载进程的最大数,单位:个 | 85 |-rw-r--r-- | 0 | u:0 | g:0 | plimits.procs | 组内挂载的所有进程 | 86 |-rw-r--r-- | 0 | u:0 | g:0 | plimits.limiter_delete | 根据写入的限制器名称,删除限制器 | 87 |-rw-r--r-- | 0 | u:0 | g:0 | plimits.limiter_add | 根据写入的限制器名称,添加限制器 | 88 |-r--r--r-- | 0 | u:0 | g:0 | plimits.limiters | 查看组内限制器 | 89 90 在/proc/plimits/下创建的plimitsA目录下文件均可读部分可写,通过write对plimitsA子目录中写入内容,完成对进程资源分配与限制。 91 - 对文件sched.quota写入时间,单位ns,可限制组内所有进程使用cpu的时间 92 - 对文件sched.period写入时间,单位ns,可设置组内统计的时间周期 93 - 对文件memory.limit写入内存,单位字节,可限制组内允许使用的内存制 94 - 对文件pids.max写入十进制数字,可限制组内允许挂载的进程个数 95 - 对文件plimits.procs写入Pid,可将进程挂到不同的plimits组 96 - 通过read读不同的文件,可查看组内资源配置使用状况 97 982. 删除plimitsA组: 99 100 首先对/proc/plimits/plimitsA/plimits.limiter_delete文件依次写入字段“sched”、“memory”、“pids”删除限制器,才能使用rmdir删除plimitsA。 101 102 | 权限 | 大小 | 用户 | 用户组 | 文件名 | 103 | --------- | ------- | ------ | ------ | ----------------------- | 104 |-rw-r--r-- | 0 | u:0 | g:0 | plimits.procs | 105 |-rw-r--r-- | 0 | u:0 | g:0 | plimits.limiter_delete | 106 |-rw-r--r-- | 0 | u:0 | g:0 | plimits.limiter_add | 107 |-r--r--r-- | 0 | u:0 | g:0 | plimits.limiters | 108 109### 开发流程 110 111plimits文件系统的主要开发流程包括创建新的plimitsA,将pid号写入/plimitsA/plimits.procs,对进程资源分组;按照字节大小写文件/plimitsA/memory.limit文件,限制plimitsA组内能使用的最大内存;对文件/plimitsA/pids.max写入十进制数字限制plimitsA组内所能挂载的进程数等;通过配置plimitsA组内限制器文件,对相应的资源进行分配和限制。亦可删除plimitsA,不限制资源的使用。 112 113### 编程实例 114 115编程示例主要是创建分组plimitsA,通过读写子目录内容,完成进程与进程资源的分组,对Plimits组内进程资源限制。 116 117``` 118#include <stdio.h> 119#include <unistd.h> 120#include <stdlib.h> 121#include <string.h> 122#include <sys/types.h> 123#include <sys/stat.h> 124#include <fcntl.h> 125 126#define LOS_OK 0 127#define LOS_NOK -1 128 129int main () 130{ 131 int ret; 132 ssize_t len; 133 int fd = -1; 134 //get main pid 135 int mainpid = getpid(); 136 char plimitsA[128] = "/proc/plimits/plimitsA"; 137 char plimitsAPids[128] = "/proc/plimits/plimitsA/pids.max"; 138 char plimitsAMemoryLimit[128] = "/proc/plimits/plimitsA/memory.limit"; 139 char plimitsAMemoryUsage[128] = "/proc/plimits/plimitsA/memory.usage"; 140 char plimitsAProcs[128] = "/proc/plimits/plimitsA/plimits.procs"; 141 char plimitsAAdd[128] = "/proc/plimits/plimitsA/plimits.limiter_add"; 142 char plimitsADelete[128] = "/proc/plimits/plimitsA/plimits.limiter_delete"; 143 char plimitsMem[128] = "/proc/plimits/memory.usage"; 144 char plimitsPid[128] = "/proc/plimits/plimits.procs"; 145 char *mem = NULL; 146 char writeBuf[128]; 147 char readBuf[128]; 148 149 /* 查看根plimits组内进程 */ 150 memset(readBuf, 0, sizeof(readBuf)); 151 fd = open(plimitsPid, O_RDONLY); 152 len = read(fd, readBuf, sizeof(readBuf)); 153 if (len != strlen(readBuf)) { 154 printf("read file failed.\n"); 155 return LOS_NOK; 156 } 157 close(fd); 158 printf("/proc/plimits组内进程:%s\n", readBuf); 159 160 /* 查看根plimits组内内存使用 */ 161 memset(readBuf, 0, sizeof(readBuf)); 162 fd = open(plimitsMem, O_RDONLY); 163 len = read(fd, readBuf, sizeof(readBuf)); 164 if (len != strlen(readBuf)) { 165 printf("read file failed.\n"); 166 return LOS_NOK; 167 } 168 close(fd); 169 printf("/proc/plimits组内已使用内存:%s\n", readBuf); 170 171 172 /* 创建plimitsA “/proc/plimits/plimitsA” */ 173 ret = mkdir(plimitsA, 0777); 174 if (ret != LOS_OK) { 175 printf("mkdir failed.\n"); 176 return LOS_NOK; 177 } 178 179 /* 设置plimitsA组允许挂载进程个数 */ 180 memset(writeBuf, 0, sizeof(writeBuf)); 181 sprintf(writeBuf, "%d", 3); 182 fd = open(plimitsAPids, O_WRONLY); 183 len = write(fd, writeBuf, strlen(writeBuf)); 184 if (len != strlen(writeBuf)) { 185 printf("write file failed.\n"); 186 return LOS_NOK; 187 } 188 close(fd); 189 190 /* 挂载进程至plimitsA组 */ 191 memset(writeBuf, 0, sizeof(writeBuf)); 192 sprintf(writeBuf, "%d", mainpid); 193 fd = open(plimitsAProcs, O_WRONLY); 194 len = write(fd, writeBuf, strlen(writeBuf)); 195 if (len != strlen(writeBuf)) { 196 printf("write file failed.\n"); 197 return LOS_NOK; 198 } 199 close(fd); 200 201 /* 设置plimitsA组内分配内存限额 */ 202 memset(writeBuf, 0, sizeof(writeBuf)); 203 //limit memory 204 sprintf(writeBuf, "%d", (1024*1024*3)); 205 fd = open(plimitsAMemoryLimit, O_WRONLY); 206 len = write(fd, writeBuf, strlen(writeBuf)); 207 if (len != strlen(writeBuf)) { 208 printf("write file failed.\n"); 209 return LOS_NOK; 210 } 211 close(fd); 212 213 /* 查看plimitsA组内允许使用的最大内存 */ 214 memset(readBuf, 0, sizeof(readBuf)); 215 fd = open(plimitsAMemoryLimit, O_RDONLY); 216 len = read(fd, readBuf, sizeof(readBuf)); 217 if (len != strlen(readBuf)) { 218 printf("read file failed.\n"); 219 return LOS_NOK; 220 } 221 close(fd); 222 printf("/proc/plimits/plimitsA组允许使用的最大内存:%s\n", readBuf); 223 224 /* 查看plimitsA组内挂载的进程 */ 225 memset(readBuf, 0, sizeof(readBuf)); 226 fd = open(plimitsAProcs, O_RDONLY); 227 len = read(fd, readBuf, sizeof(readBuf)); 228 if (len != strlen(readBuf)) { 229 printf("read file failed.\n"); 230 return LOS_NOK; 231 } 232 close(fd); 233 printf("/proc/plimits/plimitsA组内挂载的进程:%s\n", readBuf); 234 235 /* 查看plimitsA组内存的使用情况 */ 236 mem = (char*)malloc(1024*1024); 237 memset(mem, 0, 1024); 238 memset(readBuf, 0, sizeof(readBuf)); 239 fd = open(plimitsAMemoryUsage, O_RDONLY); 240 len = read(fd, readBuf, sizeof(readBuf)); 241 if (len != strlen(readBuf)) { 242 printf("read file failed.\n"); 243 return LOS_NOK; 244 } 245 close(fd); 246 printf("/proc/plimits/plimitsA组已使用内存:%s\n", readBuf); 247 248 /* 删除plimitsA组内memory限制器 */ 249 memset(writeBuf, 0, sizeof(writeBuf)); 250 sprintf(writeBuf, "%s", "memory"); 251 fd = open(plimitsADelete, O_WRONLY); 252 len = write(fd, writeBuf, strlen(writeBuf)); 253 if (len != strlen(writeBuf)) { 254 printf("write file failed.\n"); 255 return LOS_NOK; 256 } 257 close(fd); 258 259 /* 增加plimitsA组内memory限制器 */ 260 memset(writeBuf, 0, sizeof(writeBuf)); 261 sprintf(writeBuf, "%s", "memory"); 262 fd = open(plimitsAAdd, O_WRONLY); 263 len = write(fd, writeBuf, strlen(writeBuf)); 264 if (len != strlen(writeBuf)) { 265 printf("write file failed.\n"); 266 return LOS_NOK; 267 } 268 close(fd); 269 270 /* 删除plimitsA组,首先删除memory、pids、sched限制器 */ 271 memset(writeBuf, 0, sizeof(writeBuf)); 272 sprintf(writeBuf, "%s", "memory"); 273 fd = open(plimitsADelete, O_WRONLY); 274 len = write(fd, writeBuf, strlen(writeBuf)); 275 if (len != strlen(writeBuf)) { 276 printf("write file failed.\n"); 277 return LOS_NOK; 278 } 279 memset(writeBuf, 0, sizeof(writeBuf)); 280 sprintf(writeBuf, "%s", "pids"); 281 fd = open(plimitsADelete, O_WRONLY); 282 len = write(fd, writeBuf, strlen(writeBuf)); 283 284 memset(writeBuf, 0, sizeof(writeBuf)); 285 sprintf(writeBuf, "%s", "sched"); 286 fd = open(plimitsADelete, O_WRONLY); 287 len = write(fd, writeBuf, strlen(writeBuf)); 288 close(fd); 289 ret = rmdir(plimitsA); 290 if (ret != LOS_OK) { 291 printf("rmdir failed.\n"); 292 return LOS_NOK; 293 } 294 295 return 0; 296} 297``` 298 299 300### 结果验证 301 302编译运行得到的结果为: 303 304 305``` 306/proc/plimits组内进程: 3071 3082 3093 3104 3115 3126 3137 3148 3159 31610 31711 31812 31913 32014 32115 322 323/proc/plimits组内已使用内存:28016640 324 325/proc/plimits/plimitsA组允许使用的最大内存:3145728 326 327/proc/plimits/plimitsA组内挂载的进程: 32815 329 330/proc/plimits/plimitsA组已使用内存:4096 331``` 332