分类 Linux 相关 下的文章

关于 cgroup

cgroup 有现在(2020)有 2 个版本, 尽管大部分公司还在使用 v1, 不过 v2 更好. 官方文档:
https://www.kernel.org/doc/Documentation/cgroup-v1/
https://www.kernel.org/doc/Documentation/cgroup-v2.txt

下面的内容都是基于 v1:

如何查看一个进程的 cgroup 的 group name?

$ pgrep java #找到我要查看的进程号
23850
# cat /proc/23850/cgroup #这个进程的 cgroup 名字
11:devices:/docker/dfa566d
10:pids:/docker/dfa566d
9:blkio:/docker/dfa566d
8:hugetlb:/docker/dfa566d
7:freezer:/docker/dfa566d
6:cpuset:/docker/dfa566d
5:memory:/docker/dfa566d
4:cpuacct,cpu:/docker/dfa566d
3:net_prio,net_cls:/docker/dfa566d
2:perf_event:/docker/dfa566d
1:name=systemd:/docker/dfa566d

$ mount | grep cgroup # 查看 cgroup 文件系统挂载的路径 默认是 /sys/fs/cgroup/
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
(rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
...
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)

$ ls -lah /sys/fs/cgroup/cpu/docker/dfa566d/  #该进程的 cgroup 文件
-rw-r--r-- 1 root root 0 Aug 13 05:05 cgroup.clone_children
--w--w--w- 1 root root 0 Aug 13 05:05 cgroup.event_control
-rw-r--r-- 1 root root 0 Aug 13 05:07 cgroup.procs
-r--r--r-- 1 root root 0 Aug 13 05:05 cpuacct.stat
-rw-r--r-- 1 root root 0 Aug 13 05:05 cpuacct.usage
-r--r--r-- 1 root root 0 Aug 13 05:05 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Aug 13 05:05 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Aug 13 05:05 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Aug 13 05:05 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Aug 13 05:05 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Aug 13 05:05 cpu.shares
-r--r--r-- 1 root root 0 Aug 13 05:05 cpu.stat
-rw-r--r-- 1 root root 0 Aug 13 05:05 notify_on_release
-rw-r--r-- 1 root root 0 Aug 13 05:05 tasks

CPU:

https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
https://engineering.squarespace.com/blog/2017/understanding-linux-container-scheduling
cpu usage soft限制: 使用 cpu.shares 文件. 它基于各 group 之间的比重, 默认比重是 1024. 如果某个 group 的进程使用量达不到自己的比重, 就会把自己剩余的 CPU 使用时间放到一个公共的 pool, 其它使用量超过自己使用量的比重的 group 里面的进程都可以到这个 pool 去取用. 当公共 pool 里面没有可用的时候, 就按照竞争CPU 的各个 group 的比重去分配. 所以如果竞争不激烈, 这个值意义不大, 比重低的group 里面的进程也有可能使用最多的 CPU(其他 group 都有剩余).

cpu usage hard 限制: 使用 cpu.cfs_period_us & cpu.cfs_quota_us 配合. period 代表一段时间, 单位是微妙,默认值是 100ms (100000), 最大值是 1s (1000000). quota 代表在 period 期间该 group 可以使用的量, 最小可能值是 1ms(1000). -1 代表不限制. 在多 CPU core 情况下, quota 的值可能比 period 大, 代表可能是用 n 个 CPU, 比如 period 是 100ms, quota 是 300ms 代表可以使用 3 个 CPU 的 core 的量.

内存 Memory

https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
内存的限额使用 memory.limit_in_bytes 限制, 当前的使用量可以查看 memory.usage_in_bytes.

/sys/fs/cgroup/memory/docker/dfa566d/

文件系统

在 host 上面可以通过 /proc/<pid>/root/ 访问 container 里面的文件
或者可以通过 docker cp 命令来 copy 文件
在 container 里面访问 host 文件要在 container 里面加 volume 的方式

linux /proc/pid/ 下常用的文件

/proc/ 下常见的文件

 $ ls -lah
----
cmdline  # 系统 boot 的信息博阿凯 image, 和其他参数
cpuinfo  # CPU 信息
crypto   # 系统支持的加密方法
devices  # 系统的快设备和字符设备
diskstats   # 磁盘统计
filesystems # 系统支持的文件系统
interrupts  # 系统启动以来收到的 interrupt
kallsyms    # kernel 符号表
meminfo     # 内存信息
modules     
mounts      # 类似 mount 命令
partitions  # 分区信息
self        # 当前进程目录链接
swaps       # swap 信息
verison     # 系统版本
vmstat     
zoneinfo

/proc/pid/ 目录下常见有用的文件

cd /proc/11748/
ls -lah 
-----
cgroup  # 当前进程的 cgroup 信息 /sys/fs/cgroup/...
cmdline # 启动进程的命令 包括选项 参数
comm    # 启动进程的命令
coredump_filter   # core dump 要包含那些 segments
cpuset  # cpu pin(绑定)的 core
cwd     # 进程工作路径 current work directory
environ # 当前进程的环境变量
exe     # 启动进程的命令的符号链接  通过 #sudo file /proc/11748/exe 可看
fd      # 当前进程打开并在使用的所有文件  #sudo ls -lah /proc/11748/fd 可看
fdinfo  # 当前进程打开并在使用的所有文件id
limits  # 当前进程的资源限额  使用 ulimit -a 查看系统的
status  # 当前进程的基本信息, 比如父进程 ID, 内存信息
task    # 当前进程的 thread 信息

常见 perf 命令

http://www.brendangregg.com/perf.html

安装
sudo apt install linux-tools-common -y
sudo apt install linux-tools-$(uname -r)
sudo apt install linux-cloud-tools-$(uname -r) -y
查看 CPU 使用
sudo perf top

perfTop.png

perf usage help
perf -h
perf help list
perf help record
perf 列出已知 event
perf help list  #perf list [hw|sw|cache|tracepoint|pmu|event_glob]
perf list tracepoint
sudo perf list 'ext4'
perf list tracepoint | grep ext4
分析已有 perf.data 的数据
perf report
捕获 perf event 数据
sudo perf record -e syscalls:sys_exit_flock -p 11748
perf record -e block:block_rq_issue -ag  # -a: all CPU -g: call graphes(stack trace)
perf 基本统计信息
sudo perf stat -p 11748

perfstat.png

Linux core dump

什么是 core dump

core dump 是一个进程的内存瞬时映像. core dump 这个名字来自于最早的计算机的内存技术. 使用 gdb 等工具可以读取 core dump, 然后分析进程当时的运行状态和内存信息.
https://man7.org/linux/man-pages/man5/core.5.html

如何获得 core dump

  1. 给进程发各种能产生 core dump 的 signal, 比如 SIGQUIT, SIGKILL 等.
  2. 使用 gdb 等 debug 工具对正在运行的进程发送 signal, 产生 core dump.

由于 1) core dump 会占用大量的磁盘空间, 2) core dump 可能包含内存的里面某些敏感数据, 所以 Linux 尽管在得到要 trigger core dump 的信号情况下, 也由于 ulimit 的控制, 默认不产生 core dump. 因此, 如果要捕获 core dump, 首先要选择打开 core dump limit 设置.
使用 ulimit -a 命令查看当前 ulimit 设置值:

eric@host:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31660
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31660
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
修改 ulimit 设置

可以使用 ulimit -c unlimited 命令, 但是可能非 root 用户没有权限.
在 /etc/security/ 目录下, 有个 limits.conf 和 limits.d 目录(如果有 limits.d 则 limits.conf 不生效, 可以认为 limits.conf 是模板). 在 limits.d 目录下新建一个以 .conf 结尾的文本文件, 添加要改的一行.

eric@host:~$ ls /etc/security/ | grep limit
limits.conf
limits.d

core dump 的文件名

正常情况下 core dump 的文件名没有后缀, 文件名就是 core. 这个名字可以通过 /proc/sys/kernel/core_pattern 来改. 这个名字还可以使用一些模板字符来替换. 比如 %h: 主机名; %p: 进程号 %t: Epoch 毫秒数, %u: user id;

如何分析 core dump

tmp 目录文件无法执行, 报 Permission denied

今天在执行 aysnc-profiler 的时候, 遇到无法执行的问题: 为了方便文件清除, 把解压后的文件放到了 /tmp 目录, 然后把 owner 和 权限都加好, 之后切换java 进程的用户去执行, 报 Permission denied.

mkdir /tmp/profiler
tar -C /tmp/profiler -xvf async-profiler-1.7.1-linux-x64.tar.gz
sudo chmod -R 755 /tmp/profiler/*
sudo chown -R appuser /tmp/profiler
sudo su appuser
/tmp/profiler/profile.sh -d 60 -o tree -e cpu -f profile0717.log.html 
/tmp/profile/profiler.sh: Permission denied

如果使用 bash 去执行, 则报:

bash /tmp/profiler/profile.sh -d 60 -o tree -e cpu -f profile0717.log.html 
/tmp/profile/profiler.sh: line 67: /tmp/profile/build/jattach: Permission denied

既然文件 owner 和 读和执行权限都加好了, 为什么还报错呢?
原来在 /tmp 目录的挂载方式:

appsuer@test-host:/home/appuser$ mount | grep /tmp
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec)

它设置了 noexec 属性. 所以问题就知道出在那里了, 既然这样, 换个目录就解决了.