大数据时代的微服务之路
J大数据是什么,大数据如同少年谈性,都好像很明白的样子,但是谁都不怎么明白。
有人说大数据就是大量海量数据处理。是吗?我说这样理解可能有点片面。
在此我举两个小例子,希望有助于对于这个概念能做一定的阐述。
例 1:
当你有一天在树林里面运送一块大木桩,你想一次性运回农场,你牵一头牛来,这头牛来运输这块木头,拉的动吗,可以
当你有一天有10块大木桩,你还牵头牛来,它拉得动吗,可能也拉的动,但是它会比较费力,效率会低一点,但是它还是能完成任务。
当你有一天有50块大木桩,你还牵头牛来,它拉得动吗,拉不动,为什么,50块木桩的重量超过了它的负载能力,在这种情况下,这50块木头对于这头牛来说就是一个大数据。
例 2:
NASA美国航空航天总局需要24小时内完成对月球上面传输回来的数据进行计算分析,于是部署了一台计算机,24小时内完成了
突然,有一天,领导一上班说,我需要今天下班前得到当天数据报告,大家就慌了,因为正常那个部署的计算机需要16小时完成。在这种情况的,在8小时内完成对正常一天数据量的分析对于那台计算机来就是大数据。
那对于这两个例子,当遇到大数据情况下,解决方案是什么呢?
在例一的情况下,你有两个选择。第一,牵来一头大象,大象一次就能拉80个大木桩,50个对于它来说绰绰有余。第二,牵来五头牛,一样可以顺利完成任务。
在例二的情况下,你同样有两个选择,立刻把数据分析计算程序部署到一台超级计算机上面,譬如中国的天河-2,美国的Cray,这样可能一下子数据就能出来,或者你说我把程序部署到3台同等级别计算机上面,利用这3台计算机的计算能力来完成任务。
那么问题来了,从成本上面来说哪个合算,大家会惊讶的发现,在同样完成任务的情况下,五头牛的成本比一头大象成本小很多,而三台普通计算机比一台超级计算机成本小很多。而那五头牛和三台计算机,在协力合作的条件下,完成了对于任何一个单元都不可能完成的任务,这就是一个简单的分布式系统 (Distributed system)的例子,而每个单元可以从广义上称之为一个微服务(MicroService)。
微服务,一个最近被炒的很火的名字,那他到底是个什么东西呢?
微服务没有一个精确的定义,可以说这是一种软件架构风格,利用模组化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language agnostic) 的 API 集相互通讯,而实现方法也多种多样,每个公司使用微服务的出发点也不尽相同。但是微服务却有几个重要的共同特点:
1. 小而单一 (small and single resposibility),并且专注于做一件事情,只负责一个系统下的某一个功能。
譬如我们在第一个例子中的一头牛,他只做一件事情,那就是拉车运输,而且他做的很好。而你作为赶车的,也可以是整个运输系统中的一个微服务,你也负责一件事件,就是这几头牛都走同一方向,而且方向正确,你并不负责拉车。
在初步划分模块的时候,通常公司可以按照自己的业务领域来分块服务,一个典型的例子就是垂直电商系统一般可以分块为用户模块服务 Customer Service, 产品模块服务 Product Service, 订单模块服务 Order Service, 支付模块服务 Payment Service 和 运送模块服务Shipping Service,每一个服务只负责一个领域模型中所需要完成的任务。这样轻松实现整个微服务系统的松耦合和较高的维护能力。
2. 独立部署 (independently deployable),升级,扩展或者替换
每个服务都可以单独部署及重新部署而不影响整个系统。这使得服务很容易升级。
在此我们可以对比一下单体应用(monolithic application)。譬如上文中提到的垂直电商系统,在单体应用下,所有这些模块都是打包在同一个WAR,或者EAR文件下面,部署到一个应用服务器上面,这个应用服务器可以Web应用服务器,譬如TOMCAT,或者是J2EE应用服务器,譬如WebLogic, IBAM WebSpeher或者是Jboss。 通常在这样架构下,当我们需要替换,升级,或者一个简单的修改某一个模块,譬如支付模块的话,我们需要怎么做?修改支付模块代码,编译整个项目,重新打包成一个WAR,EAR文件,然后替换整个应用系统。即使我们修改的模块和其他模块没有任何关系,但是,我们必须一起替换。这就增加了我们日常的工作量和风险,譬如测试方便,除了做单元测试,我们还需要做一个集成测试,来保持我们其他模块一样工作;风险就是如果是一个架构不是很好的软件,软件个模块之间没实现松耦合,那么修改一个模块,很有可能导致另外一个模块的不工作,别告诉我你没有遇到过,当你是一个新人,加入一个开发组,team leader告诉你,把支付模块一个bug修了,你废了九牛二虎之力,很开心的修完了那个bug,通过单元测试,提交了代码,过了一会一封邮件过来,jenkins上面出错了,某一个和支付模块完全不相关的用户管理模块出错了。是谁的错,不是你的错,可能是架构师没有架构好软件,但是通常情况下,你得负责。
而微服务的独立部署能力就是为了避免这样类似的问题再出现,通常一个微服务是领域驱动设计下完成的,各模块之间有非常清楚明晰的边界。
再拿第一个例子来说,你赶着五头牛运送木桩,突然有一头牛脱水倒下了,这个时候你并不荒,打个电话到农场,给你再牵一头或者是牛,或者是驴,或者是马,你很轻松的就替换了那头倒下的牛,而且对于其他几头牛并没有影响,他们还是可以继续安全的工作。
那么有人会说,那怎么从一个单体应用,转换成一个成功,松耦合,易于升级和扩展的微服务架构的,这有一个非常有趣的话题,包括很多方面的考虑,从领域驱动设计,到技术选择和实现,到怎么一步一步分解一个巨大而复杂的单体应用,到一个个微服务,以及各个微服务之间的通信选择,毕竟当你拥有200个微服务的时候,微服务之间的通信已经不是简单的进程内呼叫了,而是通过网络协议来实现的,稳定性和性能都会有影响。
3. 轻量级通信协议 (lightweight communication protocol)
最常用的是HTTP协议下的REST,或者Message机制,譬如JMS, 或者AMQP (Advanced Message Queuing Protocol)
由于每个微服务都是一个独立的应用程序,这个独立程序可以部署在同一个,或者不同的服务器上面,从java程序角度来讲,每一个微服务就是一个java进程。所以服务之间的通信就不再是一个进程内的呼叫。我们就需要一个轻量级通信协议来完成各个分布式服务之间的通信。而这种通信可以分为两种,同步和异步。当我们需要一个同步呼叫来完成一个业务逻辑,通常会通过HTTP下的REST API来实现,通常可以选择Spring下的Restful框架或者是Oracle下的JAX-RS。而当我们需要服务之间做异步通信时,Message会是一个很好的协议。 Java微服务应用程序之间可以使用非常成熟的JMS,如果是Java和非Java程序应用之间,现在比较流行的是AMQP协议。
4. 去中心化数据管理 (decentralized data management)
多样化持久性(Polyglot Persistence),即让每一个微服务都有其自己的数据库,并且允许其各自拥有不同类型的数据持久化特性一直是微服务架构所倡导的。
当我们开发一个企业化大型应用时,我们通常会发现,数据的类型,属性和被查询和修改的频率都会不一样,而传统的单体应用下,我们通常会使用一个中心数据库,来存储所有数据。譬如一个垂直电商的应用里面可以有客户信息数据,商品数据,购物车数据,订单数据,支付数据。单体应用下,我们很可能就使用一个MYSQL数据库就解决所有问题。而微服务框架下,允许也提倡每一个服务模块下拥有自己的数据库,这个数据库可以是SQL类型的数据库,譬如Oracle,MYSQL,Postgres等等,也可以是NOSQL类型数据库,譬如MongoDB,Cassandra, Amazon DynamoDB等等,当然你也可以根据你的数据类型,在NOSQL里面来选择哪种类型的数据库。那么说我们就不能让两个或多个微服务之间共享一个数据库了吗,个人认为是不提倡,但是也不反对,具体情况具体分析。譬如当你需要一个request call里面的多个数据持久化在一个事务内完成,在这种情况下,通常一个SQL数据库会让事情变得简单。譬如当你担心数据的一致性能否得到保障,而且要达到ACID级别时,可能分布式数据管理会变得不可能。当然如果你一定要分布式管理数据的话,可以通过最终一致性(Eventual Consistency)来做。实现数据的强一致性,强最终一致性,还是最终一致性一直是分布式计算下的一个难题。这也是我们在设计微服务架构时可能会遇到也需要考虑的问题。
5. 公共设施自动化 (Infrastructure Automation)
通过采用一系列的开源软件,自动化开发,测试,部署流程,可以大大提高产品的质量和交付能力。
在决定是否要采用微服务架构前,应该考虑团队是否有足够的经验在公共设施自动化方面。实战用例告诉我们,那些在微服务系统上面取得成功的团队都拥有丰富的连续集成和连续交付能力。这涉及到一连串的自动化能力,包括编译,单元测试,功能测试,集成测试,用户体验测试和性能测试上面的自动化,包括部署自动化。我们只有通过做大量的自动化测试,才能大大的增强团队的信心。因为当我们采用微服务架构时,我们所要处理的不是一个单体应用所带来的问题,而且几十个,几百个微服务,甚至是部署在上百个服务器上面,到那时候我们再考虑自动化,可能未免太晚了。
这边也值得听一下亚马逊云服务团队一直倡导的两个微服务开发的原则:
1. Two Pizza Size
就是说每一个团队只需要定两个Pizza就能吃饱,当然这边是指美式Pizza,不是意大利 Pizza,基本就是说一个团队在6 - 10 人之间,这也完全符合一个敏捷开发团体的个数。
2. You Build It, You Run It
是指谁开发和编译的软件,谁来运行。这也就是为什么亚马逊每一个团队成员都会轮流On Call,这也是被很多亚马逊员工所批评的。
不管怎么样我们从这两个原则可以看到在采用微服务架构时候可以采用的方法,每一个团队负责一个或者多个微服务,采用自动化的编译,测试,集成,部署,检测开源工具,让这个流程变得很boring,大大提高交付能力。而且负责开发的团队当然对于软件是最熟悉的,一旦出现什么问题,可以立即就能找到根源和解决,而不是需要通过复杂的部门之间的沟通再来解决问题。
这期我们从大数据,分布式系统,谈到了当前非常流行的微服务架构以及其共享的一些重要特征。当然,当你真正开始着手开始把一个单体应用变为一系列微服务时,所需要面临的挑战还有很多,譬如怎么来对你已经存在的硕大的单体应用来解体;譬如当你成功解体到一系列的微服务后,怎么来解决由于分布式结构导致的系统性能问题;譬如当你实现了多样持久化后,发现事务处理变得积极复杂,怎么来管理分布式系统下的数据,保证数据一致性,等等。这些我们希望会在接下来几期进行讨论。