背景

最近遇到一个比较尴尬的问题,我有一个服务比较占用内存,做一些分析可能会让内存暴涨至十几个 G,但是服务器的内存又比较小,只有 4G,导致服务崩溃。

最实在的做法就是服务器扩容,但是自己测试的服务,没必要这么奢侈,但又不想一直重启服务器,官网查找发现 docker 有个 limits 的属性可以使用,本篇以内存限制简述下其使用。

简单使用

docker run -m 限制内存使用量

docker run 镜像 -m 限制大小

-m 支持的参数格式

  • b(bytes) 2b
  • k/kb 32k
  • m/mb 32mb
  • g/gb 32g

docker-compose 限制内存使用量

services:
  frontend:
    image: awesome/webapp
    deploy:
      resources:
        limits:
          memory: 50m

limits 支持的其他参数(例如:cpus, pids),用法可以上 官网 查看

示例

文件夹目录结构,三个文件在同一文件夹下,文件具体内容往下看

 - docker-compose.yaml
 - dockerfile
 - main.go

go 代码

这里给个简单的示例,一个切片,不断的增加切片大小,输出当前占用的内存大小,直到其内存大于 20M,退出程序,如下:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	ticker := time.NewTicker(time.Second)
	var s []int = []int{1, 2, 3}
	for {
		select {
		case <-ticker.C:
			var m runtime.MemStats
			runtime.ReadMemStats(&m)
			if m.Alloc > 1024*1024*20 {
				fmt.Println("程序占用内存大于20M,退出程序")
				return 
			}
			fmt.Println("当前程序占用内存大小:", m.Alloc)
			s = append(s, s...)
		}
		
	}
}

dockerfile

FROM golang:1.18-alpine as gobuilder

WORKDIR /opt

COPY ./main.go ./main.go

RUN go build -o mmm main.go

FROM alpine:latest
COPY --from=gobuilder /opt/mmm ./
ENTRYPOINT ./mmm

docker-compose.yaml

docker-compose.yaml 这里设置当内存超过 6M 时直接停止服务

version: "3"

services:
  tl:
    build:
      context: .
      dockerfile: ./dockerfile
    container_name: test_limits
    deploy:
      resources:
        limits:
          memory: 6m
    restart: always

直接执行 docker-compose up 可查看程序输出如下:
在这里插入图片描述
可以看到这里已经做出了控制,并没有输出 程序占用内存大于20M,退出程序 就已经退出程序了。

总结

当使用 docker 时,服务器有资源限制,可以考虑使用 docker 内置的 limits 属性来进行 docker 容器的资源限制,由于 docker 有重启机制,这样就不会导致服务器的宕机。

但是最好还是找到资源占用比较夸张的地方,能优化则优化,不能优化则进行服务器扩容。

本篇讲述的是比较特殊的情况,服务重启不影响正常使用。

参考

官方文档

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐