写点什么

持续交付

用户头像
lidaobing
关注
发布于: 2021 年 02 月 02 日

今天实在没啥想分享的,转一篇我的老文吧。


这次想和大家分享的是从开发到上线,特别是我们七牛在这方面关于一些持续交付的事情。在演讲之前我推荐两本书,一本是《精益创业》,更多讲的是从想法变成实现的。其实从想法变成一个代码,再到运营的阶段,通过运营阶段反馈修整你的想法,形成这样一个循环,达到用户的快速增长或者快速试错调整你的产品。我今天讲的是从想法到代码,从代码再到运营阶段。第二本书是《持续交付》发布可靠软件的系统方法,讲的是你需要做哪些事情,包括持续集成和一键部署,大家有兴趣的可以看一下。


我们回到整体,简单的想法不管是做什么,现在大部分的形式要不然是 APP,要不然是网站。我们从网站开始讲,从前往后最前面是提供静态文件或者是分发动态请求。再后来是业务逻辑层,我们尽量做到无状态设计,它的好处是一天的量从一百万上升到一千万,你从十台变成一百台就可以了,这种伸缩不用改代码,只需要后面有多少个后端而已。一个用户来访问,肯定要有相关业务逻辑,一般是用什么做呢?数据库,里面要注意两个事情,一个是容灾,一个是容错。容灾更多的是高可靠的架构处理你的需求,容错是做一些近期备份的工作。剩下的就是一个需求了,现在我们对媒体的应用非常多,用户有音频、视频等等的需求。用户上传的时候,用一些小的软件或者更直接一点上公有云存储都有很好的解决方案。剩下一些不是可选的,但是建议尽早上的就是缓冲层,目的是让数据无压力。就是你怎么保证你的数据库的数据一致性,缓存也有使用的问题。比如说机器宕了,怎么解决一下子就把数据库压跨的事情。作为一个开发人员,已经把你的想法变成了产品,接下来的问题是在一个反馈循环之后需要改代码,相当于这些东西重新上线。考虑到这些事情的时候,我们又应该做哪些事情呢?


这个过程我们称之为部署,这么多年我们一直是这么做的。第一个是安装文档,比如 wordpress,按照安装文档做这个事情,最大的问题是如果你要对它里面的东西做一些改动怎么做呢?要不然在线上修改,如果是大的改动的话,就需要重新安装一遍。相当于对你整个时间的消耗会很大,成本会高很多。第二个常见的是 FTP/SFTP,比如 PHP 这种,其实上传了之后你的整个服务就直接可用了。这里面比较麻烦一点是适用面很窄,本地要做版本管理。如果不做版本管理的话,很可能原文件都找不到了,非常尴尬。第三个常见的是 Java 里面的一些 war 文件,是你把服务端有一个 Java 的文件,需要手动拷贝,多机情况下仍然要搭配一些合适部署系统做这个事情。第四个是系统安装包,比较累一点,但是对大规模部署压力很小。比如说你有几百台、上千台的机器,以前 yahoo 是这样部署的,不知道现在是不是。最大的麻烦是系统安装这一部分比较费时间。


最后一个是可以做到一键部署,配置文件比较简单案件,比如说现场有一些小错误,你可以五分钟之内把这个错误修复掉,不用等到漫长的部署流程。puppet 和 salt 可以用来解决配置问题。在这样的情况下,基本上就把这个东西解决了。现在有一些比较新兴的部署方面的技术方向是 docker,现在有一定程度上可以取代一些虚拟机的东西,也可能成为一种新的软件分发方式。但是现在来讲,在我们看来有一些地方不太成熟,有一些严重的错误绕不过去,我们正在做研究,但是还没有完成采用。


我们多介绍一点 capistrano,右边是整个部署的目录图,下面分三个子目录,一个是软件机,再一个是目录的部署结构。再下来是一个共享的东西,比如说配置是共享的,每次部署的时候用的是同一份配置。比如说你的一些文件都是共享的,在它部署的过程中,一键部署具体怎么做呢?第一个步骤很简单,下载新的代码到 releases 目录,里面就有五个了,在当前的时间形成新的目录名,再把对应的一些代码拷贝过去。第二步是把所有的配置文件、日志目录全部链接过去。第三步是链接到最新的目录里,第四步是重启程序,相当于程序里面的定义目录都以这个为主的,你整个的程序就一下子到了新版本。你这边其实是一键做了四件事情,非常简单。第一个切换 capistrano 链接到上一个版本,测试以后马上可以回滚了,非常有用。


这种方法有一个小问题,你的机器在线上的代码修改能很好的解决,如果你的系统盘毁掉了就有一个问题,你需要重装系统。重装系统需要多少时间呢?有可能记得之前你安装完系统的时候,你打了哪些补丁、调了那些配置?配置了哪些目录和日志滚动?但是你有没有做文档化,如果做了的话,顺着文档重装一遍需要多久?如果说这段时间内做的不好,服务就下线了,做的好也许就是在一个阶段里面。你需要多久能够恢复服务,这是面临很麻烦的问题。第二个问题是业务的大量增长,你需要把你得有些服务器扩容,比如说一台扩展到十台,十台扩展到一百台。扩展带来两个问题,第一个问题是怎么把这个事情做的非常快,不用浪费很多人力。第二件事情是怎么把事情做的很对,其实扩容的机器当中有很微妙的差异,比如说原来的机器上面已经调过了,但是这个没有。怎么通过一些方法把事故消除掉?如果有这些方法大家会很高兴。新来的机器是不是监控配齐了?原来的机器一步一步积攒过了监控,但是新机器有没有呢?是我们关心的问题。


puppet/salt 这两套系统是来帮助你解决这个问题的,首先第一个所有的配置入库,你的所有机器上不管是要预装哪些软件或者怎么样,都可以在版本库里看到信息。第二个是胸模板简化配置,十台或者一百台不需要把所有文件拷贝,只需要指定一下就可以了,对应的哪些功能有哪些自然就知道了。而且也不用一台一台的应用这个配置,而且会定期做一些安全更新,或者其他的一些配置调整的东西,哪些需要重启,它可以引入一些依赖或者消息,通过这些指令使你不用想配置哪些配置了,类似的也会有一些其他的需求,这些需求都可以通过它来满足。


对于我们来讲 cap+puppet 的问题是我们要考虑的,我们回滚的时候只能回滚程序,如果程序和配置偶合的很紧的时候,新版本程序需要一个新配置,你可以用编程来解决,这样程序员就有很大负担了。第三个有中心架构,但是优化的不够好。当数量达到一千台往上的水平,它有一点支撑不住了,这是我们另外重新开发的理由。我们做云存储对数据安全非常关心,我们去线上裁判数据。开发人有很强的需求了解你的日志,你线上的一些情况。比如说网络流量,一些连接数等等都是我们开发人员想去了解的。这样的情况下,你就需要很多的脚本帮助你的开发人员了解这些情况,这些也是之前不够用的,需要我们另外开发一套新的部署系统的理由。这个新的系统我们现在已经逐步在采用了,也许将来有机会可以对外发布一下。


前面讲了从代码到上线的整个流程,尽管回滚很方便,但是你肯定不希望把错误的版本放上去。更何况有时候回滚并不能解决问题,因为有的错误已经发生了。比如说转账转错了,钱损失了,也挽回不了。你要保证代码的质量就是要测试,我们推崇的是自动测试和持续集成。首先来讲你的开发人员要写你的单元测试和一些集成测试。第二个是你每次做一些合并请求的时候,所有单元测试和集成测试都会跑一遍,保证你所有的提交不会干扰你原有的业务逻辑。负责这个代码的人员会特别注意,针对你写的新功能或者错误修复是否补充了测试?如果没有补充,直接就被拒绝了。最后发布的时候我们会有一个更加好的测试,我们这个软件可以决定跑一个大规模的测试,来决定我们这个是不是最好的版本。但是一些代码质量的可视化工作是它做不了的,比如说单元测试的总数量是否随着时间缓慢上升,你的测试覆盖率是否稳定在可接受的水平,这些都是很方便量化的。量化的可视化能够帮助主管或者其他人也好,很方便的知道这个团队或者说代码质量是否有裂化的问题,也方便大家介入。


从头串一下工具链,我们怎么做一个小事情的呢?第一个是提交 issue,所有的工作跟它关联起来。第二个是修改代码提交你的 PR(Pull Request),如果持续集成通过了,这个 PR 就合并掉了。持续集成通过,通过之后进行部署,部署上线之后再次检验 issue,然后就可以关闭了。我们把这个流程做的个很短,十几二十分钟就会完成,使得我们的试错周期更短一些。这里面有一些我们的经验教训,第一个是所谓的正规化。


正规化是几个点,第一个是所有的原码需要入库,特别是第三方软件,你迟早有一天对它修改。你尽早把它入库,针对入库的代码做一份发布系统的话,即使是第三方软件也纳入到部署流程里面来,这对你以后是一个好事。第二个是你线上的配置永远不要入代码库,因为涉及一些隐私,特别是安全问题。如果说开发人员拿到线上数据库密码的话,我们认为是一个风险。第三个是你线上的配置要入库,不是入代码,是入一个部署库。最关键的密码和私钥的部分不要做到库里面,比如说你把模板配置做到里面,让我们的整个过程很安全。整个程序也不需要上级领导盖章和批准,全部可以自动化,又比较安全


刚才提到从测试到上线流程,有一个我们提的是测试环境。集成测试可以避免一些问题,但是仍然不放心。或者说我们真的是对它不放心,我们就搭一个测试环境。比如说你可以有测试环境和线上环境乃至更多的环境,首先部署到测试环境,通过手动检验完成之后再决定是否在线上部署。测试环境做到,两点一个是跟你的线上系统不要有任何关联,不管是数据库还是怎么样的。你们之间不要共享一些共同的密钥之类的东西,这样会导致权限问题,如果别人拿到你测试系统的账号,有可能在线上系统可以用的话,这种情况下是一个安全流动,这个就是需要注意的事情。


我们另外做的是小入口,测试环境和线上环境不一样。于是特别小型的东西,现在小做一个部署,然后才大规模的放量做一些部署,挺好的。第二个是你在小入口上面,我的整个请求量和访问量非常小。非常小的时候,很多线上测试工具就可以用了。如果你有一个小入口,不管是通过什么操作做的请求,都可以达到类似的效果。在这两个情况下,都是很好的,不仅是测试手段,也是一个部署的手段。看上去也很简单,像一个一个的日志。


我们有一个遗留问题,第一个是 Go 语言的问题,是一个编译性语言,我们不希望它到服务器去做,因为对我们服务器扰动很大,我们通过可执行程序做分发。第二个问题是可执行程序分发的时候,内网达到一定程度的话,会使你的服务器扛不住。我们自己是做存储、分发的,最简单的方法是文件加一步推送到内网的分发节点,这样就可以支撑你内网上千台服务器。第三个是很多依赖外网的东西,我们很多机器是完全跟外网不能连接的。不仅外网访问不了它,它也访问不了外网。比如说像安全中心,或者说安装部署的配置脚本,就需要它去外网做一些东西,我们可以做一些图片包安装的,剩下的问题我们可以通过它绕过来。

谢谢!


发布于: 2021 年 02 月 02 日阅读数: 36
用户头像

lidaobing

关注

还未添加个人签名 2017.10.18 加入

还未添加个人简介

评论

发布
暂无评论
持续交付