✨ 添加新文章 CGroup 实验记录 记录一次有趣的工作流
This commit is contained in:
parent
565aff4a59
commit
e4c08e4b0a
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
{
|
||||
title: "CGroup 实验记录 记录一次有趣的工作流",
|
||||
description: "本文介绍了基于CGroup技术实现内存管理的开发过程。作者使用Vue3和.NET Core构建前后端,并通过C++封装libcgroup库操作CGroup。开发中采用WSL编译动态库并部署到Docker容器,使用CLion调试C++代码。解决了glibc版本兼容和FILENAME_MAX跨系统差异等问题,形成了一套容器化跨平台调试工作流。",
|
||||
draft: false,
|
||||
type: "article",
|
||||
created_at: "2025-08-30T16:48:57+08:00",
|
||||
published_at: "2025-08-30T22:41:18+08:00",
|
||||
updated_at: [ "2025-08-30T22:41:18+08:00" ],
|
||||
category: '实验',
|
||||
tags: [ "后端", "Docker" ],
|
||||
tech_stack: [ "Docker","C#", "C++" ],
|
||||
tech_stack_percent: [ 70, 60, 40],
|
||||
tech_stack_icon_names: [ "mdi:docker","mdi:language-csharp", "simple-icons:cplusplus" ],
|
||||
tech_stack_theme_colors: [ "#1c90ed", "#a179dc", "#00599c" ],
|
||||
}
|
||||
---
|
||||
## 前言
|
||||
> 本来没想水博客的,但是与一位朋友交流后,他觉得这个工作流有点意思,建议我记录一下。
|
||||
> 我不能保证这个工作流是最优的,但是在当时,它完美解决了我的问题
|
||||
|
||||
## 计算机系统实训题目描述
|
||||
### 基于CGroup技术的内存管理
|
||||
#### CGroup介绍
|
||||
CGroup是Control Groups的缩写,是OpenEuler内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物力资源(如cpu、memory、i/o等)的机制。CGroups是LXC为实现虚拟化所使用的资源管理手段。
|
||||
|
||||
#### CGroup功能及组成
|
||||
CGroup是将任意进程进行分组化管理的OpenEuler内核功能。CGroup提供将进程进行分组化管理的功能和接口的基础结构,I/O或内存的分配控制等具体的资源管理功能通过这个功能实现。这些具体的资源管理功能称为CGroup子系统或控制器。CGroup子系统有控制内存的Memory控制器、控制进程调度的CPU控制器等。运行中的内核可以使用的Cgroup子系统由/proc/cgroup来确认。
|
||||
CGroup提供了一个CGroup虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。要使用CGroup,必须挂载CGroup文件系统。这时通过挂载选项指定使用哪个子系统。Cgroups提供了以下功能:
|
||||
1. 限制进程组可以使用的资源数量(Resource limiting)。比如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会发出OOM(out of memory)。
|
||||
2. 进程组的优先级控制(Prioritization)。比如:可以使用cpu子系统为某个进程组分配特定cpu share。
|
||||
3. 记录进程组使用的资源数量(Accounting)。比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
|
||||
4. 进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。
|
||||
5. 进程组控制(Control)。比如:使用freezer子系统将进程组挂起和恢复。
|
||||
|
||||
#### 需要实现如下具体功能:
|
||||
1. CGroup内存管理的创建;
|
||||
2. CGroup设置内存资源限额;
|
||||
3. CGroup触发控制。
|
||||
|
||||
## 技术栈
|
||||
由于技术不限,为了获得相对较好的成绩,同时兼顾开发速度体验,我选择了以下技术栈:
|
||||
- 前端:Vue3 + TypeScript + Vite + Pinia + TDesign 没太多难点 后续文章不提
|
||||
- 后端:.Net Core API
|
||||
- 自构建链接库:C++ Dynamic Link Library —— CGroupEncapsulation
|
||||
- 中间件:Docker
|
||||
- 虚拟机:WSL
|
||||
|
||||
## 工作流
|
||||
### 想法与问题
|
||||
#### CGroup 调用
|
||||
CGroup 的调用不是大问题。
|
||||
退一步,可以使用纯粹文件操作 + exec运行命令行工具,但这样显然是不够优雅的。
|
||||
我选择的方案是:使用 libcgroup 这个 C 语言库,使用syscall而非调用系统命令行工具或直接进行文件操作,这样做的好处是能够获得更完善的错误处理机制。
|
||||
通过C#的P/Invoke,可以较为方便的调用C/C++动态链接库,但是也没那么方便,所以我又添加了一个中间层,封装一次libcgroup。
|
||||
#### Docker 与调试问题
|
||||
CGroup是Linux特有的,我要么直接使用wsl,要么使用Docker。
|
||||
而CGroup也算比较关键的系统功能,直接在wsl中运行可能会出现问题,所以选择使用Docker。
|
||||
使用Docker也会引入问题,关键是动态链接库的构建和调试。我的选择是:在wsl中构建动态链接库,然后将动态链接库复制到Container中使用。
|
||||
在该方法下,是无法通过VS进行跨语言调试的,我的解决方案是使用Clion连接到Docker Container,编译CGroupEncapsulation项目,然后使用main函数进行调试。
|
||||
综上,对于CGroupEncapsulation这个项目,需要两种项目文件。对于VS,将读取它的 `CGroupEncapsulation.vcxproj` 项目文件,对于Clion,将读取 `CMakeLists.txt` 项目文件。
|
||||
这个工作流唯一的问题是,重启VS会造成Container销毁,Clion需要重联,除此之外没有什么问题。
|
||||
|
||||
### 具体工作流
|
||||
对于后端,当VS启动调试时
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> WSL
|
||||
[*] --> BAC
|
||||
|
||||
state WSL {
|
||||
state "CGroupEncapsulation Compile" as CC
|
||||
[*] --> CC
|
||||
CC --> [*]
|
||||
}
|
||||
state "Backend API Compile" as BAC
|
||||
WSL --> Docker : Copy dynamic link library
|
||||
BAC --> Docker : Copy backend API DLL
|
||||
state Docker {
|
||||
state ".Net Core API Debug" as API
|
||||
[*] --> API
|
||||
API --> [*]
|
||||
}
|
||||
Docker --> [*]
|
||||
```
|
||||
如果想要调试CGroupEncapsulation这个动态链接库,则需要在Clion中连接到Docker Container 但是使用main文件运行 而不是附加到DLL
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Docker
|
||||
state Docker {
|
||||
state "CGroupEncapsulation Debug" as CCD
|
||||
state "CGroupEncapsulation Compile as Runnable" as CCR
|
||||
[*] --> CCR
|
||||
CCR --> CCD : Run main
|
||||
CCD --> [*]
|
||||
}
|
||||
Docker --> [*]
|
||||
```
|
||||
如果能够在VS中附加到Docker的DLL,同时能断点就更好了,但是目前还没找到方法。我相信是有方法的,但当时时间比较紧,平衡好时间和技术也是编程的关键。
|
||||
|
||||
## 遇到的问题
|
||||
### WSL编译后的DLL执行时报错
|
||||
结果是Docker的glibc版本过低,调整编译选项,降低到C++17后正常
|
||||
### controller_data 下 FILENAME_MAX 宏在不同系统中定义不同
|
||||
`FILENAME_MAX` 在Windows中的值为260,而在Linux中为4096,之前在用VS查阅源代码时,看到的值是260,因此使用C# P/Invoke调用时,传入的数组长度为260,结果出现报错。报错信息并不显然,这个问题卡了我一会儿的。
|
||||
|
Loading…
Reference in New Issue