TCP Wrappers 的注意事项

通常情况下,可以在 hosts.deny 里面建立一条 ALL:ALL 的规则,再到 hosts.allow 里面定义允许放行的服务。该做法理论可行,但实际操作中会遇到不少问题:任何一个有权限的人都可以通过 hosts.allow 添加权限,或者干脆将 hosts.deny 删除,因此比较好的方式是在 hosts.allow 的最后追加:
ALL:ALL:DENY

或者再追加一条:

ALL:DENY
这样即使 hosts.deny 被删除,对系统也没有影响。

另外在使用:
service : ALL : allow
service : ALL : deny
这两条规则时要注意,一旦匹配到该行,接下来的所有规则将被忽略,因此,上面这两条规则需要放在所有规则的最后,如果按下面的写法则无效:
sshd : ALL : allow
sshd : bad.host : deny
sshd : 88.4.2. : deny

正确的写法如下:
sshd : bad.host : deny
sshd : 8.8.4.2. : deny
sshd : ALL : allow

Continue reading

mount options

首先要记住这句话:
性能的提高是以数据完整性的牺牲为代价的。

下面记录了一些常见的 mount options。

1. noatime, relatime
2.6.30 以后的内核,默认都是 relatime。该标志表示如果比 mtime 的时间旧,则更新,相比 atime,对系统的写会大大的减小,不过依然存在写的可能,因此,改成 noatime 会比较合适,实践下来,这个即使没有明显的性能提高也不会降低系统的性能。有点需要注意的是,mutt 以及 tmpwatch 会使用到 atime,不过前者发现不使用 atime 也完全可以工作,后者可以修改成使用 ctime。如果出于谨慎的目的,可以使用默认的 relatime。
可以针对文件或者目录做 noatime 的设置:
# chattr +A filename
# chattr -R +A  /var/spool/

当然也可以在 fstab 文件里面针对某个分区做,加上 noatime 就好了。做完需要 remount:
# mount -o remount /mnt/
# cat /proc/mounts

2. ordered, writeback, journal
ext4 存在 3 种数据模式,writeback, ordered, journal。
* writeback 只记录 metadata,不记录 data。他是可以先写 metadata 再写 data,当机器崩溃后,会造成数据的丢失,但是不会造成数据的错乱。该模式是性能最高的一种。
* ordered  只记录 metadata,但是他提供了一种事物的模式,在有新的 metadata 需要写入前,跟其相关联的数据快会先写入。总的来说,该模式的性能比 writeback 稍低,但是比 journal 快的多。
* journal 同时记录 metadata 以及 data。此模式性能最低。

默认是 ordered,该选项只会让 metedata 被记录。根分区的设置有点特殊,需要像下面这样:
rootflags=data=writeback

Continue reading

安装 rhel 过程中遇到的 “an unhandled exception”

使用图形界面人肉测试安装台 rhel,在执行到安装 grub 的步骤中,出现了如下图所示的 "An unhandled exception has occured"

使用 scp "Save" 了 log 之后,点击 "Exit" 就转到了下面这个图片

$ cat abrt.log
executable:     /mnt/runtime/usr/bin/python
hashmarkername: anaconda
kernel:         2.6.32-220.el6.x86_64
product:        Red Hat Enterprise Linux
reason:         YumBaseError: Error: rpmdb open failed
time:           Fri 01 Feb 2013 06:19:12 PM CST
version:        6.2

anaconda-tb-Zz_jzR: Text file, 503386 bytes

description:
:The following was filed automatically by anaconda:
:anaconda 13.21.149 exception report
:Traceback (most recent call first):
:  File "/usr/lib/python2.6/site-packages/yum/config.py", line 1022, in _getsysver
:    raise Errors.YumBaseError("Error: " + str(e))
:  File "/usr/lib/python2.6/site-packages/yum/config.py", line 877, in readStartupConfig
:    startupconf.releasever = _getsysver(startupconf.installroot, startupconf.distroverpkg)
:  File "/usr/lib/python2.6/site-packages/yum/__init__.py", line 295, in _getConfig
:    startupconf = config.readStartupConfig(fn, root)
:  File "/usr/lib/anaconda/yuminstall.py", line 808, in doConfigSetup
:    YumSorter._getConfig(self)
:  File "/usr/lib/anaconda/yuminstall.py", line 362, in setup
:    self.doConfigSetup(root=self.anaconda.rootPath)
:  File "/usr/lib/anaconda/yuminstall.py", line 1284, in doBackendSetup
:    self.ayum.setup()
:  File "/usr/lib/anaconda/backend.py", line 225, in doBackendSetup
:    if anaconda.backend.doBackendSetup(anaconda) == DISPATCH_BACK:
:  File "/usr/lib/anaconda/dispatch.py", line 208, in moveStep
:    rc = stepFunc(self.anaconda)
:  File "/usr/lib/anaconda/dispatch.py", line 126, in gotoNext
:    self.moveStep()
:  File "/usr/lib/anaconda/gui.py", line 1390, in nextClicked
:    self.anaconda.dispatch.gotoNext()
:YumBaseError: Error: rpmdb open failed

END:

看上面的的 log 没看出什么端倪。后来在 RH Support 的提醒下才发现,由于这台机器之前是装过系统的,也就是说是有分区在磁盘上的,在使用自定义分区之后,需要勾选 "Format as",不然会像我一样悲剧 :-(

如果机器之前没有磁盘分区,就不会存在这个问题。这个问题估计也只有人肉的时候会发现,批量话的话,肯定会先执行

使用 low level discovery 添加不同的 instance

到目前为止,zabbix 一般的监控需求都能完全搞定,唯一有问题的就是同一台主机上不同端口的 instance 的监控,比如我在同一台主机上同时起了 27017, 27018, 27019 三个 mongod 的 instance 这类的情况。对此,这两个(1, 2)链接讨论了可行的情况。

1. Parametrized templates,这个需要引入一个抽象的 template,其实类似 nagios 里面通过 register 定义一个抽象可继承的 host/service,这个开发量比较大,目前使用不现实
2. 每一个 instance 单独定义一个 host,这个实现方式虽然可用,也比较简单,但是姿势太丑,如果一台主机有 10 个 instance,那么我需要定义 10 个不同的 host,大量重复无聊的工作
3. 通过 zabbix 2.0 引入的 low level discovery 实现,几乎没有开发量,姿势非常的优美,通过 active check 能自动的检测添加匹配要求的 instance

low level discovery 最重要的就是对不同 instance 特征的匹配问题,我们这里的情况相对比较简单,通过 netstat, lsof 把不同 mongo instance 的匹配出来,然后添加 item, graph, trigger 之类的就好了。
以下的工作参考了这两个链接(1, 2)。

按照起官方文档的解释,其匹配出的结果必须是 JSON 格式:
# cat /etc/zabbix/scripts/discovery.sh
#!/bin/bash
portarray=(`sudo lsof -iTCP -sTCP:LISTEN | grep "$1"| awk '{print $9}' | awk -F: '{if ($NF~/^[0-9].*$/) print $NF}' | sed -n 'p;n' | sort | uniq   2>/dev/null`)

length=${#portarray[@]}
printf "{\n"
printf  '\t'"\"data\":["
for ((i=0;i<$length;i++))
do
        printf '\n\t\t{ '
        printf "\"{#TCP_PORT}\":\"${portarray[$i]}\" }"
        if [ $i -lt $[$length-1] ];then
                printf ','
        fi
done
printf  "\n\t]\n"
printf "}\n"

Continue reading

rh6.2 kernel panic 级别的 bug

线上已经稳定运行了半年多,一共遇到了两次不同的 kernel panic。以下的使用的是 6.2 的标准内核 2.6.32-220.el6.x86_64。

1. Kernel panic on divide-by-zero in get_dirty_limits
这个现象是在执行 reboot 之后,出现 panic,导致机器无法启动
这个在 vm.dirty_ratio 以及 vm_dirty_bytes 同时被置为 0 时,会出现 overflow,这个 private bug 目前还没 patch 出来(rhel 6.5 会修复这个 bug),比较好的方式是将 vm.dirty_ratio = 1。

2. kernel panic at nf_nat_setup_info
如果机器上部署了 SNAT 的话,就会中标。这个只能升级 kernel 到 2.6.32-220.30.1.el6 或者更高。在升级的过程中还遇到了一个小插曲。
由于完全进不了系统,只能通过 rescue mode 进行升级。进入之后:
# uname -a
Linux localhost.localdomain 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011 x86_64 x86_64 x86_64 GNU/Linux

将需要更新的 kernel* 上传到该机器上:
# ll kernel-*
-rw-r–r– 1 root root 26408880 Feb 25 11:15 kernel-2.6.32-279.el6.x86_64.rpm
-rw-r–r– 1 root root  7990420 Jun 15  2012 kernel-devel-2.6.32-279.el6.x86_64.rpm
-rw-r–r– 1 root root  9099056 Feb 25 11:09 kernel-firmware-2.6.32-279.el6.noarch.rpm
-rw-r–r– 1 root root  1988972 Feb 25 11:09 kernel-headers-2.6.32-279.el6.x86_64.rpm

安装:
# rpm -ivh *rpm
会出现如下的 error:
kernel-firmware-2.6.32-220.el6.x86_64 conflicts with file from package kernel-firmware-2.6.32-279.el6.x86_64

只有先覆盖原来的 firmware,再安装剩余的三个:
# rpm -Uvh kernel-firmware-2.6.32-279.el6.noarch.rpm
# rpm -ivh kernel-2.6.32-279.el6.x86_64.rpm kernel-devel-2.6.32-279.el6.x86_64.rpm kernel-headers.2.6.32-279.el6.x86_64.rpm

完成,检查确认:
# cat /etc/grub.conf
# rpm -qa | grep kernel

关于第二个 bug 还要再说几句,本来这个 bug 也不是个多大的事,SNAT 挂了顶多是内网的机器无法访问外网,悲剧的是,为了省事我们的 web server 跟 SNAT 部署在同一台机器上,更悲剧的是,当时紧急上线,web server 连个 failover 都没有,最后的结果就是我们的这台前端机器两天挂了六次,损失了 !@#$%^%。
总之教训就是,1)不要图省事。2)可以做 failover 的必须做。现在侥幸的迟早会出事。
单台硬件是不稳定的,单台软件也是不稳定的,但是两台同时宕的几率应该是小之又小了,除非发生了网络故障。

除了上面两个,还有个 2.6.32 都会发生的 208.5 day 的 bug,之前线上的 ubuntu 也遇到了这类悲剧,10.04 的可以升级到 2.6.32-38;rh 6.x 的可以升级到 kernel-2.6.32-279.el6

最后,我们的一个跑在 rh6.2 的 hadoop 集群曾经遇到过 sys time、load 高出正常水平的问题,究其原因,6.2 默认开启了 THP,关闭即可。

IP 再次冲突

给二层新划分了一个 vlan,在三层上做好对应的关系,测试各网段的连通性就可以了,本来是件简单的工作,却因为一次事故变得复杂起来。
划分完毕后,在该 vlan 下新上几十台的机器。正常情况下是先确保远程卡的连通性,所以先从某台 cobbler ping,确认其是否工作正常。测试下来发现这批远程卡会出现时通时不通的情况,当时没有太在意,多 ping 了几次,也通了。后来再次连接的时候又出现了上面的问题,检查了遍涉及到的交换机的变更,没有发现问题。把目光转向了远程卡,查了下版本之类的信息,g 了下发现了不少跟我们类似的情况,遂以为是 firmware bug 之类的问题,于是升级了其中的一台,问题依然存在。
再后来由于时间关系也就没再追究(后来发现现在解决不了的问题迟早要出事),在该 vlan 下部署了一台 dhcrealy server,奇怪的是,安装完了之后,发现网络死活不同,其症状为:
1. 从本地可以 ping 通任何的的本网段的远程卡、交换机,并且没有任何的丢包
2. 从二层交换机可以 ping 通该 server,但是从三层则完全 ping 不通

第一次遇到这类正向通反向不通的情况,以为是 12.04 的机器默认把 icmp_echo_ignore_all 打开了,确认了一遍依然是 0。后来怀疑可以是三层配置的问题,之前没有发现,于是登陆上去,把 sh run 的结果跟我们另外一个环境类似的 IDC 的三层做 diff,依然没有发现任何的问题。

最后想到了看看三层的 log,这下终于有了头目:
# show logging
Log Buffer (4096 bytes):
 %IP-4-DUPADDR: Duplicate address 191.168.20.254 on Vlan4, sourced by d0c2.8e3e.0fa3
. ..
*Apr 2 06:36:53.443: %IP-4-DUPADDR: Duplicate address 192.168.20.254 on Vlan123, sourced by abcd.823e.0fc3

Continue reading