Eureka
服务端
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
编写yml
编写启动类
访问
客户端
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
编写yml
编写启动类
启动
把服务customer注册进来
Eureka注册多个服务之间访问
使用RestTemplate访问
在此服务中访问customer服务中返回字符串类型。
Eureka集群
当只有一个服务时,如果服务停止就会出现多个客户端之间无法联系,所以要启动多服务。
编写多个服务
yml文件
注意:
打开配置 register-with-eureka 与 fetch-registry
defaultZone 为其他服务的地址 如果有多个就用逗号隔开
客户端配置
指定服务地址为两个,如果多个就要用逗号隔开
将应用全部启动
Eureka安全性
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
增加配置类 对访问路径进行过滤
在yml文件中配置用户名密码
启动服务
需要登录
客户端如果想注册到此服务需要配置用户名密码
拼接用户名密码
启动服务
Eureka心跳
每隔30秒向服务端发送一个心跳
90秒不发送就会认为宕机
红字是服务端的自我保护机制
15分钟内,一个服务发送心跳比例低于85%就会触发自我保护
自我保护不会移除没有发送心跳的服务
自我保护配置默认true开启
CAP定理 C一致性 A 可用性 P 分区容错性
eureka使用AP原则
Robbin
是帮我们实现服务与服务之间的负载均衡
启动两个SEARCH服务
第一个8081
第二个
使用客户端访问SEARCH
在客户端导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
在客户端使用robbin与RestTemplate整合
加入注解@LoadBalanced
在controller直接使用RestTemplate进行访问
url不再使用EurekaClient获取 ,直接使用服务名称拼接
Robbin负载均衡策略
负载均衡策略接口
实现类 每个类就是一种策略
- RandomRule 随机访问策略
- RoundRobinRule 轮询的策略 默认这个策略
- WeightedResponseTimeRule 开始采用轮询的策略 后续根据服务响应时间来配置权重,根据权重分配
- BestAvailableRule 根据并发访问率最少的服务进行调用
采用注解配置负载均衡
采用配置的形式可以针对某一个服务来配置
Feign
实现服务间的调用
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类加入注解
编写client
此类中类名要与访问的地址方法名称一致,RequestMapping编写访问服务的方法地址。
配置robbon
编写controller
直接使用接口中方法名称可以调用服务中的方法
Feign传递参数
服务端的方法
客户端通过feign访问服务端的方法
在客户端编写接口
在客户端的controller调用client里接口方法
启动访问
Feign_Fallback 服务降级
Fallback 可以帮助我们在放问一个服务,但是此服务不能正常运行返回值时,走服务降级,避免出现问题时,整个工程不能正常运行。
- 编写服务降级类
-
在client里加入服务降级会调用哪个类
-
在配置文件中要开启服务降级
运行查看控制台
想要再客户端知道具体的报错信息需要编写fallbackFactory
-
编写fallbackFacory 类 实现FallbackFactory接口重新方法
-
修改client中注解调用的服务降级类
-
启动
查看控制台
打印报错信息
Hystrix
降级,隔离,熔断,缓存 四个功能
雪崩:一个连续的服务中间一个服务中断,导致整个服务出问题。
Hystrix指定降级方法
导入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
启动类需要加注解@EnableCircuitBreaker(电路破坏器) 断路 断路器
在controller中方法中指定降级方法
Hystrix 隔离
Hystrix线程隔离
接收请求使用tomcat的线程池,处理业务时使用Hystrix线程池
当导入hystrix依赖时,自动会启用hystrix线程池。
如何配置:
在注解中加入commandProperties属性
使用@HystrixProperty name属性名称,value值
execution.isolation.strategy 指定隔离方式 THREAD线程隔离,SEMAPHORE信号隔离
execution.isolation.thread.timeoutInMilliseconds 指定返回时间,超时调用降级方法
Hystrix信号隔离
请求访问 还是使用tomcat线程池,使用信号管理
Hystrix 熔断
服务熔断:
A服务调用B服务,但是B服务报错,导致A服务使用降级服务,如果多次访问B服务一直出现问题,就会出现熔断不再访问B服务器直接使用降级服务(断路器open),过一段时间再次访问B服务(断路器半开),如果B服务正常那恢复正常服务调用(断路器close),如果B服务还是出现问题就会再次进入不调用B服务直接降级的处理(断路器open)。
断路器监控界面
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
启动类加入注解
编写断路器界面路径类Servlet
需要配置yml否则会出现无法连接的问题
启动项目进行访问
填写路径进行访问
进行一个访问
进行有问题的访问
断路器控制
打开类
HystrixCommandProperties
- 断路器开关 circuitBreaker.enabled=true
- 失败阈值的总请求数circuitBreaker.requestVolumeThreshold=20
- 请求失败达到百分之多少时,打开断路器circuitBreaker.errorThresholdPercentage=50
- 断路器打开后多少秒拒绝请求circuitBreaker.sleepWindowInMilliseconds=5000
- 强制让服务拒绝请求circuitBreaker.forceOpen=false
- 强制让服务接收请求circuitBreaker.forceClosed=false
Hystrix缓存
- 缓存的生命周期是一次请求
- 缓存在当前线程中,方法参数为key 方法返回值为value
- 在一次请求中,方法被调用一次就会被缓存
示例
需要编写过滤器在过滤器中初始化HystrixRequestContext对象,缓存会存在这个容器中
在service层启用缓存
Zuul
实现对各个服务的管理
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
在启动类添加注解
编写YML文件
Zuul监控界面
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
填写配置文件
访问
忽略配置
访问
自定义服务配置
方式二
Zuul过滤器
过滤器代码编写
过滤代码示例
Zuul降级
当hystrix中没有指定降级方法时,启动zuul的降级
package com.tx.fallback;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class ZuulFallbackTest implements FallbackProvider {
@Override
public String getRoute() {
System.out.println("444444444444");
return "*";//那些服务会降级,*代表所有服务
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
System.out.println("当前降级的服务============:"+route);
cause.printStackTrace();//打印错误日志
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
//指定响应头信息
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return httpHeaders;
}
@Override
public InputStream getBody() throws IOException {
//返回的错误信息
String msg="当前服务"+route+"出现问题!!!!";
return new ByteArrayInputStream(msg.getBytes());
}
@Override
public HttpStatus getStatusCode() throws IOException {
//返回错误状态
return HttpStatus.INTERNAL_SERVER_ERROR;
}
@Override
public int getRawStatusCode() throws IOException {
//返回错误状态码 500
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
@Override
public String getStatusText() throws IOException {
//返回的错误信息
return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
}
@Override
public void close() {
}
};
}
}
Zuul动态路由
package com.tx.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class DynamicRouteFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER+2;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String key= request.getParameter("redis");
System.out.println(key);
if("hy".equalsIgnoreCase(key))
{
currentContext.put(FilterConstants.SERVICE_ID_KEY,"search");//需要访问的服务名称
currentContext.put(FilterConstants.REQUEST_URI_KEY,"/find");//访问的服务中的具体方法路径
}
return null;
}
}