2024年1月

Cgroups 是 linux 内核提供的功能,由于牵涉的概念比较多,所以不太容易理解。本文试图通过简单的描述和 Demo 帮助大家理解 Cgroups 。


如果你对云原生技术充满好奇,想要深入了解更多相关的文章和资讯,欢迎关注微信公众号。

搜索公众号【
探索云原生
】即可订阅


1. 什么是 Cgroups

Cgroups 是 Linux 下的一种将进程按组进行管理的机制,它提供了对一组进程及将来子进程的资源限制控制和统计的能力

这些资源包括 CPU、内存、存储、网络等。通过 Cgroups 可以方便地限制某个进程的资源占用,并且可以实时地监控进程的监控与统计信息

Cgroups 分
v1

v2
两个版本:

  • v1 实现较早,功能比较多,但是由于它里面的功能都是零零散散的实现的,所以规划的不是很好,导致了一些使用和维护上的不便。

  • v2 的出现就是为了解决 v1 的问题,在最新的 4.5 内核中,Cgroups v2 声称已经可以用于生产环境了,但它所支持的功能还很有限。

v1 和 v2 可以混合使用,但是这样会更复杂,所以一般没人会这样用。

1. 三部分组件

Cgroups 主要包括下面几部分:

  • cgroups 本身
    :cgroup 是对进程分组管理的一种机制,一个 cgroup 包含一组进程,并可以在这个 cgroup 上增加 Linux subsystem 的各种参数配置,将一组进程和一组 subsystem 的系统参数关联起来。
  • subsystem
    : 一个 subsystem 就是一个内核模块,他被关联到一颗 cgroup 树之后,就会在树的每个节点(进程组)上做具体的操作。subsystem 经常被称作"resource controller",因为它主要被用来调度或者限制每个进程组的资源,但是这个说法不完全准确,因为有时我们将进程分组只是为了做一些监控,观察一下他们的状态,比如 perf_event subsystem。到目前为止,Linux 支持 12 种 subsystem,比如限制 CPU 的使用时间,限制使用的内存,统计 CPU 的使用情况,冻结和恢复一组进程等,后续会对它们一一进行介绍。

  • hierarchy
    :一个 hierarchy 可以理解为一棵 cgroup 树,树的每个节点就是一个进程组,每棵树都会与零到多个 subsystem 关联。在一颗树里面,会包含 Linux 系统中的所有进程,但每个进程只能属于一个节点(进程组)。系统中可以有很多颗 cgroup 树,每棵树都和不同的 subsystem 关联,一个进程可以属于多颗树,即一个进程可以属于多个进程组,只是这些进程组和不同的 subsystem 关联。目前 Linux 支持 12 种 subsystem,如果不考虑不与任何 subsystem 关联的情况(systemd 就属于这种情况),Linux 里面最多可以建 12 颗 cgroup 树,每棵树关联一个 subsystem,当然也可以只建一棵树,然后让这棵树关联所有的 subsystem。当一颗 cgroup 树不和任何 subsystem 关联的时候,意味着这棵树只是将进程进行分组,至于要在分组的基础上做些什么,将由应用程序自己决定,systemd 就是一个这样的例子。

3 个部分间的关系

  • 系统在创建了新的 hierarchy 之后,系统中所有的进程都会加入这个 hierarchy 的 cgroup 根节点,这个 cgroup 根节点是 hierarchy 默认创建的。
  • 一个 subsystem 只能附加到 一 个 hierarchy 上面。
  • 一个 hierarchy 可以附加多个 subsystem 。
  • 一个进程可以作为多个 cgroup 的成员,但是这些 cgroup 必须在不同的 hierarchy 中。
  • 一个进程 fork 出子进程时,子进程是和父进程在同一个 cgroup 中的,也可以根据需要将其移动到其他 cgroup 中。

个人理解:

  • cgroup 用于对进程进行分组。
  • hierarchy 则根据继承关系,将多个 cgroup 组成一棵树。
  • subsystem 则负责资源限制的工作,将 subsystem 和 hierarchy 绑定后,该 hierarchy 上的所有 cgroup 下的进程都会被 subsystem 给限制。
    • 子 cgroup 会继承父 cgroup 的 subsystem,但是子 cgroup 却可以自定义自己的配置
  • 因此:使用时可以直接在某个已存在的 hierarchy 下创建子 cgroup 或者直接创建一个新的 hierarchy 。

注:后续的 cgroup 树就指的是 hierarchy,cgroup 则指 hierarchy 上的节点。

2. 具体架构

看完上面的描述,可能还是搞不清具体的关系,下面几幅图比较清晰的展示了 cgroup 中几部分组件的关系。

这部分内容参考:
美团技术团队

hierarchy、cgroup、subsystem 3 者的关系:

cgroups-hierarchy

比如上图表示两个 hierarchiy,每一个 hierarchiy 中是一颗树形结构,树的每一个节点是一个 cgroup (比如 cpu_cgrp, memory_cgrp)。

  • 第一个 hierarchiy attach 了 cpu 子系统和 cpuacct 子系统, 因此当前 hierarchiy 中的 cgroup 就可以对 cpu 的资源进行限制,并且对进程的 cpu 使用情况进行统计。

  • 第二个 hierarchiy attach 了 memory 子系统,因此当前 hierarchiy 中的 cgroup 就可以对 memory 的资源进行限制。

在每一个 hierarchiy 中,每一个节点(cgroup)可以设置对资源不同的限制权重(即自定义配置)。比如上图中 cgrp1 组中的进程可以使用 60%的 cpu 时间片,而 cgrp2 组中的进程可以使用 20%的 cpu 时间片。

cgroups 和 进程间的关系:

上面这个图从整体结构上描述了进程与 cgroups 之间的关系。最下面的
P
代表一个进程。

  • 每一个进程的描述符中有一个指针指向了一个辅助数据结构
    css_set
    (cgroups subsystem set)。 指向某一个
    css_set
    的进程会被加入到当前
    css_set
    的进程链表中。一个进程只能隶属于一个
    css_set
    ,一个
    css_set
    可以包含多个进程,隶属于同一
    css_set
    的进程受到同一个
    css_set
    所关联的资源限制。

  • 上图中的”M×N Linkage”说明的是
    css_set
    通过辅助数据结构可以与 cgroups 节点进行多对多的关联。但是 cgroups 的实现不允许
    css_set
    同时关联同一个 cgroups 层级结构下多个节点。 这是因为 cgroups 对同一种资源不允许有多个限制配置。

  • 一个
    css_set
    关联多个 cgroups 层级结构的节点时,表明需要对当前
    css_set
    下的进程进行多种资源的控制。而一个 cgroups 节点关联多个
    css_set
    时,表明多个
    css_set
    下的进程列表受到同一份资源的相同限制。

一个节点的控制列表中的所有进程都会受到当前节点的资源限制。同时某一个进程也可以被加入到不同的 cgroups 层级结构的节点中,因为不同的 cgroups 层级结构可以负责不同的系统资源。所以说进程和 cgroup 结构体是一个多对多的关系。

2. 如何使用 Cgroups

注:本文所有操作在 Ubuntu20.04 下进行。

cgroup 相关的所有操作都是基于内核中的 cgroup virtual filesystem,使用 cgroup 很简单,挂载这个文件系统就可以了。

一般情况下都是挂载到/sys/fs/cgroup 目录下,当然挂载到其它任何目录都没关系。

cgroups 以文件的方式提供应用接口,我们可以通过 mount 命令来查看 cgroups 默认的挂载点:

[root@iZ2zefmrr626i66omb40ryZ ~]# mount | grep cgroup
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
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/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
  • 第一行的 tmpfs 说明 /sys/fs/cgroup 目录下的文件都是存在于内存中的临时文件。
  • 第二行的挂载点 /sys/fs/cgroup/systemd 用于 systemd 系统对 cgroups 的支持。
  • 其余的挂载点则是内核支持的各个子系统的根级层级结构。

需要注意的是,在使用 systemd 系统的操作系统中,/sys/fs/cgroup 目录都是由 systemd 在系统启动的过程中挂载的,并且挂载为只读的类型。换句话说,系统是不建议我们在 /sys/fs/cgroup 目录下创建新的目录并挂载其它子系统的。这一点与之前的操作系统不太一样。

查看 subsystem 列表

可以通过查看/proc/cgroups(since Linux 2.6.24)知道当前系统支持哪些 subsystem,下面是一个例子:

DESKTOP-9K4GB6E# cat /proc/cgroups
#subsys_name    hierarchy       num_cgroups     enabled
cpuset          11              1               1
cpu             3               64              1
cpuacct         3               64              1
blkio           8               64              1
memory          9               104             1
devices         5               64              1
freezer         10              4               1
net_cls         6               1               1
perf_event      7               1               1
net_prio        6               1               1
hugetlb         4               1               1
pids            2               68              1

从左到右,字段的含义分别是:

  1. subsys_name:subsystem 的名字
  2. hierarchy:subsystem 所关联到的 cgroup 树的 ID,如果多个 subsystem 关联到同一颗 cgroup 树,那么他们的这个字段将一样,比如这里的 cpu 和 cpuacct 就一样,表示他们绑定到了同一颗树。如果出现下面的情况,这个字段将为 0:
    • 当前 subsystem 没有和任何 cgroup 树绑定
    • 当前 subsystem 已经和 cgroup v2 的树绑定
    • 当前 subsystem 没有被内核开启
  3. num_cgroups:subsystem 所关联的 cgroup 树中进程组的个数,也即树上节点的个数
  4. enabled:1 表示开启,0 表示没有被开启(可以通过设置内核的启动参数“cgroup_disable”来控制 subsystem 的开启).

hierarchy 相关操作

挂载

Linux 中,用户可以使用 mount 命令挂载 cgroups 文件系统:

语法为:
mount -t cgroup -o subsystems name /cgroup/name

  • 其中 subsystems 表示需要挂载的 cgroups 子系统
  • /cgroup/name 表示挂载点

这条命令同在内核中创建了一个 hierarchy 以及一个默认的 root cgroup。

示例:

挂载一个和 cpuset subsystem 关联的 hierarchy 到
./cg1
目录

# 首先肯定是创建对应目录
mkdir cg1
# 具体挂载操作--参数含义如下
# -t cgroup 表示操作的是 cgroup 类型,
# -o cpuset 表示要关联 cpuset subsystem,可以写0个或多个,0个则是关联全部subsystem,
# cg1 为 cgroup 的名字,
# ./cg1 为挂载目标目录。
mount -t cgroup -o cpuset cg1 ./cg1
# 挂载一颗和所有subsystem关联的cgroup树到cg1目录
mkdir cg1
mount -t cgroup cg1 ./cg1

#挂载一颗与cpu和cpuacct subsystem关联的cgroup树到 cg1 目录
mkdir cg1
mount -t cgroup -o cpu,cpuacct cg1 ./cg1

# 挂载一棵cgroup树,但不关联任何subsystem,这systemd所用到的方式
mkdir cg1
mount -t cgroup -o none,name=cg1 cg1 ./cg1

卸载

作为文件系统,同样是使用
umount
命令卸载。

# 指定路径来卸载,而不是名字。
$ umount /path/to/your/hierarchy

例如

umount /sys/fs/cgroup/hierarchy

cgroup 相关操作

创建 cgroup 比较简单,直接在 hierarchy 或 cgroup 目录下创建子目录(mkdir)即可。

删除则是删除对应
目录
(rmdir)。

注:不能直接递归删除对应目录,因为目录中的文件是虚拟的,递归删除时会报错。

也可以借助 libcgroup 工具来创建或删除。

使用 libcgroup 工具前,请先安装 libcgroup 和 libcgroup-tools 数据包

redhat 系统安装:

$ yum install libcgroup
$ yum install libcgroup-tools

ubuntu 系统安装:

$ apt-get install cgroup-bin
# 如果提示cgroup-bin找不到,可以用 cgroup-tools 替换
$ apt-get install cgroup-tools

具体语法:

# controllers就是subsystem
# path可以用相对路径或者绝对路径
$ cgdelete controllers:path

例如:

cgdelete cpu:./mycgroup

3. 演示

分别演示以下直接在某个已存在的 hierarchy 下创建子 cgroup 或者直接创建一个新的 hierarchy 两种方式。

1. 新 hierarchy 方式

创建 hierarchy

首先,要创建并挂载一个 hierarchy。

# 创建一个目录作为挂载点
lixd  ~ $ mkdir cgroup-test
# 创建一个不挂载任何subsystem的hierarchy,由于 name=cgroup-test 的 cgroup 不存在,所以这里会由hierarchy默认创建出来
 ✘ lixd  ~ $ sudo mount -t cgroup -o none,name=cgroup-test cgroup-test ./cgroup-test
 lixd  ~ $ cd cgroup-test
 lixd  ~/cgroup-test $ ls
 # 可以发现多了几个文件
cgroup.clone_children  cgroup.procs  cgroup.sane_behavior  notify_on_release  release_agent  tasks

这些文件就是 hierarchy 中 cgroup 根节点的配置项。具体含义如下:

  • cgroup.clone_ children, cpuset 的 subsystem 会读取这个配置文件,如果这个值是 1 (默认是 0),子 cgroup 才会继承父 cgroup 的 cpuset 的配置。

  • cgroup.procs 是树中当前节点 cgroup 中的进程组 ID,现在的位置是在根节点,这个文件中会有现在系统中所有进程组的 ID。

  • notify_on_release 和 release agent 会一起使用。 notify_on_release 标识当这个 cgroup 最后一个进程退出的时候是否执行了 release_agent; release_agent 则是一个路径,通常用作进程退出之后自动清理掉不再使用的 cgroup。

  • tasks 标识该 cgroup 下面的进程 ID,如果把一个进程 ID 写到 tasks 文件中,便会将相应的进程加入到这个 cgroup 中。

创建子 cgroup

然后,从刚创建好的 hierarchy 上 cgroup 根节点中扩展出两个子 cgroup:

 # 创建子cgroup cgroup-1
 lixd  ~/cgroup-test $ sudo mkdir cgroup-1
  # 创建子cgroup cgroup-1
 lixd  ~/cgroup-test $ sudo mkdir cgroup-2
 lixd  ~/cgroup-test $ tree
.
├── cgroup-1
│   ├── cgroup.clone_children
│   ├── cgroup.procs
│   ├── notify_on_release
│   └── tasks
├── cgroup-2
│   ├── cgroup.clone_children
│   ├── cgroup.procs
│   ├── notify_on_release
│   └── tasks
├── cgroup.clone_children
├── cgroup.procs
├── cgroup.sane_behavior
├── notify_on_release
├── release_agent
└── tasks

可以看到,在一个 cgroup 的目录下创建文件夹时,Kernel 会把文件夹标记为这个 cgroup 的子 cgroup,它们会继承父 cgroup 的属性。

在 cgroup 中添加和移动进程

一个进程在一个 Cgroups 的 hierarchy 中,只能在一个 cgroup 节点上存在,系统的所有进程都会默认在根节点上存在。

想要将进程移动到其他 cgroup 节点,只需要将进程 ID 写到目标 cgroup 节点的 tasks 文件中即可。

将当前 shell 所在进程添加到 tasks:

cgroup-test#cd cgroup-1
# 需要 root 权限
cgroup-1# echo $$ >> tasks
cgroup-1# cat tasks
7575
cgroup-1# cat /proc/7575/cgroup
14:name=cgroup-test:/cgroup-1 # 可以看到该进程已经被加入到cgroup中了
13:rdma:/
12:pids:/
11:hugetlb:/
10:net_prio:/
9:perf_event:/
8:net_cls:/
7:freezer:/
6:devices:/
5:blkio:/a
4:cpuacct:/
3:cpu:/
2:cpuset:/
1:memory:/
0::/

通过 subsystem 限制 cgroup 中的进程

在上面创建 hierarchy 的时候,这个 hierarchy 并没有关联到任何的 subsystem ,所以没办法通过那个 hierarchy 中的 cgroup 节点限制进程的资源占用。

即 只能在创建 hierarchy 时指定要关联哪些 subsystem,创建后就无法修改。

其实系统默认已经为每个 subsystem 创建了一个默认的 hierarchy,比如 memory 的 hierarchy。

2. 子 cgroup 方式

在很多使用 systemd 的系统中,systemd 已经帮我们将各个 subsystem 和 cgroup 树关联并挂载好了:

DESKTOP-9K4GB6E# mount |grep cgroup
tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,relatime,mode=755)
cgroup2 on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu)
cgroup on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup-test on /home/lixd/cgroup-test type cgroup (rw,relatime,name=cgroup-test)

因此我们可以直接在对应 cgroup 树下创建子 cgroup 即可。

直接进到 /sys/fs/cgroup/cpu 目录创建 cgroup-cpu 子目录即可:

DESKTOP-9K4GB6E# cd /sys/fs/cgroup/cpu
DESKTOP-9K4GB6E# mkdir cgroup-cpu
DESKTOP-9K4GB6E# cd cgroup-cpu
DESKTOP-9K4GB6E# ls
cgroup.clone_children  cpu.cfs_period_us  cpu.rt_period_us   cpu.shares  notify_on_release
cgroup.procs           cpu.cfs_quota_us   cpu.rt_runtime_us  cpu.stat    tasks

简单跑个程序测试一下,执行下面这条命令

DESKTOP-9K4GB6E# while : ; do : ; done &
[1] 12887

显然,它执行了一个死循环,可以把计算机的 CPU 吃到 100%,根据它的输出,我们可以看到这个脚本在后台运行的进程号(PID)是 12887。

查看一下 CPU 占用:

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
12887 root      25   5   14912   1912      0 R 100.0   0.0   0:33.31 zsh

果然这个 PID=12887 的进程占用了差不多 100% 的 CPU。

结下来我们就通过 Cgroups 对其进行限制,这里就用前面创建的 cgroup-cpu 控制组。

我们可以通过查看 container 目录下的文件,看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):

DESKTOP-9K4GB6E# cat /sys/fs/cgroup/cpu/cgroup-cpu/cpu.cfs_quota_us
-1
DESKTOP-9K4GB6E# cat /sys/fs/cgroup/cpu/cgroup-cpu/cpu.cfs_period_us
100000

接下来,我们可以通过修改这些文件的内容来设置限制。比如,向 container 组里的 cfs_quota 文件写入 20 ms(20000 us):

$ echo 20000 > /sys/fs/cgroup/cpu/cgroup-cpu/cpu.cfs_quota_us

这样意味着在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 CPU 时间,也就是说这个进程只能使用到 20% 的 CPU 带宽。

接下来,我们把被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

$ echo 12887 > /sys/fs/cgroup/cpu/cgroup-cpu/tasks

使用 top 指令查看一下

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
12887 root      25   5   14912   1912      0 R  20.3   0.0   2:51.05 zsh

果然 CPU 被限制到了 20%。

4. 小结

Cgroups 是 Linux 下的一种将进程按组进行管理的机制,它提供了对一组进程及将来子进程的资源限制控制和统计的能力

cgroups 分为以下三个部分:

  • cgroup 本身:对进程进行分组

  • hierarchy:将 cgroup 形成树形结构

  • subsystem:真正起到限制作用的部组件

使用步骤:

  • 1)创建 cgroup
  • 2)配置 subsystem 参数
  • 3)将进程加入到该 cgroup


如果你对云原生技术充满好奇,想要深入了解更多相关的文章和资讯,欢迎关注微信公众号。

搜索公众号【
探索云原生
】即可订阅


5. 参考

cgroups(7) — Linux manual page

Control groups series by Neil Brown

美团技术团队---Linux 资源管理之 cgroups 简介

Red Hat---资源管理指南

Linux Cgroup 系列(01):Cgroup 概述

PLC异地组网与远程控制,需求是基于园子认识的朋友提供,大体是实现PLC多个局域网异地组网,并实现远程控制、大屏展示、手机端控制、预警推送等功能。其他就是可以方便二次开发界面,以满足不同客户的需求。

目前还没有具体合作意向,只是一个构思。因为这里网关可以使用工控服务来实现,所以花了一点时间设计。

一、系统架构

说明:

1.采集终端

  • 工控盒子:用于网关控制,与PLC处于同一局域网使用Modbus-TCP协议交互。与云平台使用WebSocket连接。同时提供一套控制界面和api用于远程控制。

不带屏幕

带触控屏幕版本

  • PLC:控制各类传感器,使用RS232或RS485控制。
  • 温湿度传感器:采集温湿度
  • 电磁阀:控制水泵通路
  • 继电器:控制240V或380V电路开关

2.云平台

  • 消息推送:使用WebSocket连接网关(工控)、PC端、APP端、大屏系统。
  • 展示大屏:可视化方式展示多个组网设备状态,并实现远程控制。

  • PC端:用于后台管理,包括网关配置和下发、远程控制、预警阈值参数设置等。

  • APP端:用户手机端远程查看和控制设备,包含预警消息、设备中心等功能。

二、架构优点

  1. 灵活性高:工控端除了安装网关服务,也可以搭载NAT服务,将PLC内网IP和端口对外提供连接,方便之前的程序使用(Labview已经开发了一版)。
  2. 界面漂亮:UI使用HTML+CSS可以实现漂亮了的界面。
  3. 扩展性好:提供二次开发的能力,包括定制UI和web api。

前言

今天推荐一款由C#开源的、友好的.NET SDK管理器:Dots。

工具介绍

Dots 是一款 .NET SDK 管理器,可让您轻松安装、卸载和切换 .NET SDK。它是一款跨平台工具,可在 Windows 和 macOS 上运行,即将支持 Linux。它由 C# 编写,使用 Avalonia 作为 .NET UI 框架。

工具源代码

工具下载

  • 下载地址:
    https://github.com/nor0x/Dots/releases
  • Dots-2.0.0-win-x64.zip快速下载(网络不好的同学推荐使用):https://wwvn.lanzoul.com/iDHlH1kagp8b

工具运行

项目源码地址



更多项目实用功能和特性欢迎前往项目开源地址查看

前言

2023年对我来说是沉郁,忙碌的一年,一整年都没有写作文章。

一方面 ChatGPT 大火给我的写作热情带来了不小的打击,我想如果写的文章只是照本宣科,那确实没有写作的必要了,另一方面今年真的太忙了!实习、毕设、论文、秋招......伴随着无休止的内耗,让人喘不过气。

回看自己2021年底写的年终总结:
考研失败一周年,我进厂了
,行文之间显露出的青涩和找到实习的欣喜,殊不知那是互联网行业最后的狂欢。时至两年后的今天,互联网大环境急转直下,在这样的环境下求职,我有许多微薄体会,所以写作这样一篇文章来记述。

本文将涵盖我今年的大致经历,并着重讲解秋招部分,希望对你有所帮助。

时间线:春招 -> 4-7 入职比心直播后端技术部实习 -> 8-13 米哈游笔试 -> 8-24 比心离职 allin 秋招 -> 11-14 米哈游 oc。

正文

我必须要说,以非985/211学历为背景,求职不仅是能力相关。岗位的选择、简历的匹配度、投递的时机都是不可忽视的因素,当然这些一定程度上还是可以控制的。还有很多无法控制的可以总结成两个字的一个因素:运气。

个人背景

本硕双非,base 上海。

技术栈:Golang 为主,Java & Python 为辅。

leetcode:

image-20231231124443552

春招

2023届的秋招寒气逼人,不少学长都是在今年的春季才陆续找到工作。我在春季按照计划投递日常实习 & 暑期实习,也都大多不顺。几乎没有面试的机会。

最终通过面试的有两家:

  1. 杭州边锋网络(Golang 游戏服务端)
  2. 上海比心 App(Java 直播后端)

两家的实习薪资持平,从技术栈上我一定是倾向于边锋,但考虑到有点事就得时不时往学校跑,选择了比心。

当然选择实习的公司时,大家还可以从是否有转正 hc,公司的风评等角度考量。

比心

四月初收到了比心的面试,在通过了三轮线下面试后决定入职实习,部门是直播的后端,技术栈 Java。(通过看我 leetcode 也可以看出,5-6 月份处在了解业务,适应工作节奏的阶段,比较忙碌)

比心的基建很完善,实习期间我也学到了很多业务开发的知识,总体上来说是快速成长的几个月,只是简历上当时全是 Golang,虽做过 Java 的开发,但是免不了入职后 Java 的基础不稳影响工作效率,且学习的时候道心不坚。

放两张照片吧~公司大楼 & 儿童节团建。

image-20231231132256652

现在的秋招开启非常早,8月初开始陆续投递秋招岗位,8月24日,我从比心离职,正式 allin 秋招,当时了解到转正或是问题不大,但自己几个月的表现平平,估计给不了高的评价,加上对一线厂仍有执念,就离职了。

有点感慨,当天就发了这样一条朋友圈:

image-20231231141921983

秋招

  • 投递情况

下图是8月-10月我的一些投递记录,秋招中后期我便没有再仔细维护这张表,大家看个大概即可。

image-20231231133814442

  • 秋招感受
    • 心力憔悴:我投递的比较早,还获得了一些面试机会,但随着一次次的失败,产生了强烈的自我怀疑。加之学业压力,真的有些崩不住了。
    • 但相比周围的同学,我可能是较早筹备的缘故,已经算是情况比较好的,不少人面试机会寥寥,但其实大家水平差距不大。
  • 秋招结果
    • 面试了一些公司,很幸运最终上岸了米哈游。
  • 一些经验
    • 方向选择
      :算法、前后端、测开、运维、测试等岗位的竞争压力有所区别,如果有顾虑,就不要将鸡蛋放在一个篮子里。
    • 刷题
      必不可少,通过笔试是第一步,题量不是关键,但需要掌握常见题型(dp 很重要)。面试过程中的手撕算法题不会太难,leetcode hot 100 性价比很高。
    • 现在有很多知识博主整理的
      八股
      ,你一定不缺这些。牛客上有很多
      面试题
      ,秋招期间可以看看,对症下药效率更高。
    • 简历
      编写要下功夫,我认为你每做了一个项目或者学习了比较有意义的知识,就可以开始更新你的简历了,只有开始写了,你才知道自己缺少什么。
      (关注公众号回复 “简历” 可以获得我使用的模板)
    • 简历匹配度
      很重要,现在的简历确实很多,一二三线公司提出的用人标准也几乎一致,投递不同岗位尽可能准备不同的一份简历。
    • 当你收获了 offer,乃至不止一个 offer,有时有比薪资更值得考量的东西。
      • base 地点
      • 公司风评(脉脉)
      • 部门的工作氛围(面试中可以问,或者面试时自己也会有些感受)
      • 所属行业与你的兴趣

写给各位

哪怕我们做了上面所有的点,也就是7分的打拼,那么还有3分,是无可奈何的,这并不是我们的问题。

找工作的周期很长,从几个月到大半年,找到适合自己的节奏,保持身心健康。

最后祝大家新年快乐,感兴趣可以关注公众号
「白泽talk」
,白泽目前也打算打造一个氛围良好的行业交流群,欢迎加入:622383022。

实际存储型号H3C CF8844

环境说明:H3C存储设备存在一个坏盘需要更换。

更换准备

1. 取出备件检查完毕后放置到安全场所(请严格按照《IT产品现场工程师通用服务规(维修篇)》操作)


2. 通过ssh连接到存储控制器管理IP或通过串口连接到存储控制器。


3. 执行 showsys 命令确认维修设备序列号,与case中登记的信息以及现场设备信息核对一致方可继续进行。

4. 执行以下命令扫描存储系统以确保没有其他问题。

checkhealth -detail

警告:如果在检查运行状况扫描期间发现运行状况问题,请确认这些问题后再进行硬盘的更换。

5. 通过以下命令确定故障硬盘的位置:

通过命令输出记录下故障硬盘所在的位置(showpd输出中的CagePos字段第一段对应值)。如上示例中PD 7的盘柜编号为0,磁盘槽位

为7

警告:如果硬盘仍处于降级状态(degraded)而不是故障状态(failed),请不要尝试从盘柜中卸下硬盘,因为硬盘仍在腾空数
据。如果您移除硬盘处于降级状态(degraded),可能会丢失数据。等待硬盘进入故障状态(failed),表示数据已腾空,硬盘可
以安全更换。此过程可能需要几个小时。

6. 找到对应的故障盘将其拨下更换新盘

7. 确认数据迁移进度

8. 等待数据持续迁出

9. 数据迁完后,再查看是否还存在故障盘