spring cloud总结
一.微服务概念
什么是微服务:将一个完整的应用(单体应用)按照一定的拆分规则拆分成多个不同的服务,每个服务都能独立地进行开发、
部署、扩展。服务于服务之间通过注入RESTfulapi或其他方式调用。
SpringCloud是在SpringBoot的基础上构建的,用于简化分布式系统构建的工具集,为开发人员提供快速建立分布式系统中的
一些常见的模式。
例如:配置管理(configurationmanagement),服务发现(servicediscovery)
,断路器(circuitbreakers),智能路由(intelligentrouting),微代理(micro-proxy),
控制总线(controlbus),一次性令牌(one-timetokens),全局锁(globallocks),
领导选举(leadershipelection),分布式会话(distributedsessions),集群状态(clusterstate)
SpringCloud包含了多个子项目:例如:SpringCloud Config、SpringCloud Netflix等。
二微服务概述
**微服务架构图:
二.一微服务架构的优缺点
优点:
1.易于开发和维护:一个微服务只会关注一个特定的业务功能,所以它业务清晰、代码量较少。开发和维护单个微服务相对简单。
而整个应用是由若干个微服务构建而成的,所以整个应用也会被维持在一个可控状态。
2.单个微服务启动较快:单个微服务代码量较少,所以启动会比较快。
3.局部修改容易部署:一般来说,对某个微服务进行修改,只需要重新部署这个服务即可。
4.技术栈不受限:在微服务架构中,可以结合项目业务及团队的特点,合理地选择技术栈。
5.按需伸缩:可根据需求,实现细粒度的扩展。例如,系统中的某个微服务遇到了瓶颈,可以结合这个微服务的业务特点,增加内存
、升级CPU或者是增加节点。
缺点:
1.运维要求较高:更多的服务意味着更多的运维投人。在微服务中,需要保证几十甚至几百个服务的正常运行与协作,这给运维带来
了很大的挑战。
2.分布式固有的复杂性:使用微服务构建的是分布式系统。对于一个分布式系统,系统容错、网络延迟分布式事务等都会带来巨大的
挑战
3.接口调整成本高:微服务之间通过接口进行通信。如果修改某一个微服务接口,可能所有使用了该接口的微服务都需要做调整。
4.重复劳动:很多服务可能都会使用到相同的功能,而这个功能并没有达到分解为一个微服务的程度,这个时候,可能各个服务都会
开发这一功能,从而导致代码重复。尽管可以使用共享库来解决这个问题(例如可以将这个功能封装成公共组件,需要该功能的微服务
引用该组件),但共享库在多语言环境下就不一定行得通了。
二.二 微服务设计原则
1.单一职责原则:单一职责原则指的是一个单元(类、方法或者服务等)只应关注整个系统功能中单独、有界限的一部分。
2.服务自治原则:服务自治是指每个微服务应具备独立的业务能力、依赖与运行环境。
3.轻量级通信机制:微服务之间应该通过轻量级的通信机制进行交互。笔者认为,轻量级的通信机制应具备两点:首先是它的体量较轻,
其次是它应该是跨语言、跨平台的。例如我们所熟悉的REST协议,就是一个典型的“轻量级通信机制";
4.微服务粒度:微服务的粒度是难点,也常常是争论的焦点。应当使用合理的粒度划分微服务,而不是一味地把服务做小。在微服务的设
计阶段,就应确定其边界。微服务之间应相对独立并保持松耦合。
二.三 spring cloud 特点
1.约定优于配置。
2.适用于各种环境。开发、部署在PCServer或各种云环境(例如阿里云、AWS等)均可。
3.隐藏了组件的复杂性,并提供声明式、无xml的配置方式。
4.开箱即用,快速启动。
5.轻量级的组件。spring Cloud整合的组件大多比较轻量。例如Eureka、zuul,等等,都是各自领域轻量级的实现。
6.组件丰富,功能齐全。spring Cloud为微服务架构提供了非常完整的支持。例如,配置管理、服务发现、断路器、微服务网关等。
7.选型中立、丰富。例如,spring Cloud支持使用Eureka、Zookeeper或consul实现服务发现。
8.灵活。spring Cloud的组成部分是解耦的,开发人员可按需灵活挑选技术选型。
三.组件介绍
三.一.一关于服务发现
SpringCloud提供了多种服务发现的实现方式,例如:Eureka、Consul、Zookeeper。SpringCloud支持得最好的是Eureka,其次
是Consul,最次是Zookeeper。
这里介绍eureka
架构图:
由图可知,Eureka包含两个组件:Eureka server和Eureka Client,它们的作用如下。
* Eureka server提供服务发现的能力,各个微服务启动时,会向Eureka server注册自己的信息(例如IP、端口、微服务名称等),
Eureka server会存储这些信息。
* Eureka Client是一个Java客户端,用于简化与Eureka server的交互。
* 微服务启动后,会周期性(默认30秒)地向Eureka server发送心跳以续约自己的 “租期''。
* 如果Eureka server在一定时间内没有接收到某个微服务实例的心跳,Eureka server 将会注销该实例(默认90秒)。
* 默认情况下,Eureka server同时也是Eureka Client多个Eureka server实例,互相之间通过复制的方式,来实现服务注册表中
数据的同步。
* Eureka Client会缓存服务注册表中的信息。这种方式有一定的优势一一一首先,微服务无须每次请求都查询Eureka server,
从而降低了Eureka server的压力;其次,即使 Eureka server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者
并完成调用。
三.一.二编写eureka server
创建工程;microservice-diacover-user eureka:
1.引入依赖:
<dependencies>
<dependency>
<groupld>orgrspringframework.cloud</groupld>
<artifactld>spring-cloud-starter-eureka-server</artifactld>
</dependency>
</dependencies>
2.编写启动类:
@SpringB00tApplication
@EnableEurekaServer
public class EurekaAppIication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
3.在配置文件application.yml中添加以下内容:
Server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry : false
serviceUrl defaultZone: http://localhost : 8761
说明:
registerWithEureka:表示是否将自己注册到 eureka server默认false
fetchRegistry: 表示是否从eureka server获取注册信息
serviceUrl defaultZoneeureka: 与eureka server交互的地址,查询和和注册都依赖这个地址,多个地址用逗号分隔
三.一.三将服务注册到server
创建项目:microservice-provider-user
1.引入依赖:
<dependency>
<groupld>orgrspringframework.cloud</groupld>
<artifactld>spring-cloud-starter-eureka</artifactld>
</dependency>
2.编写启动类:
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderUserApplication {
public static void main(String[] args) {
//微服务注册与发现
SpringApplication.run(ProviderUserAppIicationacIass, args);
}
说明:
也可以使用@EnableEurekaCIient注解替代@EnableDiscoveryCIient在SpringCloud中,服务发现组件有多种选择,
例如Zookeeper、consul等。@Enab1eDiscoveryC1ient为各种服务组件提供了支持,该注解是spring-cloud-commons项目的注解,
是一个高度的抽象;而@EnableEurekaCIient表明是Eureka的Client,该注解是spring-cloud-netflix 项目中的注解,只能与Eureka
一起工作。当Eureka在项目的classpath中时,两个注解没有区别。
3.添加配置:
spring:
application:
name: microservice-provider-user
eureka:
client :
serviceUrl :
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address : true
spring.application.name :用于指定注册到eureka server上的服务名称;
instance.prefer-ip-address = true:表示将自己的ip注册到Eureka server,默认false。
三.一.四 实现高可用,集群配置
1.复制server microservice-discovery-eureka,建立server microservice-discovery-eureka-ha
2.配置host文件 127.0.0.1 peer1 peer2
3.修改application.yml
spring:
application:
name: microservice-discovery-eureka-ha
--
spring:
#指定profile-peerl
profiles: peerl
server:
port: 8761
eureka:
instance:
#指定当profile=peerl时, 主机名是peerl
hostname: peerl
client:
serviceUrl:
#将自己注册到peer2这个Eureka上面去
defaultZone: http://peer2:8762/eureka/
--
spring:
profiles: peer2
server :
port : 8762
eureka:
instance:
hostname: peer 2
client :
serviceUrl:
defaultZone: http://peerl :8761/eureka/
三.一.四用户认证
1.创建项目
2.添加依赖
<dependency>
<groupld>orgrspringframework.cloud</groupld>
<artifactld>spring-boot-starter-security</artifactld>
</dependency>
3.文件中application.yml添加
security:
basic:
enabled: true
user;
name: user
password: password123
4.eureka:
client:
serviceUrl:
defaultZone: http://user:[email protected]:8761/eureka/
多网卡环境下的ip选择
spring:
cloud:
inetutils:
忽略名字
指定正则表达式
指定ip
只用本地ip
eureka:
instance:
per-ip-address:true
三.一.五 健康检查
添加配置:
eureka:
client:
healthcheck:
enabled:true
三.二.一关于负载均衡
1.新建消费者项目
2.引入依赖
<dependency>springframework cloud</groupld>
<artifactld>spring-cloud-starter-ribbon</artifactld>
</dependency>
spring-cloud-starter-eureka 中包含ribbon 可不再引用
3.为类添加注解 @LoadBalanced
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new Rest Template();}
4.修改controller
@RestController
public class MovieController {
private static final Logger LOGGER = LoggerFactory. getLogger(MovieControl ler class) ;
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping( 'I /user/{id} " )
public User findById(@PathVariable Long id) {
return this.restTemplate.getFor0bject("http://microservice-provider-user/+id, User.class) ;}
@GetMapping( " /log-instance " )
public void logUserInstance() {
Servicelnstance servicelnstance = this. loadBalancerClient.choose(" microservice-provider-user " ) ;
MovieController.LOGGER.info("{}:{}:{}",servicelnstance.getServiceId(),
serviceInstanceugetHost(),serviceInstance .getPort();}
三.二.二 自定义ribbon配置
使用java代码自定义:
使用属性自定义:
三.二.三单独使用ribbon
1.修改配置
server:
port: 8010
spring:
application:
name: microservice-consumer-movie
microservice-provider-user:
ribbon:
list0fServers:localhost:8000, localhost:8001
三.三 关于rest api调用
三.三.一feign简介
Feign是Netflix开发的声明式、模板化的HTTP客户端。Spring Cloud对Feign进行了增强,使Feign支持了spring Mvc注解,
并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
三.三.二为消费者整合feign
1.添加依赖
<dependency>
<groupld>orgspringframework.cloud</groupld>
<artifactld>spring-cloud-starter-feign</artifactld>
</dependency>
2.创建feign接口
@FeignClient(name: mlcroservice-provider-user")
public interface UserFeignClient {
@RequestMapping(value - "/{id}" , method = RequestMethod. GET)
public User findById(@PathVariable("id") Long id);}
3.修改controller
@RestController
public class MovieController {
@Autowired
private UserFeignClient userFeignClient;
@GetMapping( "/user/{id}" )
public User findById(@PathVariable Long id){
return this.userFeignClient.findById(id);}
4.修改启动类
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class ConsumerMovieApplication{ public static void main(String[] args) {
SpringApplication run(ConsumerMovieApplication. class , args) ;}
三.三.三自定义feign配置
feign的默认配置类是FeignClientConfiguration,spring cloud允许通过注解FeignClient的
configuration属性自定义Feign,自定义级别比FeignClientConfiguration要高。
1.创建feign配置类(FeignConfiguration)
2.修改feign接口
@FeignClient(name="项目名称",configuration=FeignConfiguration。class)
public interface UserFeignClient{
//使用Feign自带的注解
@RequestLine("Get/{id}")
public User findById(@Param("id")Long id)
}
说明:和ribbon配置一样,FeignConfiguration也不能包含在成效上下文的@ComponentScan中(设计是否共享)
注:有时自定义方式满足不了需求需要手动创建Fiegn(此处不做过多说明,可参考Feign Bulider Api)
三.三.四 其他
Feign 支持继承。
有时可能需要对请求响应进行压缩,Feign也是支持。
Feign日志记录:
get请求多参数URL:1.用@requestParam("id")String id;2.requestParam Map<String,Object> msp
post请求多参数:requestMethod.Post;
三.四.一 容错机制
Hystrix简介:
Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,从而提升系统的可用性
与容错性。Hystrix主要通过以下几点实现延迟和容错。
1.包裹请求:使用Hystrixcommand(或Hystrix0bservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中执行。
这使用到了设计模式中的“命令模式"。
2.跳闸机制:当某服务的错误率超过一定阈值时,Hystrix可以自动或者手动跳闸,停止请求该服务一段时间。
3.资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,
而不是排队等候,从而加速失败判定。
4.近乎实时监控运行指标的配置编号。
5.回退机制,熔断则执行回退逻辑。
6.自我修复,熔断器打开一段时间,会自动进入“半开”状态。
三.四.二 通用方式整合Hystrix
1.复制项目
2.添加依赖
<dependency> cloud</groupld>
<groupld>orgspringframework.cloud</groupld>
<artifactld>spring-cloud-starter-hystrix</artifactld>
</dependency>
3.在启动类上加注解:@EnableCircuitBreaker或者EnableHystrix
4.修改controller 在方法上添加@hystrixCommand(fallbackmethod="fallback")(回退方法自己定义);还有@HystrixProper属性可用。
三.四.三 断路器的状态监控
<dependency>
<groupld.org/springframeworknboot</groupld>
<artifactld>spring-boot-starter-actuator</artifactld>
</dependency>
断路器的状态也会暴露在Actuator提供的/health端点中,这样就可以直观地了解断路器的状态。
持续快速(没达到频率)访问 http://peerl :8761/user/1 可看到"status" "CIRCUIT OPEN"。
三.四.四 使用Turbine聚合监控数据
简介:Turbine是一个聚合Hystrix监控数据的工具,它可将所有相关/hystrix.stream端点的数据聚合到一个组合的/turbine.stream中,
从而让集群的监控更加方便。
步骤:
1.添加依赖:
<dependency>
<groupld.org/springframeworknboot</groupld>
<artifactld>spring-boot-starter-turbine</artifactld>
</dependency>
2.启动类上添加@enableturbine
3.配置文件添加
turbine :
appConfig: microservice-consumer-movie,microservice-consumer-movie-feignhystrix-fallback-stream
clusterNameExpression: “default"
说明:一些场景下,前文的方式无法正常工作(例如微服务与Turbine网络不通),此时,可借助消息中间件实现数据收集。各个微服务
将Hystrix Command的监控数据发送至消息中间件,Turbine消费消息中间件中的数据。
三.四.五 其他
线程隔离与传播上下文(有点复杂此处不提)
feign使用Hystrix:
1.
@FeignClient(name="microservice-provider-user fallback = FeignClientFallback a class)
public interface UserFeignClient {
@RequestMapping(value-"/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);}
2.
@Component
public class FeignClientFallback implements UserFeignClient {
@0verride
public User findById(Long id) {
User user = new User();
user.setId(-1L) ;
return user;}
通过fallbackFactory查看回退原因;
为Feign禁用Hystrix:在接口上加注解@FeignClient(name="",configuration=FeignDisabledHystrixConfigeration.class);
使用Dashboard可视化监控Hystrix:
1.导入依赖
<dependency>
<groupld>orgspringframework.cloud</groupld>
<artlfactld>spring-cloud-starter-hystrix-dashboard</artifactld>
</dependency>
2.启动类上添加 @EnableHystrixDashboard
三.五 网关组件
Zuul简介
zuul是Netflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用。 zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能。
。身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
。审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
。动态路由:动态地将请求路由到不同的后端集群。
。压力测试:逐渐增加指向集群的流量,以了解性能。
。负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
。静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
。多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB(Elastic Load Balancing)使用的多样化,以及让系统的边缘更贴近系统的使用者。
spring Cloud对zuul进行了整合与增强。目前,zuul使用的默认HTTP客户端是Apache HTTP Client
优点:
1.易于监控。可在微服务网关收集监控数据并将其推送到外部系统进行分析。
2.易于认证。可在微服务网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
3.减少了客户端与各个微服务之间的交互次数。
三.五.一 编写zuul
1.引入依赖:
<dependency>
<groupld.org/springframework-cloud</groupld>:
<artifactld>spring-cloud-starter-zuul</artlfactld>
</dependency>
<dependency>
<groupld.org/springframework-cloud</groupld>:
<artifactld>spring-cloud-starter-Eureka</artlfactld>
</dependency>
2.启动类上添加 @EnableZuulProxy
3.添加配置:
server:
port: 8040
spring:
application :
name: microservice-gateway-zuul
eureka:
client :
service-url :
defaultZone: http://localhost:8761/eureka/
注:路由的详细配置
1.自定义指定访问路径
zuul:
routes:
microservice-provider-user: /user/**
2.指定忽略微服务:
zuul:
ignored-services:服务名称
3.忽略所有微服务,只有指定路由
zuul:
ignored-services:'*'
microservice-provider-user: /user/**
4.同时指定path和url
zuul:
routes:
user-routes: #指定路由名称可任意取名
url:http://localhost:8761/
path:/user/**
5.使用正则表达式匹配路由规则
借助PatternServiceRouteMapper类
6.路由前缀
Zuul:
prefix:/api
srrip-prefix:false
routes:
microservice-provider-user: /user/**
7.忽略某些路径
ignoredPatrerns:/adimn/*
三.五.二 敏感header
指定敏感 加 sensitive-headers: ****
忽略敏感 加 ignored-headers:***
三.五.三 zuul文件上传
1.建立工程
2.导入依赖
<dependency>
<groupld>org springf ramework.boot</groupld>
<artifactld>spring-boot-starter-web</artifactld>
</dependency>
<dependency>
<groupld>org springf ramework.boot</groupld>
<artifactld>spring-cloud-starter-eureka</artifactld>
</dependency>
<dependency>
<groupld>org springf ramework.boot</groupld>
<artifactld>spring-boot-starter-actuator</artifactld>
</dependency>
3.编写controller
@RequestMapping(value="/upload",method=RequestMethod.POST)
public @ResponseBody String handleFileUpload(@RequestParam(value="file",required = true) MultipartFile file)
throws IOException {
byte[] bytes - file.getBytes();
File fileT0Save new = FileCopyUtils.copy(bytes, fileToSave);
return fileToSave.getAbsolutePath();}}
4.配置文件
server:
port: 8050
eureka :
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
spring:
application:
name: microservice-file-upload
http:
multipart:
max-file-size: 2000Mb # Max file Size 默认1M
max-request-size: 2500Mb # Max request size 默认10M
三.五.三 其他
1.zuul过滤器:
过滤器是zuul的核心组件,zuul大部分功能都是通过过滤器来实现的。zuul中定义了4种标准过滤器类型:
。PRE:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
。ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
。POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
。ERROR:在其他阶段发生错误时执行该过滤器。
自定义过滤器:创建类继承抽象类ZuulFilter,重写四种方法分别返回值为,过滤器种类、过滤器执行顺序、过滤器是否执行、过滤器执行逻辑。
禁用过滤器:spring默认为Zuul启动了一些过滤器。关闭方式:zuul.<simpleClassName>.<filteType>.disabled=true.
2.zuul高可用
zuul客户端也注册到了eureka server:只需要将zuul多个节点注册到eureka server.
zuul客户端未注册到了eureka server:现实中,这种场景往往更常见,例如,zuul客户端是一个手机APP一一一不可能让所有的手机终端都注册到
Eureka server上。这种情况下,可借助一个额外的负载均衡器来实现 zuul的高可用,例如Nginx、HAProxy、F5等。
3.zuul聚合微服务:
外部请求需要查询zuul后端的多个微服务。举个例子,一个电影售票手机APP,在购票订单页上,既需要查询“电影微服务"获得电影相关信息,又需要查询
“用户微服务"获得当前用户的信息。如果让手机端直接请求各个微服务(即使使用 zuul进行转发),那么网络开销、流量耗费、耗费时长可能都无法令我们
满意。那么对于这种场景,可使用zuul聚合微服务请求一一一手机APP只需发送一个请求给zuul,由 zuul请求用户微服务以及电影微服务,并组织好数据给手机APP。
三.六 spring cloud 集中配置
config server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置内容(也可使用Subversion、
本地文件系统或vault 存储配置,限于篇幅,不做讨论),因此可以很方便地实现对配置的版本控制与内容审计。
config Client是config server(放git)的客户端,用于操作存储在config server中的配置属性。如图所示,所有的微服务都指向config Servero各个微服务在启动时,
会请求config server以获取所需要的配置属性,然后缓存这些属性以提高性能。
三.七 服务跟踪Spring Cloud Sleuth
Spring Cloud Sleuth有很多术语,看起来复杂,所以直接给思路上代码
1.建立工程
2.导入依赖
<dependency>
<groupld>org springf ramework.cloud</groupld>
<artifactld>spring-cloud-starter-sleuth</artifactld>
</dependency>
3.修改配置 application.yml
spring:
application:
name: microservice-provider-user
logging:
level:
root: INFO
org.springframeworknweba servlet.DispatcherServlet: DEBUG
由于篇幅有限,笔者无法为大家讲述微服务中的方方面面。微服务是一个非常宏观的话题,要想切实落地微服务架构,光靠看几篇博客是远远不够的。微服务粒度、
持续集成、自动化机制、组织机构的建设乃至如何从传统架构向微服务架构迁移,都是值得我们深思的问题。
spring cloud 系列还有一些更细化的东西太多了,手写麻烦,重点绝大多数都在这了。仅仅使用 spring cloud 完全没为题了,至于一些关联内容用到再去研究,没多大问题。
附录(常见注解):@Configuration
@EnableAsync
@EnableCaching
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Bean
@Primary 一个接口有多个实现类
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"cn.dlj1.springboot.dao"}) //设置Repository所在位置
@PropertySource("classpath:conf/db/db-${spring.profiles.active}.properties")
@Scheduled(cron="0/10 * * * * ?")
@ControllerAdvice 全局异常处理 全局数据绑定 全局数据预处理
@EnableResourceServer
@EnableWebSecurity
@ExceptionHandler(value = Exception.class)