从开发到上线,实战持续交付

「开发者最佳实践日」是由七牛云存储发起并联合各方小伙伴为开发者举办的系列技术沙龙,关注开发者在实际应用中可能遇到的技术问题。致力于为敢于创新的开发者们提供行业内最前沿最热门的技术干货,以技术驱动应用创新,让更多的开发者享受技术带来的生活乐趣。nginx

本次在1115的杭州开发工具专场就由5位来自不一样公司的技术负责人带来了本身的技术体会和心得,下面是七牛首席架构师李道兵带来的技术分享。程序员

李道兵:在开始以前,我想给你们推荐两本书,一本叫《精益创业》,一本叫《持续交付0》,《精益创业》讲的就是说怎么样把一个Idea变成一个事业或者说一个公司,而这个里面最推崇的,就是整个流程里面的话,第一个是从代码怎么变成服务,第二个步骤,怎么从一个服务变成去收集用户的反馈。第三个步骤,从反馈再回到开发流程。sql

此次我讲第一个流程,第二个和第三个更可能是一些产品决策的东西,我这里跳过不讲了。
关于第一个流程,有一本更加专一的书,叫《持续交付:发布可靠软件的系统方法》,第二本书比较晦涩一点,我仍是推荐前一本。我讲讲咱们七牛从开发到上线这方面有哪些实践。docker

最开始咱们提出来一个简单的或者是很是通用的互联网的网站架构,最开始进来的是Nginx,nginx把全部请求分红两路,一路是静态文件,Nginx本身服务掉了,另一个是动态服务,用到后面的应用服务器,大概是一个业务逻辑层,业务逻辑层的话,你设计好了,它应该是没有状态的,这样的话,当你的用户从1万变成100万再到1000万,应用层从一台直接铺到一百台,架构不用作任何变动,在这一层的话,你作好消除状态、方便水平伸缩就能够了。数据库

而后是数据库,数据就是Mysql的主存架够,DBA的一些Replita为(音)的架构,或者说是引入一些数据库结构,可以Hold住这些东西,好比说如今有1万的量,当你的量成为10万,变成十倍的时候,你怎么去处理,只要数据库能Hold住就能够了。api

第四个要注意的,你的用户上传的文件怎么处理,当你一台的时候,就是放磁盘,当你有两三台机器的时候,就要想两三个机器的话,用Ithink能够同步,用户访问的话,最多有一百毫秒的级别不可用的,大部分是可用的。另外用一些比较成熟的Hold住这些软件,可是如今有一些另外的选择,就是接入公有云存储,这些工具比较方便的。七牛云存储

另外当你的东西稍微大一点,你就要考虑在哪一个换缓存,一个是在Nginx(音)的业务逻辑中间,由于它相对来讲很接近出口的地方多了一个缓存层。第二个比较合适的地方,就是在业务逻辑层和数据库之间,由于数据库最后是压垮你网站性能的最后一根稻草,通常从数据库这个点压垮的,放在数据库里的话,可以大幅度下降数据库压力,这一层须要注意的,保持数据一致,避免缓存,还有缓存出现单点故障的时候,怎么避免后面整个数据库服务都被压死,这是须要去考虑的。从Idea变成普通网站,网站上线了,上线以后进入下一个循环,怎么从网站收集用户数据,或者说作一些线下访谈,从用户这里得到反馈,反馈到开发的阶段,开发阶段以后再去作一些改动,改动以后再去上线。缓存

对于咱们大部分程序员来说,这里面临一个需求,从改动到完成上线,究竟须要花多久,花多久是一回事,另外在改动过程当中,怎么让用户比较稳定地去作这些改动,而咱们将围绕着这个环节作一些讲解。安全

咱们把这个过程称之为部署,部署的话,咱们之前怎么玩这个事情的,应该说比较早期的话, 部署顺着安装文档把这个事情干完,最先玩BBS或者说早期的其余网站,咱们都是怎么来完成部署呢,就是说这个软件会有一份安装文档,告诉你要安装一个数据库,建立一个Database,须要有一个表,怎么安装,安装完之后须要改哪些配置,而后这样就能够上线了。服务器

而这种方式最大的缺陷是什么呢,你要作一些改动怎么办呢,一个方式是我在线上直接改掉。第二个方式就是把这边改掉测试完,测试完之后从新部署一遍。对于第一个方式,线上修改最大的麻烦是你的历史没有记下来,不少东西容易被遗漏,你改了,另一我的改了,这些改动互相有一些冲突或者说改动以后直接丢掉。

若是你安装重装的思路,中间的服务就有一段下线的时间,也很难作到很敏捷的上线,客户发现上面有一个错别字,第一个方案确实能够快速改掉,第二个方案可能须要几个小时,用户才能看获得。

第二个,有一段时间很流行Mysql加上PHP的结构,这个上线很简单,大部分状况就是一个FTP或者SFTP,而后上传上去,用户刷新页面,看到一个全新的网站,那这就有一个问题,它的适用面比较窄,PHP很是好用,可是对于JAVA来说的话,甚至Python为、Ruby都不是很推崇,若是用FTP上传的话,老的服务可能直接崩掉了,要作版本管理,不然回滚很很差作。

JAVA这边经常使用的是打包,把整个应用服务作成一个war包,war包传上去,这个惟一比较麻烦的,假定我已经有100台服务器,一个一个拷贝,其实也是一件很麻烦的事情,当你有100台服务器的时候,要想到一个很大的麻烦,你不是全部服务器在线上,有可能有两台三台在瘫着,某一天须要的时候从新启动上线,那么整个部署管理的话,实际上是一件很麻烦的事情,因此说你会配合一些部署系统。办法就是作成系统安装包,制做过程比较累,好比说作成RPF包,能够很方便地使用,这种大规模部署就没啥压力,雅虎之前这么作的。可是惟一一个麻烦,制做这个包的话,须要不少知识,对于程序员负担比较大。

另外是capistrano,咱们有一部分东西是在用这个东西,从Ruby社区出来的一个部署组建,用起来也算是比较方便,稍候稍微详细地讲一下。capistrano在某些方面解决的问题不是太好,好比说系统方面解决不太好,因此配置方面的话, 须要一些配合,通常配合的是Pupet或者Salt,配合得很是好。还有一个是最近一两年很流行的docker,可以大规模地改变你的整个开发和部署流程,如今不少公司在这方面作一些探索,也作一些小规模的应用,尚未把全部流程搬到这个上面来,就咱们如今来看的话,还有一些小缺点,好比说Docker改变了线上运行方式,而这个运行方式的话,自己有缺陷,好比说Docker对于网络交互能力不够大,若是是大流量的应用程序,表现不太好,另外也须要改变不少之前的日志管理,应用程序的管理,须要更多改变,须要整个运维体系一块儿跟上才能作得很好。

接下来我稍微讲一下capistrano,这个标准结构的目录结构,它有几个大的目录,一个是Release目录,Release目录下面有不少子目录,每个子目录是一长串数字,通常是时间标记,这是2014年9月19号几点几分几秒,整个部署流程是怎么样的呢。

第一步,我先给你在服务端上建立这么一个目录,建立完这个目录以后,无论用什么方法,我把你的一个新的代码也好,新的部署也好,拖到这个Release目录里面去。第二个事情,我在Release目录里面,有些东西是公用的,好比说配置文件,公用的部分的话,它会放在share里面,咱们能够看到一个配置目录,一个LOG目录,一个PID目录,还有一些system目录,咱们把公共部分放到这里以后,咱们用软连接的方式放进去以后,至关于这个Release目录里面就是很完整、可运行的程序了。

最后一步咱们作什么呢,这里有一个current目录,这个是按软连接到特定的Release目录,咱们的步骤就变成先把这个Release目录准备好,准备好了以后,而后把全部的page连接过去,而后第三步是切换Current,从老的Release切换到新的Release,而后再重启程序,新版程序就直接上线。这个时候你就开始测试,测试若是发现它有问题怎么办呢,能够回滚,回滚超级简单,我把Current从新迁回上一次Release软连接,再重起程序,整个回滚就直接完成了,这也是capistrano最大的卖点所在。同时它的整个目录体系能够定制的地方很是多,因此用起来,自我定制化能力也比较强,用起来也比较方便。

capistrano可以解决的,就是说你的代码修改了,怎么去上线这个流程,也就是说咱们刚才说的三步步骤里面,跟程序员最相关的一步,新需求来了,我要把它弄上线,有Bug了,要修复,要弄上线。仅仅作到这样的话,不太够,还须要解决一些新的问题,一台机器在线上,系统盘毁掉了,这个磁盘坏掉了,咱们多久才能把这台机器恢复出来,恢复出来咱们要作一些什么事情,咱们要先安装一个系统,多是LTS版本,同时要在上面建立用户,要部署SNG(音)的纲要,要调整日志的一些滚动方式,要调整youdimit(音)文件过多,同时还可能要去安装它的依赖,还要安装Ruby的特定版本和依赖包。

要么你就是维护一份文档,每次当你要装一台新机器的时候,安照这个文档走一遍,可是最大的问题,这种文档维护是会丢失的,若是机器不坏,你确定会修改依赖,好比说Ruby有可能从2.0升到2.1,Python可能从2.6升到2.7,在升级过程当中,你会在线上直接操做完了以后,你会把这份文档很容易忘记修改。

第二个问题,你常常在线上作一些微调的话,实际上你会忘记入库的东西。第二个问题跟第一个问题很相似的,你的用户大规模上来了,按照咱们刚才说的,你的架构自己支持水平伸缩的,很容易伸缩完了,那我就扩容到一百台,但扩容到一百台机器以后,就面临一个问题,你怎么同时部署一百台机器,是一台一台地走呢,仍是说你有什么办法去控制,从一个中心控制一百台,同时帮你作一些升级工做。

固然平常运维除了这两点,还会面临着不少问题,好比说咱们今年SSL大概前先后后出了好几回大漏洞,每次大漏洞的时候,你们的处理方式是什么呢,若是你所有用系统包,又触发全部的系统包,所有完成整个NGX(音)或者Open SSH的升级工做, NGINX(音)常常是自定义编辑的,NGINX怎么快速一次性升级完毕,今年Heartblood(音)是一个很好的例子,当这个漏洞刚出现的时候,它的攻击手法跟漏洞的报告几乎是同时出现的,也就是说你的机器在公网上多暴露一分钟,你的用户密码就多暴露一分钟,这个是很典型的例子。

这样的状况下,你的一百台机器,升级一个东西须要多久,意味着你在这方面的话,时间越长,你的损失就越大,固然用户不会由于这个东西来质疑,可是一个用户密码泄露,早晚会给你带来一些损失。

这些问题有什么比较好的解决方案呢,咱们用方式,就是puppet和salt都能很好地解决问题,它们的思路比较一致,一个至关于帮你准备好了不少基础组建,另一个的话,更多的东西须要你本身写一下。在这方面的话,它们的思路就是几点。

第一点,全部的配置都应该是入库的,这个入库是指什么呢,好比说线上的OpenSSH应该是哪个版本,我至关于在里面要作一些锁定的工做,个人Ruby应该用哪个版本,也应该锁定的,我须要建立哪些用户,一个很少、一个很多的,都是在个人配置里面写好的。个人用户,个人公要上传哪些,公要部署哪些。还有日志滚动怎么配置,这些都是入在一个配置库里面。同时来说,它们引入一些模板简化配置,好比说上一台机器,跟其余机器同样,这两台同样须要哪些组建就能够了,一样来说的话,好比说这台机器可能须要Mysql5.0的,另外的一台机器须要Mysql5.5的,那你就用一个模板,能够快速在这台机器上装5.0,另一台机器装5.5,同时管理大量机器,这也是刚才所说的很重要的问题,就是说我有一百台机器,要同时让它们作操做,同时升级组建,怎么作,利用Pub(音)可以很好地解决。剩下包括依赖的管理,改配置带来一个问题,你必需要Reload,怎么来触发,里面经过一些依赖,好比说一个服务依赖于一个配置,这个配置修改以后,这个服务的话,自动作一些Reload的工做,这个是Puppet能够作很好的实验。

固然cap+Puppet也有一些小问题的,为了解决这个问题,开发一个新的部署系统。第一个问题来说,程序和配置是分离的,前面咱们提到,用你的capistrano能够更好地帮你把程序部署上去,可是配置呢,配置通常有一个特色,它不入库的,由于咱们的配置里面,常常涉及一些比较偏机密的东西,好比说应用服务器会scret,你的服务器有用户、有密码,这类的东西都会在里面。配置咱们倾向于另一条管理思路,好比说Hubpuppet分发,就带来一个问题,你的程序更新涉及到配置的更新,程序的更新致使一个配置项含义改变了,或者增长配置项,会有这类的问题,就会带来一个问题,程序更新咱们能够很容易,咱们先把配置弄上去,而后再更新程序,再重写程序,这个流程没有问题。

问题出在什么,当你回滚的时候怎么办,当你回滚的时候,旧的程序多了一个新的配置,优雅一点的,你的程序能作得很好,你能够作新的配置,能够兼容,不优雅一点,旧程序就崩溃掉了,整个回滚就失败。咱们这个新的整个流程的话,就是说咱们的配置和程序是至关于同时部署的,这跟之前的的capistrano算是小的改进。

第二部来说的话,以前puppet带来一个问题,你的puppet,十台机器、一百台机器没有问题,能够扛得住,可是当你的服务规模再上一个台阶的时候,整个中心的性能就不够了,整个部署的流程,从你通知它部署到它部署完成,可能这个时间拉得很长,这对咱们来说是很不利的。你的危险在公网多暴露一分钟,就多一分损失。

第三个,当你的机器不少,同时机器数据比较敏感,由于咱们作存储,那么开发人员想知道机器的一些状况,可是又不能容许他登录的状况下,咱们就会开发一些辅助程序让它在不登录的状况下了解状况,监控是一个办法,可是不能太多太杂,太多太杂的话,开发人员会被迷失在数据里面,那么咱们反过来去作的话,当开发人员想知道一个数据的时候,咱们其中一个方法让你去作,去拿到这些数据。好比说你想知道磁盘的剩余空间,这是最简单的需求,另外想知道应用程序日志有哪些文件,可能想知道分别占多大的空间。好比说这个程序如今打开了多少个文件描述符,上面总共有多少个连接,这个时候帮助咱们开发人员快速了解状况,同时不用申请登录权限,这是咱们开发部署系统想去解决的问题,同时也有一些比较绚的东西,可让咱们干活更得更爽一点。

前面提到整个开发到部署上去的话,部署怎么去回滚,怎么去伸缩的问题,接下来带来另一个问题,你怎么知道你部署上去的是对的,就是说可能开发一个新功能部署上去,部署上去以后,而后砸了,用户要来抱怨你的老板,你的老板把你骂一顿,怎么去减小这种状况呢,那么咱们须要一些测试环节或者持续集成的环节,固然你也能够引入一些很纵线的测试,好比说像微软的Office,一到两年发行一个版本,以前有很长的测试流程。咱们是作互联网的,互联网绝对不但愿一连串发布一个版本,咱们但愿一天甚至一天内有屡次发布,这是互联网企业所推崇的部署模式。在频繁发布的时候,怎么避免出现愚蠢的错误,那就是你的持续集成帮上你的不少忙,持续集成的话,就是说你写了不少单元测试、集成测试,在适当的时候,帮你在你的代码上跑一遍,保证你的代码是正确的。

咱们的持续集成通常提交在两个阶段,提交了一个修改,这个修改的话,咱们是在Github上管理代码,就是ProRequst为,提交以后触一个单元测试的工做,通常控制在一分钟到五分钟以内完成,一分钟到五分钟以内以后,咱们知道此次修改是否会引起新的Bug,有没有会触发Bug这类的事情,这个Pull request,若是是安全的,有同时帮你Review了,我认为能够合并了,若是这个不过,首先想到改这个东西,好比说咱们有大量图片的转码工做。图片一个很恶心的地方在于有大量的图片格式,每种图片格式又有不少种扩展,有标准的,也有非标准的,引入大量的样本在测试程序当中测试,这个就能让咱们避免在修改的时候,不当心触动了哪些环节致使问题,咱们就知道哪儿改错了,从新来。

发布以前作一个更加大规模的测试,大概控制在十几分钟的样子,这样的测试,就可以保证放上去的版本不会有太大的问题,Jenkins上面装了一些比较好用的插件,我可以知道你的整个质量变化状况,这个模块的单元测试数量,是否是随着提交次数在慢慢增加,或者说测试覆盖率是否是稳定在一个可接收的范围,这是Jenkins能够帮你带来的东西,做为你的老板,看着Jenkins,大家真的有在添加测试,同时来说,也能知道测试覆盖率在什么样的水平,这样对于数据公开是一件很好的事。

咱们再从头看一下你的工具链,从开发上线流程怎么作的,第一个是提交issue,顺着一个Issue开始往前作,修改代码,提交PR,而后持续集成经过,合并PR,而后持续集成,经过以后就是capistrano部署,部署完成以后,立刻在线上作一次检验,若是成功了没事,若是失败就快速作一些回滚,这样对于咱们大部分的程序,均可以作相似这样的事情。

里边的话,有些事情的话比较容易忽略,有必要作一下的,你会用不少第三方的工具,好比说咱们会用Redmark(音),会用Jenkins,这些程序要不要入库,我我的建议入库,入库以后,修改时比较容易,同时可以整合到你整个的发布渠道里面,就是你发布渠道变成一个很一致的,就是同一套手法来作这个发布。第二个,前面说的,现场配置不要入代码库,软件和配置作分离,可以,帮你方便不少,开发人员没必要了解线上实际的IT五配置状况,好比说没必要实际了解数据库究竟在哪儿,数据库的用户名和密码是什么,开发人员都不须要了解,密码私要之类,即便是你的部署也不要入库,它能支持一些模板,能方便你经过模板替换掉这些的话,你的配置模板只是是这儿须要一个密码,这个密码是哪个密码,而不须要真正把密码写进去,避免别人经过攻击你的版本管理库的方式得到密码信息。

前面讲了上线流程,可是这个上线流程对咱们来说太鲁莽了一点,真正出娄子的时候,真察觉以前,用户在抱怨了,那么咱们须要一个测试环境,测试环境至关于单独找一到两台机器,在线上系统彻底独立,在部署以前的话,先部署到测试环境,而后先走一遍,而后再往线上去发。这个测试环境惟一须要注意的,我也常常看到有人犯的错误,好比说你有一个Web APP,我有一个Secret Token的概念,用在你的Cookie的签名,你的CSIF的设计上面,都会用到这个Secret token,你的测试环境和正式环境都用同一个Secret token的话,可能用户根据你在测试环境里面,注册一些特殊账号,而后再把这个cookie session挪到正式环境来用,这样致使用户环境泄露的问题,这是安全方面的东西。

测试环境的话,可以解决大部分问题,相信不少互联网公司也在用这些东西。第二个东西的话就是小入口,小入口概念的话,你在测试环境可能不出问题,可是在正式环境有可能出问题,正式环境有更加庞大的数据,或者说它的整个环境有些小差别形成的,那么咱们的作法是弄了一个小入口,它跟正式环境是共享数据库和存储,固然缓存这方面要看不一样状况,有的时候咱们选择共用,有的缓存选择独立缓存。部署的时候,再部署一个小Look,测试没问题了以后,再开始进行灰以及全量的部署。像Look的话,对咱们的帮助,不只在部署方面作一个灰度部署阶段。由于目前只是影响测试用户,同时还有一个好处,小用户流量和压力很是低,就意味着你能够作很生动的调试,好比说你在线上机器里上,你是不敢用的,咱们也彻底杜绝你们使用这种方式,由于Stris(音)会极大的下降你的服务端的性能,可是在小入口方面的话,像GBB这些东西都是能够上去使用的。像你在你的大部分状况下,因为多包太严重,根本拿不到一连串的数据包,漱口那边的话就能够拿到请求链上全部的包,帮你作一个调试方面的工做,小入口的引入,对咱们的帮助也是很大的。

前面有些问题的话,是我没提到的,最后一个小页讲一下这些问题,第一个问题是看capistrano最先的设计,是针对于Ruby、Python的语言,这些语言的特色,最大的特色是不须要编译,把源码直接扔到服务端就能够了,再去服务端编译太诡异了,通常在中间环节先编译好,再推送上去,咱们本身写了capistranoSC、NGINX的东西,整个流程就变成从GitHub(音)拖到NGINX,编译好了,再经过capistrano部署数出去,而不是像capistrano能见的范例里面能够直接推送原码。

第二个,若是你是推送十台一百台机器的话,你的服务器能扛得住,二十兆的包,一百台的话是2G,2G的话,我在千兆网上面二十秒就跑完了,可是若是服务器倒打一千台的时候,二十秒就变成二百秒,你的服务端整个跑马,这个事情咱们就作存储的还有经验了,直接推送到内网,下载的只有,至关于从境像分发的一个概念,分发能够快不少。

而后第二个,就是说咱们的不少机器是所谓村内网的机器,在部署的时候,不能访问公网,不少在升级方面不是跟方便,像咱们最简单就是用了一些外国的源代理成国内的源,其余互联网服务咱们都作一些适当的代理,可以主动发起,解决这些机器不能访问公网的问题,我想说的就是这一些,谢谢你们。

更多技术内容请访问本次活动的原文连接:http://blog.qiniu.com/?p=633

相关文章
相关标签/搜索