在网站运维实践中,除了网络、服务器等硬件故障导致的系统可用性风险外,还有来自软件系统本身的风险。
下面会介绍一些为了保证线上系统的可用而采取的一些与传统软件按开发不同的质量保证。
1.网站发布
网站需要保证7x24高可用运行,同时网站又需要不断地发布新功能吸引用户以保证在激烈的市场竞争中获得成功。
许多大型网站每周都需要发布一到两次,而中型网站则更加频繁,一些处于快速发展期的网站甚至每天发布十几次。
不管发布的新功能是修改了一个按钮的布局还是增加了一个核心业务,都需要在服务器上关闭原有的应用,
然后重新部署启动新的应用,整个过程还要求不影响用户的使用。
这相当于要求给飞行中的飞机换个引擎,既不能让飞机有剧烈晃动(影响用户体验),
也不能让飞机降落(系统停机维护),更不能让飞机坠毁(系统故障网站完全不可用)。
网站的发布过程事实上和服务器宕机效果相当,其对系统可用性的影响也和服务器宕机相似。
所以设计一个网站的高可用架构时,需要考虑的服务器宕机概率不是物理上的每年一两次,而是事实上的每周一两次。
也许你认为这个应用不重要,重启也非常块,用户可以忍受每年一到两次的宕机故障,因而不需要复杂的高可用设计。
事实上,由于应用的不断发布,用户需要面对的是每周一到两次的宕机故障。
但是网站发布毕竟是一次提前预知的服务器宕机,所以过程可以更柔和,对于用户影响更小,通常使用发布脚本来完成发布,流程如下:
发布过程中,每次关闭服务的服务器都是集群中的一小部分,并在发布完成后立即可以访问,因此整个发布过程不影响用户使用。
2.自动化测试
代码在发布到线上服务器之前需要进行严格的测试。
即使每次发布的新功能都在原有系统功能上的小幅增加,但为了保证系统没有引入未预料的Bug,网站测试还是需要对整个网站功能进行全面的回归测试。
此外还需要测试各种浏览器的兼容性,在发布频繁的网站应用中,如果使用人工测试,成本、时间及测试覆盖率都难以接受。
目前大部分网站都采用Web自动化测试技术,使用自动测试工具或脚本完成测试。
比较流行的Web自动化测试工具是ThoughtWorks开发的Selenium。
Selenium运行在浏览器中,因此Selenium可以同时完成Web功能测试和浏览器兼容测试。
大型网站通常也会开发自己的自动化测试工具,可以一键完成系统部署,测试数据生成、测试执行、测试报告生成等全部测试过程。
许多网站测试工程师的编码能力毫不逊色于软件工程师。
3.预发布验证
即使是经过严格的验证,软件不是到线上服务器之后还是会经常出现各种问题,甚至根本无法启动服务器。
主要原因是测试环境和线上环境并不相同,特别是应用需要依赖的其他服务,
如数据库、缓存、公共业务服务等,以及一些第三方服务,如电信短信网关、银行网银接口等。
也许是数据库表结构不一致,也许是接口变化导致的通信失败,也许是配置错误导致连接失败,
也许是依赖的服务线上环境还没有准备好,这些问题都有可能导致应用故障。
因此在网站发布时,并不是直接把测试通过的代码包直接发布到线上服务器,而是先发布到预发机器上,
开发工程师和测试工程师在预发布服务器上进行预发布验证,执行一些典型的业务流程,确认系统没有问题后才正式发布。
预发布服务器是一种特殊用途的服务器,它和线上的正式服务器唯一的不同就是没有配置在负载均衡服务器上,外部用户无法访问。
预发布服务器和线上正式服务器都部署在相同的物理环境,
同一个数据中心甚至同一个机架上,如果使用虚拟机,甚至可能在同一台物理服务器上,使用相同的线上配置,依赖相同的线上环境。
网站工程师通过在自己的开发机上配置hosts文件绑定域名IP关系直接使用IP地址访问预发布服务器。
如果在预发布服务器上执行的测试是成功的,基本可以保证在线上正是服务器部署时也没有问题。
不过,也有可能会因为预发布验证而引入问题。
因为预发布服务器连接的是真实的环境,所有预发布验证操作都是真实有效的数据,这些操作也许会引起不可预期的问题。
比如创建一个店铺,上架一个商品,就有可能有真的用户过来购买,如果不能操作,就会导致用户投诉。
此外,在网站应用中强调的一个处理错误的理念是快速失败(fast failed),即系统如果在启动时发现问题就立刻抛出异样,
停止启动让工程师介入排查错误,而不是启动后执行错误的操作。
4.代码控制
对于大型网站,核心应用系统和公共业务模块涉及许多团队和工程师,需要对相同的代码库进行共同开发和维护。
而这些团队对同一个应用的开发维护(开发周期和发布时间各不相同),如果代码控制环节出了问题,
可能将有问题的代码发布上线,将问题带入生产环节,导致系统故障。
网站代码控制的核心问题是如何进行代码管理,既能保证代码发布版本的稳定正确,同时又能保证不同团队的开发互不影响。
目前大部分网站使用的源代码版本控制工具是SVN,SVN代码控制和版本发布方式一般有以下两种。
(1)主干开发、分支发布
代码修改都在主干(trunk)上进行,需要发布的时候,从主干上拉一个分支(branch)发布,
即分支成为一个发布版本,如果该版本发现Bug,继续在该分支上修改发布,将修改合并(merge)回主干,直到下次主干发布。
(2)分支开发、主干发布
任何修改都不得在主干上直接进行,需要开发一个新功能或者修复一个Bug时,从主干拉一个分支进行开发,
开发完成且通过测试后,合并回主干,然后从主干进行发布,主干上的代码永远是最新发布的版本。
这两种方式各有优缺点。
主干开发、分支发布方式,主干代码反应目前整个应用的状态,一目了然,便于管理和控制,也利于持续集成。
分支开发、主干发布方式,各个分支独立进行,互不干扰,可以使不同发布周期的开发在同一应用中进行。
目前网站应用开发中主要使用的是分支开发、主干发布的方式。
可以想象,如果使用主干开发、分支发布,那么在同一个应用上,对于不同开发周期,不同发布时间的项目,
有可能A项目发布时,B项目只开发了一半,这时候的主干代码是半成品,根本不能发布。
而使用分支开发、主干发布的方式,只需要将A项目的分支合并到主干即可发布,不受B项目发布时间的影响。
目前在开源技术社区,Git作为版本控制工具,正逐步取代SVN的地位。
Git对分布式开发、分支开发等有更好的支持,也更容易在各个开发分支上及时反应主干最新跟新,
避免SVN在最后提交代码时发现主干代码差别太大难以merge成功。
如果想查看更多GIt和SVN的区别,请访问另一篇博客:http://www.cnblogs.com/yangmingxianshen/p/8361369.html
5.自动化发布
网站版本发布频繁,整个发布过程需要许多团队通力合作,发布前,多个代码分支合并回主干可能发生冲突(conflict),
预发布验证也会带来风险,每次发布又相当于一次宕机事故。因此网站发布过程中荆棘丛生,一不小心就会踩雷区。
对于有固定发布日期的网站,很多网站选择周四作为发布日,这样一周前面有三天时间可以准备发布,
后面还有一天可以挽救错误,如果选择周五发布,发现问题就需要加班加点了。
火车发布模型:将每个应用的发布过程看作一次火车旅行,火车定点运行,期间有若干站点,
每一站都例行检查,不通过的项目下车,剩下的项目继续坐着火车,直到火车到达终点(应用发布成功)。
由于火车发布模型是基于规则驱动流程,所以这个流程可以自动化采用火车发布模型的网站回开发一个自动化发布工具实现发布过程自动化。
根据响应驱动流程,自动构建代码分支,进行代码合并,执行发布脚本等。
正常流程下,可以做到发布过程无人值守,无需SCM(网站配置管理员)参与,
每个项目相关人员基于流程执行相应的操作,即可完成自动化发布。
人的干预越少,自动化程度越高,引入故障的可能性就越小。
6.灰度发布
应用发布成功后,仍然可能发现应为软件问题而引起的故障,这时候就需要做发布回滚,
即卸载刚刚发布的这个软件,将上一个版本的软件包重新发布,使系统复原,消除故障。
大型网站的主要业务服务器集群规模非常强大,比如某大型服务器应用集群服务器数量超过一万台。
一旦发生故障,即使想要发布回滚也需要很长时间才能完成,只能眼睁睁看着故障时间不断增加。
为了应付这种局面,大型网站都会使用灰度发布模式,将集群服务器分厂若干部分,持续几天才能把整个集群全部发布完毕,
期间如果发现问题,只需要回滚已发布的一部分服务器即可。
就像一个大型网络游戏,不能说一次把所有区更新完毕,而是分批次完成,即使更新失败也能回到之前版本,回滚时间也能接收。
灰度发布也常用户用户测试,即在部分服务器上发布新版本,其余服务器保持老版本(或者发布另一个版本),
然后监控用户操作行为,收集用户体验报告,比较用户对两个版本的满意度,以确定最终的发布版本。这种手段叫做AB测试。