2021年2月

本文起源于:swap 的扩容(及其他)

经常写简单命令行程序的人可能会知道,这些是标准输入输出文件和标准出错文件,在平时一般会被重定向到屏幕上,你可以看到它实际上指向的是/proc/self/fd/*

[root@quality-unicorn-3 ~]# ls /dev -alh | grep std
lrwxrwxrwx   1 root root          15 Feb  7 08:29 stderr -> /proc/self/fd/2
lrwxrwxrwx   1 root root          15 Feb  7 08:29 stdin -> /proc/self/fd/0
lrwxrwxrwx   1 root root          15 Feb  7 08:29 stdout -> /proc/self/fd/1

/proc/self/fd/*又是啥呢?
用同样的套路可以看到:

... /proc/self/fd/0 -> /dev/pts/0
... /proc/self/fd/1 -> /dev/pts/0
... /proc/self/fd/2 -> /dev/pts/0

实际上在这里的self指的就是程序自身,也就是当前所使用的bash程序,而下面fd中的0,1,2等就是对应打开文件的符号链接,它们都指向了同一个设备:/dev/pts/0。而利用secureCRT连接的设备代号即为pts/0

到这里为止一切都明白了,当我们使用终端连接的时候,在操作系统中创建了一个设备pts/0,而我们所做的所有交互都是通过这个设备进行。
stdin/stdout/stderr都被重定向至这个设备中,也就意味我们可以通过这个设备来给连接时创建的bash发送与接受命令。使用ps -A | grep bash可以看到我们启动的bash所对应的设备描述文件,即我们自己的窗口

[root@quality-unicorn-3 ~]# ps -A |grep bash
 3503 pts/0    00:00:00 bash

如果有很多个人(或者你自己开很多个窗口)同时连接,就可以看到类似如下的内容:

[root@quality-unicorn-3 ~]# ps -A |grep bash
 3503 pts/0    00:00:00 bash
 3536 pts/1    00:00:00 bash

既然我们已经知道pts/*究竟代表什么,就可以玩一些骚操作了,比如:

[root@quality-unicorn-3 ~]# echo cnm > /dev/pts/1

这样就可以往另一个人的界面中发送文字片段,或者:

[root@quality-unicorn-3 ~]# cat /dev/pts/1

这样别人输入的命令就有概率出现在你的屏幕上(有概率是因为他的输入要么出现在他自己的屏幕上,要么出现在你的屏幕上,两边不会同时出现,测试发现基本是等概率的),导致你能猜到他要输入什么信息,并且他经常需要按好几次按键才会成功。还可以把以上两点结合起来,作用读者可以自己尝试:

[root@quality-unicorn-3 ~]# cat /dev/pts/1 > /dev/pts/1 

顺便说一句,如果不是使用ssh远程连接,在这里的pts/*实际上应该为tty/*,具体背景可以在参考资料里找。

参考资料:
stdin、stdout、stderr 标准流本质上到底是什么? - 知乎
Linux下的tty和pts详解

背景

当前这个网站所使用的服务器是搬瓦工的远古套餐,RAM只有可怜的512Mb,默认的swap只有可怜的132MB,连阿里云的学生机配置都是它的四倍,上面还用LAMP搭建了好几个网站(虽然日活不高就是了),以至于每次登录到管理平台时都能看到RAM和SWAP的条条不是红的就是黄的。(这也是为啥网站这么简陋的原因)

服务器刚刚重启过,现在还是绿的,而且swap我也改过了,这是另一台的截图,莫得原先满内存的截图了

(服务器刚刚重启过,现在还是绿的,而且swap我也改过了,这是另一台的截图,莫得原先满内存的截图了)

虽然不确定是不是极低内存带来的后果,我的网站每隔几个月就会挂一次,每次都要登陆上去重启下,推测是极低内存导致的

重启记录

重启记录

既然莫得钱去升级物理机,只能从swap的角度入手了,网上搜了搜方法顺便学了下Linux的皮毛,在此记录下来,顺便希望扩容swap之后不会再出现挂掉之类的问题。

正文

由于写这篇文章的时候搭本网站的机子已经成功扩容了,以下内容是从另一台机子重新做起的,依然是搬瓦工上同配置的乞丐机:

登陆上去后首先输入free -h可以看到现在机器的内存与swap信息:

[root@quality-unicorn-3 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           496M        121M        115M         29M        258M        332M
Swap:          131M        2.5M        129M

使用swapon --show可以查看当前swap对应的文件

[root@quality-unicorn-3 ~]# swapon --show
NAME  TYPE SIZE USED PRIO
/swap file 132M 2.5M   -2

想要扩容swap可以创建一个新的swap,或者增加已有的空间,这里以扩容为例:

[root@quality-unicorn-3 ~]# swapoff /swap
[root@quality-unicorn-3 ~]# dd if=/dev/zero of=/swap bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.87611 s, 156 MB/s
[root@quality-unicorn-3 ~]# mkswap /swap
Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=fdd6a949-d585-4c31-af70-d3fbe0212a64
[root@quality-unicorn-3 ~]# swapon /swap

依次输入上面的命令就可以啦,可以使用freefree -h查看结果:

[root@quality-unicorn-3 ~]# free
              total        used        free      shared  buff/cache   available
Mem:         507912      124440       14688       30692      368784      339816
Swap:       1048572           0     1048572
[root@quality-unicorn-3 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           496M        121M         14M         29M        360M        327M
Swap:          1.0G          0B        1.0G

当然,这里使用的机器是没怎么使用内存的,如果内存本来就爆表了怎么办呢?

以下我来模拟原本内存就写满了的情况:

[root@quality-unicorn-3 memtest]# free -h
              total        used        free      shared  buff/cache   available
Mem:           495M         38M         19M        1.5M        436M         42M
Swap:          130M         76M         54M

如上所示,当前swap只剩54M,物理内存就更少了,这种情况下是不能直接删除swap的,因为swap中存储的东西不足以装入物理内存中,所以只能创建一个新的临时的swap暂时存储,再扩容原先的swap。以下是全过程:

[root@quality-unicorn-3 ~]# dd if=/dev/zero of=/swaptemp bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 6.39658 s, 168 MB/s
[root@quality-unicorn-3 ~]# mkswap /swaptemp
Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=2c971653-47df-4a23-a0ac-507d9e382a9f
[root@quality-unicorn-3 ~]# chmod 0600 /swaptemp
[root@quality-unicorn-3 ~]# swapon /swaptemp
[root@quality-unicorn-3 ~]# swapoff /swap
[root@quality-unicorn-3 ~]# dd if=/dev/zero of=/swap bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 7.40158 s, 145 MB/s
[root@quality-unicorn-3 ~]# mkswap /swap
Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=9f56cb48-ab69-4329-a81b-de4a98162e28
[root@quality-unicorn-3 ~]# swapon /swap
[root@quality-unicorn-3 ~]# swapoff /swaptemp
[root@quality-unicorn-3 ~]# rm /swaptemp
rm: remove regular file ‘/swaptemp’? y

这样swap就扩容完啦,以下是扩容后的结果:

[root@quality-unicorn-3 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           495M         54M        6.3M        1.5M        434M         26M
Swap:          1.0G         65M        958M

可以看到swap已经被扩容至1G

知其所以然

  • free命令用于显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存,如果加上-h,即free -h可以使输出结果更友好,将容量转换为合适的单位。类似的用法在其他很多命令中也有,比如ls -lhls -l相比单位更友好,还有du -hdu也类似
  • mkswap/swapon/swapoff均用于管理交换内存(swap),mkswap用于设置交换区,swaponswapoff分别用于激活与关闭交换区。使用时直接在后面跟随对应的文件即可
    文中还出现了swapon --show的用法,其作用是列出当前所有的交换区
  • dd命令用于读取、转换并输出数据,在本文中仅仅读取并输出,并无转换的操作。对于本文中出现的dd if=/dev/zero of=/swap bs=1M count=1024命令,其作用是从/dev/zero中读取数据,存入/swap文件中,每次读取与输出1M大小的数据,读写1024次即1024M,也就是1G
  • chmod 0600 /swaptemp命令用于修改/swaptemp的权限,实际上这一步不是必须的,但是如果没有这一步可能会提示当前的权限(一般是0644)不安全,建议使用0600。所以为了安全性最好加上

多学点儿

在演示时我是怎么快速把内存填满的呢?

Linux有个很神奇的功能,是可以把一个文件夹挂载至内存当中,即往这个文件夹内部写入的文件都会被写入到内存中。所以只要根据这种方法创建一个文件夹往里不停写东西就行啦:

mkdir memtemp
mount -t ramfs ramfs memtemp/
dd if=/dev/urandom of=z/file bs=1M count=128
dd if=/dev/urandom of=z/file bs=1M count=128
...

不过这是一个非常危险的行为,与在应用程序内申请内存不同,这种方式往内存里写东西似乎并没有做很多保护措施,稍微写多一点你可能就连不上服务器了,每次写入文件时一定要注意别超过物理内存的容量,当接近写满时可以输入一些其他命令(比如yum/apt list啥的)令操作系统把一些内存往swap里装。

参考资料/扩展阅读:
在 Linux 上简单模拟系统负载的方法

在使用dd命令时用到的/dev/zero/dev/urandom是什么呢?

对Linux有那么一丁点儿了解的人可能会知道,在Linux中,万物皆为文件。多有一点儿了解的可能还会知道/dev目录是设备的目录。所以在该目录下的zerourandom当然就是设备啦。

不过设备可不一定必须是物理设备,在这里的zerourandom就是虚拟设备。

zero设备的作用是可以无限从中读取出空内容(0x00),而urandom则可以无限从中读取出随机数。

zero类似的还有null,可以无限往里写入内容,写入的内容会被丢弃,与urandom类似的还有random,不过random获取到的是来自于物理设备噪声的真随机数,而urandom获取到的是伪随机数。

除此之外还有一些设备也在/dev文件夹中,可以使用ls /dev -alh来查看,这里列举几个常用的:

stdin/stdout/stderr:本来是打算把全文就放在这里的,可是越写越长放在这里有点喧宾夺主了,于是另外开了一篇:stdin/stdout/stderr 那点事儿

full:总是在向其写入时返回设备无剩余空间(错误码为ENOSPC),读取时则与/dev/zero相似,返回无限的空字符(0x00)。这个设备通常被用来测试程序在遇到磁盘无剩余空间错误时的行为。

参考资料/拓展阅读:
linux dev 常见特殊设备介绍与应用(loop,null,zero,full,random)
/dev/urandom和/dev/random的区别是什么