因为emmc存储是一种flash存储技术,其写入寿命非常有限,所以系统运行中应尽量避免数据写入。
如果我们没有装什么特殊程序的话,通常来说数据的主要写入就是/var/log目录的日志了,一天几十MB还是有的。
armbian现状
armbian其实已经考虑了这个问题,因为armbian就是给arm架构订制的debian发行版嘛,所以它默认是创建了一个内存盘(zram文件系统)挂载到了/var/log目录:
Shell
root@aml:/var/log# df -h
Filesystem Size Used Avail Use% Mounted on
udev 469M 0 469M 0% /dev
tmpfs 184M 22M 163M 12% /run
/dev/mmcblk1p2 6.4G 2.1G 4.3G 33% /
tmpfs 920M 0 920M 0% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 920M 0 920M 0% /sys/fs/cgroup
tmpfs 920M 8.0K 920M 1% /tmp
/dev/mmcblk1p1 122M 58M 64M 48% /boot
/dev/zram0 49M 15M 31M 32% /var/log
tmpfs 184M 0 184M 0% /run/user/0
1
2
3
4
5
6
7
8
9
10
11
12
root@aml:/var/log# df -h
FilesystemSizeUsedAvailUse%Mountedon
udev469M0469M0%/dev
tmpfs184M22M163M12%/run
/dev/mmcblk1p26.4G2.1G4.3G33%/
tmpfs920M0920M0%/dev/shm
tmpfs5.0M4.0K5.0M1%/run/lock
tmpfs920M0920M0%/sys/fs/cgroup
tmpfs920M8.0K920M1%/tmp
/dev/mmcblk1p1122M58M64M48%/boot
/dev/zram049M15M31M32%/var/log
tmpfs184M0184M0%/run/user/0
所以频繁的日志写入并不会直接伤害到emmc。
但是这块zram盘只有49MB,基本上1~2天就会写满,所以armbian是如何处理的呢?
经过我的研究,发现系统做了1个systemd启动任务+2个cron任务用来解决这个问题,下面简单说一下原理。
详细分析
当然是定期删除日志了,难不成还有魔法嘛。
Shell
root@aml:/var/log# cat /etc/cron.d/armbian-truncate-logs
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
*/15 * * * * root /usr/lib/armbian/armbian-truncate-logs
1
2
3
4
root@aml:/var/log# cat /etc/cron.d/armbian-truncate-logs
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
*/15****root/usr/lib/armbian/armbian-truncate-logs
每15分钟就会执行一次truncate日志,这个脚本内容如下:
Shell
treshold=75 # %
[ -f /etc/default/armbian-ramlog ] && . /etc/default/armbian-ramlog
[ "$ENABLED" != true ] && exit 0
logusage=$(df /var/log/ --output=pcent | tail -1 |cut -d "%" -f 1)
if [ $logusage -ge $treshold ]; then
# write to SD
/usr/lib/armbian/armbian-ramlog write >/dev/null 2>&1
# rotate logs on "disk"
chown root.root -R /var/log.hdd
/usr/sbin/logrotate --force /etc/logrotate.conf
# truncate
/usr/bin/find /var/log -name '*.log' -or -name '*.xz' -or -name 'lastlog' -or -name 'messages' -or -name 'debug' -or -name 'syslog' | xargs truncate --size 0
/usr/bin/find /var/log -name 'btmp' -or -name 'wtmp' -or -name 'faillog' | xargs truncate --size 0
# remove
/usr/bin/find /var/log -name '*.[0-9]' -or -name '*.gz' | xargs rm >/dev/null 2>&1
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
treshold=75# %
[-f/etc/default/armbian-ramlog]&&./etc/default/armbian-ramlog
["$ENABLED"!=true]&&exit0
logusage=$(df/var/log/--output=pcent|tail-1|cut-d"%"-f1)
if[$logusage-ge$treshold];then
# write to SD
/usr/lib/armbian/armbian-ramlogwrite>/dev/null2>&1
# rotate logs on "disk"
chownroot.root-R/var/log.hdd
/usr/sbin/logrotate--force/etc/logrotate.conf
# truncate
/usr/bin/find/var/log-name'*.log'-or-name'*.xz'-or-name'lastlog'-or-name'messages'-or-name'debug'-or-name'syslog'|xargstruncate--size0
/usr/bin/find/var/log-name'btmp'-or-name'wtmp'-or-name'faillog'|xargstruncate--size0
# remove
/usr/bin/find/var/log-name'*.[0-9]'-or-name'*.gz'|xargsrm>/dev/null2>&1
fi
其实就是看一下/var/log的zram盘是否利用率超过75%,一旦超过就扫描/var/log下面各种日志文件进行截断。
另外,我们还看到它调用:
/usr/lib/armbian/armbian-ramlog write >/dev/null 2>&1
这个脚本的write命令会把/var/log内存盘的数据rsync到/var/log.hdd/目录,而/var/log.hdd目录是emmc上的一部分。因此,我们明白在truncate日志之前会先把当前最新日志持久化到emmc上,然后再把zram内存里的日志截断掉。
另外,这个脚本还调用了logrotate程序进行日志滚动,我详细看了一下logrotate配置文件,发现它归档的是/var/log.hdd里面的日志文件,其根本目的是为了配合zram -> emmc做rsync的时候可以结合rsync –delete选项删除掉归档的老日志文件,起到控制emmc容量的目的。(大家不理解可以不关心这一段逻辑)
所以呢,这个cron会导致每15分钟就会向emmc同步一次数据,并且缩小zram盘占用容量,这无疑是对emmc的频繁伤害。
另外还有一个天级cron是进行一次write同步,也是调用的如下同步命令:
/usr/lib/armbian/armbian-ramlog write >/dev/null 2>&1
因此,最简单的就是让这个write操作失灵,不向emmc同步日志数据不就好了嘛。
解决方法
打开/usr/lib/armbian/armbian-ramlog脚本,它实际执行的是这个shell方法:
Shell
syncToDisk () {
isSafe
echo -e "\n\n$(date): Syncing logs from $LOG_TYPE to storage\n" | $LOG_OUTPUT
if [ "$USE_RSYNC" = true ]; then
${NoCache} rsync -aXWv --delete --exclude armbian-ramlog.log --links $RAM_LOG $HDD_LOG 2>&1 | $LOG_OUTPUT
else
${NoCache} cp -rfup $RAM_LOG -T $HDD_LOG 2>&1 | $LOG_OUTPUT
fi
sync
}
1
2
3
4
5
6
7
8
9
10
11
12
13
syncToDisk(){
isSafe
echo-e"\n\n$(date): Syncing logs from $LOG_TYPE to storage\n"|$LOG_OUTPUT
if["$USE_RSYNC"=true];then
${NoCache}rsync-aXWv--delete--excludearmbian-ramlog.log--links$RAM_LOG$HDD_LOG2>&1|$LOG_OUTPUT
else
${NoCache}cp-rfup$RAM_LOG-T$HDD_LOG2>&1|$LOG_OUTPUT
fi
sync
}
只需要在函数头部返回即可避免rsync:
Shell
syncToDisk () {
# no sync to protect emmc
return 0
isSafe
echo -e "\n\n$(date): Syncing logs from $LOG_TYPE to storage\n" | $LOG_OUTPUT
if [ "$USE_RSYNC" = true ]; then
${NoCache} rsync -aXWv --delete --exclude armbian-ramlog.log --links $RAM_LOG $HDD_LOG 2>&1 | $LOG_OUTPUT
else
${NoCache} cp -rfup $RAM_LOG -T $HDD_LOG 2>&1 | $LOG_OUTPUT
fi
sync
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
syncToDisk(){
# no sync to protect emmc
return0
isSafe
echo-e"\n\n$(date): Syncing logs from $LOG_TYPE to storage\n"|$LOG_OUTPUT
if["$USE_RSYNC"=true];then
${NoCache}rsync-aXWv--delete--excludearmbian-ramlog.log--links$RAM_LOG$HDD_LOG2>&1|$LOG_OUTPUT
else
${NoCache}cp-rfup$RAM_LOG-T$HDD_LOG2>&1|$LOG_OUTPUT
fi
sync
}
可以再观察一下/var/log与/var/log.hdd,会发现/var/log.hdd已经不再有后续数据更新,而/var/log仍旧会自动在75使用率的时候进行日志截断。
最后补充,armbian做了一个systemd服务:/lib/systemd/system/armbian-ramlog.service,它开机会创建zram盘,然后从emmc的/var/log.hdd中load数据到zram的/var/log路径下,完成开机初始化。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~