构建高性能微服务架构

传统架构之痛

当前的时代称为互联网的时代,互联网应用的特色每每是,新型的应用迅速出现颠覆旧的商业模式,一旦商业模式稍有转机便会有大量的厂商蜂拥而至,使得蓝海变成红海,通过短期的残酷竞争,热度每每持续较短期后,大量厂商退出市场,仅仅前二名到三名可以存活下来,最终这一波浪潮被下一波取代。咱们回想视频网站,团购网站,社交网站,微博,打车,直播等,全都呈现这种模式。程序员

因此互联网市场只有一招,天下武功,惟快不破。redis

当一种商业模式出现的时候,为了迅速切入市场,占领商业献祭,快速验证商业模式,每每软件的设计会采起传统的单体架构。数据库

传统的单体架构每每分三层,最下面一层是数据库,中间是应用程序层,全部的商业逻辑都会在这一层,最上面是页面。swift

若是商业模式比较成功,则应用会添加新的功能,一种方式是所有添加到原有的商业逻辑中,另外一种方式是开发一个全新的三层结构来支撑新的功能。缓存

 

因为是单体结构,一方面应用层里面的功能愈来愈多,如图中一个功能变为三个功能,未来可能三十个功能,另外一方面不少代码和逻辑都不能复用,如图中功能 2,每一个应用都有,这种功能常见的有认证模块,消息的编码和解码模块等。服务器

这种单体结构会带来三方面灵活性比较差。网络

第一,时间灵活性:应用快速迭代,缩短客户需求到产品上线的时间。session

互联网应用的需求随时改变,于是应用开发的迭代速度要求会比较快,传统的软件可能半年或者一年发布一个功能,而互联网应用则可能每周都发布新的功能。并且互联网产品会时常搞活动,好比双十一,每次活动不可能提早很长时间策划,从而给开发充分的产品周期。架构

然而单体结构的应用若是有了 30 个模块,每一个模块由两到三我的负责,则修改的成本会很是的大,从开发人员看来,整个架构牵一发动全身,每次修改必需要作好良好的前期设计,而且让整个团队评审,若是新的需求要改多个模块,则代码的管理和合并就成为很大的问题。负载均衡

并且不管测试,联调,上线,扩展,缩减,升级,回滚都须要从新搭建环境,须要配置软件,须要进行回归测试,运维人员须要反复的部署环境,并且没法保证环境的一致性,任何一个环境配置的小问题,都有可能致使软件使用有问题。

第二,空间灵活性:应用弹性伸缩,应对业务量忽然增加后较短期恢复。

互联网应用每每是针对终端用户的,终端用户的行为每每不如企业用户那样容易预测,终端用户可能由于促销,过节等因素致使访问量的迅速的增加,当访问遭遇峰值的时候,咱们但愿应用能够快速扩展。

然而对于单体架构,应用扩展的过程如万丈高楼平地起,一层一层慢慢盖。

若是部署在物理机上面,则还须要采购新的物理设备,若是有虚拟化平台,则须要申请新的虚拟机,而且配置好网络和存储。然而仅仅一个空的虚拟机是没有用的,上面什么环境都没有,接下来须要安装应用环境,好比 Tomcat, Apache 等,而后就是将应用,页面配置到应用环境中,尚未结束,新启动的是一个独立的系统,还须要将这个系统加入到当前的系统中,才能一块儿承担访问量,例如加入到负载均衡器的配置里面。这样每部署一套都须要从头来一遍,实在是运维人员的噩梦。

第三,管理灵活性:易部署,易迁移,服务发现,依赖管理,自动修复,负载均衡。

如今不少互联网应用都须要多地,多机房部署,有时候会从一个机房迁移到另外一个机房,若是每次变更都如上面同样从底层到顶层都作一遍,成本比较大,时间比较长。

当一个应用依赖于另外一个应用,被依赖的应该宕机以后,修复须要手动进行,从底层到顶层配置一遍,并且修复好的系统每每 IP 地址也变了,则依赖于此应用的全部应用都须要修改配置。

 

微服务化之路

要解决上面所述的三个问题,对应的有三个步骤。

第一步,去状态化,从而实现程序的可扩展。

单体架构的程序每每不少数据是保存在内存里面的,或者是本地文件系统的,例如用户访问的 session 数据,例如用户上传的照片。所谓的去状态化,就是使得应用程序仅仅运行商业逻辑,而将数据的保存所有交给外部的存储服务。内存里面的数据能够放在缓存 redis 里面,结构化数据放在统一的数据库服务里面,文件存放在对象存储里面。这样应用程序就变成了一个只有商业逻辑的应用,能够随时扩展。

这里面有一个问题就是应用程序的状态外置化了,放在统一的缓存,数据库,对象存储里面了,但是应用程序宕机了是没有问题了,再启动一个就能够,若是缓存,数据库,对象存储宕机了,数据不也是没有了么?

其实主流的开源的缓存 Redis,数据库 MySQL,对象存储 swift 等,他们设计的时候就是考虑了高可用和容灾的状况的,因此数据存储的工做就应该让专业的模块来作这件事情,而应用程序应该关注在商业逻辑的实现,从而加速开发的速度。固然这些存储模块的维护则是另外的专业人士在作的,这部分人士是缓存的专家,数据库的专家,对象存储的专家,不须要懂商业逻辑。

第二步,容器化,可编排。

与传统 IaaS 架构不一样,容器提供的不只仅是基础资源,而是将操做系统,应用运行环境以及代码打包成一个不可修改的镜像进行交付,容器的机制能够保证不管在哪里,何时运行,都能保持环境的一致性,也就是 Docker 所宣称的“Build, Ship, and Run Any App, Anywhere(一次构建,随处运行)”。

容器特别适合部署无状态的服务,上一步的无状态化,给容器化奠基了良好的基础。

一个服务每每会包含多个组件,于是会封装成为多个容器,容器之间会有相互的依赖,相互的调用,Kubernetes 能够实现服务的编排、自发现、自修复,使得复杂服务的部署变成了一次 API 调用。

如图所示,Kubernetes 管理了相互依赖的四个服务,所有部署在容器里面,分别运行在不一样的机器上面。服务之间的调用经过服务名称进行,而非固定 IP 进行,而服务名称 Kubernetes 会管理起来。

当一台服务器宕机的时候,服务 B 和服务 C 会被自动调度到另外两台机器上,因为服务是无状态的,因此没有问题。然而服务 A 和服务 D 如何再找到服务 B 和服务 C 能,这两个服务的物理主机变了,极可能 IP 也变了。实际上是没有问题的,Kubernetes 会自动将服务名和对应的 IP 地址关联起来,服务之间只要配置的是服务名,而非 IP 地址,就依然可以相互访问。

有了容器和 Kubernetes 这两个工具后,解决了管理复杂性的问题,可是须要专门的团队和技术力量,去玩转 Kubernetes。

第三步,DevOps,可迭代。

从前面的一张图中,Dev 和 Ops,开发和运维之间隔着长长的流程,致使迭代速度很慢。DevOps 就是能够加快迭代速度的一种方法。

然而如何让开发直接进入到运维流程中呢?容器的镜像不可改变性提供了方案。

Docker 能够保证容器中的运行环境,业务代码不管在哪一个环境都是一致的,惟一不一样的是不一样环境的不一样配置,能够经过环境变量注入的方式设置。有了这个模式,开发人员能够从很早就使用容器镜像的方式进行开发,而且以容器镜像的方式交付给测试,测试使用一样的镜像获得一样的环境进行测试用例的执行,当决定发布的时候,也肯定真正到了生产环境的时候,同测试环境是同样的。这样避免了环境不断重复的部署过程。

容器镜像能够手动维护和交付,可是也能够借助 CICD 持续集成的工具,来监控代码库的更改,当有程序员提交代码的时候,会触发一个 hook,这个 hook 会调用 CI 工具,告知他代码已经有更新了,能够根据最新的代码打成最新的镜像,CI 工具根据配置好的 Dockerfile,将代码打包成镜像,上传到镜像库,每次打镜像都应该有新的版本,而不该该总使用 latest。

镜像打好了之后,接下来 CD 的工具会将镜像部署到测试环境,测试人员能够就这个新的测试环境进行一轮测试,若是测试成功,则能够告知线上管理人员,能够更新新的版本。

线上管理人员在恰当的时间,使用编排工具,将容器镜像的版本改成最新的版本,从而生产环境也就更新了。若是发现生产环境有问题,新的版本有 Bug,没有问题,只要将镜像改成上个版本的镜像便可,能够保证原来那个能用的版本,全部的配置和原来同样,从而功能也同样,实现了升级和回滚功能。

固然这套持续集成的工具和流程,须要开发人员和开发流程进行改进,才能够顺利使用。

小结

只须要逐步作到如下三步,就能够实现微服务和快速交付:

  1. 去状态化:将内存数据写入缓存,将持久化数据写入数据库,将文件写入对象存储。
  2. 容器化:可弹性伸缩,自我修复,动态迁移。
  3. 微服务化:可快速迭代,持续集成。