在服务器上排除问题的头 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后台进程。
你甚至有可能找到真正的故障源头。就算还没有找到,搞清楚了上面这些情况之后,你现在也具备了深挖下去的条件。继续努力吧!
阿里这次的地铁广告,刺穿了无数创业者的心
最近被刷屏的文案特别多,但走心的却很少……
阿里钉钉最近在客村站投放了一组主题为“创业很苦,坚持很酷”的地铁广告,将26个创业故事做成了一篇微信推文,因排版怪异引发网友吐槽:治好了我多年的颈椎病……
先看我个人比较喜欢的几句:
“因为理想,成了兄弟,
因为钱,成了仇敌。”
“28岁,头发白了一半。”
“感觉自己这次会成功,
这种感觉已经是第六次。”
“陪聊陪酒赔笑,赔本。”
“怕配不上曾经的梦想,也怕辜负了所受的苦难。”
“为了想做的事儿,去做不想做的事。”
“在车里哭完,笑着走进办公室。”
“刚来三天的新同事提离职,
理由是他也决定去创业。”
“亏了钱,失去了健康。”
这样的文案总共有26组,句句扎心,有创过业的人多少都感同身受:
“没有过不去的坎儿,只有过不完的坎儿。”
“不能倒下。不想到此为止。”
“40度高烧,呆在车里,出了一身汗,然后去提案。”
“下一次,不会再为了钱低头。”
“忍受孤独”
“没有安全感的人,却要让大家有安全感”
端端正正广告的已经没人看了,创意方面得想法吸引别人的注意才行。
微信推文式广告还是第一次见:
为这张图片配一句文字:
我只是一个过客……
由此联想到钉钉去年还攻入腾讯总部楼下地铁大做撕逼广告,现在花钱买下地铁广告大方采用微信公号排版,姿态可以说是发生了180度的大转变。
这样的转变,并不意外。从策略上来说,创业产品在初期阶段,为了能快速建立差异化的认知,往往会采取比较激进的手段,而随着产品用户数越来越大,影响力越来越强,也需要照顾品牌的长线发展,注重其在公众的口碑。
世界上的公司分两种:第一种是酷公司
他们认为适应时代酷,而保持老样子不酷;拥有不酷,与更多人共享非常酷;征服者不酷,守护者很酷。
是无数个这样的酷公司,造就了今天这个酷时代……
除此以外的,我们只能称之为“其它公司”,酷公司各不相同,但他们都选择了同一种更酷的工作方式:酷公司,用钉钉。
“为了做社交软件,放弃社交。”
“只要风停了,什么猪都能摔死。”
“通宵练习了10个版本的BP,没有见到1个投资人。”
“把房子卖了,把工资发了。”
“每天一睁眼要养50个家。”
也许在未来,说不定我们还会看到有“中国酷公司”、“中国酷员工”、“中国酷老板”、“中国酷项目”、“中国酷办公室”这类的榜单被释放出来。
但“酷”的背后是互联网的协作、平等、分享的精神,以后如果以酷的形式随波逐流的话,不知道会有多少企业会买单。
针对此次阿里钉钉的广告,网友有话说:
可能钉钉这次的广告针对人群不一样,所以或多或少有一些负面信息。但是此次钉钉的主题就是为创业者所做,作为一个局外人,我只能说文案很符合创业者的心声。
同时作为不是创业者的我,看完文案都有种似曾相似的感触~
对此,你怎么看?
记一次对 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就能正常连接了。
介绍一下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地址。