一、什么是微服务
微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。
二、微服务架构优势
复杂度可控:应用拆分后,每一个微服务专注于单一功能,并通过接口提供服务。由于体积小、复杂度低,每个微服务可由一个小规模开发团队完全掌控,易于保持高可维护性和开发效率。
独立部署:微服务具备独立运行能力,可拆分部署。当更新代码时无需整个应用编译、部署,发布更加高效,缩短交付周期,同时降低对生产环境所造成的风险。
技术选型:去中心化的。多个团队情况下可以根据自身服务的需求和行业发展的现状,自由选择最适合的技术栈。微服务业务相对简单,技术栈升级时所面临风险也较低,甚至完全重构一个微服务也是可行的。
容错:当组件发生故障时,传统架构的服务很有可能在进程内扩散,形成应用全局性的不可用。在微服务架构下,故障会被隔离在单个服务中
扩展:单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性,因为每个服务可以根据实际需求独立进行扩展。
三、微服务框架选型
市面上有很多的微服务框架,比如最著名的两个 Dubbo 和 Spring Cloud。
3.1 Dubbo 是什么?
Dubbo 是阿里开发的一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。简单的说,Dubbo 就是个服务框架,说白了就是个远程服务调用的分布式框架。
官网: http://dubbo.apache.org/zh-cn/
源码: https://github.com/apache/incubator-dubbo
当当网在这个基础上扩展了Dubbox(https://github.com/dangdangdotcom/dubbox)。
它的特点:
- 远程通讯: 提供对多种基于长连接的 NIO 框架抽象封装(非阻塞 I/O 的通信方式,Mina/Netty/Grizzly),包括多种线程模型,序列化(Hessian2/ProtoBuf),以及“请求-响应”模式的信息交换方式。
- 集群容错: 提供基于接口方法的透明远程过程调用(RPC),包括多协议支持(自定义 RPC 协议),以及软负载均衡(Random/RoundRobin),失败容错(Failover/Failback),地址路由,动态配置等集群支持。
- 自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
3.1.1、框架
模块注解
- Provider: 暴露服务的服务提供方。
- Consumer: 调用远程服务的服务消费方。
- Registry: 服务注册与发现的注册中心。
- Monitor: 统计服务的调用次调和调用时间的监控中心。
- Container: 服务运行容器。
流程详解
- 0 服务容器负责启动,加载,运行服务提供者(Standalone 容器)。
- 1 服务提供者在启动时,向注册中心注册自己提供的服务(Zookeeper/Redis)。
- 2 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 3 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 4 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 5 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心(根据数据可以动态调整权重)。
3.1.2、例子
- 服务端
定义一个Service Interface:(HelloService.java)
package com.alibaba.hello.api; public interface HelloService{ String sayHello(String name); }
接口的实现类:(HelloServiceImpl.java)
package com.alibaba.hello.impl; import com.alibaba.hello.api.HelloService; public class HelloServiceImpl implements HelloService{ public String sayHello(String name){ return "Hello" + name; } }
Spring配置:(provider.xml)
<?xmlversion="1.0"encoding="UTF-8"?> <beans......> <!--Application name--> <dubbo:applicationname="hello-world-app"/> <!--registry address,used for service to register itself--> <dubbo:registryaddress="multicast://224.5.6.7:1234"/> <!--expose this service through dubbo protocol,through port 20880--> <dubbo:protocolname="dubbo"port="20880"/> <!--which service interface dowe expose?--> <dubbo:serviceinterface="com.alibaba.hello.api.HelloService"ref="helloService"/> <!--designate implementation--> <beanid="helloService"class="com.alibaba.hello.impl.HelloServiceImpl"/> </beans>
测试代码:(Provider.java)
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Provider{ public static void main(String[] args){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"provider.xml"}); //启动成功,监听端口为20880System.in.read(); //按任意键退出 } }
- 客户端
Spring配置文件:(consumer.xml)
<?xmlversion="1.0"encoding="UTF-8"?> <beans xmlns=......> <!--consumer application name--> <dubbo:applicationname="consumer-of-helloworld-app"/> <!--registry address,used for consumer to discover services--> <dubbo:registryaddress="multicast://224.5.6.7:1234"/> <!--which service to consume?--> <dubbo:referenceid="helloService"interface="com.alibaba.hello.api.HelloService"/> </beans>
客户端测试代码:(Consumer.java)
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.alibaba.hello.api.HelloService; public class Consumer{ public static void main(String[] args){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(newString[]{"consumer.xml"}); HelloService helloService = (HelloService)context.getBean("helloService"); } }
3.1.3、优点
- Dubbo 支持 RPC 调用,服务之间的调用性能会很好。
- 支持多种序列化协议,如 Hessian、HTTP、WebService。
- Dobbo Admin后台管理功能强大,提供了路由规则、动态配置、访问控制、权重调节、均衡负载等功能。
- 在国内影响力比较大,中文社区文档较为全面。
- 阿里最近重启维护
3.1.4、不足
- Registry 严重依赖第三方组件(zookeeper 或者 redis),当这些组件出现问题时,服务调用很快就会中断。
- Dubbo 只支持 RPC 调用。使得服务提供方(抽象接口)与调用方在代码上产生了强依赖,服务提供者需要不断将包含抽象接口的 jar 包打包出来供消费者使用。一旦打包出现问题,就会导致服务调用出错,并且以后发布部署会成很大问题(太强的依赖关系)。
- 另外,Dubbo RPC 本身不支持跨语言(可以用跨语言 RPC 框架解决,比如 Thrift、gRPC(重复封装了),或者自己再包一层 REST 服务,提供跨平台的服务调用实现,但相对麻烦很多)
- Dubbo 只是实现了服务治理,其他微服务框架并未包含,如果需要使用,需要结合第三方框架实现(比如分布式配置用淘宝的 Diamond、服务跟踪用京东的 Hydra,但使用相对麻烦些),开发成本较高,且风险较大。
- 社区更新不及时(虽然最近在疯狂更新),但也难免阿里以后又不更新了,就尴尬了。
- 主要是国内公司使用,但阿里内部使用 HSF,相对于 Spring Cloud,企业应用会差一些。
3.2 Spring Cloud 是什么?
Spring Cloud 基于 Spring Boot,为微服务体系开发中的架构问题,提供了一整套的解决方案——服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。
官网:http://spring.io/projects/spring-cloud
3.2.1、Spring Boot介绍
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是Spring Boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,Spring Boot整合了所有的框架(不知道这样比喻是否合适)。
Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。
Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。Spring Boot的核心思想就是约定大于配置,多数Spring Boot应用只需要很少的Spring配置。采用Spring Boot可以大大的简化你的开发模式,所有你想集成的常用框架,它都有对应的组件支持。
简单来说,Spring Boot 是 Spring 的一套快速配置脚手架,使用默认大于配置的理念,用于快速开发单个微服务。
3.2.2、Spring Cloud都做了哪些事
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包
3.3 两者比较
3.3.1、性能比较
使用一个Pojo对象包含10个属性,请求10万次,Dubbo和Spring Cloud在不同的线程数量下,每次请求耗时(ms)如下:
线程数 | Dubbo | Spring Cloud |
10线程 | 2.75 | 6.52 |
20线程 | 4.18 | 10.03 |
50线程 | 10.3 | 28.14 |
100线程 | 20.13 | 55.23 |
200线程 | 42 | 110.21 |
说明:客户端和服务端配置均采用阿里云的ECS服务器,4核8G配置,Dubbo采用默认的Dubbo协议。
点评:Dubbo支持各种通信协议,而且消费方和服务方使用长链接方式交互,通信速度上略胜Spring Cloud,如果对于系统的相应时间有严格要求,长链接更合适。
而Spring Cloud 抛弃了 Dubbo 的 RPC 通信,采用的是基于 HTTP 的 REST 方式。严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生 RPC 带来的问题。而且 REST 相比 RPC 更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。
3.3.2、生态圈比较:
Dubbo | Spring Cloud | |
注册中心 | Zookeeper | Spring Cloud Netflix Eureka |
调度方式 | RPC | REST API |
监控 | Dubbo-monitor | Spring Boot Admin |
断路器 | 不完善 | Spring Cloud Netflix Hystrix |
网关 | 无 | Spring Cloud Netflix Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务 | 无 | Spring Cloud Sleuth |
消息总线 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
… | … | … |
Dubbo 专注 RPC 和服务治理,Spring Cloud 则是一个微服务架构生态。
鉴于服务发现对服务化架构的重要性,Dubbo 实践通常以 ZooKeeper 为注册中心(Dubbo 原生支持的 Redis 方案需要服务器时间同步,且性能消耗过大)。针对分布式领域著名的 CAP 理论(C——数据一致性,A——服务可用性,P——服务对网络分区故障的容错性),Zookeeper 保证的是 CP ,但对于服务发现而言,可用性比数据一致性更加重要,AP 胜过 CP,而 Eureka 设计则遵循 AP 原则。
Spring Cloud 支持 Consul(CA)和 Zookeeper,但不推荐使用。
四、Spring Cloud的核心
- 分布式/版本化配置
- 服务注册和发现
- 路由
- 服务和服务之间的调用
- 负载均衡
- 断路器
- 分布式消息传递
我们再来看一张图:
通过这张图,我们来了解一下各组件配置使用运行流程:
- 请求统一通过API网关(Zuul)来访问内部服务.
- 网关接收到请求后,从注册中心(Eureka)获取可用服务
- 由Ribbon进行均衡负载后,分发到后端具体实例
- 微服务之间通过Feign进行通信处理业务
- Hystrix负责处理服务超时熔断
- Turbine监控服务间的调用和熔断相关指标
五、Spring Cloud体系介绍
上图只是Spring Cloud体系的一部分,Spring Cloud共集成了30个子项目,里面都包含一些第三方的组件或框架
Spring Cloud 工具框架
- Spring Cloud Config 配置中心,利用git集中管理程序的配置。
- Spring Cloud Netflix 集成众多Netflix的开源软件,如:Zuul,Eureka,Hystrix,Ribbon
- Spring Cloud Bus 事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化
- Spring Cloud for Cloud Foundry 利用Pivotal Cloudfoundry集成你的应用程序
- Spring Cloud Cloud Foundry Service Broker 为建立管理云托管服务的服务代理。
- Spring Cloud Cluster 提供Leadership选举。
- Spring Cloud Consul 封装了Consul操作,一个服务发现与配置工具,与Docker容器可以无缝集成。
- Spring Cloud Security 基于spring security的安全工具包,为你的应用程序添加安全控制
- Spring Cloud Sleuth 日志收集工具包,封装了Dapper和log-based追踪,和Zipkin,HTrace,ELK兼容。
- Spring Cloud Data Flow 大数据操作工具,是一个混合计算模型,结合了流数据与批量数据的处理方式。
- Spring Cloud Stream 数据流操作开发包,封装了与Redis、Rabbit、Kafka等发送接收消息。
- Spring Cloud Task 提供云端计划任务管理、任务调度
- Spring Cloud Zookeeper 操作Zookeeper的工具包,用于使用zookeeper方式的服务发现和配置管理。
- Spring Cloud for Amazon 亚马逊网络服务快速集成。
- Spring Cloud Connectors 便于云端应用程序在各种PaaS平台连接到后端,如:数据库和消息代理服务。
- Spring Cloud Starters Spring Boot式的启动项目,为Spring Cloud提供开箱即用的依赖管理
- Spring Cloud CLI 以命令行方式快速建立云组件
- … …
六、总结
微服务是一种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。Spring Boot是一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务;Spring Cloud是一个基于Spring Boot实现的服务治理工具包;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架。
Spring Boot/Cloud是微服务实践的最佳落地方案。