一个忧伤的引子 “在某个寒冬的夜晚,当你躺在温暖的被窝里,这时清脆、悦耳的报警短信声接连不断的响起,你长叹一声,拿起手机,拨通运维同学的电话:喂,二哥,服务器怎么啦,啊,内网不通,还在排查,那怎么办、多久能恢复啊...。一会儿项目经理、产品经理、测试经理纷纷来电询问,电话已被打爆,多方商量后决定:先切DNS到其他机房,关掉报警,开发、运维跟进问题,待解决后出故障报告。报警总算消停了,你望着窗外渐渐泛白的天空,陷入沉思,哎:你的黎明要到了,我的黎明在哪里啊。。。”。 很心酸、很自嘲,但是确实很现实,我们希望能有一些通用的解决方案,把开发人员从一些常见的故障中解救出来。
先确定是要椅子还是桌子 首先要定义我们要做和能做的,我们很懒,不想重复造轮子,可能这也是每个程序员入行被告知的第一条准则,我们只想找几块现成的木板,把他们钉起来就好。因为你现在费力实现的每一个功能,可能早已经有极好的解决方法贡献在开源社区,如果可以,那就直接用现成的。我们已经有GSLB了,这是一个全局路由与流量调度的方案,非常优秀,是一个设计通用的方案,但是因为它的设计通用,所以有些需求不能做到定制化,我们想在应用层做一些定制化的方案补充和完善它,并不想做一些重复的工作。 分析这些问题,经常是因为内网故障、DB存储不可用、机器宕机、服务过载等原因导致服务不能正常响应,且这些故障一般并不能在分钟级别内修复。所以我们需要检测后端服务的健康度,在后端服务不健康时,做一些自动的容灾处理。 既然要做容灾,容灾方案本身需要是高可用的,或者说在这个层面是高可用的,因为是基于应用层的容灾,我们选择了nginx lua(openResty)。因为nginx的非阻塞式模式,在有过载保护的情况下我们基本可以定义它为高可用。而且它有很丰富的组件,开放式的API很容易做定制化的需求,在restful风格的下基于lua做一些容灾、降级的策略非常简单、明了、优雅,不与后端的服务耦合,这种可插拔式的方式我太喜欢了。 如何找到好轮子枯燥但又不得不说的技术方案 因为业务的性质,数据量变化并不太频繁,而且请求的数据大多集中在一些热点的数据,我们对广场类的请求加入了nginx的缓存(lrucache,参考链接1 )。之所以加入nginx而非后端web容器的中加入针对URL的缓存主要有一些考虑:首先是可以少一次网络的交互;其次是后端服务响应是基本都是同步的,可能会出现阻塞的问题;还有很重要的一点,就是并不希望开发过于关注缓存配置,跟代码耦合也太严重,当然还有后端服务的本地缓存一般过于笨重,GC的性能消耗也需要考虑。这里缓存有两个实现,纯Lua的和基于外部接口的,缓存命中高的推荐使用前者。 做自动的容灾需要后端服务的健康度检查(healthCheck,参考链接2),可以在这个基础上加一些简单的定制化的功能:在后端部份机器故障时调整nginx缓存的时间;在后端全部服务不可用时,切换域名到镜像机房的CDN域名,后续还有进来的请求返回重定向到镜像机房的CDN域名。 因为要做镜像机房的容灾,首先每个机房的服务能力要有一定的冗余,否则因为某个机房故障引起连锁反应就悲剧了。其次,过载保护也需要提前做好,这个课题太大,这里不方便展开,但是过载保护的指标一定要明确,一般来源于性能测试的结果。因为广场类的请求量过大,如果完全靠冗余设备,有点浪费。我们靠CDN厂商帮我们扛一部分的流量。为了防止故障时过多的CDN回源请求,平时我们会有一部分流量走CDN,这样可以做热加载。现在基本大部分的CDN厂商都支持推送更新,在内容有更新时我们会实时推送CDN的更新。 简单的图示:
Simple is best 我们要让开发、运维人员操作简单,但是引入这个方案,必然会带来一些问题,例如部署文件手工替换太复杂,会给运维带来很大的工作量,由于涉及到的机器众多很容易出错,而且由于涉及到多个机房的很多服务器,配置项的修改也很麻烦。 有强迫症的人伤不起,容不得半点瑕疵。所以这里我们把部署改为了rpm的方式,分为全量和增量两种,一般情况下采取增量的方式,增量覆盖常用的lua文件和库文件,大版本迭代或者升级时采取全量替换的方式(除了配置文件),开发人员只需要关心功能的实现,不需要太多的关注部署的细节,加上我们的发布平台,运维同学基本上也是一键完成部署;我们把通用的配置迁移到了配置中心,定时动态拉取,非常方便,只保留少部分差异化的采取手工配置的方式,这样运维只需要在配置中心做简单的修改,就能同步到所有的机器,工作量小也不容易出错。
达到预期的效果就好 这个方案上线一个星期就在一次服务器内网故障时生效,统计日志结果:为我们挽回了97%的请求。现在在晚上业务高峰期的时候,如果内网响应慢时也会自动生效。当方案生效时用户基本不会有感知,这就是我们预期的效果。
临了,请容我再多说几句 开发人员也需要关注业务的可用性,这不是运维同学一个人的事。 有的时候并不需要太高大上的技术,也能做些有意义的事情,如添加必要的容灾降级开关。 事后的补救不如事前的预防,请平时多关注服务的质量,提前发现服务的瓶颈,给出对应的解决方案。 talk is cheap,coder们动起来,做点我们能做的,我们真的可以做点什么。 参考链接: 1:https://github.com/openresty/lua-resty-lrucache 2:https://github.com/openresty/lua-resty-upstream-healthcheck 运维帮近期活动预告,点击了解详情 |