NAT 跟默认网关的问题(dual NAT)

由于要做数据同步,需要对我们内网的机器做 1 对 1 IP nat map,这样可以通过访问一台 nat 路由设备 map 到我们内网的机器。

先说常规性的做法。
一般情况下,这台 nat 设备会充当内网的 gateway,这样在这台 nat 上做一个 dnat 就可以顺利解决了。比如我 GW 的地址是 192.168.1.24,我想通过一对一的方式 map 到后面的 192.168.1.33 这台开放了 28017 TCP 的机器:
# iptables -t nat -A PREROUTING -d 192.168.1.24 -j DNAT –to-destination 192.168.1.33

像上面这样就可以了,但是如果 192.168.1.24 这台机器本身就开放了 28017 端口则会比较悲剧,因此,另外一种做法是选一个不存在的 IP,比如 192.168.1.200,这样可以任意的建立 socket 而不用担心其 TCP 端口被占用:
# iptables -t nat -A PREROUTING -d 192.168.1.200 -j DNAT –to-destination 192.168.1.33

当然,上面这两种方式都不是很规范,比较好的还是指定 IP 以及 port,像下面这样:
# iptables -t nat -A PREROUTING -p tcp -m tcp -d 192.168.1.24 –dport 10000 -j DNAT   –to-destination 192.168.1.33:28017


上面的情况比较简单,现在来看看下面这种情况,也就是非常规性的做法,专业术语叫 "dual NAT"。
环境跟上面的不大一样,最终要访问的机器的 default gateway 并非指向了 nat 设备,也就是他们二者没有任何关系。具体的环境可以看 superuser 上的这个案例,在这种情况下,仅仅做一个 dnat 是不够的,还需要再做一次 snat 这样才能在回包的时候走正确的路由。
以他为例,在 client 把包发给 PC1 后,首先经过下面这条规则:
# iptables -t nat -A PREROUTING -p tcp -m tcp -d 1.0.0.1 –dport 80 -j DNAT  –to-destination 172.16.0.3:80

于是该包的 src(假设为 192.168.1.1:22222) 不变,dst 由 1.0.0.1:80 变成了 172.16.0.3:80,紧接着,经过 POSTROUTING:
# iptables -t nat -A POSTROUTING -p tcp -m tcp -d 172.16.0.3 –dport 80 -j SNAT –to-source 172.16.0.1:22222

于是该包的 src 由 192.168.1.1:22222 变成了 172.16.0.1:22222,这样修改后的包变成了 src 172.16.0.1:22222,dst 172.16.0.3:80,通过这种方式,成功的绕过了 PC3 default gateway 的问题。
如果仅仅包含 PREROUTING 这条 rule,那么包就变成了 src 192.168.1.1:2222,dst 172.16.0.3:80,虽然包能抵达 PC3,但是在返回的时候,PC1 发现原来的 (192.168.1.1:2222 <-> 1.0.0.1:80) 变成了 (192.168.1.1:2222 <-> 172.16.0.3:80),就直接发 R(Unskilled Attackers Pester Real Security Folks)标志了。可以看看我下面这个模拟的抓包结果:
16:06:36.694253 IP 192.168.1.1:2222 > 172.16.0.3.80: Flags [SEW], seq 868362120, win 5840, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
16:06:36.694279 IP 172.16.0.3.80 > 192.168.1.1:2222: Flags [S.E], seq 1535533077, ack 868362121, win 5840, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
16:06:36.694591 IP 192.168.1.1:2222 > 172.16.0.3.80: Flags [R], seq 868362121, win 0, length 0

所以,记住,如果是这种非网关的形式,务必要 PREROUTING 跟 POSTROUTING 同时做。

理解了上面的问题,再说下我们线上的问题。当时脑子昏了随便找了台开启了 ip_forward 的服务器充当这台 NAT 设备,并且我只开启了 PREROUTING,结果可想而是,没法建立 TCP 链接,搞清楚了问题之后就找了台网关的机器,同时配备了内外网,从外界的客户端通过这个公网 IP 访问内部的机器就很简单了。同样的还是分两种情况,如果要访问的内部机器的 GW 指向这台 nat 设备,很简单,直接 PREROUING,如果没有指向,那么记得再添加一个 POSTROUTING:
# iptables -t nat -A PREROUTING -d nat_public_ip -j DNAT –to-destination  dst_server_ip
# iptables -t nat -A POSTROUTING -d dst_server_ip -j SNAT –to-source nat_private_ip

ref:

http://blog.peter-b.org/2011/08/01/using-iptables-to-map-an-internal-address-to-an-external-one/

ifconfig 下面的一些字段(errors, dropped, overruns)

一台机器经常收到丢包的报警,先看看最底层的有没有问题:
# ethtool  em2 | egrep 'Speed|Duplex'
        Speed: 1000Mb/s
        Duplex: Full

# ethtool  -S em2 | grep crc
     rx_crc_errors: 0

Speed, Duplex, CRC 之类的都没问题,基本可以排除物理层面的干扰。
通过 ifconfig 可以看到 overruns 字段在不停的增大:
# for i in `seq 1 10`; do ifconfig em2 | grep RX | grep overruns; sleep 1; done

dropped 出现问题的倒是遇到过几次,overruns 的倒是第一次遇到,再看看下面这个:
# ethtool  -S em2 | grep drop
     dropped_smbus: 0
     tx_dropped: 0
     rx_queue_0_drops: 26649441
     rx_queue_1_drops: 26096911
     rx_queue_2_drops: 22712954
     rx_queue_3_drops: 16581572
     rx_queue_4_drops: 27349880
     rx_queue_5_drops: 6178622
     rx_queue_6_drops: 19882243
     rx_queue_7_drops: 18802558

发现数值也在不停的增加。G 了一下,发现这些 errors, dropped, overruns 表示的含义还不大一样。根据这篇文档的解释:
# ifconfig em2
em2       Link encap:Ethernet  HWaddr AC:85:3D:A9:03:0D  
          inet addr:211.211.211.211  Bcast:211.211.211.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:17141208886 errors:0 dropped:0 overruns:164254181 frame:0
          TX packets:14685534428 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2619578349554 (2.3 TiB)  TX bytes:1479317006067 (1.3 TiB)
          Memory:94b00000-94b20000

RX errors: 表示总的收包的错误数量,这包括 too-long-frames 错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等。
RX dropped: 表示数据包已经进入了 Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。
RX overruns: 表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer。很明显,overruns 的增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃了,而 CPU 无法即使的处理中断是造成 Ring Buffer 满的原因之一,上面那台有问题的机器就是因为 interruprs 分布的不均匀(都压在 core0),没有做 affinity 而造成的丢包。
RX frame: 表示 misaligned 的 frames。

对于 TX 的来说,出现上述 counter 增大的原因主要包括 aborted transmission, errors due to carrirer, fifo error, heartbeat erros 以及 windown error,而 collisions 则表示由于 CSMA/CD 造成的传输中断。

在梳理这些 error/drop/discard 的时候,由于涉及到不同的 NIC 型号,ethtool/netstat 或者是直接从 proc 里面获取到的数据所代表的意思还不完全一样,比如上面通过 ethtool 得到的「丢包」是通过 rx_queue_NUM_drops 这个字段表示的,而通过 netstat 看到的却是 RX-OVR 表示的,一个是 overruns 一个是 dropped,字面意思完全不同:
# netstat -i | column  -t
Kernel  Interface  table
Iface   MTU        Met    RX-OK        RX-ERR  RX-DRP  RX-OVR     TX-OK        TX-ERR  TX-DRP  TX-OVR  Flg
em2     1500       0      17159519100  0       0       164254181  14701510290  0       0       0       BMRU

不管是使用何种工具,最终的数据无外乎是从下面这两个文件获取到的:

  1. /sys/class/net/em2/statistics/
  2. /proc/net/dev

# cat /proc/net/dev | column  -t
Inter-|            Receive      |        Transmit
face               |bytes       packets  errs      drop       fifo  frame  compressed  multicast|bytes  packets      errs  drop  fifo  colls  carrier  compressed
em2:2621515020998  17153788154  0        0         164254181  0     0      0           1480433225509    14696703883  0     0     0     0      0        0

对于上面出现的若干种问题,一方面是做好监控,另外一方面是出现问题的时候及时的想到各种的可能,无外乎那么几种。Google 过程中发现了 stackexchange 上还没人回答的问题,结合上面的,我顺便回答了一下,基本,遵循里面的四点,95% 以上的场景应该能轻松应对。

ref:
http://serverfault.com/questions/561107/how-to-find-out-the-reasons-why-the-network-interface-is-dropping-packets
http://serverfault.com/questions/448768/cat-proc-net-dev-and-ip-s-link-show-different-statistics-which-one-is-lyi

http://www.linuxjournal.com/content/queueing-linux-network-stack

ops 的 technical support

Technical support 是一项非常有挑战性的工程。做 ops 的多少要遇到一些这类的问题,对外你是客户,厂商给你提供技术支持;对内,你需要服务客户,给很多分不清 ip 是什么如何做 bind 的码农们提供技术支持敦促其改进。
每次客户的系统出问题,你屁颠屁颠的跑到现场去花了几天几夜帮他修复了一个非常棘手的问题,自然值得骄傲,但是如果有比这个更好的方式,为何不试试看,很高兴的看到,有很多的公司已经在这方面做的很完善。
首先说说我们的老合作伙伴,RedHat,一般系统出了问题,我们会先排查,不到万不得已不会去开 case,我觉得这是对大家的尊重。开 case,自然要讲清问题发生的背景,现象,可能的原因等等问题,尤其是前两者,这需要你话费很大的时间以比较精炼准确的语言去描述,这样对方的 technical support 才能尽快的领悟到问题所在,尤其是一个涉及多个层次的复杂的系统问题。人跟动物最重要的区别就是人类会使用工具,好的工程师能写出大大解放客户双手,同时提高自己获取背景信息的好工具,sosreport 就是一个明显的体现。
其实原理一点都不复杂,就是一个 python 脚本,把当前的系统做了一个 snapshot,将重要的基本配置信息全部打包到了 sosreport-HOSTNAME.CASENUM-DATE.tar.xz 这个文件里面了,解压开来无非就是一些系统的信息文件:
# ll /tmp/HOSTNAME-2014052115241400657060/
total 44
drwxr-xr-x  3 root root 4096 May 21 15:24 boot/
drwxr-xr-x 36 root root 4096 May 21 15:24 etc/
drwxr-xr-x  3 root root 4096 May 21 15:24 lib/
drwxr-xr-x  7 root root 4096 May 21 15:24 proc/
drwxr-xr-x  2 root root 4096 May 21 15:24 root/
drwxr-xr-x 30 root root 4096 May 21 15:24 sos_commands/
drwxr-xr-x  2 root root 4096 May 21 15:24 sos_logs/
drwxr-xr-x  2 root root 4096 May 21 15:24 sos_reports/
drwxr-xr-x  4 root root 4096 May 21 15:24 sys/
drwxr-xr-x  5 root root 4096 May 21 15:24 var/
lrwxrwxrwx  1 root root   37 May 21 22:51 chkconfig -> sos_commands/startup/chkconfig_–list
lrwxrwxrwx  1 root root   25 May 21 22:51 date -> sos_commands/general/date
lrwxrwxrwx  1 root root   27 May 21 22:51 df -> sos_commands/filesys/df_-al
lrwxrwxrwx  1 root root   31 May 21 22:51 dmidecode -> sos_commands/hardware/dmidecode
lrwxrwxrwx  1 root root   24 May 21 22:51 free -> sos_commands/memory/free
lrwxrwxrwx  1 root root   29 May 21 22:51 hostname -> sos_commands/general/hostname
lrwxrwxrwx  1 root root   35 May 21 22:51 ifconfig -> sos_commands/networking/ifconfig_-a
lrwxrwxrwx  1 root root   81 May 21 22:51 installed-rpms -> sos_commands/rpm/rpm_-qa_–qf_NAME_-_VERSION_-_RELEASE_._ARCH_INSTALLTIME_date_–
lrwxrwxrwx  1 root root   48 May 21 22:51 java -> sos_commands/general/alternatives_–display_java
lrwxrwxrwx  1 root root   35 May 21 22:51 lsb-release -> sos_commands/lsbrelease/lsb_release
lrwxrwxrwx  1 root root   25 May 21 22:51 lsmod -> sos_commands/kernel/lsmod
lrwxrwxrwx  1 root root   36 May 21 22:51 lsof -> sos_commands/process/lsof_-b_M_-n_-l
lrwxrwxrwx  1 root root   27 May 21 22:51 lspci -> sos_commands/hardware/lspci
lrwxrwxrwx  1 root root   29 May 21 22:51 mount -> sos_commands/filesys/mount_-l
lrwxrwxrwx  1 root root   38 May 21 22:51 netstat -> sos_commands/networking/netstat_-neopa
lrwxrwxrwx  1 root root   30 May 21 22:51 ps -> sos_commands/process/ps_auxwww
lrwxrwxrwx  1 root root   27 May 21 22:51 pstree -> sos_commands/process/pstree
lrwxrwxrwx  1 root root   32 May 21 22:51 route -> sos_commands/networking/route_-n
lrwxrwxrwx  1 root root   22 May 21 22:51 sar21 -> sos_commands/sar/sar21
lrwxrwxrwx  1 root root   29 May 21 22:51 sestatus -> sos_commands/selinux/sestatus
lrwxrwxrwx  1 root root   28 May 21 22:51 uname -> sos_commands/kernel/uname_-a
lrwxrwxrwx  1 root root   27 May 21 22:51 uptime -> sos_commands/general/uptime
lrwxrwxrwx  1 root root   39 May 21 22:51 vgdisplay -> sos_commands/devicemapper/vgdisplay_-vv

这些信息对问题的诊断是至关重要的,正所谓一图胜千言,很多时候,一条命令胜过几千个单词的描述。

在这方面做的很优秀的的还包括 github,这个跟 RedHat 比,基本就是以黑盒子,我也没必要花经历去 hack 他,出了问题,很简单,直进到管理后台,把 "Download diagnostics info" & "Download support bundle" 的信息发送给他们就好了。

上面提到的两家公司的做法非常值得我们学习,比如可以用在对内的 technical support 上,依葫芦画瓢,执行一下 sosreport 是不是能很快的知道当前系统的整体状况,这比一群码农围着你,尤其遇到那种遇到问题完全失控的,你一言我一语的解释不清要高效的多。
technical support 是项很有挑战,需要具备综合能力,能站在高处俯视系统的工作;除此之外,还能提高与码农们沟通的能力,要知道大部分的码农都是不善于表达自己,很多时候,是无法把自己遇到的问题给表述清楚的,能把他们「哄」开心了,也算是一项不大不小的成就了。总之,多接些这样的活儿,虽然很费时间,尤其遇到一些非常 tricky 的问题,但是对提高自己的综合能力非常有帮助。

阿里云靠不靠谱

偶然的机会看到博客园在用阿里云的服务,大致跟进了一下,惨不忍睹。

从工程的角度来说,博客园这里分享的每一篇博客都蛮有价值的,大家不妨学习下。博客园也是个悲剧,正如他自己说的「正确的糟糕选择」。整的来说,阿里云这几年肯定是在不断的进步的,这个是毋庸置疑的,但是绝对值有多大我不清楚。AWS 前几年也是故障频出,aliyun 出点故障也算正常,但是我是肯定不会用的。

TCP queue 的一些问题

先来回顾下三次握手里面涉及到的问题:
1. 当 client 通过 connect 向 server 发出 SYN 包时,client 会维护一个 socket 等待队列,而 server 会维护一个 SYN 队列
2. 此时进入半链接的状态,如果 socket 等待队列满了,server 则会丢弃,而 client 也会由此返回 connection time out;只要是 client 没有收到 SYN+ACK,3s 之后,client 会再次发送,如果依然没有收到,9s 之后会继续发送
3. 半连接 syn 队列的长度为 max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)  决定
4. 当 server 收到 client 的 SYN 包后,会返回 SYN, ACK 的包加以确认,client 的 TCP 协议栈会唤醒 socket 等待队列,发出 connect 调用
5. client 返回 ACK 的包后,server 会进入一个新的叫 accept 的队列,该队列的长度为 min(backlog, somaxconn),默认情况下,somaxconn 的值为 128,表示最多有 129 的 ESTAB 的连接等待 accept(),而 backlog 的值则由 int listen(int sockfd, int backlog) 中的第二个参数指定,listen 里面的 backlog 的含义请看这里。需要注意的是,一些 Linux 的发型版本可能存在对 somaxcon 错误 truncating 方式
6. 当 accept 队列满了之后,即使 client 继续向 server 发送 ACK 的包,也会不被相应,此时,server 通过 /proc/sys/net/ipv4/tcp_abort_on_overflow 来决定如何返回,0 表示直接丢丢弃该 ACK,1 表示发送 RST 通知 client;相应的,client 则会分别返回 read timeout 或者 connection reset by peer。上面说的只是些理论,如果服务器不及时的调用 accept(),当 queue 满了之后,服务器并不会按照理论所述,不再对 SYN 进行应答,返回 ETIMEDOUT。根据这篇文档的描述,实际情况并非如此,服务器会随机的忽略收到的 SYN,建立起来的连接数可以无限的增加,只不过客户端会遇到延时以及超时的情况。

可以看到,整个 TCP stack 有如下的两个 queue:
1. 一个是 half open(syn queue) queue(max(tcp_max_syn_backlog, 64)),用来保存 SYN_SENT 以及 SYN_RECV 的信息。
2. 另外一个是 accept queue(min(somaxconn, backlog)),保存 ESTAB 的状态,但是调用 accept()。

注意,之前我对 Recv-Q/Send-Q 的理解有些误差,使用 ss 获取到的 Recv-Q/Send-Q 在 LISTEN 状态以及非 LISTEN 状态所表达的含义是不同的。从 tcp_diag.c 源码中可以看到二者的区别:

LISTEN 状态: Recv-Q 表示的当前等待服务端调用 accept 完成三次握手的 listen backlog 数值,也就是说,当客户端通过 connect() 去连接正在 listen() 的服务端时,这些连接会一直处于这个 queue 里面直到被服务端 accept();Send-Q 表示的则是最大的 listen backlog 数值,这就就是上面提到的 min(backlog, somaxconn) 的值。
其余状态: 非 LISTEN 状态之前理解的没有问题。Recv-Q 表示 receive queue 中的 bytes 数量;Send-Q 表示 send queue 中的 bytes 数值。

要理解上面总结的这些,可以参见下这两个案例(1, 2)。 

通过 "SYNs to LISTEN sockets dropped" 以及 "times the listen queue of a socket overflowed" 这两个 netstat -s 获取到的 TCP 状态,可以很快的发现系统存在的一些问题。
任何一个包含 "dropped" 或者 "overflowed" 并且数值一直居高不下的 metric 从字面含义理解来看,都不是一个好现象。

对于 Nginx 来说,backlog 的默认值为 511,这个可以通过 ss/netstat 的 Send-Q 确认:
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     0      511                       *:80                       *:*     

可以通过适当的增大 nginx 的 backlog 以及 somaxconn 来增大队列:
listen 80 backlog=1638

上面说了这么多,其实就是为了引入下面这个问题。
我们线上一个基于 Netty 的代码,3.5.12 的版本,监控显示 "times the listen queue of a socket overflowed" 常年居高不下,动辄几十 K,通过 ss,我们发现其 backlog 的值只有 50:
Recv-Q Send-Q           Local Address:Port               Peer Address:Port   
0      50                           *:6928                          *:*        users:(("java",454409,196))

g 了一下,发现这个版本复用了 Java 默认的 50 这个值。将其增加到 1024 测试,监控曲线一下子降低到了 0。

除了上面这些,还有一个比较基础的 net.core.netdev_max_backlog,如果内核接受包的速度大于被 userspace 处理的速度,该值定义了可以在接口输入最大的的包数量。

chartbeat 分享了两篇很精彩的文档,其中涉及到了 queue 的一些问题。
Lessons learned tuning TCP and Nginx in EC2 1
Lessons learned tuning TCP and Nginx in EC2 2

ref:

http://madalanarayana.wordpress.com/2014/04/13/learnings-on-tcp-syn/

Redhat & Ubuntu systemtap 安装及使用

原本以为是个比较简单的活儿,后来忙了一个晚上加半个白天差不多五六个小时的时间才搞定,主要时间都花在 Ubuntu 上了,归结起来是 Ubuntu 在商业化技术支持方面跟 Redhat 比还是有不少差距的。不管是哪个发行版本,默认都不会安装 debuginfo 的包,所以最重要的是搞定这几个包。
Redhat 的安装教程直接参照官方的说明
RedHat 默认的 Subscription 里面的 Base-Channel(Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64) 只包含 kernel-debuginfo-common 这个包,但是不包含 kernel-debuginfo 这个包,后来才发现在 Subscription 里面增加一个 RHEL Server Debuginfo (v.6 for x86_64) channel 就能找到后者了。当时没注意,于是 kernel-debuginfo-common 使用的是官方的 repo,而 kernel-debuginfo 则是用的是 CentOS 的 repo,理论上来说,应该没什么大区别,但是实践发现还是有问题的,比如 Build Date 不通,会导致 "build-id mismatch" 的问题:
# stap test.stp
ERROR: Build-id mismatch: "kernel" vs. "vmlinux" byte 0 (0x3d vs 0xfe) address
0xffffffff81508160 rc 0
Warning: /usr/bin/staprun exited with status: 1
Pass 5: run failed.  Try again with another '–vp 00001' option.

可以通过下面的方式验证:
# rpm -qif /boot/vmlinuz-2.6.32-279.el6.x86_64 /usr/lib/debug/lib/modules/2.6.32-279.el6.x86_64/vmlinux

或者:
# rpm -qi kernel-debuginfo-2.6.32-279.el6.x86_64
Name        : kernel-debuginfo             Relocations: (not relocatable)
Version     : 2.6.32                            Vendor: CentOS
Release     : 279.el6                       Build Date: Fri 22 Jun 2012
09:31:57 PM CST
Install Date: Wed 21 May 2014 01:26:13 AM CST      Build Host:
c6b9.bsys.dev.centos.org
Group       : Development/Debug             Source RPM:
kernel-2.6.32-279.el6.src.rpm
Size        : 1521941269                       License: GPLv2
Signature   : RSA/SHA1, Mon 25 Jun 2012 06:12:09 AM CST, Key ID
0946fca2c105b9de
Packager    : CentOS BuildSystem <http://bugs.centos.org>
URL         : http://www.kernel.org/
Summary     : Debug information for package kernel
Description :
This package provides debug information for package kernel.
This is required to use SystemTap with kernel-2.6.32-279.el6.x86_64.

# rpm -qi kernel-debuginfo-common-x86_64-2.6.32-279.el6.x86_64
Name        : kernel-debuginfo-common-x86_64  Relocations: (not relocatable)
Version     : 2.6.32                            Vendor: Red Hat, Inc.
Release     : 279.el6                       Build Date: Thu 14 Jun 2012
08:20:19 AM CST
Install Date: Wed 21 May 2014 12:34:47 AM CST      Build Host:
x86-008.build.bos.redhat.com
Group       : Development/Debug             Source RPM:
kernel-2.6.32-279.el6.src.rpm
Size        : 180674047                        License: GPLv2
Signature   : RSA/8, Thu 14 Jun 2012 08:49:26 AM CST, Key ID 199e2f91fd431d51
Packager    : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
URL         : http://www.kernel.org/
Summary     : Kernel source files used by kernel-debuginfo packages
Description :
This package is required by kernel-debuginfo subpackages.
It provides the kernel source files common to all builds.

总之,保证下面几个包的完全出自同一个 repo,对应的 $(uname -r) 一样就可以了。
kernel-2.6.32-279.el6.x86_64
kernel-debuginfo-common-x86_64-2.6.32-279.el6.x86_64
kernel-debuginfo-2.6.32-279.el6.x86_64

更新之后:
# rpm -qif /boot/vmlinuz-2.6.32-279.el6.x86_64 /usr/lib/debug/lib/modules/2.6.32-279.el6.x86_64/vmlinux
Name        : kernel                       Relocations: (not relocatable)
Version     : 2.6.32                            Vendor: Red Hat, Inc.
Release     : 279.el6                       Build Date: Thu 14 Jun 2012
08:20:19 AM CST
Install Date: Mon 25 Feb 2013 11:25:11 AM CST      Build Host:
x86-008.build.bos.redhat.com
Group       : System Environment/Kernel     Source RPM:
kernel-2.6.32-279.el6.src.rpm
Size        : 119491893                        License: GPLv2
Signature   : RSA/8, Thu 14 Jun 2012 08:44:50 AM CST, Key ID 199e2f91fd431d51
Packager    : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
URL         : http://www.kernel.org/
Summary     : The Linux kernel
Description :
The kernel package contains the Linux kernel (vmlinuz), the core of any
Linux operating system.  The kernel handles the basic functions
of the operating system: memory allocation, process allocation, device
input and output, etc.
Name        : kernel-debuginfo             Relocations: (not relocatable)
Version     : 2.6.32                            Vendor: Red Hat, Inc.
Release     : 279.el6                       Build Date: Thu 14 Jun 2012
08:20:19 AM CST
Install Date: Wed 21 May 2014 01:35:13 AM CST      Build Host:
x86-008.build.bos.redhat.com
Group       : Development/Debug             Source RPM:
kernel-2.6.32-279.el6.src.rpm
Size        : 1521941269                       License: GPLv2
Signature   : RSA/8, Thu 14 Jun 2012 08:48:56 AM CST, Key ID 199e2f91fd431d51
Packager    : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
URL         : http://www.kernel.org/
Summary     : Debug information for package kernel
Description :
This package provides debug information for package kernel.
This is required to use SystemTap with kernel-2.6.32-279.el6.x86_64.

然后通过默认的 repo,按部就班的安装 systemtap 就可以了。确认下 /lib/modules/2.6.34.7/build 是 ln 到 /usr/src/kernels/2.6.32-279.el6.x86_64/。

Ubuntu 的可以参照这篇文档来做,对于 10.04 2.6.32-38-server 的机器来说,依然还是可行的。
添加 repo,安装对应的 linux-image-$(uname -r)-dbgsym:
codename=$(lsb_release -c | awk  '{print $2}')
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename}      main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates  main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse
EOF

sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys ECDCAD72428D7C01
sudo apt-get update
sudo apt-get install linux-image-$(uname -r)-dbgsym

不过当一切都安装好了之后,发现 kernel 的版本号并不是真正对应的,默认机器跑的是 2.6.32-38.85,新安装的 debuginfo 是 2.6.32-38.83:
root@unode10-plog-db1:~# dpkg -l | grep linux-image
ii  linux-image-2.6.32-38-server        2.6.32-38.85                                      Linux kernel image for version 2.6.32 on x86
ii  linux-image-2.6.32-38-server-dbgsym 2.6.32-38.83                                      Linux kernel debug image for version 2.6.32

所以把 linux-image 也换了,直接跟 2.6.32-38.83 统一,ftp.ubuntu.com 上找到对应的 linux-image-2.6.32-38-server_2.6.32-38.83_amd64.deb,dpkg 安装就好了。

安装只是个开始,用来发现诊断问题才是真正开始把工具给利用起来。Dtrace 的作者 Brendan 11 年的时候写了篇使用心得,撇开一些主观的情绪因素,上面遇到的一些问题还是值得参考的。
Systemtap 的使用可以参考官方的两篇文档,一篇入门,一篇相当于 manual,其实这些都能直接 man 到。

然后就是根据需求 google 各种 stp 脚本了,跑出来的结果如果不熟悉 kernel function & syscall 的话,需要花些时间理解下,否则没法分析问题了。
如果需要在 production 机器上做,直接安装 systemtap-runtime,在同等配置的机器上把 ko 文件做好丢到 production 上跑就好了。后来偶然的机会发现了一篇不错的中文安装文档