搞懂微服务,从捕捉一头野猪说起
看上图,当一条猎狗抓一只兔子的时候是不是很轻松,毕竟兔子的体型比狗小的多。
但当一条猎狗去捕捉野猪呢,那我们就可以等着吃狗肉了。野猪的力量和体型不比狗小,对于狗来说,野猪就是大数据。
一条狗治不了那我就安排多条,一条负责咬耳朵,一条咬喉咙,一只条咬肚子,分工明确,成功把野猪拿下。
为了捕捉到野猪我可以有两个选择,一个是养头猎豹,一个是养三条土狗。养猎豹的话是不可能的,属于保护动物,就算可以养,成本也高。养三条土狗的成本远远比养一头猎豹的低的多,但能达到的目的是一样的。这三条土狗就组成一个简单的分布式系统,每条狗都相当于一个微服务,不同的分工,协力合作。
微服务没有一个精确的定义,可以说这是一种软件架构风格,利用模组化的方式组合出复杂的大型应用程序,各功能区块使用通过 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或者是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,PostgreSQL等等,也可以是Nosql类型数据库,譬如MongoDB,Cassandra, Amazon DynamoDB等等,当然你也可以根据你的数据类型,在NOSQL里面来选择哪种类型的数据库。
那么说我们就不能让两个或多个微服务之间共享一个数据库了吗,个人认为是不提倡,但是也不反对,具体情况具体分析。譬如当你需要一个request call里面的多个数据持久化在一个事务内完成,在这种情况下,通常一个SQL数据库会让事情变得简单。譬如当你担心数据的一致性能否得到保障,而且要达到ACID级别时,可能分布式数据管理会变得不可能。
当然如果你一定要分布式管理数据的话,可以通过最终一致性(Eventual Consistency)来做。实现数据的强一致性,强最终一致性,还是最终一致性一直是分布式计算下的一个难题。这也是我们在设计微服务架构时可能会遇到也需要考虑的问题。
5. 公共设施自动化 (Infrastructure Automation)
通过采用一系列的开源软件,自动化开发,测试,部署流程,可以大大提高产品的质量和交付能力。
在决定是否要采用微服务架构前,应该考虑团队是否有足够的经验在公共设施自动化方面。实战用例告诉我们,那些在微服务系统上面取得成功的团队都拥有丰富的连续集成和连续交付能力。
这涉及到一连串的自动化能力,包括编译,单元测试,功能测试,集成测试,用户体验测试和性能测试上面的自动化,包括部署自动化。我们只有通过做大量的自动化测试,才能大大的增强团队的信心。因为当我们采用微服务架构时,我们所要处理的不是一个单体应用所带来的问题,而且几十个,几百个微服务,甚至是部署在上百个服务器上面,到那时候我们再考虑自动化,可能未免太晚了。
好了,已经深夜了。本文从大数据,分布式系统,谈到了当前非常流行的微服务架构以及其共享的一些重要特征。当然,当你真正开始着手开始把一个单体应用变为一系列微服务时,所需要面临的挑战还有很多。
譬如怎么来对你已经存在的硕大的单体应用来解体;譬如当你成功解体到一系列的微服务后,怎么来解决由于分布式结构导致的系统性能问题;譬如当你实现了多样持久化后,发现事务处理变得积极复杂,怎么来管理分布式系统下的数据,保证数据一致性等等。
继续关注,下次接着说~~
--end--
作者介绍:机械自学转型大数据开发,目前任职于西班牙外企,致力于传播大数据技术。