在线升级驱动的思路

线上有的服务器停机应用比较大,单身如果又遇到网络驱动之类的有bug那就麻烦了,徘徊于等死与找死之间。想着所有的机器都是双上联做了bond的,可不可以一次升级一个网卡呢?做了bond单次挂1个网卡应该是无损的。 上周把我的这个想法给内核组的同学说了,没有想到这周就给出了具体的方案。我自己稍微测试了下,把脚本的一些细节地方修改了下昨天测试2个网卡连续切换驱动10次无丢包。 不过有实际的大流量的时候还有待验证。

August 24, 2013 · 1 min · pm

SPF记录

SPF(发信方策略框架)记录就是在txt记录(现在也有专门的spf记录)里标明该域的邮件只能从指定的服务器发出,否则都是假冒的。现在有2个版本,spf1和spf2。不过被转发的邮件就不能通过SPF检查的。比如用163的邮箱给一个用gmail的人发邮件,对方又把自己的邮箱直接转发到了qq的邮箱上,这样就不能通过spf校验。简单看看spf格式的txt记录:dig -t txt google.comgoogle.com. 3600 IN TXT “v=spf1 include:_spf.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all” 继续dig -t txt _spf.google.com 结果是“v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all”再继续

August 19, 2013 · 1 min · pm

服务器hang的检查

做运维的都知道,最怕的不是机器直接挂掉,而是怕机器hang在那里,能ping通但是又登录不上去。周末加班写了个检测脚本,发送icmp包进行ping的检查,如果有返回再继续做ssl端口的检查或者ssh登录的检查。python不像perl下直接有个很好用的net::ping,自己网上找了个python-ping,修改了一下放脚本里面直接用。 #!/usr/bin/env python2.7 import socket import sys import paramiko import os import select import struct import time import threading import Queue import copy import string import hashlib from collections import deque ICMP_ECHO_REQUEST = 8 # Seems to be the same on Solaris. class CheckHang: def init(self,server): self.server=server def check_ssh(self): """ return 1 when i can’t ssh to the server """ ssh = paramiko.SSHClient() key = paramiko.RSAKey.from_private_key_file("/home/pm/keys/id_rsa") ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(self.server,username=“root”,pkey=key,timeout=1) flag=1 ssh.close() except: flag=0 return flag def check_ssh_port(self,port): """ check the 22 port alive, return 1 when the port is alive. """ port_test = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: port_test.settimeout(1) ...

August 18, 2013 · 4 min · pm

openwrt设置vlan tag

前面试过openwrt下把个别的端口单独划分到独立的vlan,使得连到这个端口的机器的IP是单独一个vlan的IP。今天测试了一下单个端口直接绑定到多个vlan,客户端机器自己使用vlan id来标记。 config interface 'loopback' option ifname 'lo' option proto 'static' option ipaddr '127.0.0.1' option netmask '255.0.0.0' config interface 'lan' option ifname 'eth1.0' option type 'bridge' option proto 'static' option ipaddr '192.168.1.1' option netmask '255.255.255.0' config interface 'lan1' option ifname 'eth1.1' option type 'bridge' option proto 'static' option ipaddr '192.168.100.1' option netmask '255.255.255.0' config interface 'lan2' option ifname 'eth1.2' option type 'bridge' option proto 'static' option ipaddr '192.168.200.1' option netmask '255.255.255.0' config interface 'wan' option ifname 'eth0' option proto 'dhcp' config interface 'wwan' option proto 'dhcp' config switch eth1 option re set 1 option enable_vlan 1 config switch_vlan option device eth1 option vlan 0 option ports '0 1 2t 5*' config switch_vlan option device eth1 option vlan 1 option ports '2t 5*' config switch_vlan option device eth1 option vlan 2 option ports '2t 5*' 以上就是把db120的eth3除了在默认的vlan 0内,还在vlan1和vlan2里面,vlan1使用192.168.100.0/24的段,而vlan2使用192.168.200.0/24的段。dnsmasq加上对于的dhcp配置 ...

August 17, 2013 · 2 min · pm

虚拟机上LVM测试

LVM可以配合RAID方便灵活调正分区的大小。虚拟机简单试了下还是很方便1. 创建一个RAID5mdadm –create /dev/md1 –run –level=5 -n 3 /dev/sdc /dev/sdb /dev/sda 2.创建LVM2.1 初始物理卷create pvpvcreate /dev/md0pvdisplay /dev/md1 2.2 创建卷组vgcreate raidlvm /dev/md1vgchange -a y raidlvmvgdisplay raidlvm2.3 创建逻辑卷lvcreate -L1G -nusrfs raidlvmlvcreate -L1000M -nrootfs raidlvmlvdisplay /dev/raidlvm/rootfslvdisplay /dev/raidlvm/usrfsmkfs.ext4 /dev/raidlvm/usrfs2.4 调整卷大小umountlvextend -L+1Gsize2fs /dev/mapper/raidlvm-rootfseize2fs /dev/mapper/raidlvm-rootfsresize2fs /dev/mapper/raidlvm-rootfsmount -a

August 11, 2013 · 1 min · pm

LVS DR模式到TUN模式的平滑迁移。

一般情况下大家在使用LVS的时候都很喜欢直接用DR模式,觉得DR模式的效率是最高。不过实际上DR模式在很多时候给我们带来的约束也非常大,最明显的莫过于LVS机器需要和RS机器能有一张网卡共处在一个vlan下。机房环境比较复杂的时候还用DR模式经常会受到各种的约束,比如同一个VLAN的IP都被用光了、同一个交换机下机柜没有空位了,etc。所以实际上我们也经常使用TUN模式。最近遇到一个之前使用DR模式,现在不能扩容的情况,上午就尝试在测试环境测试了一下DR模式到TUN模式的切换,整体影响和LVS主备切换的时候差不多,影响可控。实际的背景是现在LVS1和LVS2做互备给DNS1、DNS2做负载均衡。但是因为找不到机为能和LVS机器挂同一个VLAN下,所以我现在需要把LVS的模式修改为TUN模式,以便对RS直接扩容。机器列表: LVS: 192.168.100.16 LVS1-slave 192.168.100.17 LVS2-slave VIP:192.168.100.8 DNS Server: 192.168.100.18 DNS1 192.168.100.22 DNS2 192.168.100.38 DNS3(NEW) 192.168.128.29 DNS4(NEW) keepalived原来的配置文件: vrrp_instance dns { !state MASTER state BACKUP interface bond0 lvs_sync_daemon_interface bond0 virtual_router_id 51 priority 99 advert_int 1 nopreempt garp_master_delay 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.100.8/22 dev bond0 label bond0:1 #配置的时候主要掩码不要写错了 } } virtual_server 192.168.100.8 53 { delay_loop 30 lb_algo rr lb_kind DR ha_suspend persistence_timeout 0 protocol TCP real_server 192.168.100.18 53 { weight 100 TCP_CHECK { connect_port 53 connect_timeout 3 nb_get_retry 3 delay_before_retry 10 } ...

July 28, 2013 · 3 min · pm

openwrt划分多个vlan

原本是想把db120的eth1绑定的三个端口划分为3个vlan,每个vlan也单独配置一个SSID。结果比较悲剧的是b43的驱动不支持多个SSID。简单讲一下如何划分多个vlan。对于DB120来说,靠近电源的网口其实是eth0,原版的固件是把这个网卡和eth1桥接了,使得有4个lan口。刷了openwrt后LAN4就变成了WAN口(eth0),LAN1-3是eth1。可以单独配置一下把LAN3划到一个单独的VLAN config interface 'loopback' option ifname 'lo' option proto 'static' option ipaddr '127.0.0.1' option netmask '255.0.0.0' config interface 'lan' option ifname 'eth1.0' option type 'bridge' option proto 'static' option netmask '255.255.255.0' option ipaddr '10.10.10.1' config interface 'lan2' option ifname 'eth1.1' option type 'bridge' option proto 'static' option netmask '255.255.255.0' option ipaddr '10.10.20.1' config interface wan option ifname eth0 option proto dhcp config interface 'wwan' option _orig_ifname 'wlan0' option _orig_bridge 'false' option proto 'static' option ipaddr '192.168.3.2' option netmask '255.255.255.0' option gateway '192.168.3.1' option dns '192.168.3.1' config 'switch' 'eth1' option 'reset' '1' option 'enable_vlan' '1' config 'switch_vlan' option 'device' 'eth1' option 'vlan' '0' option 'ports' '0 1 5*' config 'switch_vlan' option 'device' 'eth1' option 'vlan' '1' option 'ports' '2 5*' port 5是CPU,port 0-2分别对应的LAN1-3,以上就是把LAN3划到单独的VLAN,IP段是10.10.20.1/24,而LAN1-2的IP段是10.10.10.1/24。另外需要配置一下dhcp加一段 ...

July 27, 2013 · 1 min · pm

linux做软RAID10

最近拿到的几个12块盘的服务器,都是没有RAID卡的。自己就简单做了一下软RAID。 用/dec/sd[b-l]1创建一个raid10的/dev/md1,其中一个做备用盘。 mdadm –create /dev/md1 –run –level=10 -n 10 /dev/sd[b-l] -x 1 mkdir /mnt/data ; mkfs.ext4 /dev/md1 2.把mda1加到fstab/dev/md1 /mnt/data ext4 defaults,noatime 0 03.把阵列信息加到/etc/mdadm.confmdadm –detail –scan » /etc/mdadm.conf 状态查看可以 #cat /proc/mdstat Personalities : [raid10] md1 : active raid10 sdl[10](S) sdk[9] sdj[8] sdi[7] sdh[6] sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0] 9767564800 blocks super 1.2 512K chunks 2 near-copies [10/10] [UUUUUUUUUU] unused devices: #mdadm –detail /dev/md1 /dev/md1: Version : 1.2 Creation Time : Sat Jul 20 00:33:49 2013 Raid Level : raid10 Array Size : 9767564800 (9315.08 GiB 10001.99 GB) Used Dev Size : 1953512960 (1863.02 GiB 2000.40 GB) Raid Devices : 10 Total Devices : 11 Persistence : Superblock is persistent ...

July 17, 2013 · 2 min · pm

搭建私有的apt源

内部搞了个apt源,简单记录一下,主要参考了:http://www.debian-administration.org/articles/286 新建立目录结构mkdir test/{conf,dists,incoming,indices,logs,pool,project,tmp} 2.新建配置文件 2.1 conf/distributionsOrigin: GNUerLabel: GNUer’s repositoryCodename: testingArchitectures: amd64Components: mainDescription: Description of repository you are creating2.2 conf/optionsverboseask-passphrasebasedir . 3.包的维护 导入包需要使用reprepro reprepro -b /home/mirrors/test/ includedeb testing /home/test_deb/dropbox_1.6.0_amd64.deb删除包reprepro -v -b /home/mirrors/test/ remove testing dropbox apt源的配置新增deb http://192.168.2.2/test testing main

July 13, 2013 · 1 min · pm

二分法查找指定时间的日志

二分法是很基础的一个查询方法。试想一个场景,应用的访问量非常大,单天的日志单个文件上100G,要准实时地统计出TPM的大小。没有什么storm之类的高级玩意,就自己写脚本进行统计的话其实不太好搞。这个时候可以试试每次用二分法找出上一分钟的日志所在的偏移量,然后再顺序读入日志进行处理,可以比较高效地跳过大量的日志。python简单写了个[python]#!/usr/bin/env pythonimport reimport datetimeimport sysclass logtools:"""this tools can get the bind qps and the ips which query with high frequency"""def __init__(self,filename="/xx/acess.log"):self.logname=filenametry:#print "logs is",filenameself.fd=open(filename,"r")except IOError:print "open log failed"sys.exit(1)def __del__(self):try:self.fd.close()except:print "close fd failed"def get_last_min(self):now=datetime.datetime.now()last=datetime.datetime.now()+datetime.timedelta(minutes=-2)qps_time=datetime.datetime.now()+datetime.timedelta(minutes=-1)t=qps_time.strftime(‘\s+%H:%M:’)t2=qps_time.strftime(‘%H:%M’)return (int(last.strftime("%s")),t,t2)def get_current_min(self):time_reg=re.compile("\s+(?P\d+):(?P\d+):(?P\d+)")now=datetime.datetime.now()i=1while True:line=self.fd.readline()if not line:return Nonematch=time_reg.search(line)i=i+1if match:match_time=datetime.datetime(year=now.year,month=now.month,day=now.day,hour=int(match.group("hour")),minute=int(match.group("min")),second=int(match.group("sec")),)breakreturn int(match_time.strftime("%s"))def get_last_seek(self,last_time):old_seek=self.fd.tell()self.fd.seek(0,0)start_seek=self.fd.tell()start_time=self.get_current_min()pos_off=len(self.fd.readline())*2self.fd.seek(0,2)end_seek=self.fd.tell()self.fd.seek(-pos_off,2)end_time=self.get_current_min()#print "time range:",start_time,last_time,end_time#print "pos_off:",pos_offif last_time < start_time:print "error last-timereturn end_seekelif last_time > end_time:print "error %d > %d"%(last_time,end_time)return end_seektime=0while (end_seek – start_seek > 2*pos_off and end_time – start_time > 3) :half_seek=int((end_seek+start_seek)/2)self.fd.seek(half_seek,0)half_time=self.get_current_min()#print "%d –<%d>—%d"%(start_seek,half_seek,end_seek)if last_time<=half_time:end_seek=half_seekself.fd.seek(end_seek,0)end_time=self.get_current_min()else:start_seek=half_seekself.fd.seek(start_seek,0)start_time=self.get_current_min()time+=1#print "search %d times"%timereturn half_seekdef get_tpm(self):reg=self.get_last_min()[1]+"\d{2}"reg_time=self.get_last_min()[2]regex=re.compile(reg)time_pre=self.get_last_min()[0]pos=self.get_last_seek(time_pre)self.fd.seek(pos,0)query=0line=self.fd.readline()while line:if line == None:breakelif regex.search(line):query+=1line=self.fd.readline()print "%s qps %d"%(str(reg_time),query)a=logtools(filename=sys.argv[1])a.get_tpm() [/python] ...

July 10, 2013 · 1 min · pm