本文是专题:建站日记中的第8篇,共12篇

写下文本,源于我最近一次失败的尝试。我的VPS是限定最高内存用量的,上限为2G,如果内存用完了,就会出现Cannot allocate memory无法获取可用内存的故障,导致SSH无法远程登录,也网站性能也急剧下降。这个问题可以通过限制Apache和Mysql的配置来预防。可以做保守配置来杜绝这样的问题。但是由于我的配置比较乐观,可能在某些木马攻击或者劣质网站爬虫的骚扰下,前几天出现过一次内存不足问题,导致不得不请求服务商帮我重启了一下运行了60多天的服务器,让我非常伤心。所以我尝试了一下,可否通过建立脚本,监控运行状况来自动重启Apache和Mysql来释放内存,避免重启服务器,好让我的uptime千秋万代地积累下去?

最容易想到的就是采用Crontab来做了,下面是我第一次的尝试。脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#check free memory and decide how to maintain system.
#Albert Zhu 朱文昊 V0.1 http://zhuwenhao.com
MinFreeMem='100000' #only restart apache below this number
BadFreeMem='10000'  #retart apache and mysql below this number
CurrentMem=$(cat /proc/meminfo | grep -i MemFree | cut -d ':' -f2 | cut -d 'k' -f1)
CurrentMem=$(($CurrentMem+0))
#echo "CurrentMem="$CurrentMem
#echo "MinFreeMem="$MinFreeMem
#echo "BadFreeMem="$BadFreeMem
if [ $BadFreeMem -gt $CurrentMem ];
then
        echo `date "+%Y-%m-%d-%H-%M-%S"`
        echo "CurrentMem="$CurrentMem
        echo "restarted two service"
        service apache2 restart;
        service mysql   restart;
else
 
        if [ $MinFreeMem -gt $CurrentMem ];
        then
                echo `date "+%Y-%m-%d-%H-%M-%S"`
                echo "CurrentMem="$CurrentMem
                echo "restarted apache"
                service apache2 restart;
        fi
        echo `date "+%Y-%m-%d-%H-%M-%S"`
        echo "Free Memory is Good!"
fi

然后使用cron job来自动运行 crontab –e 后加入

1
* * * * * ./memmonitor.sh >> ./memmonitor.log

这样我的脚本会每分钟运行一下,怎么样?感觉很爽吧!于是压力测试,Apache在强大的并发连接下,很快内存飙升,2G内存立马没了。结果,当Cron job醒来后,内存不足,自己都运行不起来,崩溃~~~

分析一下,感觉是cron job每分钟运行一次,太慢!造成对内存感觉不灵敏,等到发现,已经晚了。cron设计最快也就是每分钟运行。于是改用死循环来做,也就是做成守护进程Daemon,对内存每秒钟检查一次,够好了吧?

继续压力测试,依然崩溃~~~~~

于是review脚本,发现 service apache2 restart这样的语句,本身需要较大的内存,而且貌似要等到apache的子进程把当前服务提供完后,才终止(这点我不是很确定,不要太相信)。如果在DDOS下,哪里有空等服务结束?应当直接kill掉。修改脚本为如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#check free memory and decide how to maintain system.
#Albert Zhu 朱文昊 V0.2 http://zhuwenhao.com
KillAllApacheSon ()
{
ListPIDtoKill=$(ps  -u wwwrun | grep httpd | cut -d ' ' -f1)
echo "List PID to Kill "$ListPIDtoKill
i=1
while [ true ];
do
        GetPIDtoKill=$(echo ${ListPIDtoKill} | cut -d ' ' -f${i})
        GetPIDtoKill=$(($GetPIDtoKill+0))
        if [ $GetPIDtoKill -gt 0 ];
        then
                kill $GetPIDtoKill
                echo "kill "$GetPIDtoKill
                i=$(($i+1))
        else
                break;
        fi
done
echo "Killed Apache Son Num: "$i
}
KillMysql ()
{
GetPIDtoKill=$(ps -u mysql | cut -d ' ' -f1)
GetPIDtoKill=$(($GetPIDtoKill+0))
if [ $GetPIDtoKill -gt 0 ];
then
        kill $GetPIDtoKill
        echo "kill mysql and PID is "$GetPIDtoKill
fi
}
CheckMem ()
{
MinFreeMem='100000' #only restart apache below this number
BadFreeMem='10000'  #retart apache and mysql below this number
CurrentMem=$(cat /proc/meminfo | grep -i MemFree | cut -d ':' -f2 | cut -d 'k' -f1)
CurrentMem=$(($CurrentMem+0))
#echo "CurrentMem="$CurrentMem
#echo "MinFreeMem="$MinFreeMem
#echo "BadFreeMem="$BadFreeMem
if [ $BadFreeMem -gt $CurrentMem ];
then
        echo `date "+%Y-%m-%d-%H-%M-%S"`
        echo "CurrentMem="$CurrentMem
        echo "restarted two service"
        KillAllApacheSon
        KillMysql
        service mysql   restart
else
 
        if [ $MinFreeMem -gt $CurrentMem ];
        then
                echo `date "+%Y-%m-%d-%H-%M-%S"`
                echo "CurrentMem="$CurrentMem
                echo "restarted apache"
                KillAllApacheSon
        fi
        echo `date "+%Y-%m-%d-%H-%M-%S"`
        echo "Free Memory is Good!"
fi
}
renice -15 $$ >> ./second.log
#echo $(nice)
while [ true ];
do
#       sleep 1
        usleep 100
        CheckMem>>./second.log
done

这次修改比较幸苦,感觉一个小脚本写到这份上,对我来说也算得上是高级bash编程了吧?呵呵。拉出来溜溜?惨不忍睹。依然无法实现预期功能。为什么?难道1秒钟也太漫长?

于是请出usleep,每隔100毫秒就检查内存一次。我的cpu 10%都用在这个脚本上了,结果怎么样?没用! 写到这里,我心灰意冷了,彻底放弃。亲爱的朋友,有谁能帮帮我呢?

我写出上面的文字来,除了期待高手来解救我之外,还有一个原因。仔细想想看,我的这些脚本不能在VPS上实现功能,但应该可以在独立服务器或者PC上工作,为什么呢?因为VPS一旦接近耗尽内存,那真的是一点memory都allocate不处理,所以脚本本身就无法继续执行.但是对于独立服务器或者PC, 都有swap机制. 在物理内存耗尽的情况下, 会拿硬盘来充数,虽然速度慢很多,但以上的两个版本的脚本,都有可能正常工作.所以如果你测试以上脚本可用,请告诉我,抚慰一下我受伤的心吧 :)

专题导航前一篇后一篇