3月 19

服务器上固态硬盘使用情况追踪测试

2012年8月17日 在服务器上装了一块固态硬盘,当时做了个测试
http://www.simonzhang.net/?p=1298

测试磁盘写能力
time dd if=/dev/zero of=/cache/test.dbf bs=8k count=300000
a

测试磁盘读能力
time dd if=/cache/test.dbf of=/dev/null bs=8k
b

  因为服务器还在工作,并且有20G的左右的缓存数据在使用,能保持这个效率还是不错。

查看一下磁盘健康情况,使用smartmontools工具
# yum install -y smartmontools

常用命令:
健康状况
smartctl -H /dev/hdb
列出错误日志。如果日志量过大,应该尽快更换
smartctl -l error /dev/hdb
所有信息
smartctl -a /dev/hdb

信息里面有温度,加电时间,等详细信息。

附录加载部分
/dev/system/root/ext4 discard,errors=remount-ro,noatime 0 1

3月 08

linux下查看使用硬盘IO过高的进程

  服务器cpu使用率不高,load比较高,所以要查看一下IO。硬盘IO可以通过命令vmstat或iostat获得(也可以用yum 安装dstat获得),网络IO可以用iftop命令获取。但是不知道那个进程使用硬盘IO比较高,通过查找没有找到相关命令,只好自己写个脚本进行统计处理。
  本脚本在CentOS6下(kernel2.6以上)python2.6测试通过。
  直接运行脚本,默认情况下收集3秒钟数据,显示读写最高的前三个进程。如用参数可以使用命令“python fhip.py 4 5 3”,第一个数位每次收集读写数据的间隔秒数,第二个数是打印出读写最多的n个进程,第三个为运行脚本的次数。因为参数部分写的比较简单那,所以用参数必须3个全写。

#!/bin/python 
#-*- coding:utf-8 -*- 
# Filename:    find_high_io_process
# Revision:    1.0 
# Date:        2013-3-8 
# Author:      simonzhang 
# web:         www.simonzhang.net 
# Email:       simon-zzm@163.com 
### END INIT INFO
import os
import re
import sys
import time
from string import strip

####
sys_proc_path = '/proc/'
re_find_process_number = '^\d+$'

####
# 通过/proc/$pid/io获取读写信息
####
def collect_info():
    _tmp = {}
    re_find_process_dir = re.compile(re_find_process_number)
    for i in os.listdir(sys_proc_path):
        if re_find_process_dir.search(i):
            # 获得进程名
            process_name = open("%s%s/stat" % (sys_proc_path, i), "rb").read().split(" ")[1]
            # 读取io信息
            rw_io = open("%s%s/io" % (sys_proc_path, i), "rb").readlines()
            for _info in rw_io:
                cut_info = strip(_info).split(':')
                if strip(cut_info[0]) == "read_bytes":
                    read_io = int(strip(cut_info[1]))
                if strip(cut_info[0]) == "write_bytes":
                    write_io = int(strip(cut_info[1]))
            _tmp[i] = {"name":process_name, "read_bytes":read_io, "write_bytes":write_io}
    return _tmp


def main(_sleep_time, _list_num):
    _sort_read_dict = {}
    _sort_write_dict = {}
    # 获取系统读写数据
    process_info_list_frist = collect_info()
    time.sleep(_sleep_time)
    process_info_list_second = collect_info()
    # 将读数据和写数据进行分组,写入两个字典中
    for loop in process_info_list_second.keys():
        second_read_v = process_info_list_second[loop]["read_bytes"]
        second_write_v = process_info_list_second[loop]["write_bytes"]
        try:
            frist_read_v = process_info_list_frist[loop]["read_bytes"]
        except:
            frist_read_v = 0
        try:
            frist_write_v = process_info_list_frist[loop]["write_bytes"]
        except:
            frist_write_v = 0
        # 计算第二次获得数据域第一次获得数据的差
        _sort_read_dict[loop] = second_read_v - frist_read_v
        _sort_write_dict[loop] = second_write_v - frist_write_v
    # 将读写数据进行排序
    sort_read_dict = sorted(_sort_read_dict.items(),key=lambda _sort_read_dict:_sort_read_dict[1],reverse=True)
    sort_write_dict = sorted(_sort_write_dict.items(),key=lambda _sort_write_dict:_sort_write_dict[1],reverse=True)
    # 打印统计结果
    print "pid     process     read(bytes) pid     process     write(btyes)"
    for _num in range(_list_num):
        read_pid = sort_read_dict[_num][0]
        write_pid = sort_write_dict[_num][0]
        res = "%s" % read_pid
        res += " " * (8 - len(read_pid)) + process_info_list_second[read_pid]["name"]
        res += " " * (12 - len(process_info_list_second[read_pid]["name"])) + "%s" % sort_read_dict[_num][1]
        res += " " * (12 - len("%s" % sort_read_dict[_num][1])) + write_pid
        res += " " * (8 - len(write_pid)) + process_info_list_second[write_pid]["name"]
        res += " " * (12 - len("%s" % process_info_list_second[write_pid]["name"])) + "%s" % sort_write_dict[_num][1]
        print res
    print "\n" * 1


if __name__ == '__main__':
    try:
        _sleep_time = sys.argv[1]
    except:
        _sleep_time = 3
    try:
        _num = sys.argv[2]
    except:
        _num = 3
    try:
        loop = sys.argv[3]
    except:
        loop = 1
    for i in range(int(loop)):
        main(int(_sleep_time), int(_num))

linux查找IO高的进程的源码

2月 21

服务器 自动封锁和解封IP 对付攻击

  服务器流量暴涨,首先通过访问日志查看。每个IP并发不是很高,分布也很广,但是都是只访问主页,可见不是抓取服务导致。通过“netstat -nat|awk ‘{print awk $NF}’|sort|uniq -c|sort -n”t命令查看,连接中还有很多SYN_RECV、TIME_WAIT、ESTABLISHED。看来是小型的攻击。首先是修改web服务的配置,缩减了timeout时间,在nginx上禁止一部分并发比较高的IP,小改系统参数。流量降了20M,但还是太高。nginx虽然禁止了IP,如果用浏览看是一个空白页面,但是每个连接还会产生很小的流量。最后决定将最小的返回值也封掉,直接在iptables上drop掉连接。每个超限IP暂定封2天。写个脚本自动运行。

  此脚本在在centos5.3+python2.6.6使用通过。需要注意,此脚本统计日志完毕会将nginx日志文件清空,如需保留日志,请自行修改。每次加载iptables规则时会清楚上次所有规则,如果有使用其它规则也要自行处理。

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    drop_ip_iptables.py
# Revision:    1.0
# Date:        2013-2-21
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import os
import time
from string import strip


#### 参数和脚本中使用到的系统命令
nginx_log = "/usr/local/nginx/logs/nginx.access.log"
# 统计nginx日志中IP访问数量
check_comm = "/bin/cat %s |awk ' ''{print $1}'|sort |uniq -c|sort -n -k1 -r" % nginx_log
# 放在crontab中10分钟跑一次,访问超出n次的全部封掉
overproof = 3000
# 被封地址记录文件
# 文件中记录封IP时间和IP地址。时间单位为秒
lock_ip_list = "/usr/local/nginx/logs/lock_ip_list.txt"
# 被封地址解开时间。时间单位为秒
unlock_time = 3600*24*2 


def manage_lock_ip():
    # 获取当前时间
    get_now_time = int(time.time())
    # 管理日志字典
    man_ip = {}
    # 处理日志中的IP
    try:
        log_file = open('%s' % lock_ip_list, 'rb').readlines()
        for get_ip_info in log_file:
            _get_ip_info = strip(get_ip_info).split(' ')
            man_ip['%s' % _get_ip_info[1]] = int(_get_ip_info[0])
    except:
        exit(0)
    # 清空iptable列表,和ip记录日志
    os.popen('/sbin/iptables -F')
    clean_file = open('%s' % lock_ip_list, 'rb+')
    clean_file.truncate()
    # 开始处理IP,被封没有超时的IP写入iptables和日志中
    log_file = open('%s' % lock_ip_list, 'ab')
    for loop_ip in man_ip.keys():
        if (get_now_time - man_ip[loop_ip]) < unlock_time:
            os.popen('/sbin/iptables -I INPUT -s %s -j DROP' % loop_ip)
            log_file.write('%s %s\n' % (man_ip[loop_ip], loop_ip))
    log_file.close()
        


def main():
    # 已封IP地址字典
    drop_ip_list = {}
    # 加载已封IP日志
    try:
        log_file = open('%s' % lock_ip_list, 'rb').readlines()
        for get_drop_ip_info in log_file:
            _get_drop_ip_info = strip(get_drop_ip_info).split(' ')
            drop_ip_list['%s' % _get_drop_ip_info[1]] = int(_get_drop_ip_info[0])
    except:
        os.mknod('%s' % lock_ip_list)
    # 获取nginx日志中的访问超高的ip并写入日志
    access_high_ip = os.popen('%s' % check_comm).readlines()
    for get_ip_count in access_high_ip:
        try :
            _get_ip_count = strip(get_ip_count).split(' ')
            _get_ip = _get_ip_count[1]
            _get_count = _get_ip_count[0]
        except:
            pass
        if (int(_get_count) > int(overproof)) and (_get_ip not in drop_ip_list.keys()):
            now_time = int(time.time())
            log_file = open('%s' % lock_ip_list, 'ab+')
            log_file.write('%s %s\n' % (now_time, _get_ip))
            log_file.close()
    # 统计完毕清空nginx日志
    log_file = open('%s' % nginx_log, 'wb')
    log_file.truncate()
    # 处理要封的IP和要解开的IP
    manage_lock_ip()


if __name__ == '__main__':
    main()

再补充两条日志分析命令
# 单位时间内统计单个IP只访问首页的数量:
#check_comm = “/bin/cat %s|grep ‘GET / HTTP/1.1’|awk ‘ ”{print $1}’|sort |uniq -c|sort -n -k1 -r” % nginx_log
# 单位时间内统计单个IP访问相同页面的数量
#check_comm = “/bin/cat %s|awk -F'”‘ ‘{print $1 $2}’|awk ‘ ”{print $1″ “$6” “$7” “$8}’|sort -k2,4 -r|uniq -c|sort -n -k1 -r” % nginx_log

源码下载
drop_ip_tables

2月 20

学习《Linux系统灾难恢复技术和方法》分区表丢失

http://doc.chinaunix.net/linux/201211/2511264.shtml Linux系统灾难恢复技术和方法

  我所保存的数据都是冗余的分布在不同地域的服务器上,所以之前没有做过磁盘分区损坏恢复的试验。今天看到这篇文章觉得很好,学习学习。以后也备份一下以备需要。
备份到usb中
[root@FCoE ~]# dd if=/dev/sda of=/mnt/sda.mbr bs=512 count=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000777948 s, 658 kB/s

救援模式下恢复
bash-4.1# dd if=/usb/sda.mbr of=/dev/sda bs=1 count=64 skip=446 seek=446

1月 04

centos下搭建yum服务器自动同步源

  在内网中建立yum服务器,内网linux服务器可以使用yum升级。这样做有两个好处,一内网服务器不用登陆公网比较安全,二节约了流量,不用每台服务器更新都连到公网上。
  安装配置比较简单。需要nginx或apache,本次只列出了nginx配置。还需要rsync工具,建议使用命令“yum install -y rsync”。
  yum服务器内网地址192.168.100.100

Nginx配置

#######################################yum server
server {
        # 直接使用IP地址
        server_name 192.168.100.100;
        # 开启自动显示目录
        autoindex on;
        # 显示文件大小
        autoindex_exact_size off;
        # 显示服务器本地时间
        autoindex_localtime on;
        # yum放置目录
        root    /u01/yumserver/;
        # 内网可见
        allow 192.168.100.0/24;
        # 除上列ip均不能查看
        deny all;
        # 限制ip后会报403错误,做个跳转
        error_page 400 403 404 500 502 503 504 = http://www.simonzhang.net;
        }

同步脚本,将脚本有可执行权限,将此设置到crontab即可。

#!/bin/bash
# -------------------------------
# Revision: 
# Date:        2012-12-11
# Author:      simonzhang
# Email:       simon-zzm@163.com
# Web:         www.simonzhang.net
# ------------------------------- 

# base value
# 要同步的源
YUM_SITE="rsync://mirrors.kernel.org/centos/"
# 本地存放目录
LOCAL_PATH="/u01/mirrors/centos/"
# 需要同步的版本,我只需要5和6版本的
LOCAL_VER="5 5* 6 6*"
# 同步时要限制的带宽
BW_limit=512
# 记录本脚本进程号
LOCK_FILE="/var/log/yum_server.pid"
# 如用系统默认rsync工具为空即可。
# 如用自己安装的rsync工具直接填写完整路径
RSYNC_PATH=""

# check update yum server  pid
MY_PID=$$
if [ -f $LOCK_FILE ]; then
    get_pid=`/bin/cat $LOCK_FILE`
    get_system_pid=`/bin/ps -ef|grep -v grep|grep $get_pid|wc -l`
    if [ $get_system_pid -eq 0] ; then
        echo $MY_PID>$LOCK_FILE
    else
        echo "Have update yum server now!"
        exit 1
    fi
else
    echo $MY_PID>$LOCK_FILE
fi

# check rsync tool
if [ -z $RSYNC_PATH ]; then
    RSYNC_PATH=`/usr/bin/whereis rsync|awk ' ''{print $2}'`
    if [ -z $RSYNC_PATH ]; then
        echo 'Not find rsync tool.'
        echo 'use comm: yum install -y rsync'
    fi
fi

# sync yum source
for VER in $LOCAL_VER;
do 
    # Check whether there are local directory
    if [ ! -d "$LOCAL_PATH$VER" ] ; then
        echo "Create dir $LOCAL_PATH$VER"
        `/bin/mkdir -p $LOCAL_PATH$VER`
    fi
    # sync yum source
    echo "Start sync $LOCAL_PATH$VER"
    $RSYNC_PATH -avrtH --delete --bwlimit=$BW_limit --exclude "isos" $YUM_SITE$VER $LOCAL_PATH$VER
done

# clean lock file
`/bin/rm -rf $LOCK_FILE`

echo 'sync end.'
exit 1

centos_yum_server

客户端配置
编辑/etc/yum.repos.d/CentOS-Base.repo
#base
[base]
name=CentOS-$releasever – Base
baseurl=http://192.168.100.100/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#released updates
[updates]
name=CentOS-$releasever – Updates
baseurl=http://192.168.100.100/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#additional packages that may be useful
[extras]
name=CentOS-$releasever – Extras
baseurl=http://192.168.100.100/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever – Plus
baseurl=http://192.168.100.100/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#contrib – packages by Centos Users
[contrib]
name=CentOS-$releasever – Contrib
baseurl=http://192.168.100.100/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6