(一)Spring Cloud 直击微服务作用、架构应用、hystrix降级

直击微服务作用

微服务架构:

遇到了什么问题?

将单体架构拆分成微服务架构后,如果保证多个服务(项目)正常运行?
哪个技术可以解决这个问题?
微服务技术
服务治理: 服务管理,维护服务与服务之间的关系
这个技术如何使用?
netflix/网飞:
SpringCloud: ★
Alibaba: ★

软件架构

架构: 结构

软件架构: 软件的结构

淘宝架构演进过程:

100并发 -> 千万并发,阿里淘宝的 14 次架构演进之路!

软件架构演进过程:

单体架构: All in one
优点: 架构简单 部署方便
缺点:
耦合度高,维护成本大
技术栈受限
使用场景: 用户量小,一般情况下开发学生管理系统
分布式架构:
将大项目拆分成多个小项目
微服务架构:
拆分原则:
单一职责: 一个服务只做一件事情(不允许出现冗余的功能或模块)
自治: 团队独立,技术独立,部署独立,数据库独立
面向服务: 微服务开发完毕后,需要对外提供统一的访问接口(对接规范)
隔离性强: 服务调用做好隔离、容错、降级,避免出现级联问题
微服务技术:
各个公司将自己的单体架构的项目拆分成微服务架构项目后,都有自己的解决方案.我们学习时,主要学习SpringCloud官方提供的微服务组件,SpringCloud官方使用的组件主要来自NetFlix和Alibaba
学习微服务其实就是学习相关的微服务组件,一个组件可以解决微服务拆分后的一类问题.

如何使用:

准备微服务环境

创建两个数据库,分别写一套对应的增删改查操作

依赖

<dependency>

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR10</version>
<type>pom</type>
<scope>import</scope>
</dependency>

Eureka组件

遇到了什么问题?
  • order-service在发起远程调用的时候,该如何得知user-service实例的ip地址和端口?
  • 有多个user-service实例地址,order-service调用时该如何选择?
  • order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?
    哪个技术可以解决这个问题?
    Eureka组件可以解决
    这个技术如何使用?
    1.搭建Eureka服务端
    2.在微服务中整合Eureka客户端
    3.在消费者方,通过服务名称获取提供者的地址,负载均衡进行访问

RestTemplate对象

RestTemplate: 模拟浏览器的行为向服务器发送请求

java 复制代码
/**
 * @Author: huahua
 * @name:RestTemplateTest
 * @Date:2023/7/18 10:41
 */
@SpringBootTest
public class RestTemplateTest {
    /**
     * RPC(Remote Procedure Call Protocol): 远程过程调用
     *      只要实现了两台机器之间的数据交互就可以称之为远程过程调用
     * RestTemplate: 封装了远程调用的客户端
     *
     */
    @Autowired
    private RestTemplate restTemplate;

    // get方式的请求
    @Test
    public void test01(){
        // 向目标服务器发送请求,并接收对应的结果
        //String resp = restTemplate.getForObject("http://user-service/user/1", String.class);
        //TbUser resp = restTemplate.getForObject("http://user-service/user/1", TbUser.class);
        // 携带参数
        //TbUser resp = restTemplate.getForObject("http://user-service/user/findByName/柳岩", TbUser.class);
        //System.out.println(resp);

        ResponseEntity<TbUser> resp = restTemplate.getForEntity("http://127.0.0.1:8081/user/1", TbUser.class);
        // 获取响应状态
        HttpStatus statusCode = resp.getStatusCode();
        // 获取响应数据
        TbUser tbUser = resp.getBody();
        // 获取响应头
        HttpHeaders headers = resp.getHeaders();
        // 获取响应头中的cookie头
        List<String> list = headers.get("Set-Cookie");
        System.out.println(statusCode);
        System.out.println(tbUser);
        System.out.println(headers);
        System.out.println(list);

    }
    /**
     * 请求头设置参数,访问指定接口
     */
    @Test
    public void test03(){
        String url="http://127.0.0.1:8081/user/2";
        //设置请求头参数
        HttpHeaders headers = new HttpHeaders();
        headers.add("token","damimi");
        //请求头填充到请求对象下
        HttpEntity<Map> entry = new HttpEntity<>(headers);
        //发送请求
        ResponseEntity<TbUser> responseEntity = restTemplate.exchange(url, HttpMethod.GET, entry, TbUser.class);
        TbUser result = responseEntity.getBody();
        System.out.println(result);
    }
    /**
     * post模拟form表单提交数据
     */
    @Test
    public void test04(){
        String url="http://localhost:8081/user/save";
        //设置请求头,指定请求数据方式
        HttpHeaders headers = new HttpHeaders();
        //告知被调用方,请求方式是form表单提交,这样对方解析数据时,就会按照form表单的方式解析处理
        headers.add("Content-type","application/x-www-form-urlencoded");
        //组装模拟form表单提交数据,内部元素相当于form表单的input框
        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("username","迪丽热巴");
        map.add("address","天津");
        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
        /*
            参数1:请求url地址
            参数2:请求方式 POST
            参数3:请求体对象,携带了请求头和请求体相关的参数
            参数4:响应数据类型
         */
        ResponseEntity<TbUser> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, TbUser.class);
        TbUser body = exchange.getBody();
        System.out.println(body);
    }

    /**
     * post发送json数据
     */
    @Test
    public void test05() throws JsonProcessingException {
        String url="http://localhost:8081/user/save2";
        //设置请求头的请求参数类型
        HttpHeaders headers = new HttpHeaders();
        //告知被调用方,发送的数据格式的json格式,对方要以json的方式解析处理
        headers.add("Content-type","application/json; charset=utf-8");
        //组装json格式数据
        HashMap<String, String> reqMap = new HashMap<>();
        reqMap.put("username","zhangsan");
        reqMap.put("address","上海");
        ObjectMapper objectMapper = new ObjectMapper();
        String reqMapJson = objectMapper.writeValueAsString(reqMap);
        //构建请求对象
        HttpEntity<String> httpEntity = new HttpEntity<>(reqMapJson, headers);
          /*
            发送数据
            参数1:请求url地址
            参数2:请求方式
            参数3:请求体对象,携带了请求头和请求体相关的参数
            参数4:响应数据类型
         */
        ResponseEntity<TbUser> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, TbUser.class);
        //或者
        // Account account=restTemplate.postForObject(url,httpEntity,Account.class);
        TbUser body = responseEntity.getBody();
        System.out.println(body);
    }

    @Test
    public void test07(){
        ResponseEntity<String> resp = restTemplate.getForEntity("http://www.takungpao.com/news/index.html", String.class);
        String body = resp.getBody();
        System.out.println(body);
    }
}

Ribbon

当服务从Eureka中拉取多个服务地址时,Ribbon可以实现负载均衡(从多个地址中选择一个)

在RestTemplate对象上添加注解 @LoadBalanced

Hystrix组件

作用: 解决雪崩问题

雪崩问题: 在一个业务链路中,由于下游服务的故障,导致整个链路关联的所以服务宕机.

解决方案:

服务降级: 换一种方式快速给上游服务一个响应.

服务熔断: 当出错率到达一定的阈值时,直接熔断,不再访问下游服务,直接降级.

服务降级

1.导入启动器

在消费者/上游服务方导入

<!-- Hystrix启动器 -->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>

</dependency>

2.在引导上开启Hystrix支持

@EnableHystrix

3.编写降级逻辑

a.在需要降级的方法上降级注解: @HystrixCommand(fallbackMethod="降级方法名")

b.编写降级的方法

降级处理的方法,与原方法返回值,参数列表保持一致

java 复制代码
package com.bw.order.controller;

import com.bw.order.domain.TbOrder;
import com.bw.order.domain.TbUser;
import com.bw.order.service.TbOrderService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: huahaua
 * @name:OrderController
 * @Date:2023/8/14 18:48
 */
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private TbOrderService orderService;
    // 此方法执行超时后,调用对应降级的方法快速处理业务
    @RequestMapping("/findById/{id}")
    @HystrixCommand(fallbackMethod="findUserByIdForFail")
    public TbOrder findById(@PathVariable Integer id){
        TbOrder order = orderService.findById(id);
        return order;
    }

    // todo:降级处理的方法,与原方法返回值,参数列表保持一致
    public TbOrder findUserByIdForFail(Integer id){
        TbOrder order = new TbOrder();
        order.setName("你的小可爱走丢了....服务降级");
        return order;
    }
}

4.注意事项和配置

Hystrix默认降级时间为1秒钟

配置降级时间:

java 复制代码
hystrix:
  command:
    default:
      execution.isolation.thread.timeoutInMilliseconds: 2000 # 单位毫秒
相关推荐
KYGALYX5 小时前
服务异步通信
开发语言·后端·微服务·ruby
yunteng5217 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入
麦聪聊数据7 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
程序员侠客行8 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
bobuddy9 小时前
射频收发机架构简介
架构·射频工程
桌面运维家10 小时前
vDisk考试环境IO性能怎么优化?VOI架构实战指南
架构
金牌归来发现妻女流落街头10 小时前
【从SpringBoot到SpringCloud】
java·spring boot·spring cloud
一个骇客11 小时前
让你的数据成为“操作日志”和“模型饲料”:事件溯源、CQRS与DataFrame漫谈
架构
鹏北海-RemHusband12 小时前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构