Spring Could
代码示例参考:git@github.com:chendingwu/SpringCloudExample.git
Eureka注册中心
依赖坐标
<!--eureka启动器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
使用注解@EnableEurekaServer,标注它是一个Eureka服务
package cn.cdw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author DW-CHEN
* Eureka Server服务
*/
@SpringBootApplication
@EnableEurekaServer //启用eureka server
public class EurekaServer {
public static void main(String[] args) {
SpringApplication.run(EurekaServer.class, args);
}
}
配置文件
server:
port: 8761
spring:
application:
name: eureka-server #应用名称,会在eureka中作为服务的id标识号(serverId) 将会在eureka的Application中显示,后面需要使用该名称来获取它的访问路径
#eureka配置
#dashboard 表示eureka的web控制台配置
#server 示eureka的服务端配置
#client 表示eureka的客户端配置
#instance 表示eureka的实例配置
eureka:
instance:
hostname: localhost #主机名
client:
service-url:
defaultZone: httt://${eureka.instance.hostname}:${server.port}/eureka #EurekaServer地址,现在是自己的地址,如果是集群,需要写其他的server地址,后面客户端使用该地址和eureka进行通信
register-with-eureka: false #是否将自己也注册 默认是true,如果是集群,是要注册自己的
fetch-registry: false #表示是否拉取,默认为true, 需不需要去获取服务,如果是集群,是需要拉取服务的
服务注册
eureke客户端依赖
<!--eureka启动器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在引导类启动器使用注解启用eureka功能(@EnableEurekaClient)
package cn.cdw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author DW-CHEN
*/
@SpringBootApplication
@EnableEurekaClient //启用eureka客户端
public class Consumer {
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
}
配置文件(指定应用名和指定eureka服务器地址)
server:
port: 8200
spring:
application:
name: consumer #项目应用名
eureka:
instance:
hostname: localhost #主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:8761/eureka #连接eureka服务中心
续约(renew)
- 在注册服务完成之后,服务提供者会位置一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer ”我还活着“,这个我们称为服务的续约(renew)
#配置续约
#服务续约间隔,默认为30秒,每隔30会给注册中心发送一次心跳
lease-renewal-interval-in-seconds: 10
#服务失效时间,默认为90秒,如果90秒注册中心都收不到服务器的心跳,那么就认为它宕机了,
lease-expiration-duration-in-seconds: 20
注意:这两个默认值在生产环境不要修改,默认即可
失效剔除
-
有时我们的服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,导致服务中心并未收到”服务下线请求“。也导致达到了续约失效时间,这时服务注册中心在启动时会创建一个定时任务,默认每隔一段时间(默认60秒)将续约失效的服务剔除。这样的操作称为失效剔除,
-
可以通过 eureka.server.eviction-interval-time-in-ms参数进行修改,单位为毫秒。
#失效剔除,默认间隔60秒,单位为毫秒
server:
eviction-interval-timer-in-ms: 60000
自我保护
- 可以通过一下配置来关闭自我保护;生产环境下需要开启
eureka.server.enable-self-preservation
#关闭自我保护
server:
enable-self-preservation: false #不写默认为打开自我保护
负载均衡(Ribbon)
-
默认算法为轮询算法
-
负载均衡是一种算法,可以通过算法实现从地址列表中获取一个地址进行服务调用;
在springcloud中提供了负载均衡器: Ribbon
熔断器Hystrix
-
它是微服务系统中是一款提供保护机制的组件
-
Hystrix是netflix开源的ige延迟和容错库,用于隔离访问远程服务,第三方库,防止出现级联失败
雪崩问题
微服务中,服务间调用关系错综复杂,一个请求可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路
线程隔离
用户请求不直接访问服务,而是使用线程池中空闲得线程访问服务,加速失败判断时间
hystrix熔断器启动器依赖
<!--熔断器Hystrix启动器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
开启熔断器(consumer启动引导了使用注解@EnableCircuitBreaker)
package cn.cdw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author DW-CHEN
*/
@SpringBootApplication
@EnableEurekaClient //启用Eureka客户端
@EnableCircuitBreaker //启动Hystrix
public class Provider {
public static void main(String[] args) {
SpringApplication.run(Provider.class, args);
}
}
@SpringCloudApplication
- 这个注解它里边包含了
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
这三个常用注解,我们可以使用这个@SpringCloudApplication注解来代替之前的三个注解
超时设置
-
超时就是发送的请求 超过指定的时间没有接收到请求,就是超时
-
Hystrix默认超时时间为1秒:请求在超过1秒后 就是回去 执行降级处理,
-
我们可以通过如下配置修改超时时间值
#配置超时的时间 单位为毫秒
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
这个配置会作用于全局所有方法
熔断器
熔断器的三个状态
Closed
- 关闭状态(断路器关闭),所有请求都正常访问
Open
- 打开状态(断路器打开),所有请求都会被降级。Hystrix会对请求情况计数,当一定时间内请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值为50%,请求次数最少不低于20次
Half Open
- 半开状态,不是永久 的,短路器打开后会进入休眠时间(默认5秒)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会关闭断路器,否则继续保持打开,在次进行休眠计时
#配置熔断器策
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000 #熔断器超时时间,默认为1秒
circuitBreaker:
requestVolumeThreshold: 20 #触发熔断器最小请求次数,默认20次
sleepWindowInMilliseconds: 5000 #熔断后休眠时长,默认为5秒
errorThresholdPercentage: 50 #触发熔断错误比例阈值,默认为 50%
Feign(伪装)
-
feign可以把rest的请求进行隐藏,伪装成类是SpringMVC的 controller一样,不用自己再拼接url,拼接参数等操作;这些都交给feign去做
-
Feign作用 : 自动根据参数拼接http请求 地址。
Feign启动器依赖
<!--Feign启动器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 定义FeignClient接口(@FeignClient声明为Feign客户端)
Feign负载均衡及熔断
负载均衡
- Feign本身已经集成了Ribbon依赖和自动配置,因此不需要额外引入依赖,也不需要再注册RestTemplate对象
建立链接的超时时长
就是连接的时候,连接的时长
#配置Feign请求超时时长
ribbon:
ConnectTimeout: 1000 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
-
因为ribbon内部有重试机制,一旦超时,会自动重新发起请求。当失败的时候,重试的次数可以去配置
-
如果不希望重试,可以添加以下配置
#配置Feign不重试
ribbon:
MaxAutoRetries: 0 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 0 # 重试多少次服务
OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
请求压缩
Spring Cloud Feign支持对请求和响应进行GZIP压缩,以减少通信过程中性能损耗。
配置请开启请求和响应压缩
#配置开启请求和响应的压缩
feign:
compression:
request:
enabled: true #开启请求压缩
response:
enabled: true #开启响应压缩
配置请求类型以及压缩大小限制
feign:
compression:
request:
enabled: true #开启请求压缩
#设置请求数据类型及触发压缩大小限制
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型,这些都是默认类型
min-request-size: 2048 # 设置触发压缩的大小下限,这个也是默认值
日志级别
前面我们是通过logging.level.xx=debug来 设置日志级别,然而这个对Feign客户端而言不会产生效果,因为@FeignClient注解修改的客户端在被代理时,都会创建一个新的Feign.Logger实例。我们需要额外指定这个日志级别才可以。
Feign日志支持4种级别
-
NONE:不记录任何日志信息,这是默认值
-
BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
-
HEADERS:在BASIC的基础上,额为记录了请求和响应的头信息
-
FULL:记录所有请求和响应的明细,包括头信息,请求体,元数据
Spring Cloud Gateway网关
Spring Cloud Gateway的核心就是一系列的过滤器,可以将客户端的请求转发到不同的微服务;
主要作用:过滤和路由
启动器依赖
<!--eureka启动器依赖,gateway网关与需要暴露自己的服务注册到eureka服务注册中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--gateway启动器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
配置文件
server:
port: 80
spring:
application:
name: gateway #项目应用名
cloud:
gateway:
routes: #路由配置,转发规则
- id: gateway_provider #唯一标识,就是你要访问的服务在eureka注册中心的应用名,默认是UUID
uri: http://localhost:8100/ #转发路径
predicates: #条件,用于请求网关路径的匹配规则
- Path=/book/**
面向服务的路由
刚才我们在配置文件写的路由规则中,把路径对应的服务地址写死了,如果同一服务有多个实例的话,这样做显然不合理。
应该根据服务的名称,去 eureka服务注册中心查找 服务对应的所有实例列表,然后进行动态路由!!!
修改配置文件通过服务名获取服务实例
因为已经配置了eureka客户端,可以从eureka获取服务的地址信息
server:
port: 80
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka #连接eureka服务中心
spring:
application:
name: gateway #项目应用名
cloud:
gateway:
routes: #路由配置,转发规则
- id: gateway_provider #服务提供者
uri: lb://provider #动态路由uri格式:lb://eureka应用名
predicates: #条件,用于请求网关路径的匹配规则
- Path=/book/**
- id: gateway_consumer #服务消费者
uri: lb://consumer #动态路由uri格式:lb://eureka应用名
predicates: #条件,用于请求网关路径的匹配规则
- Path=/bookStore/**
lb://
- lb(使用负载均衡器LoadBalancer的缩写)
路由前缀
- 对请求到网关服务的地址添加或去除前缀
添加前缀(PrefixPath)
- 配置路由器的过滤器PrefixPath,通过路由过滤器filters配置通过PrefixPath配置了前缀
filters:
#在请求路径添加前缀/user
- PrefixPath=/user
去除前缀(StripPrefix)
- 在gateway中可以通过配置路由的过滤器StripPrefix,实现映射路径中地址的去除
filters:
#去除前缀
- StripPrefix=1 #表示过滤一个路径,2表示过滤两个路径,以此类推
过滤器
- gateway作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作往往时通过网关提供的过滤器来实现的。
常见的过滤器
-
AddRequestHeader 对匹配上的请求加上Header
-
AddRequestParameters 对匹配上的请求路由添加参数
-
AddResponseHeader 对网关返回的响应添加Header
-
Stripfix 对匹配上的请求路径去除前缀
局部过滤器
通过,spring.cloud.gateway.routes.filters配置在具体的路由下,只作用在当前路由上;自带的过滤器都可以配置或自定义 按照自定义过滤器的方式。
如果配置spring.cloud.gateway.default-filters上会对所有的路由生效;也算是全局过滤器,但是这些过滤器的实现上都是要实现GatewayFilterFactory接口
全局过滤器
不需要在配置文件中配置,作用在所有路由上;实现GlobalFilter接口即可
负载均衡和熔断
Gateway默认就已经集成了Ribbon负载均衡和Hystrix熔断机制。但是所有的超时策略都是走的默认值,比如熔断器默认只有一秒,很容易就触发了,因此建议手动将进行配置
#配置熔断器策
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 #熔断器超时时间,默认为1秒
#配置Feign请求超时时长,负载均衡
ribbon:
ConnectTimeout: 1000 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
MaxAutoRetries: 0 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 0 # 重试多少次服务
OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
Gateway跨域配置
- 一般网关都是所有微服务的统一入口,必然在被调用的时候会出现跨域问题。
跨域
在js请求访问中,如果访问的地址与当前服务器的域名,ip或者端口号不一致则称为跨域请求。如不解决则不能获取到对应地址的返回结果
也就是说之有在前端使用js发送ajax请求才会出现跨域请求;如果在后端发送请求到其他服务器是不会出现跨域请求的
如:从http://localhost:9090中的js访问http://localhost:9000的数据,因为端口不同,所以也是跨域请求。
在访问Spring cloud Gateway网关服务器的时候,如果出现跨域的话;可以在网关服务器中通过配置解决,允许那些服务是可以跨域请求的;具体配置如下:
Gatway跨域配置
#Gateway跨域配置
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
#allowedOrigins: "*" # 这种写法或者下面的都可以,*表示全部
allowedOrigins:
- "http://docs.spring.io"
allowedMethods:
- GET
注意:
上述配置表示:可以允许http://docs.spring.io的get请求方式获取服务数据
allowedOrigins指定允许访问的服务地址,如:http://localhost:1000也是可以的
'[/**]'表示对所有访问到网关服务器的请求地址
Gateway与Feign的区别
-
gateway作为整个应用的流量入口,接收所有的请求,如PC,移动端等,并且将不同的请求转发至不同的处理微服务模块,其作用可视为nginx;大部分情况下用作于权限鉴定服务端浏览控制
-
Feign则是将当前微服务的部分服务接口暴露出来,并且主要用于各个微服务直接的服务调用
-
gateway网关一般直接给终端请求使用,feign一般用在微服务之间调用
Spring Cloud Config分布式配置中心
作用:可以通过需改git仓库中的配置文件实现其他所有微服务的配置文件修改
在分布式系统中,由于服务数据非常多,配置文件分散在不同的微服务项目中,管理不方便。
为了方便配置文件集中管理,需要分布式配置中心组件
Spring Cloud Config分布式配置中心,它支持配置文件放在配置服务本地,也支持放在Git仓库(GitHub / 码云)
配置中心本质上也是一个微服务,同样需要注册到eureka服务注册中心!
配置文件的命名方式:
- {application}-{profile}.yml或{application}-{profile}.properties
application为应用名称
profile用于区分开发环境,测试环境,生产环境等
如:user-dev.yml,表示用户微服务开发环境下使用的配置文件。
配置中心微服务
依赖坐标
<!--spring cloud config配置中心依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--eureka注册client依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
使用注解@EnableConfigServer标注为配置中心服务
配置文件
#访问端口
server:
port: 10000
spring:
application:
name: config-server #应用名
#配置配置中心
cloud:
config:
server:
git:
uri: #复制github上自己配置的配置文件仓库地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka #eureka服务注册中心
获取配置中心配置
依赖坐标
<!--配置中心依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
创建一个bootstrap.yml配置文件,配置读取配置中心的配置文件
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka #eureaka服务注册中心
spring:
cloud:
#配置从远程仓库拉取的配置信息
config:
#配置远程仓库名{application}
name: user #与远程仓库的{application}的名保持一致
#配置远程仓库的{profile}名
profile: dev #保持和远程参考的{profile}名保持一致
label: master #远程仓库的版本保持一致
discovery:
enabled: true #配置使用配置中心
service-id: config-server #指定配置中心的服务id,从配置中心获取配置信息
bootstrap.yml配置文件也是Spring Boot的默认配置文件,而且其加载的时间相比于application.yml更早。
application.yml和bootstrap.yml虽然都是Spring Boot的默认配置文件,但是定位却不同。bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般不会变动的。application.yml可以用来定义应用级别的一些参数配置,如果搭配spring cloud config使用,application.yml里定义的文件可以实现动态替换
bootstrap.yml配置文件相当于项目启动时的引导文件,内容相对固定。applcation.yml配置文件是微服务的一些常规配置参数,变化比较频繁
Spring Cloud Bus服务总线
…