竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


188月/170

在服务器上排除问题的头 5 分钟

发布在 邵珠庆

遇到服务器故障,问题出现的原因很少可以一下就想到。我们基本上都会从以下步骤入手:

一、尽可能搞清楚问题的前因后果

不要一下子就扎到服务器前面,你需要先搞明白对这台服务器有多少已知的情况,还有故障的具体情况。不然你很可能就是在无的放矢。

必须搞清楚的问题有:

  • 故障的表现是什么?无响应?报错?
  • 故障是什么时候发现的?
  • 故障是否可重现?
  • 有没有出现的规律(比如每小时出现一次)
  • 最后一次对整个平台进行更新的内容是什么(代码、服务器等)?
  • 故障影响的特定用户群是什么样的(已登录的, 退出的, 某个地域的…)?
  • 基础架构(物理的、逻辑的)的文档是否能找到?
  • 是否有监控平台可用? (比如Munin、Zabbix、 Nagios、 New Relic… 什么都可以)
  • 是否有日志可以查看?. (比如Loggly、Airbrake、 Graylog…)

最后两个是最方便的信息来源,不过别抱太大希望,基本上它们都不会有。只能再继续摸索了。

 

 

二、有谁在?

$ w

$ last

用这两个命令看看都有谁在线,有哪些用户访问过。这不是什么关键步骤,不过最好别在其他用户正干活的时候来调试系统。有道是一山不容二虎嘛。(ne cook in the kitchen is enough.)

三、之前发生了什么?

$ history

查看一下之前服务器上执行过的命令。看一下总是没错的,加上前面看的谁登录过的信息,应该有点用。另外作为admin要注意,不要利用自己的权限去侵犯别人的隐私哦。

到这里先提醒一下,等会你可能会需要更新 HISTTIMEFORMAT 环境变量来显示这些命令被执行的时间。对要不然光看到一堆不知道啥时候执行的命令,同样会令人抓狂的。

四、现在在运行的进程是啥?

$ pstree -a

$ ps aux

这都是查看现有进程的。 ps aux 的结果比较杂乱, pstree -a 的结果比较简单明了,可以看到正在运行的进程及相关用户。

五、监听的网络服务

$ netstat -ntlp

$ netstat -nulp

$ netstat -nxlp

我一般都分开运行这三个命令,不想一下子看到列出一大堆所有的服务。netstat -nalp倒也可以。不过我绝不会用 numeric 选项 (鄙人一点浅薄的看法:IP 地址看起来更方便)。

找到所有正在运行的服务,检查它们是否应该运行。查看各个监听端口。在netstat显示的服务列表中的PID 和 ps aux 进程列表中的是一样的。

如果服务器上有好几个Java或者Erlang什么的进程在同时运行,能够按PID分别找到每个进程就很重要了。

通常我们建议每台服务器上运行的服务少一点,必要时可以增加服务器。如果你看到一台服务器上有三四十个监听端口开着,那还是做个记录,回头有空的时候清理一下,重新组织一下服务器。

六、CPU 和内存

$ free -m

$ uptime

$ top

$ htop

注意以下问题:

  • 还有空余的内存吗? 服务器是否正在内存和硬盘之间进行swap?
  • 还有剩余的CPU吗? 服务器是几核的? 是否有某些CPU核负载过多了?
  • 服务器最大的负载来自什么地方? 平均负载是多少?

 

七、硬件

$ lspci

$ dmidecode

$ ethtool

有很多服务器还是裸机状态,可以看一下:

  • 找到RAID 卡 (是否带BBU备用电池?)、 CPU、空余的内存插槽。根据这些情况可以大致了解硬件问题的来源和性能改进的办法。
  • 网卡是否设置好? 是否正运行在半双工状态? 速度是10MBps? 有没有 TX/RX 报错?

 

八、IO 性能

$ iostat -kx 2

$ vmstat 2 10

$ mpstat 2 10

$ dstat --top-io --top-bio

这些命令对于调试后端性能非常有用。

  • 检查磁盘使用量:服务器硬盘是否已满?
  • 是否开启了swap交换模式 (si/so)?
  • CPU被谁占用:系统进程? 用户进程? 虚拟机?
  • dstat 是我的最爱。用它可以看到谁在进行 IO: 是不是MySQL吃掉了所有的系统资源? 还是你的PHP进程?

 

九、挂载点 和 文件系统

$ mount

$ cat /etc/fstab

$ vgs

$ pvs

$ lvs

$ df -h

$ lsof +D / /* beware not to kill your box */

  • 一共挂载了多少文件系统?
  • 有没有某个服务专用的文件系统? (比如MySQL?)
  • 文件系统的挂载选项是什么: noatime? default? 有没有文件系统被重新挂载为只读模式了?
  • 磁盘空间是否还有剩余?
  • 是否有大文件被删除但没有清空?
  • 如果磁盘空间有问题,你是否还有空间来扩展一个分区?

 

十、内核、中断和网络

$ sysctl -a | grep ...

$ cat /proc/interrupts

$ cat /proc/net/ip_conntrack /* may take some time on busy servers */

$ netstat

$ ss -s

  • 你的中断请求是否是均衡地分配给CPU处理,还是会有某个CPU的核因为大量的网络中断请求或者RAID请求而过载了?
  • SWAP交换的设置是什么?对于工作站来说swappinness 设为 60 就很好, 不过对于服务器就太糟了:你最好永远不要让服务器做SWAP交换,不然对磁盘的读写会锁死SWAP进程。
  • conntrack_max 是否设的足够大,能应付你服务器的流量?
  • 在不同状态下(TIME_WAIT, …)TCP连接时间的设置是怎样的?
  • 如果要显示所有存在的连接,netstat 会比较慢, 你可以先用 ss 看一下总体情况。

你还可以看一下 Linux TCP tuning 了解网络性能调优的一些要点。

 

十一、系统日志和内核消息

$ dmesg

$ less /var/log/messages

$ less /var/log/secure

$ less /var/log/auth

  • 查看错误和警告消息,比如看看是不是很多关于连接数过多导致?
  • 看看是否有硬件错误或文件系统错误?
  • 分析是否能将这些错误事件和前面发现的疑点进行时间上的比对。

 

十二、定时任务

$ ls /etc/cron* + cat

$ for user in $(cat /etc/passwd | cut -f1 -d:); do crontab -l -u $user; done

  • 是否有某个定时任务运行过于频繁?
  • 是否有些用户提交了隐藏的定时任务?
  • 在出现故障的时候,是否正好有某个备份任务在执行?

 

十三、应用系统日志

这里边可分析的东西就多了, 不过恐怕你作为运维人员是没功夫去仔细研究它的。关注那些明显的问题,比如在一个典型的LAMP(Linux+Apache+Mysql+Perl)应用环境里:

  • Apache & Nginx; 查找访问和错误日志, 直接找 5xx 错误, 再看看是否有 limit_zone错误。
  • MySQL; 在mysql.log找错误消息,看看有没有结构损坏的表, 是否有innodb修复进程在运行,是否有disk/index/query 问题.
  • PHP-FPM; 如果设定了 php-slow 日志, 直接找错误信息 (php, mysql, memcache, …),如果没设定,赶紧设定。
  • Varnish; 在varnishlog 和 varnishstat 里, 检查 hit/miss比. 看看配置信息里是否遗漏了什么规则,使最终用户可以直接攻击你的后端?
  • HA-Proxy; 后端的状况如何?健康状况检查是否成功?是前端还是后端的队列大小达到最大值了?

 

结论

经过这5分钟之后,你应该对如下情况比较清楚了:

  • 在服务器上运行的都是些啥?
  • 这个故障看起来是和 IO/硬件/网络 或者 系统配置 (有问题的代码、系统内核调优, …)相关。
  • 这个故障是否有你熟悉的一些特征?比如对数据库索引使用不当,或者太多的apache后台进程。

 

你甚至有可能找到真正的故障源头。就算还没有找到,搞清楚了上面这些情况之后,你现在也具备了深挖下去的条件。继续努力吧!

168月/170

阿里这次的地铁广告,刺穿了无数创业者的心

发布在 邵珠庆

最近被刷屏的文案特别多,但走心的却很少……

阿里钉钉最近在客村站投放了一组主题为“创业很苦,坚持很酷”的地铁广告,将26个创业故事做成了一篇微信推文,因排版怪异引发网友吐槽:治好了我多年的颈椎病……

先看我个人比较喜欢的几句:

“因为理想,成了兄弟,

因为钱,成了仇敌。”

“28岁,头发白了一半。”

“感觉自己这次会成功,

这种感觉已经是第六次。”

“陪聊陪酒赔笑,赔本。”

“怕配不上曾经的梦想,也怕辜负了所受的苦难。”

“为了想做的事儿,去做不想做的事。”

“在车里哭完,笑着走进办公室。”

“刚来三天的新同事提离职,

理由是他也决定去创业。”

“亏了钱,失去了健康。”

这样的文案总共有26组,句句扎心,有创过业的人多少都感同身受:

“没有过不去的坎儿,只有过不完的坎儿。”

“不能倒下。不想到此为止。”

“40度高烧,呆在车里,出了一身汗,然后去提案。”

“下一次,不会再为了钱低头。”

“忍受孤独”

“没有安全感的人,却要让大家有安全感”

端端正正广告的已经没人看了,创意方面得想法吸引别人的注意才行。

微信推文式广告还是第一次见:

为这张图片配一句文字:

我只是一个过客……

由此联想到钉钉去年还攻入腾讯总部楼下地铁大做撕逼广告,现在花钱买下地铁广告大方采用微信公号排版,姿态可以说是发生了180度的大转变。

这样的转变,并不意外。从策略上来说,创业产品在初期阶段,为了能快速建立差异化的认知,往往会采取比较激进的手段,而随着产品用户数越来越大,影响力越来越强,也需要照顾品牌的长线发展,注重其在公众的口碑。

世界上的公司分两种:第一种是酷公司

他们认为适应时代酷,而保持老样子不酷;拥有不酷,与更多人共享非常酷;征服者不酷,守护者很酷。

是无数个这样的酷公司,造就了今天这个酷时代……

除此以外的,我们只能称之为“其它公司”,酷公司各不相同,但他们都选择了同一种更酷的工作方式:酷公司,用钉钉。

“为了做社交软件,放弃社交。”

“只要风停了,什么猪都能摔死。”

“通宵练习了10个版本的BP,没有见到1个投资人。”

“把房子卖了,把工资发了。”

“每天一睁眼要养50个家。”

也许在未来,说不定我们还会看到有“中国酷公司”、“中国酷员工”、“中国酷老板”、“中国酷项目”、“中国酷办公室”这类的榜单被释放出来。

但“酷”的背后是互联网的协作、平等、分享的精神,以后如果以酷的形式随波逐流的话,不知道会有多少企业会买单。

针对此次阿里钉钉的广告,网友有话说:

可能钉钉这次的广告针对人群不一样,所以或多或少有一些负面信息。但是此次钉钉的主题就是为创业者所做,作为一个局外人,我只能说文案很符合创业者的心声。

同时作为不是创业者的我,看完文案都有种似曾相似的感触~

对此,你怎么看?

28月/170

记一次对 G-F-W 防火墙的探究

发布在 邵珠庆

突然朋友传了一个数据包给我,说他的openVPN连不上了。

抓包发现刚一握手结束便收到了一个RST包,导致一直连不上。我打开数据包,发现果然如此:

可以看到,三次握手刚完毕,客户端发送第一个控制消息到服务端,便收到了服务端发送的RST数据包,一直如此。

应该是有中间设备搞的鬼,于是我又到服务器端抓取了些数据:

果然的,服务器也收到了RST数据包,于是两者的连接便断开了。

再仔细分析下客户端的RST数据包:

IP包的序号是12345,TTL是120。再看正常的数据包:

IP包的序号是0,TTL是46。很明显RST数据包的TTL比正常的要大,而且每次RST的IP序号都是12345,应该是GFW没错了。

正常情况下初始的TTL是64,正常收到的TTL是46,跳数是15,说明我的电脑到服务器之间经过了15个路由设备。

为了证明这点,查看服务端收到的正常数据包:

服务器收到的TTL是50,因为我的电脑还要经过内部的一个路由器,所以TTL差了1。

同时查看服务端RST数据包的TTL值:

TTL值为117,因此得到的信息如下:

客户端->服务器:15、GWF->服务器:117、GFW->客户端:120。

假设GFW每次发送的TTL值都固定不变且为x,则有:x-117+x-120=15;得x=126。

所以GFW和我的电脑的跳数应该是6:

图示的应该就是GFW的位置。

接下来问题来了,她是怎么识别出openVPN流量的呢?

我猜测是根据数据包的特征来识别的,那么我单独发送单个数据包,应该也会返回RST数据,根据这一理论,我用scapy发送了单个的数据包,内容和三次握手之后客户端发送的第一个数据包一样,但结果是失望的,并没有收到RST数据包。

于是进一步猜测,TCP连接之后再发送相应的数据包,应该能收到RST,于是又根据这一理论,写下了如下代码:

from scapy.all import *
vpn_payload = "\x00\x0e\x38\x24\x5d\x21\xaa\x3a\x11\x2f\xb3\x00\x00\x00\x00\x00"
conf.verb = 0
vpn_s = IP(dst="yovey.me",id=12345)/TCP(sport=58620,dport=1194,flags="S",seq=0)
print "sending syn"
vpn_s.show()
ans0,unans0 = sr(vpn_s)
print "recv packet,seq = ",ans0[0][1].seq
ans0[0][1].show()
vpn_sa = IP(dst="yovey.me",id=12346)/TCP(sport=58620,dport=1194,flags="A",seq=1,ack=ans0[0][1].seq+1)
print "sending ack"
vpn_sa.show()
ans1,unasn1 = sr(vpn_sa,timeout=1)
vpn = IP(dst="yovey.me",id=12347)/TCP(sport=58620,dport=1194,flags="PA",seq=1,ack=ans0[0][1].seq+1)/vpn_payload
print "sending vpn payload"
ans2,unasn2 = sr(vpn)
ans2[0][1].show()

运行程序,还是没有收到RST数据包。

于是我打开tcpdump,抓取了发包过程的数据包,发现了问题:

在服务器返回syn+ack之后,客户端居然发送了RST到服务器,导致连接断开。经过短暂的思考,才明白客户端网卡在收到来自服务器的syn+ack之后,发现并没有进程在监听该数据包的端口,于是发送了RST数据包给服务器。

必须让客户端不发送RST数据包才行,想到可以通过iptable来过滤数据包,于是在iptable中添加如下规则:

iptables -t filter -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

再运行程序,一切都在计划之中:

还是熟悉的IP序号,还是熟悉的TTL,看来GFW已经可以根据连接来识别流量了,真是下了血本啊。

想到建立连接,我立马联想到不用建立连接的UDP,是不是UDP数据只需要根据单个数据包就能识别了?于是将服务器配置成UDP模式,再次打开openVPN,特么的居然连上了!于是问题解决了,将配置改成UDP就能正常连接了。

28月/170

介绍一下GFW的工作原理和封锁技术

发布在 邵珠庆

GFW是Great Fire Wall的缩写,即“长城防火墙”。这个工程由若干个部分组成,实现不同功能。长城防火墙主要指TG监控和过滤互联网内容的软硬件系统,由服务器和路由器等设备,加上相关的应用程序所构成。

首先,需要强调的是,由于中国网络审查广泛,中国国内含有“不合适”内容的的网站,会受到政府直接的行政干预,被要求自我审查、自我监管,乃至关闭,所以GFW的主要作用在于分析和过滤中国境内外网络的资讯互相访问。

GFW对网络内容的过滤和分析是双向的,GFW不仅针对国内读者访问中国境外的网站进行干扰,也干扰国外读者访问主机在中国大陆的网站。

一 关键字过滤阻断

关键字过滤系统。此系统能够从出口网关收集分析信息,过滤、嗅探指定的关键字。主要针对HTTP的默认端口:80端口,因为HTTP传播的内容是明文的内容,没有经过加密,而GFW是一个IDS(Intrusion detection system)。普通的关键词如果出现在HTTP请求报文的头部(如“Host: www.youtube.com”)时,则会马上伪装成对方向连接两端的计算机发送RST包(reset)干扰两者正常的TCP连接,进而使请求的内容无法继续查看。如果GFW在数据流中发现了特殊的内文关键词(如轮子,达赖等)时,其也会试图打断当前的连接,从而有时会出现网页开启一部分后突然停止的情况。在任何阻断发生后,一般在随后的90秒内同一IP地址均无法浏览对应IP地址相同端口上的内容。

二 IP地址封锁

IP地址封锁是GFW通过路由器来控制的,在通往国外的最后一个网关上加上一条伪造的路由规则,导致通往某些被屏蔽的网站的所有IP数据包无法到达。路由器的正常工作方式是学习别的路由器广播的路由规则,遇到符合已知的IP转发规则的数据包,则按已经规则发送,遇到未知规则IP的数据,则转发到上一级网关。

而GFW对于境外(中国大陆以外)的XX网站会采取独立IP封锁技术。然而部分XX网站使用的是由虚拟主机服务提供商提供的多域名、单(同)IP的主机托管服务,这就会造成了封禁某个IP地址,就会造成所有使用该服务提供商服务的其它使用相同IP地址服务器的网站用户一同遭殃,就算是正常的网站,也不能幸免。其中的内容可能并无不当之处,但也不能在中国大陆正常访问。现在GFW通常会将包含XX信息的网站或网页的URL加入关键字过滤系统,并可以防止民众透过普通海外HTTP代理服务器进行访问。

三 特定端口封锁

GFW会丢弃特定IP地址上特定端口的所有数据包,使该IP地址上服务器的部分功能(如SSH的22、VPN的1723或SSL的443端口等)无法在中国大陆境内正常使用。

在中国移动、中国联通等部分ISP(手机IP段),所有的PPTP类型的VPN都被封锁。

2011年3月起,GFW开始对Google部分服务器的IP地址实施自动封锁(按时间段)某些端口,按时段对www.google.com(用户登录所有Google服务时需此域名加密验证)和mail.google.com的几十个IP地址的443端口实施自动封锁,具体是每10或15分钟可以连通,接着断开,10或15分钟后再连通,再断开,如此循环,令中国大陆用户和Google主机之间的连接出现间歇性中断,使其各项服务出现问题。GFW这样的封锁手法很高明,因为Gmail并非被完全阻断,这令问题看上去好像出自Google本身。这就是你们认为Google抽风的原因。

四 SSL连接阻断

GFW会阻断特定网站的SSL加密连接,方法是通过伪装成对方向连接两端的计算机发送RST包(RESET)干扰两者间正常的TCP连接,进而打断与特定IP地址之间的SSL(HTTPS,443端口)握手(如Gmail、Google文件、Google网上论坛等的SSL加密连接),从而导致SSL连接失败。

当然由于SSL本身的特点,这并不意味着与网站传输的内容可被破译。

五 DNS劫持和污染

GFW主要采用DNS劫持和污染技术,使用Cisco提供的IDS系统来进行域名劫持,防止访问被过滤的网站,2002年Google被封锁期间其域名就被劫持到百度。中国部分ISP也会通过此技术插入广告。

对于含有多个IP地址或经常变更IP地址逃避封锁的域名,GFW通常会使用此方法进行封锁。具体方法是当用户向DNS服务器提交域名请求时,DNS返回虚假(或不解析)的IP地址。

全球一共有13组根域名服务器(Root Server),目前中国大陆有F、I这2个根域DNS镜像,但现在均已因为多次DNS污染外国网络,而被断开与国际互联网的连接。

DNS劫持和污染是针对某些网站的最严重的干扰。

干扰的方式有两种:

一种是通过网络服务提供商(Internet Service Provider)提供的DNS服务器进行DNS欺骗,当人们访问某个网站时,需要要把域名转换为一个IP地址,DNS服务器负责将域名转换为IP地址,中国大陆的ISP接受通信管理局的屏蔽网站的指令后在DNS服务器里加入某些特定域名的虚假记录,当使用此DNS服务器的网络用户访问此特定网站时,DNS服务便给出虚假的IP地址,导致访问网站失败,甚至返回ISP运营商提供的出错页面和广告页面。

另一种是GFW在DNS查询使用的UDP的53端口上根据blacklist进行过滤,遇到通往国外的使用UDP53端口进行查询的DNS请求,就返回一个虚假的IP地址。