一、微服务直接调用
通过RestTemplate订单服务直接访问视频服务
1、在SpringBoot启动类中添加RestTemplate对象交给SpringBoot管理。
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
2、在订单服务中,自动注RestTemplate对象,通过restTemplate.getForObject()方法远程调用视频服务。
Video video = restTemplate.getForObject("http://localhost:9000/api/v1/video/find_by_id?
存在问题:
- 服务之间的IP信息写死
- 服务之间⽆无法提供负载均衡
- 多个服务直接关系调用维护复杂
二、解决上面问题:微服务应用和机器器越来越多,调用方需要知道接口的网络地址,不易维护。
解决方法:使用注册中心进行管理。
原理:
- 服务注册:服务提供者provider,启动的时候向注册中心上报自己的网络信息
- 服务发现:服务消费者consumer,启动的时候向注册中心上报自己的网络信息,拉取provider的相关网络信息
- 核心:服务管理理,是有个服务注册表,心跳机制动态维护,服务实例在启动时注册到服务注册表,并在关闭时注销。
主流的注册中心:zookeeper、Eureka、consul、etcd、Nacos
1、nacos搭建安装
- 解压安装包
- 进入bin⽬目录
- 启动 sh startup.sh -m standalone
- 访问 localhost:8848/nacos
- 默认账号密码 nacos/nacos
2、子服务pom文件添加nacos依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starteralibaba-nacos-discovery</artifactId>
</dependency>
3、yml文件配置Nacos地址
spring:
application:
name: xdclass-video-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
4、SpringBoot启动类增加注解
@EnableDiscoveryClient
5、子服务之间的调用(订单服务调用视频服务)
@RequestMapping("/save")
public VideoOrder save(int videoId){
VideoOrder videoOrder = new VideoOrder();
List<ServiceInstance> instances = discoveryClient.getInstances("xdclass-video-service");
Video video = restTemplate.getForObject("http://"+instances.get(0).getHost()+":"+instances.get(0).getPort()+"/api/v1/video/find_by_id?videoId="+videoId, Video.class);
videoOrder.setCreateTime(new Date());
videoOrder.setId(video.getId());
videoOrder.setVideoId(video.getId());
videoOrder.setVideoImg(video.getCoverImg());
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setServerInfo(video.getServerInfo());
return videoOrder;
}
缺点:
- 同一个服务多个节点,无法做到多种策略的负载均衡
- 每个服务都需要拼接连接地址,不易维护、开发
三、解决上面问题:同一个服务多个节点,无法做到多种策略的负载均衡,每个服务都需要拼接连接地址,不易维护、开发。
解决方法:AlibabaCloud集成Ribbon实现负载均衡。
原理:
- Ribbon 是一个客户端负载均衡工具,通过Spring Cloud封装,可以轻松和AlibabaCloud整合
- 订单服务增加@LoadBalanced 注解
步骤:
1、Ribbon与RestTemplate结合,实现负载均衡
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
2、通过Ribbon负载均衡调用视频服务
Video video = restTemplate.getForObject("http://xdclassvideo-service/api/v1/video/find_by_id?videoId="+videoId, Video.class);
通过视频服务在nacos注册是服务名称进行调用,Ribbon服务自动从nacos拉取对应服务列表,并进行负载均衡调用。
负载均衡策略略调整:
在spring boot 配置文件中添加如下配置
xdclass-video-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
策略 | 命令 | 描述 |
RandomRule | 随机策略 | 随机选择server |
RoundRobinRule | 轮询策略 | 按照顺序选择server(默认) |
RetryRule | 重试策略 | 当选择server不成功,短期内尝试选择一个可用的server |
AvailabilityFilteringRule | 可用过滤略 | 过滤掉⼀直失败并被标记 为circuit tripped的server,过滤掉那些⾼并发链接的server(activeconnections超过配置的阈值) |
WeightedResponseTimeRule | 响应时间加权策略 | 根据server的响应时间分 |
ZoneAvoidanceRule | 区域权重策略 | 综合判断server所在区域 的性能,和server的可用性,轮询选择server |
缺点:ribbon代码存在的问题:不规范,风格不统一,维护性比较差,需要拼接http请求
四、优化ribbon代码存在的问题:不规范,风格不统一,维护性比较差,需要拼接http请求
解决方法:通过Open-Feign使用Java接口注解的方式调用Http请求。
原理:
- SpringCloud(Open-Feign)提供的伪http客户端(本质还是⽤用http),封装了了Http调用流程,更适合面向接口化,让用Java接口注解的方式调用Http请求.
- 不用像Ribbon中通过封装HTTP请求报文的方式调用 ,Feign默认集成了了Ribbon
步骤:
1、spring boot pom文件中加入feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、配置注解
启动类增加@EnableFeignClients
3、增加一个接口,并添加@FeignClient注解
订单服务增加接⼝口,服务名称记得和nacos保持⼀一样
@FeignClient(name="xdclass-video-service")
4、编写GET请求实现方法,并添加@GetMapping注解
@GetMapping(value ="/api/v1/video/find_by_id")
Video findById(@RequestParam("videoId") int videoId);
5、编写POST请求实现方法,并添加@PostMapping注解
//订单服务这边
@PostMapping(value = "/api/v1/video/save")
Video saveVideo(@RequestBody Video video);
@PostMapping("/api/v1/video/save1")
public Object save(@RequestBody Video video){
System.out.println(video.getTitle());
return video;
}
Ribbon和feign两个的区别和选择:
- 选择feign默认集成了ribbon,写起来更加思路清晰和方便
- 采用注解方式进行配置,配置熔断等方式方便
五、解决高并发下的微服务容错方案,解决微服务容错问题
解决方法:通过Sentinel服务设置限流、熔断、降级、隔离策略提供微服务容错能力。
优势:
- 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性
- 丰富的应用场景:消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
- 完备的实时监控:Sentinel 同时提供实时的监控功能
- 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合
步骤:
1、微服务引入Sentinel依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、Sentinel控制台搭建
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentineldashboard-1.8.0.jar
3、多个微服务接入Sentinel配置
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
port: 9999
4、配置限流策略
5、Sentinel自定义异常-整合Open-Feign
【新版】实现BlockExceptionHandler并且重写handle方法
public class XdclassUrlBlockHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
//降级业务处理理
Map<String,Object> backMap=new HashMap<>();
if (e instanceof FlowException){
backMap.put("code",-1);
backMap.put("msg","限流-异常啦");
}else if (e instanceof DegradeException){
backMap.put("code",-2);
backMap.put("msg","降级-异常啦");
}else if (e instanceof ParamFlowException){
backMap.put("code",-3);
backMap.put("msg","热点-异常啦");
}else if (e instanceof SystemBlockException){
backMap.put("code",-4);
backMap.put("msg","系统规则-异常啦");
}else if (e instanceof AuthorityException){
backMap.put("code",-5);
backMap.put("msg","认证-异常啦");
}
// 设置返回json数据
httpServletResponse.setStatus(200);
httpServletResponse.setHeader("content-Type","application/json;charset=UTF-8");
httpServletResponse.getWriter().write(JSON.toJSONString(backMap));
}
}
6、开启Feign对Sentinel的支持
feign:
sentinel:
enabled: true
7、创建容错类, 实现对应的服务接口
@Service
public class VideoServiceFallback implements VideoService {
@Override
public Video findById(int videoId) {
Video video = new Video();
video.setTitle("熔断降级数据");
return video;
}
@Override
public Video saveVideo(Video video) {
return null;
}
}
8、配置feign容错类,添加注解
@FeignClient(value = "xdclass-video-service",fallback = VideoServiceFallback.class)