目录
4.在sp05-eureka工程的启动类添加注解@EnableEurekaServer,启动自动配置
2 02/03/04 的application.yml 都添加 eureka注册配置
3 .主程序启用服务注册发现客户端,启动,并访问 eureka 查看注册信息
1. 05-eureka工程创建两个配置文件并添加两个服务器的 profile 配置文件
四 订单业务,通过Fegin的声明式客户端接口作远程调用商品和用户
1 . 添加OpenFeign依赖,使用EditStarts搜索添加
2. sp04-orderservice工程的启动类添加@EnableFeignClients
4.向OrderServiceImpl类依赖注入商品和用户业务接口
6.2 商品业务中ItemController类添加随机阻塞
常见的注册中心:nacos, eureka,zookeeper,etcd,consul...
一 搭建eureka 注册
1.新建 spring 模块: sp05-eureka
2 添加 eureka server 依赖
3 pom.xml 调整版本:
- springboot: 2.3.2.RELEASE
- springcloud: Hoxton.SR6 6不行改成8或者12
4 yml
- 禁用自我保护模式
- 主机名
- 针对单台服务器,不向自己注册,不从自己拉取
5 启动类的注解:
1.创建eureka注册中心工程
2.修改pom文件的版本和熔断版本
注意:这里Hoxton.SR6或者Hoxton.SR9可能都会造成springcloud版本的不正确,尝试其他的版本,比如:Hoxton.SR8
3.修改配置文件的后缀为.yml,编辑配置文件
spring:
application:
name: eureka-server
#8001 8101 8201
#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
4.在sp05-eureka工程的启动类添加注解@EnableEurekaServer,启动自动配置
作用:
(1)@EnableEurekaServer的作用是向容器中加入一个标识类Marker 。
(2)EurekaServerAutoConfiguration类上的@ConditionalOnBean({Marker.class})注解通过对容器中有无Marker类,实现了开关控制效果同时这个类装载了多个bean,这些bean是实现eureka服务端的主要功能。
(3)EurekaServerInitializerConfiguration是初始化eureka的实现类,这个类实现了SmartLifeCycle接口,通过生命周期回调方法初始化eureka
5.修改改 hosts 文件,添加 eureka 域名映射
位置: C:\Windows\System32\drivers\etc\hosts
添加以下内容:
127.0.0.1 eureka1
127.0.0.1 eureka2
6.启动eureka启动类,登录并访问eureka测试
二 eureka 注册与发现
1 02/03/04pom文件添加eureka服务依赖
- 双击shift-->搜索pom.xml-->ctrl选中02/03/04三个pom文件
- 分别在pom文件dependencies标签内-->右键generate-->Edit Starts-->出现speing.io搜索框不修改-->ok
- 搜索eureka-->双击选择eureka Discovery Client -->ok
- 会添加以下依赖内容
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
加载上面依赖之后,会自动添加下面这个依赖,其中SR12版本可能会报错,可以换成8
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2 02/03/04 的application.yml 都添加 eureka注册配置
#客户端应用请求地址: /eureka 子路径
#用浏览器查看 eureka 控制台地址: /
#defaultZone: 如果使用云服务,可以购买不同地点的服务器,自己的服务器地址必须时defaultZone
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka
3 .主程序启用服务注册发现客户端,启动,并访问 eureka 查看注册信息
修改 item-service、user-service 和 order-service,
主程序启动类上添加 @EnableDiscoveryClient
注解
4.eureka四条运行机制
-
注册 客户端会一次一次反复连接服务器进行注册,直到注册成功为止
-
拉取 客户端每30秒拉取一次注册表,来刷新注册表
-
心跳 客户端每30秒发送一次心跳,如果服务器连续三次收不到一个服务的心跳,会删除这个服务
-
自我保护模式:
- 由于网络不稳定,网络中断,15分钟内,85%服务器出现心跳异常,就会进入自我保护模式
- 在这种特殊情况下,所有服务都不删除
- 网络恢复正常后,可以自动退出保护模式
- 开发调试期间,可以禁用保护模式,避免影响测试
三 eureka 高可用测试,以Item商品高可用为例
1. 05-eureka工程创建两个配置文件并添加两个服务器的 profile 配置文件
2. 两个启动类分别配置启动参数
如果在命令行运行,可以在命令行中添加参数:
java -jar xxx.jar --spring.profiles.active=eureka1 --server.port=2001
3 访问 eureka 服务器,查看注册信息
2001/2002都要启动:
4 eureka客户端注册时,向两个服务器注册
修改以下微服务的配置文件: 作用是当一个 eureka 服务宕机时,仍可以连接另一个 eureka 服务
- sp02-itemservice
- sp03-userservice
- sp04-orderservice
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
四 订单业务,通过Fegin的声明式客户端接口作远程调用商品和用户
1.pom.xml添加Fegin依赖
2.启动类添加注解:@EnableFeginClient
3.定义两个客户端接口
- ItemClient
- UserClient
4.修改OrderServiceImpl完成远程调用
1 . 添加OpenFeign依赖,使用EditStarts搜索添加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. sp04-orderservice工程的启动类添加@EnableFeignClients
该注解的作用是启动Feign客户端并创建代理对象进行远程调用
3.创建商品客户端接口和用户客户端接口
package cn.tedu.sp04.feign;
import cn.tedu.sp01.entity.Item;
import cn.tedu.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 java.util.List;
/*获取商品列表,减少库存
* 三个配置:
* 1.调用哪个服务
* 2.调用这个服务的那个路径
* 3.向这个路径提交什么参数
* 有可能出现错误: ..... not found: "item-service"
* 1. 服务没有启动,注册表中不存在 "item-service"
* 2. 服务已经启动,有注册信息,需要等待 30 秒刷新注册表
* */
@FeignClient(name = "item-service")//指定注册表里的名字
public interface ItemClient {
@GetMapping("/{orderId}")
JsonResult<List<Item>> getItems(@PathVariable String orderId);
@PostMapping("/decreaseNumber")
JsonResult<?> decreaseNumber(List<Item> items);
}
package cn.tedu.sp04.feign;
import cn.tedu.sp01.entity.User;
import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/{userId}")
JsonResult<User> getUser(@PathVariable Integer userId);
@GetMapping("/{userId}/score")
JsonResult<?> addScore(@PathVariable Integer userId,
@PathVariable Integer score);
}
4.向OrderServiceImpl类依赖注入商品和用户业务接口
package cn.tedu.sp04.service;
import cn.tedu.sp01.entity.Item;
import cn.tedu.sp01.entity.Order;
import cn.tedu.sp01.entity.User;
import cn.tedu.sp01.service.OrderService;
import cn.tedu.sp04.feign.ItemClient;
import cn.tedu.sp04.feign.UserClient;
import cn.tedu.web.util.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private ItemClient itemClient;
@Autowired
private UserClient userClient;
@Override
public Order getOrder(String orderId) {
log.info("获取订单,orderId="+orderId);
// TODO: 远程调用商品,获取商品列表,从04订单调用02商品
/*调用流程:
* 浏览器-->OrderController-->OrderServiceImpl-->itemClient
* -->ItemController-->ItemService*/
JsonResult<List<Item>> items = itemClient.getItems(orderId);
// TODO: 远程调用用户,获取用户数据
JsonResult<User> user = userClient.getUser(8);//真实项目中要获取已登录用户的id
//等添加nacos服务注册中心时再修改
Order order = new Order();
order.setId(orderId);
order.setUser(user.getData());
order.setItems(items.getData());
return order;
}
/*添加订单*/
@Override
public void addOrder(Order order) {
//目前只做一个日志,后期会添加数据库
log.info("添加订单:"+ order);
// TODO: 远程调用商品,减少库存
itemClient.decreaseNumber(order.getItems());
// TODO: 远程调用用户,增加积分
userClient.addScore(order.getUser().getId(),1000);
}
}
5.订单业务进行请求测试,反复访问,
后台:
6 Feign集成了Ribbon,实现负载均衡和重试
默认已经启用负载均衡和重试
6.1 Ribbon重试
远程调用后台服务失败时,可以自动重试调用
1. 失败时:出现异常,一台服务器宕机.阻塞延迟超时
2. 重试参数:默认总共重试2次,(x+1)*(y+1)
- MaxAutoRetries:单台服务器重试次数,默认值是0 --请求一次--x
- MaxAutoRetriesNextServer:更换服务器次数,默认值是1 --请求一次--y
- ReadTimeout: 等待响应的超时时间,默认是1000ms,即1秒
- OkToRetryOnAllOperations: 是否对所有请求方式都重试,默认只对Get请求重试
- ConnectTimeout: 与后台服务器建立网络连接的超时时间
6.2 商品业务中ItemController类添加随机阻塞
测试:
后台 :出现延迟信息
反复刷新访问页面有10%概率请求失败:
五 API 网关 Zuul
Zuul
- 统一的调用入口
- 统一的权限校验
- 集成Ribbon
- 集成Hystrix
统一的调用入口
步骤:
- 新建spring模块:sp06-zuul
- 添加依赖:zuul/ eureka client/ sp01
- yml配置文件配置转发规则
- 启动类注解:@EnableZuulProxxy
#转发规则
#service-id:作为访问子路径是默认配置,zuul会根据注册表完成自动配置
#最后手动配置,防止注册表不全
zuul:
route:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
第一步:新建zuul的工程
第二步:修改pom文件版本,添加三个依赖
其中,zuul依赖可能需要版本,那就根据maven仓库推荐添加合适的版本:
<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.9.RELEASE</version>
</dependency>
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>sp01-commons</artifactId>
<version>1.0-SNAPSHOT</version>
第三步:修改配置文件.properties改为.yml,编辑配置文件内容
spring:
application:
name: zuul
server:
port:3001 #zuul网关端口号
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
#转发规则
#service-id:作为访问子路径是默认配置,zuul会根据注册表完成自动配置
#最后手动配置,防止注册表不全
zuul:
routes:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
第四步: 添加@EnableZuulProxy 注解,添加网关过滤器
作用:增加三个过滤器
- pre类型过滤器
- route类型过滤器:RibbonRoutingFilter/SimpleHostRoutingFilter
第五步:url测试 ,因为添加了随机阻塞,可能会报504,需要多次刷新访问
- http://localhost:3001/item-service/3
- http://localhost:3001/user-service/8
- http://localhost:3001/user-service/8/score?score=1000
- http://localhost:3001/user-service/9
- http://localhost:3001/order-service/7
但请求路径参数的用户名,设置的没有此用户时,就会报出504异常:
- http://localhost:3001/order-service/add?id=123&user=8&items=5