crontab manual
https://www.computerhope.com/unix/ucrontab.htm#command-entries
使用systemd-run 替换
# systemd-run --on-active=30 /bin/touch /tmp/foo
# systemd-run --on-active="12h 30m" --unit someunit.service
https://www.computerhope.com/unix/ucrontab.htm#command-entries
# systemd-run --on-active=30 /bin/touch /tmp/foo
# systemd-run --on-active="12h 30m" --unit someunit.service
docker 有3种方式使用系统存储:
-v dir1:dir2
。将宿主机的目录dir1挂载到容器的dir2目录,实际执行的mount -o bind
类似命令--mount type=tmpfs,destination=/dir
, tmpfs是退出即释放的一种文件系统docker使用的文件系统经过很多变化,而且在各发行版下可能不同,但目前主流的是overlay2,执行docker info
查看当前使用的是overlay2
sudo docker info | grep Storage
Storage Driver: overlay2
除了overlay2,还有aufs(ubuntu),devicemapper(centos),btrfs和zfs。他们的实现都不同,都能支持分层和支持写时复制(Cow/copy-on-write),而他们实现的方式有区别,所以效率也有区别
而容器就是在镜像顶层压栈
了一个可写
层,而且是临时的,当容器销毁时,这层的文件也会删除
写时复制 copy-up 会导致第一次写时造成延迟,特别是大文件,拷贝起来费时。 但第二次就不会延时, 而且overlay2 有caching, 相比其它文件系统,更减少延时
touch /var/lib/rpm/*
当运行docker容器时查看挂载
overlay on /var/lib/docker/overlay2/04ea1faa8074e5862f40eecdba968bd9b7f222cb30e5bf6a0b9a9c48be0940f2/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/B74PWZCBMRCWXFH5UL2ZXB5WEU:/var/lib/docker/overlay2/l/WNHICVPVSDNUGSCZW435TPSMOK,upperdir=/var/lib/docker/overlay2/04ea1faa8074e5862f40eecdba968bd9b7f222cb30e5bf6a0b9a9c48be0940f2/diff,workdir=/var/lib/docker/overlay2/04ea1faa8074e5862f40eecdba968bd9b7f222cb30e5bf6a0b9a9c48be0940f2/work)
在保存容器后(docker commit),会多一层,里面包含了修改的文件,以及删除后生成的without文件,然后生成镜像
但对于以下特殊目录文件不会提交, 因为这些文件是运行时docker 要根据用户配置进行修改的。
例如docker 的link选项,会在容器的hosts 文件里定义对应的容器名->容器ip
.
├── A
│ ├── aa
│ └── a.txt
├── B
│ ├── a.txt
│ └── b.txt
├── C
│ └── c.txt
└── worker
└── work [error opening dir]
sudo mount -t overlay overlay -o lowerdir=A:B,upperdir=C,workdir=worker /tmp/test/
/tmp/test/
├── aa
├── a.txt
├── b.txt
└── c.txt
mount | grep 'overlay'
overlay on /tmp/test type overlay (rw,relatime,lowerdir=A:B,upperdir=C,workdir=worker)
https://docs.docker.com/storage/storagedriver/
遇到过一个面试题, 以下程序打印几个'A'
#include <stdio.h>
#include <unistd.h>
int main() {
printf("A");
fork();
printf("A");
}
#include <stdio.h>
#include <unistd.h>
int main() {
printf("A\n");
fork();
printf("A");
}
#./a.out > r.log
#cat r.log
分为无缓冲、行缓冲和全缓冲
发现有些程序可以输出到屏幕,重定向到文件后,执行ctl+c
退出后却没有任何内容,例如以下
#include <stdio.h>
#include <unistd.h>
int main(void) {
while (1) {
printf("Hello World\n");
sleep(1);
}
}
#./a.out > r.log
while read line ;do
#or while read -r line ;do
echo $line
done < $1
cat $1 | while read line ;do
echo $line
done
使用for时,结果略有不同, for以空格为一行
for line in $(cat $1) ;do
echo $line
done
https://bash.cyberciti.biz/guide/Reads_from_the_file_descriptor_(fd)
https://forum.xda-developers.com/t/guide-rom-8-1-lineageos-15-1-huawei-mediapad-m3-8-4-btv-w09-btv-dl09.4085995/
在debian上,之前一直用curlfs工具,将远程目录mount到本地目录。系统升级之后发现这个包没有了, 原来因为ftp不安全,所以现在推荐sshfs。
https://www.linuxtechi.com/configure-sftp-chroot-debian10/
# accept tupe and list
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n
print(sum)
calc([1,2])
calc((1,2,3))
# accept varidict argument
def calc2(*numbers):
sum = 0
for n in numbers:
sum = sum + n
return sum
calc2(0)
calc2(1,2,3,4)
numbers = [1,2,3]
# transform list to varidcit argument
print(calc(*numbers))
# varidict named arguments will be transformed to dict
# only accept named varidict argument
def person2(**kw):
if 'hello' in kw:
passs
print(kw)
# accept compose argument in sequence: normal argument & named varidict argument
def person(name, age, **kw):
print('name', name, 'age', age, 'other', kw)
person('mike',12)
person('mike',12, city='sh')
person('mike',12, city='sh', birth=1990)
person2(name='mike',age = 12, city='sh', birth=1990)
# compose normal type argument, varidict type argument, and varidict named type argument
def f2(a, b, c=0, *d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
cs=[3,4]
f2(1,2,*cs,hello='hello')
# use * to sepcify named type argument
def f3(a,b,c,*,d,e):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'e =', e)
# don't accept other named argument
f3(1,2,3,d=4,e=5)
# use tupe and dict can call all kind of function
# so *arg and **kw are always used to forward all argument to another function of any type of argument
args = (1,2,3)
kw = {'c':1,'d':2}
f2(*arg, **kw)
# at last, use base type for default value
Linux的命令行是非常强大的生产工具,现实中的问题好多可以不写复杂的编程代码而通过命令来解决, 而且不过几行代码而已
当执行which的时候,比如which echo
会输出'shell built-in command'而不是返回路径,就说明这个命令是内建命令
shell在执行内建命令时是直接执行,而非内建命令则fork一个子进程来执行
xargs可以将输入多进程并发处理,配合find
非常厉害。 配合wget就是一个并发爬虫了
EXAMPLES
find /tmp -name core -type f -print | xargs /bin/rm -f
Find files named core in or below the directory /tmp and delete them. Note that this will work incorrectly if there are any filenames containing newlines or spaces.
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
Find files named core in or below the directory /tmp and delete them, processing filenames in such a way that file or directory names containing spaces or newlines are correctly
handled.
find /tmp -depth -name core -type f -delete
Find files named core in or below the directory /tmp and delete them, but more efficiently than in the previous example (because we avoid the need to use fork(2) and exec(2) to
launch rm and we don't need the extra xargs process).
cut -d: -f1 < /etc/passwd | sort | xargs echo
Generates a compact listing of all the users on the system.
ls 本来是行分隔的 awk将ls的换行符变为|分割
ls | awk '{ ORS="|"; print; }'
echo $(ls)
则把ls的换行符变为空格
declare可以指定变量的类型'-i'为整形,'-r'制度(等同shell的readonly),'-g'全局变量
shell默认是字符串,使用'-i'后,数学运算不需要let
#retry=0
declare -i retry=0
while [ $retry -lt 30 ] ; do
ps aux --cols=1024 | grep xxx
if [ $? -eq 0 ] ; then
exit 0
fi
sleep 1
#let retry=$retry+1
retry=$retry+1
done
因为很多函数需要处理error, 当存在全局变量时,可能会覆盖全局变量
var global_var int = 1
func foo(){
// 此时覆盖了全局变量
global_var, err := os.OpenFile("file")
}
var global_var int = 1
func foo(){
var err error
global_var, error = os.OpenFile("file")
}
数组和slice使用上如同c++里的std::array和std::vector, 数组的长度固定,slice长度可以2倍扩容
但有传参上有大区别: golang中数组是值传递,相当于将整个数组复制一遍,而slice是引用传递,所以slice用得多,map同理
定义数组和slice:
// 数组
var a [3] int
arr := [5] int {1,2,3,4,5}
var array2 = [...]int {6,7,8}
q := [...] int {1,2,3} // 省略长度
q2 := [...] int {99, -1} // 前99项为0,第100个元素是-1
// slice
s1 := []int{1, 2, 3}
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} //a是数组
s2 := a[2:8]
s3 := make([]int, 10, 20)
两者很多时候可以相互替换,但是在不同类型上,有区别
对于基本类型string, int, boolean, 数组,var声明
即初始化
var str string // 自动初始化为空字符串
var inter int // 自动初始化为0
var bo bool // 自动初始化为false
// 可以直接使用
fmt.Printf("%s %d %t", str, inter, bo)
而对于slice, map, chann类型而言, 使用var m map[int]string
只是声明,需要再用make
来获得内存和初始化
var m map[int] string // 此时不能使用m
m = make(map[int] string){1:"a",2:"b"}
fmt.Println(m[1])
m := make(map[int] string){1:"a", 2:"b"}
m := map[int] string{1:"a", 2:"b"}
vscode使用clangd作为c++的lsp非常好用,可以支持跳转、补全、clang-tidy、提示,但同时也对配置有要求,我的12Gi内存经常不够用而非常卡
于是摸索了一下,发现有两个问题:
1. clangd会占用很多内存
2. clangd在处理代码文件时会产生pch文件默认放到/tmp目录占用内存
这里会说怎么解决这2个问题,也顺便用到systemd-tmpfiles工具
由于代码比较复杂,随便跳转几个文件就开始感到卡顿,一会就不能动了。切换X界面到终端, 执行free
命令,可以看到shared和buff/cache两个部分占用很大内存
~ > free -h
total used free shared buff/cache available
Mem: 11Gi 7.1Gi 721Mi 1.0Gi 3.7Gi 3.1Gi
Swap: 0B 0B 0B
通过man可以知道这几项的意思, 可见share在我的系统指'/tmp', 因为tmpfs挂载在/tmp目录
shared
Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)
buffers
Memory used by kernel buffers (Buffers in /proc/meminfo)
cache
Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
buff/cache
Sum of buffers and cache
cat /proc/meminfo
查看到buff占用不大,不是内核问题(因为我用的最新内核,所以抱有怀疑态度)
~ > cat /proc/meminfo | grep "Buffers\|Cached"
Buffers: 308440 kB
Cached: 3297168 kB
所以主要是/tmp目录占用内存过大,以及clangd占用内存过大
-background-index=0
时,才能避免内存占用过大~ > ls /tmp/*.pch -lh
-rw-r--r-- 1 100M May 13 11:18 /tmp/preamble-133598.pch
-rw-r--r-- 1 104M May 13 11:17 /tmp/preamble-457bd6.pch
-rw-r--r-- 1 104M May 13 11:17 /tmp/preamble-465a46.pch
-rw-r--r-- 1 104M May 13 11:18 /tmp/preamble-99f5e5.pch
-rw-r--r-- 1 99M May 13 11:17 /tmp/preamble-b56fad.pch
systemd-tmpfiles 通过systemd-tmpfiles-clean.timer
定时调用systemd-tmpfiles-clean.service
, 来清理零时文件,且是默认启动的。
虽然/tmp目录使用的内存挂载tmpfs
(也有写发行版使用物理磁盘来挂载),在重启时会清空,但对于服务器这种常年不会重启的系统,就需要这样的机制清理内存/磁盘。
timer默认的配置文件,OnBootSec=15min
表示在系统启动15分钟后开始执行,而OnUnitActiveSec=1d
表示在执行一次后,1天后再执行
~ > cat /usr/lib/systemd/system/systemd-tmpfiles-clean.timer
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Daily Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
[Timer]
OnBootSec=15min
OnUnitActiveSec=1d
上面的timer会定时调用systemd-tmpfiles-clean.service
这个服务
~ > sudo systemctl status systemd-tmpfiles-clean.service
○ systemd-tmpfiles-clean.service - Cleanup of Temporary Directories
Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.service; static)
Active: inactive (dead) since Wed 2021-05-12 16:37:27 HKT; 22h ago
TriggeredBy: ● systemd-tmpfiles-clean.timer
Docs: man:tmpfiles.d(5)
man:systemd-tmpfiles(8)
Process: 36637 ExecStart=systemd-tmpfiles --clean (code=exited, status=0/SUCCESS)
上面是timer的设置,这个timer适合服务器,但并不建议修改它们。而是添加规则,再手动调用systemd-tmpfiles --clean
配置规则的方法可以查看man tmpfiles.d 5
,但只建议在/etc 和 ~/ 目录添加规则, 前者对所有用户生效,后者只对自己生效
TMPFILES.D(5) tmpfiles.d TMPFILES.D(5)
NAME
tmpfiles.d - Configuration for creation, deletion and cleaning of volatile and temporary files
SYNOPSIS
/etc/tmpfiles.d/*.conf
/run/tmpfiles.d/*.conf
/usr/lib/tmpfiles.d/*.conf
~/.config/user-tmpfiles.d/*.conf
$XDG_RUNTIME_DIR/user-tmpfiles.d/*.conf
~/.local/share/user-tmpfiles.d/*.conf
直接从/usr/lib/tmpfs.d/ 找合适的配置,拷贝到自己的目录再改
删除/tmp/*.pch文件的效果
~ > free
total used free shared buff/cache available
Mem: 12158548 7808240 854296 1010820 3496012 3019688
Swap: 0 0 0
~ > rm /tmp/*.pch
~ > free
total used free shared buff/cache available
Mem: 12158548 7804356 1169052 699936 3185140 3334460
Swap: 0 0 0
shared项少了许多, 再设置background-index=0
后,内存占用大大减小
使用systemd-tmpfs 来清除文件的方式不太适合这种场景, 但其本身是非常功能强大的管理工具