随着移动互联网时代的兴起,提供高性能、高可用性、高扩展性的服务已经不仅仅是大公司的专利,而逐渐成为所有互联网 + 公司的标配需求。本文介绍网易如何利用多年的互联网架构经验和网易蜂巢的平台,帮助客户进行架构改进、微服务化、性能调优。
传统架构之痛
当前的时代称为互联网的时代,互联网应用的特点往往是,新型的应用迅速出现颠覆旧的商业模式,一旦商业模式稍有起色便会有大量的厂商蜂拥而至,使得蓝海变成红海,经过短时间的残酷竞争,热度往往持续较短时间后,大量厂商退出市场,仅仅前二名到三名能够存活下来,最终这一波浪潮被下一波取代。我们回想视频网站,团购网站,社交网站,微博,打车,直播等,全都呈现这种模式。
所以互联网市场只有一招,天下武功,唯快不破。
当一种商业模式出现的时候,为了迅速切入市场,占领商业献祭,快速验证商业模式,往往软件的设计会采取传统的单体架构。
传统的单体架构往往分三层,最下面一层是数据库,中间是应用程序层,所有的商业逻辑都会在这一层,最上面是页面。
如果商业模式比较成功,则应用会添加新的功能,一种方式是全部添加到原有的商业逻辑中,另一种方式是开发一个全新的三层结构来支撑新的功能。
由于是单体结构,一方面应用层里面的功能越来越多,如图中一个功能变为三个功能,将来可能三十个功能,另一方面很多代码和逻辑都不能复用,如图中功能 2,每个应用都有,这种功能常见的有认证模块,消息的编码和解码模块等。
这种单体结构会带来三方面灵活性比较差。
第一,时间灵活性:应用快速迭代,缩短客户需求到产品上线的时间。
互联网应用的需求随时改变,因而应用开发的迭代速度要求会比较快,传统的软件可能半年或者一年发布一个功能,而互联网应用则可能每周都发布新的功能。而且互联网产品会时常搞活动,比如双十一,每次活动不可能提前很长时间策划,从而给开发充分的产品周期。
然而单体结构的应用如果有了 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,没有问题,只要将镜像改为上个版本的镜像即可,可以保证原来那个能用的版本,所有的配置和原来一样,从而功能也一样,实现了升级和回滚功能。
当然这套持续集成的工具和流程,需要开发人员和开发流程进行改进,才可以顺利使用。
网易蜂巢帮助企业构建高性能微服务架构
前面的三板斧,去状态化,容器化,持续集成,分别解决了空间灵活性,管理灵活性,时间灵活性。但是需要招聘一个 DBA,Redis 的专家,持续集成的专家,容器的专家,Kubernetes 的专家,对于一个创业公司来讲,这些专家往往比较难招聘到,而且与核心的业务逻辑没有关系。
下面就介绍一下网易蜂巢帮助企业构建高性能微服务架构背后的黑科技。
第一,高性能的 IaaS 平台。
蜂巢的容器是基于 IaaS 平台的,IaaS 平台是基础设施,基础设施如果搭建不好,会对上层的 PaaS 和 CaaS 有性能方面的影响。所谓 IaaS 层,主要就是计算,网络,存储,如果 IaaS 层不能提供高可靠的,高性能的基础设施,则容器里面的网络和存储性能也会受影响。
蜂巢做的计算方面的改进主要是针对 KVM 的,如果我们自己搭建一套 OpenStack 平台,创建虚拟机的时候,会发现虚拟机的创建时间是分钟级别的,有时候会几分钟甚至十几分钟。然而容器是秒级启动的,毫无疑问,KVM 的启动速度会大大拖累容器的启动。经过分析 KVM 的启动时间,发现 cloud-init 的配置时间最长,而且默认的 KVM 镜像会启动大量不需要的服务,当然首先做的事情就是对 KVM 镜像进行裁剪,并且不使用 DHCP 的方式分配 IP,而是采取静态 IP 注入的方式进行,这样 KVM 的启动也降到了秒级。
对于网络方面,基于 Neutron 的虚拟网络管理,最底层的技术是基于 Openvswitch 的,通过 vxlan 给每一个租户分配一个 vxlan id,从而可以实现租户之间的隔离。为了保证每个租户的网络带宽,需要通过 Linux TC 和流表对 Openvswitch 虚拟出来的网卡进行 QoS。并且对于大量的网络小包进行了优化。
对于存储方面,所有的本地盘和云盘都是基于 SSD 盘的,保证了虚拟机的 IO 性能。对于远程访问云盘,支撑 iscsi 方式和 ceph 方式,对于 ceph 集群,尤其是 OSD 的部分进行的优化。
第二,MySQL 内核开发能力和独立分支,保证主从切换时数据零丢失。
如果一个 MySQL 数据可以满足需求的情况下,主从同步复制的方式,可以保证主从之间数据的一致性,在使用开源 MySQL 进行主从复制的时候,虽然主从切换可以配置,但是无法保证数据完全不丢失。这对需要强事务性的业务来讲,是个很大的问题。
如果一个 MySQL 数据库不足以满足需求的情况下,就需要分库分表了,这个蜂巢也是有分布式数据库 NDDB 来处理这个事情。
第三,容器的优化。
在容器使用的过程中,容器的网络问题,尤其是跨主机互访问的问题是比较大的问题,Docker 虽然本身提供了 Overlay 的网络,但是在性能方面表现一般。在能够实现互访问的基础上,还需要能够和租户管理结合起来,保证不同的租户的网络之间是完全隔离的。另外,容器的网络除了互联的问题,还需虚拟防火墙,虚拟 VPN,虚拟负载均衡器。最后,很多已经使用网易云 IaaS 的业务,也需要 IaaS 层和容器层互通。在这些方面,其他的容器网络解决方案例如 Flannel,Calico 都不能满足要求。
既然 IaaS 层使用 Neutron 和 Openvswitch 的方案,并且经过性能调优和安全增强,自然容器的网络也可以使用 Openvswitch 的方案,满足上述的要求。
除了网络问题,容器的存储也是一个问题。容器是比较适合部署无状态的服务的,对于有状态的服务,我们还是希望将用户数据放置在外置的远程云盘中,这样容器宕机和跨主机迁移,都不影响外部的数据,而且数据盘还可以打快照,做备份和恢复。
第四,编排层 Kubernetes 的优化。
之所以选择 Kubernetes 作为服务编排的框架,主要考虑到以下几点。
-
Kubernetes 功能完善,产品理念成熟。资源调度、服务发现、运行监控、扩容缩容、负载均衡、灰度升级、失败冗余、容灾恢复、DevOps 都有对应的方案。
-
定义了构建分布式业务系统的标准化架构层,即 Cluster、Node、Pod、Label 等一系列的抽象都是定义好的,为服务编排提供了一个简单、轻量级的方式。
-
社区活跃度高,被大量的云计算技术提供商和用户采用。在容器的编排领域有广泛的群众基础。
当然 Kubernetes 作为一个开源软件,也不会是完美的。
首先遇到的问题是 Kubernetes 支持多租户的问题,默认情况下 NameSpace 只隔离 replication controller、pod 等资源,node 与存储、网络等是共享状态,实现真正的多租户隔离需要将所有资源隔离。不同租户不共享 node,每个租户的认证与授权独立。这样就避免了在公有云场景下,用户使用容器的安全性问题。
第二个问题,就是当集群规模扩大到一定的规模,任务的调度就遭遇了瓶颈,默认情况下,任务队列中所有操作都是串行执行,通过改进为多优先级队列、deadline 机制,可有效解决这一问题。
还有一个问题,当集群规模大了之后,一个 etcd 集群不能满足要求,根据 Pod/Node/RC 等资源到拆分不同的 etcd 集群。现在 1.3 已经支持将不同资源分布在不同的 etcd 集群,而我们其实在 1.0 的版本上就已经做了相应的实践。
从上面的叙述可以看出,要构建高性能的微服务架构,既需要基础架构层面的性能调优,也需要服务编排层面的调度优化,也不能缺少应用层面的微服务化,是一个端到端的工作。
如图所示,绿色的部分是网易蜂巢基于多年的互联网经验,在各个层面进行了优化后,推出的组件,作为一个创业公司,不需要招聘一个 IaaS 平台管理的团队,数据库 DBA 的团队,分布式存储的团队,容器和服务编排的团队,网络调优的团队,而仅仅只需要聚焦企业核心的业务层面就可以了,如图中红色的部分。这样才能将主要的力量集中在产品快速上线,抢占新一轮互联网 + 风口。
企业只需要逐步做到以下三步,就可以实现微服务和快速交付。
- 去状态化:将内存数据写入缓存,将持久化数据写入数据库,将文件写入对象存储。
- 容器化:可弹性伸缩,自我修复,动态迁移。
- 微服务化:可快速迭代,持续集成。
网易在所有组件的选型的时候,都是采取了业界最主流的开源平台和方案,并且完全兼容开源软件的 API,使得平台做到足够的开放、标准、稳定和不绑定。
作者简介
刘超,网易云计算解决方案总架构师。10 年云计算领域研发及架构经验,Open DC/OS 贡献者。长期专注于 Kubernetes、OpenStack、Hadoop、Docker、Lucene、Mesos 等开源软件的企业级应用及产品化。曾出版《Lucene 应用开发揭秘》。
感谢陈兴璐对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论