我所知道的云计算
文 | 范济安
云世界里的技术日新月异,新名词一个接着一个让人应接不暇,从虚拟化开始,VMware、HyperV、KVM,到云管理平台VSphere、SystemCenter、OpenStack,再到容器领域的Docker、Kubernetes、Mesos、Swarm,资源管理调度的Yarn、Mesos和今天的微服务Micro Service。这些东东到底是干嘛的?能解决什么问题?它们之间有木有关联性?作为多年来运营商IT的一名架构师,笔者试着从自己的角度解读下云技术的演进与实践。目的不是论证各项技术,而是想把一些碎片化的知识串接起来,让大家知道来龙去脉,在有必要的时候做出选择或去深度研究。当然,文中的观点只代表作者本人,对与不对供大家参考、指正。
1. 虚拟化与x86
最早有硬件服务器(Server)和软件应用(Application),两者之间夹了个操作系统(OS),让应用程序可以通过它来使用CPU、内存和存储等。从定位来看叫它系统软件更加贴切,以区别于应用软件。
慢慢硬件和OS就绑在一起了,IBM的Aix,HP的HP-UX,Sun的Solaris;微软是个例外,可在不同的PC服务器上跑Windows。这种局面闹得应用也不得不选择自己的营地,一旦落定后要想再迁移可得费老鼻子劲了,用户要花钱花力冒风险,厂家赚的盆满钵溢的。
后来基于统一x86架构的PC服务器越做越好,价格便宜而且有多家产品可选择,再加上出了个开源的OS,Linux,在上面开发应用让您随时可以更换底层的机器,这一局面大大降低了硬件成本。呼啦一下新应用都在x86上开发了,有些企业甚至下了行政命令不许再买小机了。几家硬件巨头也只好随风跟进,但时间一长,利润空间越挤越小,Sun出局了(卖给Oracle了),IBM把X86产品线转给联想了,只有HP还在那儿苦苦地撑着,x86产品线在中国也和紫光合并了。
不过x86在体量和性能上都不如Unix小机,那它怎么能承受的住原来小机上的那些负载呢?工程师们总是有法子的,单机负载不是太大吗?我干脆弄个业务组网,把应用在每台x86上都装一份,然后在前端放个LB(负载均衡器),把原来一台机器上的负载分配到不同的机器上,把负载给均衡了。
您要是专家立马会问那数据怎么办?应用程序要是太大了太重了怎么办?为了好保证数据一致性,数据还得放在同一个库里,所以在一堆x86后面往往都有台仍旧是小机的数据库服务器。应用太大了启动起来费半天劲怎么办?还是化整为零的办法,用了个一般人看了后懵懵的名字叫“应用服务化”或“容器化”。
人们追求效率追求成本的努力永不间断。在实际生产中x86的使用率并不高,只有10%左右。刚刚在x86上落定的IT人又再琢磨能不能再优化些,让一台x86当多台机器使用?虚拟化应运而生。
虚拟化是个啥玩意儿?说白了就是夹在硬件和OS之间一个叫做Hypervisor的东西。它可以把一台物理机里的CPU、内存、硬盘存储都抓过来,化整为零重新分配给一个个叫做虚机的“小盒子”。这个概念其实在小机上就存在。每个小盒子具备了一定的硬件资源后,再给它装个OS它就能像台真正的机器一样给应用使用。那个Hypervisor就像个监工,哪个小盒子里的资源要是不够用了,它就动态地多给一些。这是件多好的事儿呀!再加上一帮专门忽悠人的老美给它取了个云里雾里的名字叫“云计算”,弄了个像供水电一样的销售使用模式,这家伙x86+虚拟化一下子就火起来了,风靡了全世界。
2. 云化资源管理
这小盒子一多,多到能有成千上万个,这时候云管理平台就出来了,它要管理的主要对象是虚机集群。这时候知道点云计算的您肯定会举手说OpenStack。
哈哈,您先别急,听我慢慢道来。刚刚从Unix小机解放出来的用户试着走进虚拟世界,但很快发现又有被厂家绑定的危险。虚拟软件的老大VMware自打推出它的Hypervisor之后,很快又推出了它的管理平台vSphere;另一大佬微软比VMware胃口还大,从操作系统Windows、到虚拟软件HyperV,当然忘不了它的管理平台SystemCenter。昂贵的软件使用费逼的用户又一次转向开源社区。一下子虚拟化管理领域热闹非凡,混战到最后剩下的有Eucalyptus(国内叫桉树)、CloudStack和OpenStack几家了。
关于他们的优劣和成败原因的分析,已有很多。三者中,Eucalyptus出身最学术,CloudStack出身商业味最浓,OpenStack介于两者之间。CloudStack 和Eucalyptus一样,最开始并不开源,开源后还留了点尾巴,而且自己控制着商业版本。等发现这种模式玩不转了,卖给了Citrix,全部开源后,发现大家已经都在玩OpenStack了。其实OpenStack发布后直到CloudStack被Citrix再转卖出去为止,它的易用性和稳定性一直和CloudStack有差距。但是架不住OpenStack免费、完全开源、没有商业公司控制。咳,人都贪便宜,不想被束缚。
按道理OpenStack只是个虚机管理工具,可是一旦一家独大之后人们对它的期望也就越来越高,就集万千宠爱于一身。存储要管(Cinder、Swift),网络SDN也要管(Neutron);虚机要管(Nova、Glance),物理机也要管(Ironic),闹不好连遗留下来的小机也得一并纳入;光是硬件资源还不过瘾,中间件、大数据(Sahara) 等也都要拢过来。资源种类多了,资源之间的编排(Heat) 也越做越复杂。以前只是管理和集成,现在要深入到更底层的资源了,还要考虑收费计价(Ceilometer)。竞争对手一个个倒下,看似势头无敌的时候,也就是最危险的时候。这危险一是来自内部,要做那么些功能开源社区跟不上趟了,开发落后于需求,用户不得不自己找一帮高手来开发;二是来自外部,来自它所需要管理的对象:虚机。
3. 容器时代的到来
大家还记得虚机是什么吧!虚机就是物理机上的一个个“盒子”,盒子里装着OS,OS之上是各自的应用。问题就出在这OS上。因为操作系统本身就是一个软件程序,一个很重的系统软件因为它包含了形形色色的各类功能。好多功能应用根本就用不上,譬如Web服务器负责处理网络请求,数据库服务器负责数据库的运行和数据库访问,等等。这些服务器可能永远都用不上OS中显示器、多用户、多进程等功能。这些场景下的虚机和OS的任务很明确,就是提供最好的存储、计算、网络性能。但是OS并没有随着虚拟化而重建,大而全的OS功能越多重启它耗费的时间就越长,也因此拖累了虚机。
这时候两大改造运动开始了,一个是把OS搬到“盒子”外面让大家共享,一个是把OS做轻,去掉那些无用的功能。剩下的“盒子”就是当红子鸡 “Docker” 或容器(其实这两种技术改造路线是相辅相成的)。做轻量级OS比较有名的两个代表(一看公司的名字就知道干嘛的了)一个叫CoreOS,另一个叫Unikernel。最初CoreOS是一家容器化Linux服务器操作系统创业公司,同时,该公司使用自家的Linux系统CoreOS为Docker提供服务,并为Docker作出了巨大的贡献。令人出乎意料的是CoreOS却与Docker分道扬镳,另起炉灶,并开发了类Docker的开源容器Rocket。后来在Linux基金会的调解下,这两家公司互让一步,联手打造开放容器技术项目(OCP)。OCP是一个非营利性组织,它实际上采用了Docker的技术作为开源容器的软件技术标准。既然开源了,CoreOS也就放了Docker一马。做轻OS的另一个厂家Unikernel后来干脆被Docker收购了。自此,Docker成了容器的代名词。
4. 容器集群管理
Docker被应用接受了,逐渐推广了,问题也出来了。问题一是和虚机管理平台一样,容器一多管理上成了问题啦,需要个容器集群管理系统。问题二是容器是轻量级的,用它来承载大块头的应用是不适合的。容器集群管理系统里出了Mesos、Kubernetes和Swarm,这里面谷歌开源出来的Kubernetes被业界公认为是目前最好的工具,但Mesos对集群资源调度及跨集群任务执行有自己的特长而Swarm是Docker公司自己出的Docker管理工具。
Kubernetes是谷歌开源的容器集群管理系统(可以认为是谷歌输给Docker容器之战后采用的另一种战略体现),为封装应用的容器提供资源调度、部署运行、服务发现、扩容缩容等一整套功能。Kubernetes不光光是简单地对Docker的整个生命周期进行管理,它更像个DevOps的PaaS平台,面向应用开发者提供开发、测试和运行Docker的环境;它对外提供的是RESTful的API端口,每个端口对应的是封装了应用的Docker或Docker组合(POD),是将POD打了标签后的服务(Service),或是POD的复制。因为分布式应用出于性能或高可用性的考虑,需要复制多份资源,并且根据负载情况动态伸缩。
相比于Kubernetes,Mesos根本提不上对Docker有什么管理功能。Kubernetes所有的如服务注册、发现,对外提供RESTful接口等PaaS功能都需要由Mesos之外的一个叫Marathon的组件来完成。Mesos本身更注重对底层资源的调度,把每台机器上的CPU、内存、存储聚在一起提供给上层的应用框架使用。每个框架会根据分配到的资源再细分到各个任务或容器上。如果要拿苹果比苹果的话,应该拿Kubernetes和Mesos+Marathon来比较。
5. 集群资源管理与调度
说到这儿有必要把集群资源管理调度搞搞清楚。容器也好,虚机也好,怎样根据底层可使用的物理资源的多少来把它们分配给容器或虚机使用?这就是调度或动态调度。OpenStack 做不好这事,它不能在虚机和资源之间进行调度(VMware的vSphere可以,它有个DRS功能)。Mesos可以,它可以在计算框架和资源之间进行调度;如果计算框架自身具备面向框架内任务的细颗粒度资源调度,而这些任务又是用容器来承载的,那么我们也可以认为Mesos可以在容器与资源之间进行调度(两级调度)。
这种调度的目的就是要提高设备资源的使用率。譬如当你的大数据平台已不再是唯一的Hadoop集群,其它的数据处理框架如Spark、Storm、Kafka等也需要组成集群要你来运行时,你肯定会考虑到资源利用率,运维成本,数据共享等因素。企业一般都希望将所有这些框架部署到一个公共的集群中,让它们共享集群的资源,并对资源进行统一使用,这样,便诞生了资源统一管理与调度平台,其中典型代表就是Mesos和Hadoop生态体系内的Yarn。
首先,资源统一管理和调度平台应该提供一个全局跨域的资源管理器。所有接入的框架要先向该资源管理器申请资源,申请成功之后,再由框架自身的调度器决定将分配到的资源交由哪个任务使用;也就是说,整个大的系统是个双层调度器,第一层是统一管理和调度平台,另一层是框架自身的调度器。
弄清了这一点也就弄清了Mesos和Yarn的各自定位。Mesos是第一层的资源统一管理与调度,它所覆盖的框架集群有大数据类的(Yarn所能支撑的)和非大数据类的(Yarn不能支撑的)。第二层是计算框架自带的调度器如Yarn(或Kubernetes等),对分配到的资源进行再次分配;也就是说,Mesos将大部分调度任务授权给了计算框架。总结来说,Mesos首先完成粗粒度的资源分配,即:将资源分配给框架,然后由框架进行细粒度的资源分配;而Yarn进行细粒度的分配,即:将资源分配给某个任务。
Yarn和Mesos是否单独执行资源调度还没有到下定论的时候,双方也都还在继续演进当中,以支持越来越多的框架。好在Mesos不仅仅是做大数据分布式计算的框架,所以Mesos往往被称为数据中心操作系统,DCOS,是软件定义数据中心的利器。为了让两者能够更好地整合在一起,发挥各自的作用,业界试着用一个叫Myriad的组件来做Y2M或M2Y。不过Myriad的稳定性还有待验证,目前还不能用它来做生产组网。在过渡时期,我们可能不得不考虑由Mesos和Yarn分别组网的情况。
至此,我们可以大致勾勒出来新一代云平台的边际图:
- 底层是各类硬件资源,以x86物理机为主,混搭着虚机、小型机、SAN存储、SDS存储、SDN网络等。
- 这些资源统一由OpenStack(或其它云管理软件)云平台来负责管理,管理内容包括自动化部署(OS、虚拟软件等)、可视化监控、IaaS多租户管理、资源组件目录、用户门户等。
- 在这些资源之上我们可以部署Mesos,用它来汇聚底层资源(CPU、内存、存储)并根据需求动态提供给上层的框架(Kubernetes、Hadoop、Spark、Storm、Kafka、MySQL、Redis等)。
- 这些框架如带有自身的资源调度器,可将分配到的资源二次细分到各自的任务或容器中。
6. 应用的服务化与微服务化
在前面谈到容器是轻量级的,用它来承载大块头的应用是不适合的。所以要想通过容器来运行应用必须要对应用进行划小处理。这要比应用迁移至x86上,数据库能不能在虚机上跑之类的云化改造来的更动筋骨一些。传统的企业级应用是单体应用(monolithic application),比如运营商的系统,业务非常复杂,这种巨型系统,首先要关注的是如何根据业务划分子系统。这种划分是一种垂直切分,十几年前开始风行的SOA(Service Oriented Architecture)就是基于这种垂直划分后的子系统的。在SOA体系里,每个子系统都是独立的服务(Service),通过服务接口与外部协作。既然有垂直切分就得有水平切分。传统的企业级应用一般是分层结构,如表现层、应用层和数据层。如果将垂直切分后的子系统按三层架构来设计,我们会得到更细一步的“服务”。这种横竖切割的过程也叫做服务化过程。SOA还同时提供了调用服务的接口协议,XML和WS(Web Service),提供服务之间的通信与整合枢纽:企业服务总线(ESB),服务编排所需要的业务规则流程引擎(BPM)等。
按照SOA这种思想和架构原则来改造应用无疑相当于推翻重新开发一遍,在成本上很难接受而且工作过于复杂。 因此大部分企业实践SOA的思路不是划小应用,而是做不同应用系统间的松耦合集成,让系统与系统之间通过服务接口(Service API)和企业服务总线(ESB)进行交互。
应用没有被划小,传统的复杂应用只是通过API将其功能和数据进行了开放,但还装不进轻量级的容器Docker中。实际上应用服务化的目的不是为了使用容器,而是想解决三大问题:一是应用的维护问题,二是应用的开发问题,三是应用的部署问题。
一个简单的应用会随着时间推移逐渐变大。几年后,一个小而简单的应用因为改来改去会变成一个庞然大物。一旦你的应用变成一个庞大而又复杂的怪物,维护开发团队肯定会很痛苦。敏捷开发和快速部署举步维艰,其中最主要的问题就是这个应用太复杂,以至于任何一个程序员都不可能搞懂它。因此,修正bug和添加新功能会变得非常困难,并且很耗时。
我们所要寻求的是加快开发速度和减少变更代价。怎样才能加快开发速度呢?如果我们的开发不是重造轮子,而是每一次做新产品都可以利用已有的东西,那就会好很多。怎样才能减少变更代价呢?如果我们能够理清功能模块之间的关系,合理分层,每次变更只需要修改其中某个部分,甚至不需要修改代码,仅仅是改变参数配置就可以了。 我们先不看软件行业,来看一下建筑行业,他们是怎么盖楼房的呢?施工之前先设计,把整个楼房分解为不同预制件,比如钢筋混凝土的楼板、门窗、石膏隔断墙等,分别在各地生产,最后在现场组装,所以整个搭建过程非常快。之后的维修也是那块坏了,换那块,不用一动就上下一大串、左右一大片。
除去开发和维护方面的问题之外,我们还要解决的是应用部署问题。谁没听说过由于程序员登录生产现场误操作导致整个应用瘫痪,长期无法访问的现象?这些现象反映了很多企业的应用部署还是停留在“大锅饭”阶段。所谓的大锅饭就是包含众多功能的应用软件被部署到生产环境时,基本都是以文件的型式打成一个大软件包,然后被部署到一个应用服务器上,如WebLogic、Tomcat等(也可以把这些应用服务器看成个大容器)。应用服务器可以提供很多基础服务比如HTTP服务器,服务目录或共享库包等。问题出在同一个应用服务器会接受好几个不同应用的部署,使得在扩展性、维护性和资源使用上会有很多磕磕绊绊、互相牵连的事情发生。比如当你改动或新添一个功能后,你需要重新部署你的软件到应用服务器上,要重新启动你的应用服务器。装满沉重应用的它需要很长时间来启动;如果可怜的你因为赶活儿没仔细测试你修改后的软件,应用服务器启动不了或启动一段时间后又趴下了,那你造成的影响不光光是你自己的应用而且连累了应用服务器上所有其它的应用。我敢保证摊上这事儿的你,死的心都有了!
这时候不用我说,你大概也明白了为什么我们要把一个复杂的应用服务化了,也就是说划小了。
划小后的应用成了一项项服务(Service),用Docker容器把每个单项服务和它运行所需要的基础软件环境封装在一起,单独地部署,直接运行在标准的x86硬件资源之上。如果你划小后的应用出了问题,影响范围也只限于它而已。你想增添个新功能,你就加一项容器服务,无需牵一发而动全身。某项服务使用频次高了,不够用了,你就把它的容器多复制几份,前面加个负载均衡机制就解决了系统的容量问题、高并发问题。
这时的我已经不用再过多跟您解释什么是“微服务”了。微服务定义:采用一组服务的方式来构建一个应用,服务独立部署在不同的进程中,不同服务通过一些轻量级交互机制来通信,例如 RPC、HTTP(也就是REST) 等,服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。
微服务与SOA有很多相同之处。两者都属于典型的、包含松耦合分布式服务的系统结构。但是两种架构背后的意图是不同的:SOA尝试将应用集成,一般采用中央管理模式(ESB模式)来确保各应用能够交互运作。微服务尝试部署新功能,快速有效地扩展开发团队。它着重于分散管理、代码再利用与自动化执行。
7. 分布式数据库
应用服务化了,采用了分布式架构被部署在x86服务器上了。可数据呢?前面说过三层架构的应用展现层和业务逻辑层都可以做云化改造,唯独后端的数据层还因为数据一致性的问题停留在小型机上,成为了瓶颈(访问量大、扩展性差)。企业的核心数据库系统一般都采用“小型机+高端商用数据库+高端存储阵列”的集中式架构,也就是我们常说的IOE(IBM的小机、Oracle的数据库、EMC的存储)。传统架构的主要问题在于它只允许纵向(Scale-in)而不是横向扩展(Scale-out)。纵向扩展的意思就是在机器内加配置,加CPU,加内存,加硬盘,加到最后就加不了了;而横向扩展则能让您加机器,加节点;一台不够,两台,两台不够十台、百台、千台,形成了集群,形成了我们所说的分布式架构。这后种形式的扩展优越性不言而喻。那您肯定会说应用都划小了,怎么不把数据库也分了得了?
和应用切分一样,我们也可以对数据库通过一系列垂直和水平切分将数据分布到不同的DB服务器上,然后通过路由中间件访问特定的数据库。然而我们面临的困难首先是网络延时问题。因为原来依靠单机内部的通信现在要搬到外面来,成了机器与机器之间的通信,系统的开销一下子因为网络通信而增大。这种通信的代价会使系统单次提交的时间延迟。延迟提高会导致数据库锁定时间变长,使得性能比单机数据库具有明显差距。
分布式数据库面临的另一个问题是数据一致性问题。一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。而一致性又可以分为强一致性与弱一致性。强一致性就是在任意时刻,所有节点中的数据是一样的。弱一致性又有很多种类型,目前分布式系统中广泛实现的是最终一致性。所谓最终一致性,就是不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。也可以简单的理解为在一段时间后,节点间的数据会最终达到一致状态。
这些问题恰恰是分布式数据库的短板,就像它的可扩展性和可用性优点一样明显。鱼和熊掌不可兼得。根据著名的CAP理论,在分布式数据库应用中,任何分布式系统只可同时满足CAP其中两点,无法三者兼顾。
- Consistency(一致性),数据一致更新,所有数据变动都是同步的;
- Availability(可用性),好的响应性能,集群中某些节点宕掉了系统照用;
- Partition tolerance(分区容错性) ,可靠性。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CA 系统是要求高可用并且实时一致性。单点数据库是符合这种架构的。
AP 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
CP 系统是要求满足一致性,分区容忍性,通常性能不是特别高。
我们不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。所以分布式的数据库也应该设计成多样的。比如将分析类型应用所需要的数据迁移至以Hadoop为主的分布式NoSQL数据库,将对实时一致性要求不是很高的一些应用迁移至分布式MySQL数据库等。这里有必要提一下分布式关系型数据库中的路由中间件。
数据库中间件对数据库云化改造或对整个IT架构的分布式改造起着非常重要的作用,它能提供的典型功能有分库分表、读写分离、负载均衡、Failover 等。
从用户角度来看,代理中间件提供的就是一个传统的数据库表,支持标准的SQL语句,对前端业务系统来说,可以大幅降低开发难度,提升开发速度。对整个IT架构来说,因为这个中间件可以拥有一个多种数据库的数据服务,拼在一起可以满足CAP要求。
8. 结束语
x86、虚拟化、容器、分布式数据库、微服务,所有这一切都是为了把我们的IT系统搭建起一个面向服务的架构,一个广义上的SOA。
从另一方面来看,SOA也好,微服务也好,虚拟化也好,容器也好,如果形不成一个公司的整体战略,达到整个生态系统的共识,那么最好不要大张旗鼓地去搞什么全民皆兵的战役。其结果往往以失败而告终。当然谨慎地在自己的部门领域内做些新技术的尝试性工作也未尝不可,这种创新精神还是值得鼓励的。
革命尚未成功,同志仍需努力。