1.eureka注册中心
注册中心服务端主要对外提供了三个功能:
服务注册:
服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表。
提供注册表:
服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表。
同步状态:
Eureka Client 通过注册、心跳机制和 Eureka Server 同步当前客户端的状态。
2.创建项目
2.1添加eureka依赖
2.2修改pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud1</artifactId>
<groupId>cn.tedu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sp05-eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sp05-eureka</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
2.3修改application.yml文件
# 应用名称
spring:
pplication:
name: eureka-server
#2001,3001,4001,5001,6001
server:
port: 2001
eureka:
server:
enable-self-preservation: false #禁用自我保护机制
instance:
hostname: eureka1 #主机名
client:
register-with-eureka: false #不向自己注册
fetch-registry: false #不从自己拉取
Eureka四条运行机制:
1.注册:客户端会一次一次的反复注册,直到注册成功为止。
2.拉取:客户端每隔30秒,重复的拉取、刷新本地缓存的注册表。
3.心跳:客户端每隔30秒向服务器发送心跳,如果服务器连续3次收不到一个服务的心跳,就会删除该服务的注册信息。
4.自我保护模式:
网络不稳定,或网络中断时,15分钟内85%服务器都出现心跳异常
,会进入自动保护模式;
这种特殊情况下,会保护所有注册信息不删除;
等待网络回复正常后,自动退出保护模式;
开发调试期间应该禁用保护模式,避免影响测试。
2.4启动类添加@EnableEurekaServer注解
2.5为02、03、04工程添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.6 02工程配置文件添加
spring:
application:
name: user-service
server:
port: 8101
#用户的demo数据
#[{id:7,username:xx,password:xx},{8..},{9..}]
sp:
user-service:
users: "[{\"id\":7, \"username\":\"abc\",\"password\":\"123\"},
{\"id\":8, \"username\":\"def\",\"password\":\"456\"},
{\"id\":9, \"username\":\"ghi\",\"password\":\"789\"}]"
#/eureka 子路径是客户端调用的 REST API 路径,浏览器不能访问
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka
- defaultZone:默认地点,也可以从云服务商购买不同地点的eurea服务
2.7修改 hosts 文件,添加 eureka 域名映射
C:\Windows\System32\drivers\etc\hosts
管理员打开
添加内容:
127.0.0.1 eureka1
127.0.0.1 eureka2
2.8启动,并访问测试
http://eureka1:2001
3.Eureka 和 “服务提供者”的高可用
3.1item-service 高可用
启动参数 --server.port 可以覆盖yml中的端口配置;
通过启动参数设置启动的端口:
java -jar item.jar --server.port=8001
java -jar item.jar --server.port=8002
启动测试:
3.2Erueka高可用
添加两个服务器的 profile 配置文件:
application-eureka1.yml:
#2001,3001,4001,5001,6001
server:
port: 2001
eureka:
instance:
hostname: eureka1 #主机名
client:
register-with-eureka: true #false不向自己注册,profile的配置会覆盖公用配置
fetch-registry: true #false不从自己拉取,profile的配置会覆盖公用配置
service-url:
defaultZone: http://eureka2:2002/eureka #eureka1启动时向eureka2注册
application-eureka2.yml:
#2001,3001,4001,5001,6001
server:
port: 2002
eureka:
instance:
hostname: eureka2 #主机名
client:
register-with-eureka: true #false不向自己注册,profile的配置会覆盖公用配置
fetch-registry: true #false不从自己拉取,profile的配置会覆盖公用配置
service-url:
defaultZone: http://eureka1:2001/eureka #eureka1启动时向eureka2注册
访问 eureka 服务器,查看注册信息:
http://eureka1:2001/
http://eureka2:2002/
3.3eureka客户端注册时,向两个服务器注册
修改以下微服务:
sp02-itemservice
sp03-userservice
sp04-orderservice
#/eureka 子路径是客户端调用的 REST API 路径,浏览器不能访问
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
4. 02orderservice远程调用02和03
4.1添加feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
4.2启动类添加@EbableFeignClients注解
4.3添加两个远程调用接口
package cn.tedu.sp04.feign;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.web.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* 1.调用哪个服务
* 2.调用这个服务的哪个路径
* 3.向这个路径提交什么参数
* */
@FeignClient(name="item-service",contextId = "itemClient")
public interface ItemClient {
//获取订单的商品列表
@GetMapping("/{orderId}")
JsonResult<List<Item>> getItems(@PathVariable("orderId") String orderId);
//减少商品库存
@PostMapping("/decreaseNumber")
JsonResult<?> decreaseNumber(@RequestBody List<Item> items);
}
package cn.tedu.sp04.feign;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp01.web.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "user-service",contextId = "userClient")
public interface UserClient {
//获取用户
@GetMapping("/{userId}")
JsonResult<User> getUser(@PathVariable("userId") Integer userId);
//增加用户积分
@GetMapping("/{userId}/score") //?score=1000
JsonResult<?> addScore(@PathVariable("userId") Integer userId,
@RequestParam Integer score);
}
4.4在订单实现类远程调用两个接口
5.Feign集成Ribbon
Ribbon提供负载均衡和重试的功能
Ribbon重试:调用后台服务失败(异常、超时、宕机),可以自动发起重试调用。
随机向一台服务器请求,请求失败(重试次数默认为0)则会更换服务器(更换服务器次数默认为1)。
单台服务器的重试次数MaxAutoRetries(默认0)(x),更换服务器的次数 MaxAutoRetriesNextServer(默认1)(y),最大请求次数(x+1)*(y+1)
在itemController模拟阻塞运算:
//模拟阻塞运算
if (Math.random()<0.9){//90%概率执行阻塞代码
//阻塞时长随机0-5秒
int t = new Random().nextInt(5000);
log.info("阻塞:"+t);
Thread.sleep(t);
}
- ribbon.MaxAutoRetries:重试次数,默认为0
- ribbon.MaxAutoRetriesNextServer:更换服务器次数,默认为1
- ribbon.ReadTimeout:超时时间,默认1000
- ribbon.ConnectTimeout:与后台服务器建立连接的超时时间,默认1000
- ribbon.OkToRetryOnAllOperations:是否对所有类型请求都重试,默认只对GET请求重试
6.Zuul API网关
统一的入口:
1.新建spring模块:sp06-zuul
选择eureka client依赖
2.添加依赖:zuul、eureka client、sp01
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud1</artifactId>
<groupId>cn.tedu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sp06-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sp06-zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencies>
<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>
</dependency>
</dependencies>
</project>
3.配置yml:
# 应用名称
spring:
application:
name: zuul
# 2001,3001,4001,5001,6001
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureks1:2001/eureka, http://eureks2:2002/eureka,
#路由转发规则
#最好手动配置
zuul:
routes:
item-service: /item-service/** # **包含深层子路径,*只含当前一层路径
user-service: /user-service/**
order-service: /order-service/**
4.启动类加@EnableZuulProxy注解
启用zuul网关
先启动两个eureka服务,启动02、03、04,最后启动zuul
7.统一权限校验
模拟登录检查:
http://localhost:3001/order-service/order123456 没有登录,不允许访问
http://localhost:3001/order-service/order123456?token=fdshnkj 已经登录可以访问
1.新建过滤器,继承ZuulFilter
2.按照规则实现ZuulFilter
3.添加注解@Component
- zuul的自动配置类会自动配置过滤器
添加过滤类:
@Component
public class AccessFilter extends ZuulFilter {
//过滤器类型,pre前置,routing 运行 post后置,error错误
@Override
public String filterType() {
//return "pre";
return FilterConstants.PRE_TYPE;//前置过滤器
}
//过滤器顺序号
@Override
public int filterOrder() {
return 6;//放在第6位
}
//针对当前请求,是否执行过滤代码
@Override
public boolean shouldFilter() {
//调用item-service需要判断权限
//否则,不判断权限,直接跳过过滤代码
//获取请求上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//从上下文对象获得调用的服务id
String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);//("serviceId)
//如果服务id是 item-service,返回true,否则返回false
return "item-service".equalsIgnoreCase(serviceId);//IgnoreCase忽略大小写
}
//过滤代码
@Override
public Object run() throws ZuulException {
// http://localhost:3001/order-service/order123456?token=fdshnkj
//获取请求上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//从上下文获得request对象
HttpServletRequest request = ctx.getRequest();
//从request取出token参数
String token = request.getParameter("token");
//如果没有token,null,""
if (StringUtils.isBlank(token)) {
//阻止继续调用
ctx.setSendZuulResponse(false);
//直接向客户端返回响应
String json = JsonResult.build().code(400).msg("未登录").toString();
ctx.addZuulResponseHeader("Content-Type", "application/json;charset=UTF-8");
ctx.setResponseBody(json);
}
return null;
}
}
Zuul集成Ribbon
- 默认启用了负载均衡
- 默认不启用重试,一般不在网关添加重试功能,否则可能造成后台服务器压力过大,出现大面积故障,重试功能应该尽量靠后添加
Zuul启用重试:
1.添加依赖:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2.修改配置文件:
Zuul集成Hystrix
向后台服务转发调用,使用Hystrix进行容错和限流
Zuul默认已经启用了Hystrix。不做任何配置
8.Hystrix
容错(降级)和限流(熔断)工具
Zuul集成Hystrix添加降级
1.新建降级类,实现FallBackProvider接口
2.按接口规则实现
3.添加注解:@Component
zuul的自动配置类可以完成自动配置
Hystrix熔断:
流量过大,出现故障,可以熔断,断开链路,减轻后台服务的压力
使用Actuator暴露Hystrix监控日志
Hystrix利用Actuator来暴露自己的监控日志
添加Actuator:
Actuator时Springboot提供的一个项目指标工具
- 健康状态
- spring容器 中所有对象
- springmvc映射的所有路径
- java虚拟机堆内存镜像
Actuator依赖:
暴露监控日志:
Hystrix数据监控-Hystrix Dashboard
1.新建spring模块:sp07-hystrix-dashboard
2.添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud1</artifactId>
<groupId>cn.tedu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sp07-hystrix-bashboard</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sp07-hystrix-bashboard</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
</project>
3.配置文件
server:
port: 4001
hystrix:
dashboard:
proxy-stream-allow-list: localhost
4.启动类加注解@EnableHystrixDashboard
5.访问: http://localhost:4001/hystrix
然后在里边输入http://localhost:3001/actuator/hystrix.stream测试