2015 年 11 月 28 日,架构与运维的年度大趴——又拍云架构与运维大会·北京站圆满落幕了。近 1500 名来自全国各地的 IT 小伙伴们让现场热火朝天,而 23 位享誉互联网技术业界的大神们的登场,初页CTO丁乐 在会上作了题为《分布式以后还能敏捷吗?》,以下是分享实录:
对我们来说,敏捷开发也好,快速迭代也好,用户可能觉得很专业。因为对用户来说他们只需要看到两周或者三周有新的功能,这是他们着重的关注点。
首先简单介绍一下初页,它被称之为 H5 版的 Instagram。目前初页已经由工具形式慢慢演进为文艺青年的专区,在更加广泛的媒体平台里继续传播。
我们做初页 APP 不是重新发明 H5 ,而是让人人都可以创造 H5 的内容。经过一个比较短的制作流程,可能只需要一分钟就可以做一个 H5 。大家见过朋友圈里面分享出来的初页非常炫,点开以后可以飞来飞去,可以交互,还有摇一摇各种各样的功能,这些效果我们通过初页 APP 可以非常快速的全部给制作出来。
BOSS 说,快速写出性能非常好的高质量可靠代码很重要。性能非常好,质量也要非常高,不能一锤子买卖,不要搞完以后下次维护非常的麻烦。要可靠,一定不能挂掉,这些都要在短时间内搞定实际还是有不少挑战。
所以我们只能想办法把这条曲线拉平,在当中进行取舍,说到底就是一个快字。我们的 APP 每两周会有一次迭代,速度和质量没有平衡好,口碑可能就会下降。任何因素都可能都会成为质量下降的原因,然而这并不是我们希望看到的。
程序员的一天其实就是在解决现在的 BUG 和 开发新的功能,监控到到性能瓶颈的时候解决性能瓶颈。但是为什么每次上线之后各种各样的毛病一下子就冒出来了,有什么办法可以解决吗?
初页现有架构
首先介绍下初页目前的架构,目前主要由计算服务和后面的运维与运营系统组成。
计算服务由 passport、works(作品服务)、social、message、counter 组成,每一个服务集群都是一个域名,自己管理缓存,存储,计算等。类似这样的服务我们还有若干。运营系统主要是 Boss 系统,里面涵盖了各种大大小小的报表。同时,还具有数据上的运营能力。运维则是由日志,监控,部署和分析审计这些系统组成。
都遇到过哪些问题
这些系统如何是如何工作的呢?下面具体来看下。
这个是一个用户主页,顶上是用户信息的那一块,中间绿的是我们计数提供的服务,底下是作品列表。看似很简单的一个页面,但是到服务端可能一个请求过来了,需要一次性把需要的数据的吐出去。
但是服务拆分后,随便一个服务都需要多个其他服务的支持。比如顶部的用户数据,除去用户信息之外还有他的粉丝和关注信息。想获取顶部的用户信息,调用一次接口可能内网转了好几层,最后拼装成了一个界面需要的数据。
期初,我们做了一个冗余,方便业务端自己做类似排序和筛选的需求,到最后发现太痛苦了,因为服务越来越多,同步数据工作量比较大,最后干脆做成一个内部调用。典型的是底下的作品数,作品列表中还有浏览跟分享,点赞评论等各种各样的计数。一段时间的发展后,又提出各种维度的排序需求。
开发跟调试会变得很麻烦,因为服务化了就会造成等待。什么意思呢?今天程序员 A 开发一个功能,我依赖他的数据接口,他不开发完成,我这边流程肯定跑不通。陷入这样的循环后,会造成很大的矛盾。正是因为服务化了,所以我们并行开发时都要求先Mock接口不影响其他同学开发,上线后的接口都要做到向后兼容。
找 BUG 困难,难明确问题,A 调到 B ,调到 C ,反复调来调去,只要有一方有问题了就会造成找 BUG 很困难。比如说登录,最开始找服务端,为什么会登录失败呢?服务端说这是谁调用的,他调用方法有问题,你找他去吧。这种状况显然有问题。
总结一下之前遇到的问题,第一个沟通成本很高,开发与调试变的非常麻烦,因为要占用大量的时间来做无效的沟通。另一个是找 BUG 很困难,很难明确问题到底出在谁头上?因为一个服务经过很多次调用,反映到前端,再报出一个错误信息,基本上是很难挖到底的。
接下来我们做了什么?
第一,服务集群化。我们的架构基本和其他互联网公司的一致。根据业务切成服务集群,每个服务集群里又提供若干数量的微服务。
调用之间记录 Request ID 方便查找和跟踪调用链条。与过去混乱提供的微服务方式相比,切完系统之后解除了耦合,便于监控与审计。但服务多了之后我们部署起来就有压力了,慌乱之间还可能出现低级错误。
第二,搭建快速部署的平台。解决了前端跟后端的交付压力问题。里面的功能比较多,比如截图中的发布列表,回滚等,会有发布流程的配置。比如后端发布的交付流程是这样的,首先把代码 pull 下来,然后开始进行编译,把正式环境的配置拉下来,如果需要发布的是一个测试版,这个时候会把测试服务器的配置拉下来打包,下一步开始往服务器上推一个伪生
具体是什么意思呢?我们先把 A 下掉再对 A 进行一下验证,跑完自动的验证程序后然后再跑一下预热和测试的脚本等。跑完之后,觉得这个服务 OK 了就行了。如果觉得还有问题,可以设成手动上线,一台一台的上。比如有十台服务器,我们前面两台手动,后面八台就自动了,一个开关可以直接设置。后面演变成了关键业务需要审核,怎么办?在发布的时候可以做一个审核流程,每一个项目可以订制自己审核的标准,完成审核之后再到线上去。
前端交付跟后端交付非常像,也是先拉代码,压缩指定脚本,合并静态资源,最后的生成 mapconfig 来做资源坐标对应。每个步骤都经过了精心的优化,比如 png 会根据颜色自动做 8 位或者 24 位的判断压缩。
处理完资源后,会生成一个 deployid ,发布了以后想先试一下看行不行,只需要在网络环境下做一下手脚,就能使一帮人或者某一个人使用特定的版本,而不用把整个的线上全换掉。这使得我们具备了一定的灰度能力,比如先把一部分的服务给设置成新的版本,在监控系统里面再遛一圈,看有没有什么错误,如果没有错误,整个服务器做一个全面的切换。
这个 ID 可以把整个前端的所有代码做整个的切换,代码版本跟版本之间是可以同时存在的,所有的接口是相互兼容的。像这种部署任务,我们每天有时候达到七、八次,或者是更多。最后的上线过程跟后端一模一样。
开发和测试阶段,我们会用 Docker ,网络方面会用到 VPN ,因为都在云嘛。有时想调试比较麻烦,会通过 VPN 直接连上我们生产环境的内网,如果有必要可以向运维申请一个只读的权限,进去看一些东西。这个时候内网就显得非常必要了,因为调 BUG 的时候会更快一点。
为什么使用 Docker 呢?因为资源利用率高,启动速度非常快,有的时候想做快速验证,用虚拟机的话,只能用快照或者用镜像,想做一次验证成本很大,特别是我们的服务又非常多,每一个服务如果都是一个镜像,随便就是几十个镜像,速度是没有办法提升的。一台物理机可以做很多 Docker ,我们买了一台物理机放到机位里面,局域网使用这个非常方便,每次做测试用这个启动都是秒级的。我们的开发想把这个环境拿回家开发,但是又不想全部再搭建一遍,怎么办呢? Pull 一下,所有的环境都可以搞定。
另外一个是搭建日志平台解决找 BUG 的问题,一个服务内部又去调用其他服务的若干接口,查找调用链还是过于麻烦。所以我们搭建日志平台,把所有的日志都收集监控到位。
此外,还开发了 WebApi 用于客户端和前端。会有这样的一些场景,比如我们想看到用户调用一个接口的整个过程是什么样的,分别跑到哪一些服务器拿什么样的数据,以及在哪一步报了什么样的错误,都可以直接输入查找出来。通过它排错会非常快,定位问题很容易。
除此之外,接口审计也是没问题的。比如我们做了很多的聚合,有实时接口调用情况, TOP10 , TOP100 等。还比如,看这个接口在某个时段提供了多少流量,并发是多少。 搭建这套系统之前,我们想看数据都是手动写代码拉取各个服务器中的日志分析。
分布式以后还能再敏捷吗?
回过头来看,我们解决了什么问题。沟通成本高,迭代速度变慢,我们通过服务化开发,之后再有自动部署系统解决。开发与调试变麻烦,必要的时候申请只读权限,进入生产环境调试。还有找 BUG 非常困难,我们搭建了 ELK ,帮助明确问题和解决问题,然后结合 zabix 做了各种监控。
做完这么多东西之后,是不是真的解决了问题,相信有些同学会说,标题党。我想说的是遇到问题解决问题,我们每天都在写程序服务用户,为什么不花点时间服务下自己。完善这些基础服务在未来对于迭代速度是非常有帮助的。所以,分布式以后还能再敏捷吗?在合适的时候完善基础架构,我觉得就是有可能的。