SpringCloud微服务架构升级总结
⼀、背景
1.1 应⽤系统的架构历史
1.2 什么是微服务?
起源:微服务的概念源于 2014 年 3 ⽉ Martin Fowler 所写的⼀篇⽂章“Microservices”。⽂中内容提到:微服务架构是⼀种架构模式,它提倡将单⼀应⽤程序划分成⼀组⼩的服务,服务之间互相协调、互相配合,为⽤户提供最终价值。
通信⽅式:每个服务运⾏在其独⽴的进程中,服务与服务间采⽤轻量级的通信机制互相沟通(通常是基于 HTTP 的 RESTful API)。
微服务的常规定义:微服务是⼀种架构风格,⼀个⼤型复杂软件应⽤由⼀个或多个微服务组成。系统中的各个微服务可被独⽴部署,各个微服务之间是松耦合的。每个微服务仅关注于完成⼀件任务。
把原来的⼀个完整的进程服务,拆分成两个或两个以上的进程服务,且互相之间存在调⽤关系,与原先单⼀的进程服务相⽐,就是“微服务”。(微服务是⼀个⽐较级的概念,⽽不是单⼀的概念)
1.3 微服务架构的优势
可扩展性:在增加业务功能时,单⼀应⽤架构需要在原先架构的代码基础上做⽐较⼤的调整,⽽微服务架构只需要增加新的微服务节点,并调整与之有关联的微服务节点即可。在增加业务响应能⼒时,单⼀架构需要进⾏整体扩容,⽽微服务架构仅需要扩容响应能⼒不⾜的微服务节点。
容错性:在系统发⽣故障时,单⼀应⽤架构需要进⾏整个系统的修复,涉及到代码的变更和应⽤的启停,⽽微服务架构仅仅需要针对有问题的服务进⾏代码的变更和服务的启停。其他服务可通过重试、熔断等机制实现应⽤层⾯的容错。
技术选型灵活:微服务架构下,每个微服务节点可以根据完成需求功能的不同,⾃由选择最适合的技术栈,即使对单⼀的微服务节点进⾏重构,成本也⾮常低。
开发运维效率更⾼:每个微服务节点都是⼀个单⼀进程,都专注于单⼀功能,并通过定义良好的接⼝清晰表述服务边界。由于体积⼩、复杂度低,每个微服务可由⼀个⼩规模团队或者个⼈完全掌控,易于保持⾼可维护性和开发效率。
Spring Cloud作为⽬前最流⾏的微服务开发框架,不是采⽤了Spring Cloud框架就实现了微服务架构,具备了微服务架构的优势。正确的理解是使⽤Spring Cloud框架开发微服务架构的系统,使系统具备微服务架构的优势(Spring Cloud就像⼯具,还需要“做”的过程)。
1.4 什么是Spring Boot?什么是Spring Cloud?
Spring Boot框架是由Pivotal团队提供的全新框架,其设计⽬的是⽤来简化基于Spring应⽤的初始搭建以及开发过程。SpringBoot框架使⽤了特定的⽅式来进⾏应⽤系统的配置,从⽽使开发⼈员不再需要耗费⼤量精⼒去定义模板化的配置⽂件。
Spring Cloud是⼀个基于Spring Boot实现的云应⽤开发⼯具,它为基于JVM的云应⽤开发中的配置管理、服务注册,服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集状态管理等操作提供了⼀种简单的开发⽅式。
1.5 微服务、Spring Boot、Spring Cloud三者之间的关系
思想:微服务是⼀种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。
脚⼿架:Spring Boot是⼀套快速配置脚⼿架,可以基于Spring Boot快速开发单个微服务。
多个组件的集合:Spring Cloud是⼀个基于Spring Boot实现的服务治理⼯具包;Spring Boot专注于快速、⽅便集成的单个微服务个
体;Spring Cloud关注全局的服务治理框架。
⼆、技术解析
2.1 Everything is jar, Everything is http
Spring Boot通过@SpringBootApplication注解标识为Spring Boot应⽤程序。所有的应⽤都通过jar包⽅式编译,部署和运⾏。
@SpringBootApplication
public class Application {
private static final Logger LOGGER = Logger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
LOGGER.info(”启动成功!");
}
}
每个Spring Boot的应⽤都可以通过内嵌web容器的⽅式提供http服务,仅仅需要在pom⽂件中依赖spring-boot-start-web即可,原则上微服务架构希望每个独⽴节点都提供http服务。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.2 Spring boot Task 任务启动和定时任务
在Spring Boot需要启动任务时,只要继承CommandLineRunner接⼝实现其run⽅法即可。
@SpringBootApplication
public class ClientDataListener implements CommandLineRunner
public void strings) throws Exception {
clientInfoListenerHandler();
}
}
在Spring Boot需要执⾏定时任务时,只需要在定时任务⽅法上增加@Scheduled(cron = “0 15 0 ?”)注解(⽀持标准cron表达式),并且在服务启动类上增加@EnableScheduling的注解即可。
@SpringBootApplication
@EnableScheduling
public class Application {
private static final Logger LOGGER = Logger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
LOGGER.info(”启动成功!");
}
}
// some class
@Scheduled(cron = "0 15 0 * * ?")
public void someTimeTask() {
***
}
2.3 Spring boot Actuator 监控
Actuator是spring boot提供的对应⽤系统⾃⾝进⾏监控的组件,在引⼊spring-boot-start-web基础上引⼊spring-boot-starter-actuator即可。    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.4 Spring cloud Config 配置中⼼
在我们实现微服务架构时,每个微服务节点都需要⾃⾝的相关配置数据项,当节点众多,维护就变得⾮常困难,因此需要建⽴⼀个中⼼配置
服务。
Spring Cloud Config分为两部分。Spring Cloud Config server作为⼀个服务进程,Spring Cloud Config File为配置⽂件存放位置。
2.5 Spring cloud Eureka 服务注册中⼼
服务注册的概念早在微服务架构之前就出现了,微服务架构更是把原先的单⼀应⽤节点拆分成⾮常多的微服务节点。互相之间的调⽤关系会⾮常复杂,Spring Cloud Eureka作为注册中⼼,所有的微服务都可以将⾃⾝注册到Spring Cloud Eureka进⾏统⼀的管理和访问(Eureka和Zookeeper不同,在AOP原则中选择了OP,更强调服务的有效性)
2.6 Spring cloud Zuul 服务端智能路由
当我们把所有的服务都注册到Eureka(服务注册中⼼)以后,就涉及到如何调⽤的问题。Spring Cloud Zuul是Spring Cloud提供的服务端代理组件,可以看做是⽹关,Zuul通过Eureka获取到可⽤的服务,通过映射配置,客户端通过访问Zuul来访问实际需要需要访问的服务。所有的服务通过spring.application.
name做标识,
不同IP地址,相同spring.application.name就是⼀个服务集。当我们增加⼀个相同spring.application.name的节点,Zuul通过和Eureka通信获取新增节点的信息实现智能路由,增加该类型服务的响应能⼒。
2.7 Spring cloud Ribbon 客户端智能路由
与Spring Cloud Zuul的服务端代理相对应,Spring Cloud Ribbon提供了客户端代理。在服务端代理中,客户端并不需要知道最终是哪个微服务节点为之提供服务,⽽客户端代理获取实质提供服务的节点,并选择⼀个进⾏服务调⽤。Ribbon和Zuul相似,也是通过和Eureka(服务注册中⼼)进⾏通信来实现客户端智能路由。
2.8 Spring cloud Sleuth 分布式追踪
2.9 Spring cloud Zipkin 调⽤链
2.10 Spring cloud Feign http客户端
Spring Cloud Feign是⼀种声明式、模板化的http客户端。使⽤Spring Cloud Feign请求远程服务时能够像调⽤本地⽅法⼀样,让开发者感觉不到这是远程⽅法(Feign集成了Ribbon做负载均衡)。
把远程服务和本地服务做映射
@FeignClient(name = "rabbitmq-http", url = "${SKYTRAIN_RABBITMQ_HTTP}")
public interface TaskService {
@RequestMapping(value = "/api/queues", method = RequestMethod.GET)
public String query(@RequestHeader("Authorization") String token);
}
以调⽤本地服务的⽅式调⽤远程服务
@Autowired
private TaskService taskService;
private String queryRabbitmqStringInfo() {
byte[] credentials = Base64 .encodeBase64((rabbitmqHttpUserName + ":" + rabbitmqHttpPassword).getBytes(StandardCharsets.UTF_8));
java spring框架搭建String token = "Basic " + new String(credentials, StandardCharsets.UTF_8);
return taskService.query(token);
}
2.11 Spring cloud Hystrix 断路器
三、微服务实践
3.1 我们开发的⼏个微服务组件—应⽤管理中⼼
应⽤管理中⼼可以对每个已经注册的微服务节点进⾏停⽌,编译,打包,部署,启动的完整的上线操作。
3.2 我们开发的⼏个微服务组件—zookeeper数据查询中⼼
zookeeper数据查询中⼼根据zookeeper地址,端⼝,命令获取zookeeper数据信息。
3.3 我们开发的⼏个微服务组件—微服务健康检测中⼼
健康检测中⼼周期性检查每个微服务的状态,当发现有微服务状态处于DOWN或连接超时时,触发报警。
3.4 我们开发的⼏个微服务组件—定时任务查询中⼼
// 在BeanPostProcessor⼦类中拦截
@Component
public class SkytrainBeanPostProcessor implements BeanPostProcessor, Ordered {
***
/**
* Bean 实例化之后进⾏的处理
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
beanPostProcessor.postProcessAfter(bean, beanName);
return bean;
}
***
}
// 拦截后获取定时任务注解
***
public Object postProcessAfter(Object bean, String beanName) {
Class targetClass = TargetClass(bean);
Map annotatedMethods = MethodIntrospector.selectMethods(targetClass,
new MethodIntrospector.MetadataLookup() {
public Set inspect(Method method) {
Set scheduledMethods = MergedRepeatableAnnotations(method,                            Scheduled.class, Schedules.class);
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
}
});
if (!annotatedMethods.isEmpty()) {
String className = Name();
for (Map.Entry entry : Set()) {
Method method = Key();
for (Scheduled scheduled : Value()) {
String key = className + ":" + Name();
String value = String();
taskInfos.put(key, value);
}
}
}
return null;
}
***
// 获取定时任务后注册
***
public void taskRegister() {
String nodeInfo = ipAddress + ":" + serverPort + ":";
try {
/**
* 定时任务
*/
Map infos = taskInfos;
for (Entry item : Set()) {
String taskId = nodeInfo + Key();
String taskParameter = Value();
JSONObject info = new JSONObject();
info.put("taskId", taskId);
info.put("taskParameter", taskParameter);
info.put("applicationName", applicationName);
info.put("taskType", "schedule");
LOGGER.String());
}
catch (Exception ex) {
<("", ex);
}
}
***
3.5 微服务的分类
微服务平台组件
公共服务组件
基础服务组件/业务服务组件
3.6 整体微服务架构图