• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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