【叶峰】:今天的这个分享,这个标题是使用12个理念去快速建立高可维护性的应用。若是你们能很好的应用12条法则的话,咱们能够更加的对抗 software erosion。这个12条比则是Adam Winggins提出来的12条理念。前端
可是如今不少团队在本身的摸索中,已经发现了这12条其中的一部分。而后我也跟不少朋友聊过这个话题,若是是来自大公司的话,他们不少会认为这12条应该是平常应该作的事情。若是来自创业公司或者小团队来讲,这12条理念会让开发速度变慢。但其实这12条理念其实能够很是好的对抗software erosion。git
它的本意是随着时间的流逝被消磨或者腐蚀掉了。前面几个星期前写的代码,如今已经看不太懂,或者说公司有一个系统,你如今有一个新的需求,你要知足这个需求,就是要知足这12条例子最快地实现这个需求。若是如今运行得很好的一个产品,可能一两年以后操做系统更新了,底层的依赖已经变了,这时你重启系统,发现已经不能运动了,不知道怎么回事。这样的版本由于系统资源不够了,必需要进行清理。咱们讲一下Heroku这个公司,有很厉害的iOS开锁的做者。这家公司并非很是成功的,由于它在10年被收购的时候,我看了一下它线上只有大概一万个运用,他们的现金流应该是比较有限的。可是他们有很是强大的工程能力,他们仍是在10年的时候被两亿美金收购掉了。你们可能都回用git去管理代码,平时部署会很麻烦,可是你只要用git push就能够完成代码的版本了。docker
我只要fork一下就能够了,若是个人生活环境有什么变化,我能够直接fork一份。咱们为何不直接用Heroku去开发呢?由于Heroku比全部的EPS都要贵一点,还有一个最大的问题,其实是很强的问题,部分AT是被墙掉的,因此没有办法。其实Heroku有不少的开源能够去用,可是咱们发现这些克隆的版本都有不少的限制,咱们并非必定要造一个Heroku出来,去作咱们的开发。我只须要在Heroku这个创始人他们在建立Heroku的这个过程当中,学习会了这套理念,把这套理念用到咱们的开发中就能够了。这边是具体的12条,根据咱们的实践下来,就是这12条。数据库
咱们并不须要所有都去应用出来。可是其中的部分,其实仍是挺有价值的。第一条实际上它的原文讲的是每个代码都要用独立的代码仓库去管理,到如今就是microservices的架构。咱们知道Twitter每次公共的API调用都产生超过100次的内部API调用。ruby
有利于开发团队进行协做、下降部署成本,异常快速回滚。这个就是咱们用到的内部的一些私有的仓库,遵照这条发做的话会有一些好处,好比说一份代码我只要修改一下定制就能够了。若是说一个系统没有办法用一份代码存储的话,说明它必须切分红多个代码仓库。这边咱们用到三个比较基础的东西,这个模型层,其实是私有的Ruby的代码库。服务器
它封装了一些对数据库的操做,它是独立成一个代码仓库,咱们能够经过环境变量注入只读的数据库,这样能够确保它是很干净的。还有一个只写的对外提供APT的接口。在这里把它分红不一样的子系统,咱们能够用X-Rate-Limit。这样的好处在于不论是客户端的问题仍是内部的其余子系统的问题,或者说是来自外界的恶意攻击,咱们均可以有办法把攻击降到最低。第二点跟刚刚一开始提到的,若是你须要系统迁移或者系统升级,这种状况下怎么样保证系统很容易的进行迁移。须要对依赖作声明。这边的话是Gemfile的示例,这个文件会具体的申明用到哪个库的数据。你能够保证用到的都是如出一辙的版本。这样仍是有点抽象,这里举个例子,Sidekg和系统默认的版本不一致,若是我用Bundle exec,未来万一他们是不兼容的,或者代码迁移到其余系统,这个系统默认的库就是不兼容的。架构
固然目前特别流行的docker是能够很容易地知足这个需求,今天就不讲这个事情。还有第三点的话,咱们提倡把配置放到Unix的环境变量中。一开始是放在代码常量里面,可是代码常量有个很差的地方,你要修改的话要来回地改动代码。这样会影响你在代码仓库的一个状况。若是你在好比说上线前的版本和上线后的版本配置不同的话,你要在代码仓库维持两个分支,确定这样是不合理的。仍是举个例子,若是是ruby的话他有一个比较推崇的.ENB。运维
第四点和第三点关系很大的,咱们对外部系统的依赖,好比说咱们要访问七牛的API,咱们建议放在稳定变量,包括其余的子系统。刚刚咱们提到了就是咱们的模型层,咱们会有对外暴露的两个接口,这两个接口会注入进来。这边有个简单的测试,你永远不该该把不该该提交的代码仓库提交出去。这边是个简单的示例,这个脚本是很简单的执行环境命令。若是咱们用dot enb的话,无论用什么语音都是很容易实现的。可是它对整个系统的稳定性的帮助是很是大的。tcp
第五点的话其实对于咱们实践下来,其实感受并非特别的重要,你们看一下就好。ide
第六是这样的,就是应用应该做为没有状态的进程去运行。除了和持久化相关的服务,其余服务都是应该无状态的。这么作有什么很差的地方?你没有办法确保同一个客户同样的进程保存在里面,并且下一次这个客户的请求也会到其余的机器上。
咱们刚刚提到了能够经过环境变量的注入依赖,咱们提倡把每个独立的应用绑定,就是内嵌HTTP的库。他们直接对外绑定端口,对外提供服务,而不是依赖外部的服务容器运行。这个绑定的端口它未必以HTTP的协议进行运行。
而且咱们刚刚提到以这样的方式去申明的话,这些服务就能够做为其余的服务的依赖。高层次的API就能够基于低层次的API执行了。以这样的一种方式去作的话,接下去有很是好的应用,就是说咱们在最前端能够用layer awore tcp proxy进行。若是它get某一个路径的话,咱们能够转化到对应的m point上面。还有相似的作法,以相似的这种TCP的代理方式,咱们能够很简单地复制一份流量。我若是要进行系统的性能测试,我确定不能在正常环境下测,可是我若是部署两份如出一辙的流量,这样子一是能够作性能的压力测试,另外在线若是线上有什么bug的话,新系统若是要上线,我同样能够用这样的方式测试。相同的流量下来,它会有什么样的反应。这种方式在GitHub的应用,它不可能容许DNS的这种方式随机给你指定某一个机器去响应你的请求。由于每一个推的,每一个往上面push的代码都是跟我的相关的。可是以这种方式去作的话,就能够捕捉到Git协议里面的一段,而后咱们能够抓出你的用户名,能够定向到对应的机器上去。这样能够作到很容易的扩容。
第八点,扩容的方式咱们提倡是以多进程的模型进行扩容。
虽然是以多进程的模式扩容的话,并不表明每一个进程是单进程的。由于咱们刚刚提到了,咱们提倡服务都是无状态的。每一个服务都是无状态,扩容就很容易。能够把一样的进程部署到不一样的服务器上。后面两点实际上讲述多进程的模式,咱们提供的服务就不该该把本身变成系统的daemon。常见的把一个程序绑在后台的一种方式,但这几种方式其实都不太好的。第二个是把代码放在阿帕奇的容器里面运行,这样两份代码互相会有冲突,你使用阿帕奇这样的容器。另外的话像ruby的unicon,这样子也是不够好的。都会遇到不少奇怪的问题,若是进程挂掉了怎么办?进程异常退出,会飘到其余的PID上面。若是咱们没有作好好的环境隔离的话,会有不纯净的环境,额外的环境变量会对系统形成异常的影响。这边仍是以Ruby为例子,咱们以procfile示例,对外提供FTTP的服务,这两个脚本随时会由于各类缘由退出,若是以这样的方式导出到upstyle。
第九点是快速启动,优雅关闭。
第十点的话,咱们仍是但愿开发、测试、部署的环境要尽可能接近。
不少公司由于分工很明确,代码是开发写的,生产环境和运行是运维的事情。做为负责开发,要从需求的正确性到日后,整个代码的正确性都是应该负责的。第二条机器太慢的状况已经比较少见了,因此咱们尽可能保证开发的环境和运行的环境是同样的。持续集成很重要,其实不少人,特别是小团队可能会以为持续集成,搞测试是一件很烦的事情。其实不是的,你要很简易的搭一个不断地跑测试的服务器是很重要的。它会往这个服务发一个HTTP的包,无论成功、失败会发出来一份文件。整个环境的搭载是很容易的,大概一两个小时就能够搭起来了。我一直是写Ruby的,对于创业公司来讲这样可能会有点过了,由于不少时候大家不知道会作成什么样子。这种状况回归测试是很重要的,遇到一个bug,写一个测试可以重现它。下一次这个测试会直接告诉你怎样作的,这样也是回到刚刚的一个主题,未来这个代码不可维护了。任何的改动破坏到原来的东西,测试都会跑不过。第十点,我以为是特别重要的一点。若是每一个系统都往文件里面写的话,每个日志都会分摊在不一样的地方,一旦出了问题,你都不知道该去看哪里的日志了。
据我我的得经验,服务器满了,都是日志把磁盘写满了。理想的状况下,应该是把全部的日志直接标准输出,再从印象到服务器上,这是理想的情况。
全部的日志统一分析和处理。我一个朋友他跟我讲说这12点其实对他们公司来讲都是很正常的作法,可是小团队的话若是搭这样一套环境比较困难,咱们如今目前尚未搭本身的日志服务,如今用的是一个国外的paper trail的服务。
这样作的另外的好处就在于我能够作日志报警,若是出现这样的一个状况的话,我必须收到一封邮件。无论里面多少个子系统,任何一个子系统出现问题,我均可以收到一封邮件。好的,谢谢你们,今天的分享就到这里。
PS:开发者最佳实践日·第8期-互联网产品从设计到上线 北京站
报名地址:http://qiniu-8.eventdove.com