1.微服务简介
传统的单体架构已经很难满足互联网技术的发展要求。主要体现在两方面:一是随着业务复杂度的提高,代码的可读性、可扩展性和可读性在降低;二是维护系统、修改系统的成本在提高。
微服务是著名的OO(Object oriented)专家Martin Fowler提出的,用来描述将软件应用程序设计为独立部署的服务的一种特殊方式。
1.1 单体架构及其存在的不足
在软件设计中经常提及和使用经典的3层模型,即表示层、业务逻辑层、数据访问层。
- 表示层 用于直接和用户交互,亦称交互层
- 业务逻辑层 业务逻辑处理层
- 数据访问层 对数据库进行读写操作
一个典型的单体应用就是将所有的业务场景的表示层、业务逻辑层、数据访问层放在一个工程中,最终经过编译、打包,部署在一台服务器上。例如典型的J2EE工程是将表示层的JSP、业务逻辑层的Service/Controller、数据访问层的Dao打成war/jar包部署在Tomcat/Jetty等Servlet容器中运行。
小型应用的初始阶段典型架构LAMP系统,即服务器采用Linux系统、开发应用程序语言PHP、部署在Apache服务器、采用MySQL数据库。
随着业务的发展业务复杂度越来越高,单体架构暴露出不足之处:
- 业务越来越复杂,单体应用代码量越来越大,代码可读性、可维护性和可扩展性下降。
- 并发能力有限。
- 测试难度增大,业务之间存在依赖关系。
针对这些情况,可以采取的措施:
- 将单体应用集群化部署,增加负载均衡服务器。用负载均衡服务器分发高并发的网络请求,服务器的负载不再成为瓶颈。
- 增加集群部署的缓存服务器和文件服务器,并将数据库读写分离,提高并发处理能力。添加缓存服务器缓解数据库的数据以及数据库读取数据的压力;MySQL主从热备份可以将主数据库服务器数据同步到从数据库服务器,读写分离能改善数据库的负载能力。
此时存在的不足:
- 仍然为单体应用,代码可读性可维护性依然很差。
- 对海量的用户访问,数据库将成为瓶颈。
- 持续交付能力差。
1.2 微服务
微服务概念提出者Martin Fowler:
简而言之,微服务架构的风格,就是将单一程序开发成一个微服务,每个微服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP RESTful API。这些服务围绕业务能力划分构建,并通过完全自动化部署机制独立部署。这些服务可以使用不同的编程语言以及不同的数据存储技术,以保证最低限度的集中式管理。
1.2.1 微服务特点
-
微服务数据通信
微服务通信倾向于使用HTTP这种简单的通信机制,通常是使用RESTful API。这种接受请求、处理业务逻辑、返回数据的HTTP模式非常高效,并且与平台和语言无关。
服务与服务之间也可以通过轻量级消息总线通信,例如RabbitMQ/Kafka等。
服务之间通信的数据格式一般为JSON/XML,这两种数据格式与语言、平台、通信协议无关。另外一种就是用Protobuf进行数据序列化,经过序列化的数据为二进制数据,比JSON更轻量,需要反序列化才能读懂。
通过HTTP或消息总线进行通信也存在弊端,其通信机制是不可靠的。
-
微服务独立性
按照业务划分的微服务单元独立部署,并运行在各自的进程中。每个微服务都有自己独立的数据库,服务与服务之间不需要提供数据库集成,而是提供API接口互相调用。
-
微服务自动化部署
单体应用只需部署一次,而微服务架构有多少个服务就需要部署多少次。相关技术有Docker容器技术、自动化部署工具(如Jenkins)。
-
微服务集中化管理
Spring Cloud采用Eureka来注册服务和发现服务。此外Zookeeper/Consul都是优秀的服务集中化管理框架。
-
分布式架构
分布式系统是集群部署的,分布式系统的复杂任务通过计算机之间的相互协作来完成。
分布式系统通过网络协议来通信,在空间上没有任何限制。
微服务架构是分布式架构,分布式系统本身具有复杂性,体现在服务的独立性和服务间相互调用的可靠性,以及分布式事务、全局锁、全局id等。
分布式系统数据一致性存在一定困难。
高并发情况下,如果一个服务出现故障或者网络延迟,会导致线程阻塞,在很短时间内该服务的线程资源消耗殆尽最终不可用。由于服务相互依赖,可能会导致整个系统的不可用,这就是雪崩效应。
-
熔断机制
为防止雪崩效应发生,Spring Cloud采用了**熔断器(**Hystrix Circuit Breaker)做熔断。当服务b出现故障,请求失败次数超过设定阀值后,服务b就会开启熔断器,不进行任何业务逻辑操作而执行快速失败,直接返回请求失败的信息。
熔断器还有自我修复机制。当服务b熔断后,经过一段时间半打开熔断器。半打开熔断器检查一部分请求是否正常,其他请求仍然执行快速失败,检查的请求如果响应成功,则判断服务b正常并关闭熔断器;如果还不正常则继续打开熔断器。
1.2.2 微服务优势
- 将复杂的业务分解成若干独立的小业务。
- 可以根据业务在拆分业务,具有极强的横向扩展能力。
- 单个微服务内部高内聚,服务之间完全独立,使微服务可以采用任何开发语言和技术来实现。
- 维护成本降低。
- 服务单元独立部署,即独立运行在某个进程中。
- AP架构,即具有高可用和分区容错特点。高可用主要体现在系统不间断提供服务,具有较强的负载能力。分区容错使系统更加健壮。
1.2.3 微服务不足
-
微服务复杂度
微服务是分布式系统,具有分布式系统的复杂性。开发者需要选出最佳通信机制并解决网络服务较差时带来的风险。而由于服务的相互依赖,修改某一个服务可能会对其他服务产生影响,也可能给测试带来影响。
-
分布式事务
分布式系统著名的CAP理论,同时满足一致性(Consistency)、可用性(Availability)、分区容错(Partition-tolerance)是一件不可能的事。分布式系统中P是基本要求,而单体服务是CA系统。微服务系统通常是AP系统,那么如何解决数据一致性问题呢?答案是使用分布式事务。通常情况下,只有关系型数据库在特定的数据引擎下才支持事务,大多数非关系型数据库是不支持事务的(Redis支持事务)。微服务架构中分布式事务一直都是一个难以解决的问题,业界给出的解决办法通常是两阶段提交。
以网上购物场景举例,用户购买了一部手机价格1000元,需要从用户账户扣除1000元同时手机库存减一。采用微服务架构,账户是一个服务,商品是另一个服务,这时不能使用数据库自带的事务,常常用到两阶段提交。
第一阶段:service-account发起分布式事务,交给事务协调器TC处理。事务协调器TC向所有参与的事务节点发送处理事务操作的准备操作。所有参与节点执行准备操作,将Undo和Redo信息写进日志并向事务管理器返回准备操作是否成功。
第二阶段:事务管理器收集所有节点的准备操作是否成功,如果都成功则通知所有节点执行提交操作;如果有一个失败则执行回滚操作。
两阶段提交能够大大提高分布式事务成功的概率。但如果在第一阶段都成功了,而第二阶段某一个节点失败,仍然会导致数据不准确,这时一般需要人工根据日志处理。另外如果某一参与节点网络出现异常会导致整个事务处于阻塞状态,大大降低数据库性能。
-
服务划分
Martin Fowler对微服务拆分给出的建议是:服务之间无耦合,任何一个服务都可以被替换,有严格的边界。需要根据具体业务场景来拆分业务。
-
服务部署
提到微服务,往往会想到Docker、DevOps,其中微服务是核心,Docker是容器技术,DevOps是部署手段或理念。
1.2.4 微服务与SOA
SOA(Service Oriented Architecture),面向服务架构。微服务将复杂的业务组件化实际上也是面向服务思想的体现。