2016年10月15日,一个让我难忘的日子。

那天晚上,我正在家里看电视,手机突然响了,是服务器监控的告警短信:"CPU使用率超过90%,请及时处理。"

我心里一紧,赶紧打开电脑,登录服务器。一看,CPU使用率100%,内存使用率95%,负载均衡(load average)高达20多,网站已经打不开了。

我当时就懵了。我的博客,平时每天也就几百IP,流量很小,服务器配置也不高(1核2G),从来没有出过问题。今天怎么突然这样了?

一、事件发生

我先看了一下Nginx的访问日志,发现访问量突然暴涨。平时每秒也就几个请求,那天每秒有几百个请求,而且还在不断增加。

再看一下访问来源,发现大部分流量都来自微博。原来,我前几天写的一篇技术文章,被一个微博大V转发了,然后就火了。转发、评论、点赞,越来越多,流量就像洪水一样涌过来。

我那篇文章,讲的是PHP性能优化的一些技巧,可能是因为写得比较实用,被大V看上了,转发了。然后,就像滚雪球一样,越来越多的人看到,越来越多的人访问我的博客。

但是,我的服务器配置太低了,1核2G,根本扛不住这么大的流量。很快,CPU就满了,内存也满了,PHP-FPM进程被占满,新的请求无法处理,网站就打不开了。

而且,因为网站打不开,用户会不断刷新,这又增加了服务器的负担,形成了恶性循环。服务器越来越卡,最后几乎瘫痪了。

二、应急处理

看到服务器快挂了,我赶紧开始应急处理。

第一步:重启服务

我先重启了PHP-FPM和Nginx,希望能释放一些资源,让网站恢复正常。但是,重启之后,很快又被打满了,因为流量还在不断涌进来。

重启只能暂时缓解,不能解决根本问题。

第二步:开启缓存

我之前在服务器上装了Redis,但是博客的缓存没有完全开启。紧急情况下,我赶紧开启了页面缓存,把文章页面缓存到Redis里,这样就不需要每次请求都查询数据库和渲染PHP了,直接从Redis里读取缓存的HTML,性能会好很多。

开启缓存之后,服务器的负载降了一些,CPU从100%降到了70%左右,网站也能打开了,虽然还是有点慢,但是至少能访问了。

第三步:限制连接数

虽然开启了缓存,但是流量还是很大,服务器还是有点吃力。我又在Nginx里配置了连接数限制,限制每个IP的并发连接数,防止单个IP占用太多连接。

同时,我也配置了请求速率限制,防止单个IP发送太多请求。

限制之后,服务器的负载又降了一些,CPU降到了50%左右,网站访问也流畅了一些。

第四步:上CDN

虽然开启了缓存和限制,但是服务器还是在承受很大的流量。我知道,这样下去不是办法,服务器迟早还是会被打挂。

我赶紧注册了一个CDN服务(内容分发网络),把博客的域名解析到CDN上,让CDN来缓存静态资源和页面,用户的请求先到CDN,CDN有缓存就直接返回,没有缓存才回源到我的服务器。

上了CDN之后,服务器的负载一下子就降下来了,CPU降到了20%左右,内存也降了很多。因为大部分请求都被CDN缓存了,只有很少的请求会回源到我的服务器。

上了CDN之后,网站不仅能正常访问了,而且访问速度也更快了,因为CDN的节点离用户更近,响应更快。

第五步:监控和观察

做完这些应急处理之后,我开始密切监控服务器的状态,观察流量的变化。

流量在持续了几个小时之后,慢慢降下来了。毕竟,微博的热度是有时效的,几个小时之后,那篇文章就不再是热门了,流量也就慢慢降下来了。

到了凌晨,流量基本恢复正常了,服务器也稳定了。我这才松了一口气,瘫在椅子上,感觉像打了一场仗。

三、原因分析

事件平息之后,我开始反思,为什么会出现这种情况?原因主要有几个:

1. 服务器配置太低

我的服务器是1核2G的入门级配置,平时小流量没问题,但是遇到大流量就扛不住了。CPU和内存都不够,PHP-FPM进程很快就被占满,无法处理新的请求。

2. 没有开启缓存

之前,我的博客没有完全开启缓存,每次请求都要查询数据库、渲染PHP,这对服务器的压力很大。如果提前开启了缓存,即使流量大一些,服务器也能扛住。

3. 没有CDN

之前,我的博客没有上CDN,所有请求都直接打到我的服务器上。如果上了CDN,静态资源和页面都由CDN缓存,服务器的压力会小很多。

4. 监控和告警不够完善

虽然我有基本的监控和告警,但是告警的阈值设置得太高了,CPU到90%才告警。如果阈值设置得低一些,比如70%,就能更早地发现问题,更早地处理,不会等到服务器快挂了才发现。

而且,我没有流量异常检测,如果有流量突然暴涨,应该提前告警,让我有时间准备。

5. 没有应急预案

之前,我没有考虑过流量突然暴涨的情况,也没有应急预案。遇到问题的时候,只能手忙脚乱地临时处理,走了很多弯路。如果提前有应急预案,就能更快、更有序地处理问题。

四、后续的优化和改进

这次事件,给了我很大的教训。事件平息之后,我对博客做了一系列的优化和改进,避免以后再出现类似的情况。

1. 升级服务器配置

我把服务器从1核2G升级到了2核4G,CPU和内存都翻倍了。这样,即使遇到流量暴涨,服务器也能扛住一段时间,不会很快就被打挂。

当然,升级服务器会增加成本,但是对于一个博客来说,2核4G的配置也不贵,每个月也就几十块钱,还是能接受的。

2. 完善缓存机制

我完善了博客的缓存机制,开启了页面缓存、数据库查询缓存、对象缓存等。大部分请求都能直接从缓存里读取,不需要查询数据库和渲染PHP,性能提升了很多。

而且,我还设置了缓存的自动刷新和过期时间,保证缓存的有效性。

3. 上CDN

我把博客永久地上了CDN,静态资源(图片、CSS、JS等)都由CDN缓存,页面也由CDN缓存。这样,即使遇到流量暴涨,大部分请求也会被CDN缓存,不会打到我的服务器上。

而且,CDN还能提升访问速度,因为CDN的节点离用户更近,响应更快。对于全国甚至全球的用户来说,访问体验都更好。

4. 完善监控和告警

我完善了服务器的监控和告警,监控的指标包括CPU使用率、内存使用率、磁盘使用率、网络流量、请求数、响应时间等。

告警的阈值也设置得更合理了,CPU到70%就告警,内存到80%就告警,流量异常也会告警。这样,就能更早地发现问题,更早地处理。

而且,我还设置了多种告警方式,包括短信、邮件、微信,确保我能及时收到告警。

5. 制定应急预案

我制定了详细的应急预案,包括流量暴涨、服务器故障、数据库故障、网络故障等各种情况的处理流程。

比如,流量暴涨的应急预案:

  1. 检查服务器状态,确认问题
  2. 开启缓存(如果没开启)
  3. 限制连接数和请求速率
  4. 上CDN(如果没上)
  5. 升级服务器配置(如果需要)
  6. 密切监控,观察流量变化

有了应急预案,遇到问题的时候,就能按照流程有序地处理,不会手忙脚乱。

6. 数据库优化

我对数据库做了优化,包括添加索引、优化查询语句、分表分库(如果需要)等。数据库查询的性能提升了,即使流量大一些,数据库也不会成为瓶颈。

7. 代码优化

我对博客的代码也做了优化,减少了不必要的数据库查询,优化了PHP代码的执行效率,减少了内存占用。代码优化之后,页面的响应速度更快了,服务器的负载也更低了。

五、经验和教训

这次事件,虽然是一次危机,但是也让我学到了很多东西。以下是我的一些经验和教训:

1. 要有危机意识

不要觉得自己的网站流量小,就不会遇到问题。流量可能会因为各种原因突然暴涨,比如被大V转发、被搜索引擎收录、被热门网站引用等。要有危机意识,提前做好准备,避免遇到问题的时候手忙脚乱。

2. 缓存是个好东西

缓存是应对高并发的利器。开启了缓存,大部分请求都能直接从缓存里读取,不需要查询数据库和渲染PHP,性能会提升很多。不管网站大小,都应该开启缓存。

3. CDN是个好东西

CDN不仅能提升访问速度,还能分担服务器的流量压力。遇到流量暴涨的时候,CDN能缓存大部分请求,保护源站不被打挂。对于任何网站来说,CDN都是值得投入的。

4. 监控和告警很重要

监控和告警,能让你及时发现问题,尽早处理。不要等到服务器快挂了才发现问题,那时候可能已经来不及了。完善的监控和告警,是网站稳定运行的保障。

5. 应急预案很重要

遇到问题的时候,如果有应急预案,就能按照流程有序地处理,不会手忙脚乱。提前制定应急预案,考虑各种可能的情况,能让你在危机面前更加从容。

6. 不要贪便宜,服务器配置要合理

不要为了省钱,买配置太低的服务器。配置太低的服务器,遇到流量暴涨很容易被打挂。根据网站的流量和需求,选择合理的服务器配置,是网站稳定运行的基础。

当然,也不需要买配置太高的服务器,浪费钱。合理就好。

7. 危机也是机会

虽然这次事件是一次危机,但是也让我学到了很多东西,对博客做了很多优化和改进。经过这次事件,我的博客更加稳定了,性能也更好了。

所以,危机也是机会。遇到问题不要怕,认真分析,总结经验,持续改进,就能让自己变得更强。

六、写在最后

线上流量突然暴涨,我的服务器差点挂了。

这是一次真实的运维经历,有慌乱,有教训,也有收获。虽然那天晚上忙到凌晨,很累,但是也学到了很多东西。

经过这次事件,我的博客更加稳定了,性能也更好了。缓存、CDN、监控、告警、应急预案,该有的都有了。现在,即使再遇到流量暴涨,我也不慌了,因为我已经做好了准备。

作为一个程序员,不仅要会写代码,还要懂一些运维知识。网站上线之后,运维是很重要的一部分。监控、告警、缓存、CDN、负载均衡、应急预案,这些都是运维的基本功。

希望我的这次经历,能给大家一些参考。如果你的网站也遇到过类似的情况,或者有什么运维的经验,欢迎在评论区分享,我们一起交流。

最后,用一句话总结:

"平时多流汗,战时少流血。"

运维也是一样,平时多做好准备,遇到危机的时候才能从容应对。