namespace可以帮我们把资源隔离,但不能对资源的使用做限制。比如我想限制某个进程用多少CPU,多少内存话,怎么办呢?答案就是用cgroup
什么是cgroup
cgroup是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO等等)的机制。
体验下cgroup
我们直接体验下cgroup的内存和CPU限制。
一.cgroup的内存限制
示例代码mem.go:
package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 1000; i++ {
b := make([]byte, 1e7 * i)
fmt.Println(len(b))
time.Sleep(time.Second * time.Duration(1))
}
time.Sleep(time.Second * time.Duration(1000))
}
编译下运行:
root@xxg-txy:~/docker# go build mem.go
root@xxg-txy:~/docker# ./mem
0
10000000
20000000
30000000
40000000
通过htop命令可以看到mem占用的内存越来越多。
接下来我们给mem程序配置一个cgroup限制。
1. 创建一个限制内存的cgroup
mkdir /sys/fs/cgroup/memory/test
2.关闭交换分区
swapoff -a
3.限制内存为300M
echo $((300*1024*1024)) > /sys/fs/cgroup/memory/test/memory.limit_in_bytes
4.使用cgroup配置再次运行脚本:
cgexec -g memory:test ./mem
会发现随着占用的内存越来越多,当超过cgroup的限制时,程序被系统kill掉了:
root@xxg-txy:~/docker# cgexec -g memory:test ./mem
0
10000000
20000000
30000000
40000000
50000000
60000000
70000000
80000000
90000000
100000000
110000000
120000000
130000000
140000000
150000000
160000000
170000000
180000000
190000000
200000000
210000000
220000000
230000000
240000000
250000000
260000000
270000000
280000000
290000000
300000000
Killed
二.cgroup的CPU限制
示例代码cpu.go:
package main
func main() {
for{}
}
编译下运行,会看到程序占用的CPU接近90%
接下来我们配置下cgroup,把它限制到50
1.创建一个cpu的cgroup
mkdir /sys/fs/cgroup/cpu/test
2.限制为50%
echo 50000 > /sys/fs/cgroup/cpu/test/cpu.cfs_quota_us
3.使用cgroup配置再次运行脚本:
cgexec -g cpu:test ./cpu
可以看到CPU被限制在了50%左右
在go中使用cgroup
通过go封装的标准库,我们可以在go中配置并使用cgroup。
为了方便我们演示和查看,这里使用stress命令直接获取内存验证。比如我想直接从系统里拿500M内存,可运行如下命令:
stress --vm-bytes 500m --vm-keep -m 1
测试代码如下:
package main
import (
"os/exec"
"syscall"
"os"
"log"
"io/ioutil"
"strconv"
"path"
)
const procSelf = "/proc/self/exe"
const cgroup = "docker"
const cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory"
func main() {
if os.Args[0] == procSelf {
// cmd进程在cgroup规则下运行
cmd := exec.Command("/usr/bin/stress","--vm-bytes","500m","--vm-keep", "-m","1")
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
os.Exit(-1)
}
}
cmd := exec.Command(procSelf)
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
log.Fatal(err)
os.Exit(-1)
}else{
// 创建cgourp规则
os.Mkdir(path.Join(cgroupMemoryHierarchyMount, cgroup), 0755)
ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount, cgroup, "tasks"),[]byte(strconv.Itoa(cmd.Process.Pid)), 0644)
ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount, cgroup, "memory.limit_in_bytes"),[]byte("200m"), 0644)
}
cmd.Process.Wait()
}
运行该脚本,会发现内存被限制在了200M。
谢谢阅读。