1

本文来自三拾众筹系统架构师陈晓辉的演讲,题为“持续交付开发流程支撑创新业务”,介绍了三拾众筹基于网易蜂巢的系统开发实践。现将分享内容整理如下:

三拾众筹项目介绍

图片描述

三拾众筹是一个创新型的业务,我们的理想是做不一样的众筹平台:

  1. 基于内容产品提供众筹服务

  2. 专注探寻最有创意的想法、最有温度的故事

  3. 深耕影视、游戏、音乐、传媒、动漫等泛文娱领域

从2016年7月份项目筹备以来,经过两个多月的开发,10月份平台正式上线运营。目前的团队规模不大,属于内部创业的状态,但是我们的口号是:再小的力量,也能掷地回响。

图片描述

今天的分享是从技术角度介绍一下我们如何构建这个持续开发的流程,来支撑我们的创新业务。

在运行一个创新业务的时候,我们的技术会面临很大的挑战,这和我们创新业务的特点是相关的:

  1. 业务是快速变更的,不可能想好所有的事情才开始启动我们的项目,所以刚开始的时候,所谓的创新更多的是在试错。我们希望项目在做的时候,不断地收集反馈,不断地调整方向,最终找到突破点。而在不断调整方向的过程中,技术必须做到及时响应。当业务需要技术提供弹药的时候,技术不能说我们还在调研,我们还在建厂房,功能不能变更。

  2. 业务爆发式地增长。前面我们说去找方向,那什么是正确的方向,其实很难去判断,但是至少我们不是为了维持某种状态去做的,因为我们是一个从无到有的过程。一旦我们找到了正确的方向,接下来业务就会出现一个提升或者扩张,但是时间是无法预期的,往往是爆发式的,很难线性地去判断。但是对于技术来讲,如何能够不拖业务爆发的后腿,是一个棘手的问题。当业务有很大流量导入的时候,我们的系统不能撑不住,挂了。

  3. 资源成本投入。所有的创新项目资源都是有限的,如果资源很多,往往就没有了创新的土壤。资源不多就必须将有限的资源用在刀刃上。

图片描述

面对这三项挑战,我们的技术团队必须具备三项技术能力:

  1. 快速迭代:产品要快速交付,快速部署。

  2. 可扩展:系统能够通过横向扩展的方式,支撑更大的流量。

  3. 技术有按需的能力,只扩展应该扩展的模块。

这让我们这个创业团队想要借助云的力量,借助网易云容器平台的力量。

对于云来讲,按需的能力是天然的,在网易云上,我们是按需按时分配的;而快速迭代和可扩展,是云的潜力,使得我们不需要采购机器,安装系统,部署环境。

那三拾众筹如何才能发挥云的潜力,如何设计我们的系统,使用什么样的开发过程,才能让云真正的帮助我们的业务?

这里有一个重要的概念,就是 Cloud Native。之前有人翻译为云原生应用,我觉得比较直白,我起了一个小清新的名字,叫做向云而生。

这表示我们的应用应该设计为面向云和容器平台去应用的。

设计目标

  • 使用标准化流程自动配置(declarativeformats for setup automation),从而使新的开发者花费最少的学习成本加入这个项目。

  • 和操作系统之间尽可能地划清界限,在各个系统中提供最大的可移植性。

  • 适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。

  • 将开发环境和生产环境的差异降至最低,并使用持续交付实施敏捷开发。

  • 可以在工具、架构和开发流程不发生明显变化的前提下实现扩展。

另外还有12原则

三拾众筹非常相信12原则,把整个系统按照12原则进行设计。

12 Factors
I. Codebase-One codebase tracked in revision control, many deploys
II. Dependencies-Explicitly declare and isolate dependencies
III. Config-Store config in the environment
IV. Backing services-Treat backing services as attached resources
V. Build, release, run-Strictly separate build and run stages
VI. Processes-Execute the app as one or more stateless processes
VII. Port binding-Export services via port binding
VIII. Concurrency-Scale out via the process model
IX. Disposability-Maximize robustness with fast startup and graceful shutdown
X. Dev/prod parity-Keep development, staging, and production as similar as possible
XI. Logs-Treat logs as event streams
XII. Admin processes-Run admin/management tasks as one-off processes

系统架构

如图是三拾众筹的系统概览,也是我们当前系统的部署架构

图片描述

三拾众筹的架构采用的是服务化的架构,是由一系列相互协同的服务组成的。服务之间有协作的过程,服务对外也提供了统一的界面。每一个服务本身有自己的存储,有自己的缓存。

所有的服务分两个区域,也即服务分两种类型。第一是应用的服务,第二是基础服务。

在应用服务里面,对外有一个主站服务,同时承担了 API网关的职责。它会把前台的请求分发到后台,并且根据规则进行路由。

服务与服务之间都是通过 Restful API也即 HTTP的方式,服务之间会有明确的依赖关系,而且依赖关系的强弱在这里用实线和虚线做区分。通过这些依赖关系来构成和编排我们的服务。

我们最初上线的平台也不是这样的,而是只有一个众筹平台。是随着功能的丰富,应对更快的变化,而逐渐拆分的,例如对于支付模块,当我们需要接入更多的支付方式,针对支付有更多的优化需求的时候,我们需要独立出一个收银台的模块,进行服务拆分。包括会员,包括订单的部分。

为了支撑应用服务的环境,我们还有一些基础设施服务。

比如注册中心,服务之间有自动的服务注册与服务发现的机制。我们的所有服务是通过注册中心进行相互关联的,不需要人工的编排,是可以自动地发现服务。

我们可以通过服务的控制台去管理服务。我的服务状态是什么,对应的版本就是什么。

每个应用都涉及到一些配置参数,如果配置参数扔在每个服务上的话,对于运维来说代价就比较高了。对于微服务架构来讲,必然需要一个集中化,可分发的配置中心,也是在基础服务中的。

我们会使用 Git仓库作为配置的后端,通过配置中心去分发 Git仓库中的配置,同时后面我们还会提到,有一个流程来管理整个过程。

在这个架构里,所有的组件都在容器里面。每个服务构建的结果就是镜像,在运行期就体现为容器。

这里面的每个服务都使用的是网易云的无状态服务,除了构建服务。构建服务是从代码构建为镜像,是在我们自己的服务器上运行,也是一个容器。

设计要点

接下来我分享一下我们设计时的考虑及实现要点:

Cloud Native的设计

  1. 从设计开始,我们就隔离了基础设施和后端服务依赖,这个隔离一方面是由容器来做的,隔离了应用和服务器之间的关系。另一方面,应用层我们用了很多的框架,例如后面提到的 springboot和 springcloud,我们使用公共的开源框架和工具,把一些面向服务化,容器化的基础功能进行实现,对于应用本身不需要关心这些过程,只需要关注中间层,根据 spring的规约来进行开发。

  2. 从一开始,就把配置和代码进行分离。将配置和镜像进行分离。

  3. 对于编排的问题,通过 springcloud和 consul进行服务发现的功能,来实现服务的自动编排。

  4. 我们实现了持续集成和持续交付的开发过程,显式地分离了构建,发布,运行的整个过程。这也是今天分享的一个主题。

容器化的实践

  1. 广泛使用了容器,在我们看来,容器就是服务。当我们实现一个新功能的时候,首先要考虑需不需要单独拆分为一个新的服务。

  2. 通过提供一批基础镜像,来简化服务的开发,可以说是应用开发的模板

  3. 使用了网易云基础设施平台,因为他非常开放,技术导向,对程序员友好。提供了丰富的 API,通过这些 API可以实现自动化,实现自动交付。另外蜂巢提供了很多基础 PaaS服务,包含数据库,缓存,CDN,对象存储,负载均衡等,降低构建服务的难度,提高开发效率。我们几乎用了所有的 PaaS服务,使得我们不必过多关心平台层面的东西。

微服务基础设施

  1. 服务的注册,发现和负载均衡机制。这个机制目前是通过 spring cloud来做的。Spring cloud是一个非常完整的微服务开发的框架,他的主要作用是在应用和设施之间提供一个抽象层,让我们用一致的 API去使用不同的服务发现机制,比如基于 Java开发的 eureka,包括我们使用的 consul。

  2. 我们实现了配置中心

  3. 我们实现了服务控制台,可以查看各个服务的状态,以及获取服务状态变更的消息通知,还有对于服务端点 Endpoint本身进行管理。对于微服务架构来说,每一个服务的端点 Endpoint应该更加智能,这是和 SOA的区别。我们也是这样的,对于每一个服务,我们借助 springcloud提供的一系列管理端口,我们的服务控制台可以通过这些管理端口去控制它,包括去查看和修改某一个服务节点的配置,查看某个节点的日志,这都是可以通过服务控制台去实现的。

  4. 持续交付的过程,后面会详细描述协作流程和自动化交付的机制。

技术清单

蜂巢
• 集群和容器、镜像仓库
• RDS、缓存
• 负载均衡、对象存储

服务模板
• consul
• spring boot/cloud
• Rest RPC: spring mvc, feign, ribbon,(客户端的负载均衡)
• nginx (外部 HTTP请求的转发), consul-template (配置和配置中心打通)
• dumb-init (Docker里面运行服务的工具)

持续集成
• Gitlab-CE (私有代码仓库,协作流程和配置管理的入口)
• docker、maven
• flyway, junit, h2, mockito, spring test (持续集成的关键点是自动化的验证)

镜像构建

为了尽量降低服务本身和基础设施之间的关联,在构建基础镜像的时候,分成几个层次去考虑。

  1. 最里面的一层,是OS和系统工具的一层,我们是基于 Debian系统进行构建的。

  2. 应用环境的部分是和应用分离开来的,包括 JDK,consul服务发现的机制等,这里有个小工具 dumb-init,可以在一个 Docker里面实现多进程。如果在 Docker里面使用多进程会有一个比较大的坑:如果某个进程死掉,他的子进程就会变成僵尸进程,没有办法收回,导致我们关闭 Docker容器的时候是需要强制杀掉的。这对于程序需要优雅关机来说是很有问题的,Dumb-init可以解决这个问题,另外 dumb-init还可以实现信号的重写。比如有些应用是需要接收一些信号,比如 ctrl+C才能结束的,为了响应 SIGINT信号,可以通过 dumb-init进行转发。

  3. 在应用层的 Dockerfile会非常简单,选择一个正确的基础镜像,然后把包打进去就可以了。
    图片描述

基于 Gitflow代码管理和协作流程

Gitflow是一个代码管理的流程,我们基于它实现了一个协作的流程。这个协作的流程体现在我们如何去发布我们的新版本,如果修改线上的 Bug,如果进行开发,怎么集成测试,最重要的是怎么去验证,验证什么东西。整个过程都需要自动化,且都是通过 gitlab-ce提供的界面。最重要的两个界面是 Merge Request和自动化 Pipeline来做的。

所有的问题修改,所有的提测,都是通过 gitlab-ce的 Merge Request界面进行操作的。一旦 Merge Request接受之后,都会有一个跟在后面的 Pipeline,一个持续集成或者持续发布的任务来完成后续工作,这些后续工作就是我们交付的流程。

我们使用蜂巢的两个环境,来作为开发和测试环境以及线上环境。对于特定的环境,我们自动构建和发布之后,会自动地进行部署,对于开发人员,QA人员,甚至线上预发环境的运维人员来说,他们只需要在 Gitlab里面操作完了,相应的版本就构建上去了,这些版本都会在镜像仓库中,会对应我们的分支,会有独立的版本。我们还可以按需去部署更多的环境,去进行检验,比如线上的扩展验证。

图片描述

如图所示,左上角为提交的 Merge Request,右面为 Merge Request的详情,如果点击 Accept Merge Request就会触发左下角的 Pipeline进行整改发布流程。

整个交付流程如图所示:

图片描述

  1. 开发有一个主分支称为 develop,但是所有功能的开发都不在 develop上开发,而是新开分支进行开发,可以根据发布的时间点确定某个功能是不是要上线,例如图中在这一版中,feature x, y可以上线,于是 Merge到 develop分支,而 feature z赶不上这一版,会在以后的版本上线,所以暂且不 Merge到 develop分支。

  2. Feature x,y合并 develop分支需要经过 Code Review,一旦合并后,会触发自动构建镜像的 Pipeline,然后自动部署 develop环境。开发需要在这个环境里面做集成和基本的测试,包含单元测试和冒烟测试,当集成和基本的测试遇到缺陷的时候,需要回到 feature所在的分支进行缺陷修复,修复后重新 Merge到 develop,从而重新部署 develop环境。当开发任务代码质量可以达到的时候,方才提测到 QA。

  3. 有一个 Release分支用于做测试验证,提测的发起是由 develop分支 Merge到 release版本实现的。每次做 release的时候,首先会从 Master分出一个版本到 release,Master分支的版本是当前的线上版本,则 Develop Merge到 release,其实是和线上版本的一个合并,保证当前的开发版本和线上版本可以兼容。这次 Merge会触发 Pipeline构建镜像,并且自动发布 release环境, QA可以对这个环境进行自动化测试,或者手工测试,保证代码可以达到发布的质量。如果测试出现缺陷,则需要回到 feature所在的分支进行缺陷修复,修复后重新 Merge到 develop,从而重新部署 develop环境,在 develop环境测试完毕后,再次 Merge到 release,然后 QA再测试,如此反复,直到可以达到上线标准。

  4. 一个 release分支可以达到上线标准,则将 release分支合并回 master分支,这次 Merge会触发 Pipeline自动构建镜像,自动部署预发环境。线上运维人员可以对预发环境进行测试。

  5. 如果预发环境没有问题,线上运维人员可以从镜像手工部署两套线上环境中的一套,如图中 Online A和 Online B,做灰度发布,新老版本先更新其中一套环境,然后前端通过负载均衡器将请求不断的从老版环境切换到新版环境。

  6. 如果需要性能测试,性能测试人员可以手工从镜像部署一套性能测试环境进行测试。

  7. 如果线上发现缺陷,则需要从 Master上分出一个分支到 hotfix,hotfix修复完毕进行测试后需要合并到 Master分支,同时需要合并代码到 develop分支。

配置管理

图片描述

如图是一个配置管理的流程。

所有的配置文件都放在代码仓库 Gitlab里面,进行代码级别的管理。

编辑配置文件 app.properties和 app-A.properties,然后提交,通过 Merge Request提交到 Gitlab里面。

在 Gitlab界面里面,点击 accept进行代码合并,合并后触发 webhook,调用配置中心。

Git2Consul从 Gitlib中 pull所有的配置文件,并且将配置文件的内容通过 consul的客户端同步到 consul中。

Profile=A的 app和 Profile=B的 app通过 consul的客户端将配置从 consul中配置到服务中,完成配置的管理。

总结

最后总结一下就是:

  1. 最大化利用开源工具和云端技术建立微服务和敏捷基础设施,构建 Cloud Native 应用,充分释放云的潜力。

  2. 其次,基于容器技术自动化构建、发布和配置流程,改进敏捷交付环境和产品快速迭代能力,及时有力支撑业务。目前三拾众筹基于网易蜂巢平台,从新系统设计到上线仅需1 ~ 3周;

  3. 最后,通过实践打磨的方案才能适合自己,开放性是选择云平台关键评估因素


网易云
311 声望117 粉丝