SpringCoold

一、单体项目应用存在的问题

一个成功的应用必然有一个趋势:用户量会不断增加,项目的业务也会不断扩展用户量的增加也会带来高并发的问题,高并发问题的解决方案

  • 应用服务器:–> 单体优化–>集群(负载均衡,分布式并发)
  • 数据库服务器 -->数据库优化 --> 缓存redis–>分布式数据库

项目业务的扩展,也会带来一些问题

  • 项目结构越来越臃肿(项目结构和代码复杂,项目体积逐渐变得庞大)
  • 项目结构和代码复杂导致项目不易维护和二次开发、扩展和更新就会变得困难
  • 项目体积逐渐变得庞大导致启动时间越来越长,生产力大受限制
  • 单体应用中任何一个模块的任何一个bug都会导致整个系统不可用(单点故障)
  • 复杂的单体项目也会带来持续部署的障碍
  • 单体项目使得采用新的技术和框架变得困难

二、微服务架构

2.1 微服务架构的概念

微服务架构,是一种架构概念,就是将一个单体应用中的每个功能分解到各各离散的服务中,以实现对单体项目解耦,并提供更加灵活的服务支持

2.2 微服务架构优点

  • 解决了单体项目的复杂性问题
  • 每个服务都可以由单独的团队开发
  • 每个服务都可以使用单独的技术栈进行开发
  • 每个服务都是独立的进行部署和维护
  • 每个服务都可以独立进行扩展

2.3 微服务架构缺点

  • 微服务架构的本身就是一个缺点,如何把握"微"的粒度
  • 微服务架构是一个分布式系统,虽然单个服务变得简单,但是服务之间存在相互的调用,整个服务架构系统变得复杂
  • 微服务架构还需要依赖分布式架构
  • 微服务的单元测试及调用比较复杂
  • 部署基于微服务架构的应用程序变得非常复杂
  • 进行微服务架构的应用程序开发的技术成本变得更高

三、微服务架构开发需要解决的问题

在微服务架构开发的系统中,必然会存在很多个服务,服务之间需要需要感知对方的存在,需要进行服务间的调用,该如何实现呢?—进行微服务架构开发需要解决的问题:

  1. 如此多的服务,服务之间如何相互发现
  2. 服务与服务之间该如何通信?
  3. 如果某个服务挂了,该如何处理
  4. 前端访问多个不同的服务时该如何统一访问路径呢

3.1 服务之间如何相互发现的问题

微服务架构 — 每个服务只处理一件事情/一个步骤,在一个复杂的业务中必然存在服务之间的相互调用,服务想要相互调用就需要先发现对方

  • 服务注册与发现中心也是一台独立服务器
  • 1.服务提供者在服务注册与发现中心进行注册
  • 2.服务注册与发现中心进行服务记录,并与服务提供者保持心跳
  • 3.服务消费者通过服务注册与发现中心进行服务查询(服务发现)
  • 4.服务注册与发现中心返回可用的服务的服务地址列表
  • 5.服务消费通过负载均衡访问服务提供者

3.2 服务之间如何进行通信

服务消费者在调用服务提供者时,首先需要通过服务注册与发现中心进行服务查询,返回服务列表给服务消费者,服务消费者通过LoadBalance调用服务提供者,那他们之间是如何通信的呢 ------数据传输规程

服务与服务之间的通信方式有2种:

  • 同步调用
  • 异步调用

3.2.1 同步调用

  • REST(SpringCloud(Netflix,SpringCloud Alibaba)) --------- 学这个√
    • 基于HTTP协议的请求和响应
    • 更容易实现,技术更灵活
    • 支持多种语言,同时可以实现跨客户端
    • 适用面广
  • RPC(Dubbo)
    • 居于网络层协议通信
    • 传输效率高
    • 安心性更高
    • 如果有统一的开发规则或者框架,开发效率是比较高的

3.2.2 异步调用

服务间的异步通信通常是通过消息队列实现的

3.3 服务挂了怎么办

3.3.1 服务故障雪崩

在一条服务中调用链中,因为某个服务节点的故障导致依赖这个服务的服务就会别阻塞,如果此时有大量的用户请求涌入,产生阻塞的用户就可能会因为自由被耗尽而导致服务器瘫痪。

服务之间存在依赖,单个服务的故障可能会导致整个系统造灾难,这就是服务故障的雪崩效应

3.3.2 如何预防(解决)

  • 服务集群 ---- 尽量保证每个服务可用
  • 服务降级与熔断 ----- 避免请求阻塞,造成正常的服务出现故障

3.4 客户端如何统一访问多个接口服务?

四、微服务架构框架

4.1主流的微服务架构框架

  • Dubbo(阿里、开源apache):2012年推出、2014年停更、2015年又继续更新
  • Dubbox(当当网基于Dubbo的更新)
  • jd-hydra(京东基于Dubbo的更新)
  • SpringCloud Netfix
  • ServiceComb(CSE)华为2017年

4.2 SpringCloud简介

SpringCloud是一个基于SpringBoot实现的微服务架构应用开发框架,它为我们进行微服务架构应用开发提供了服务注册与发现、熔断器、网关路由、配置管理、负载均衡、消息总线、数据监控等一系列工具。

  • SpringCloud比较成熟的两个体系:

    • Spring Cloud Netflix

    • Spring Cloud Alibaba

4.3 Spring Cloud 核心组件

  • Spring Cloud Netflix

    • Eureka 服务注册与发现中心,用于服务治理
    • Ribbon:服务访问组件、进行服务调用,实现了负载均衡
    • Hystrix:熔断器,服务容错管理
    • Feign:服务访问组件(对Ribbon和Hystrix封装)
    • zuul:网关组件
  • Spring Cloud Config配置管理的组件 ---- 分布式配置中心

  • Spring Cloud Bus 消息总线

  • Spring Cloud CXonsul 服务注册与发现中心(功能类似Eureka)

4.4 SpringCloud 版本介绍

  • SpringCloud:A-H,2020.0.2
  • SpringCloud 版本对SpringBoot版本是有依赖的
    • A ---- 1.2
    • B ---- 1.3
    • C ---- 1.4
    • D ---- 1.5
    • F - G - H ---- 2.x+

五、搭建服务注册与发现中心

使用Spring Cloud Netflix 组件中的Eureka 搭建服务注册与发现中心

5.1 创建SpringBoot应用,添加依赖

  • spring web
  • eureka server

5.2 配置服务注册与发现中心

server:
  port: 8761

spring:
  application:
    name: service-eureka
eureka:
  client:
    service-url:
      defaultzone: http://192.168.43.223:8761/eureka
    register-with-eureka: false
    fetch-registry: false

5.3 在启动类中添加 @EnableEurekaServer 注解

package com.luo.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class ServiceEurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceEurekaApplication.class, args);
    }
}

5.4 运行及访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j6SqYIZy-1662558983807)(/Users/gen_hua/Desktop/Java_note/Markdown/服务与注册.png)]

六、服务注册

创建保存订单的服务(order-add)注册到服务注册中心

6.1 创建SpringBoot应用

创建Spring Boot 应用,完成功能开发

6.2 注册服务

将能够完成特点业务的Spring Boot 应用作为服务提供者,注册到服务注册与发现中心

6.2.1 添加依赖

  • eureka-server 【注意版本】
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

6.2.2 配置application.yml

## 当前服务的服务端口
server:
  port: 9001

## 当前服务的服务应用名,会作为服务唯一表示注册到eureke
spring:
  application:
    name: order-add
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_2010_sc?characterEncoding-utf-8
    username: root
    password: root

mybatis:
  mapper-locations: classpath:mappers/*
  type-aliases-package: com.luo.order.beans

## 配置Eureka服务注册与发现的地址
eureka:
  client:
    service-url:
      defaultzone: http://localhost:8761/eureka

6.2.3 在当前服务应用启动类添加注解

package com.luo.order;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@MapperScan("com.luo.order.dao")
@EnableEurekaClient
public class OrderAddApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderAddApplication.class, args);
    }
}

九、服务发现-Feign

9.1 基础配置

9.1.1 创建SpringBoot应用,添加依赖

  • spring web
  • eureka server
  • OpenFeign

9.1.2 配置application.yml

server:
  port: 8002

spring:
  application:
    name: api-order-add-feign

eureka:
  client:
    service-url:
      defaultzone: http://localhost:8761/eureka

9.1.3 在启动类添加注解

  • @EnableDiscoveryClient // 声明为服务消费者
  • @EableFeignClients // 声明启用feign客户端
package com.luo.api.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient   // 声明为服务消费者
@EnableFeignClients      // 声明启用feign客户端
public class ApiOrderAddFeignApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiOrderAddFeignApplication.class, args);
    }
}

9.2 服务调用

进行Feign进行服务调用的时候,需要手动创建一个服务访问客户端(接口)

9.2.1 创建Feign客户端

@FeignClient("order-add")   //代表需要访问的服务客户端
public interface OrderAddClient {

    @PostMapping("order/add")
    public ResultVO addOrder(Order order);
}

9.2.2 使用Feign客户端调用服务

@Service
public class OrderServiceImpl implements OrderAddService {

  
  	// 就是上面的这个接口
    @Autowired
    private OrderAddClient orderAddClient;


    @Override
    public ResultVO saveOrder(Order order) {

        ResultVO resultVO = orderAddClient.addOrder(order);

        return resultVO;
    }
}

9.3 Feign传参

9.3.1 POST请求

  • 通过请求体传递对象

    • 服务提供者
    @PostMapping("/add")
    public ResultVO addOrder(@RequestBody Order order){
    
      System.out.println("order/add/进来了。。。。。。。。。。。。。。。。。");
      System.out.println(order);
      return orderService.saveOrder(order);
    }
    
    • 服务调用者(Feign客户端)
    @FeignClient("order-add")
    public interface OrderAddClient {
    
      @PostMapping("order/add")
      public ResultVO addOrder(Order order);
    }
    
  • 通过请求行传值

    • 服务提供者
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @Autowired
        private OrderService orderService;
    
        @PostMapping("/add")
        public ResultVO addOrder(@RequestBody Order order,String str){
    
            System.out.println("order/add/进来了。。。。。。。。。。。。。。。。。");
            System.out.println(order);
            System.out.println(str);
    
            return orderService.saveOrder(order);
        }
    }
    
    • 服务调用者(Feign客户端)
    @FeignClient("order-add")
    public interface OrderAddClient {
    
        //1、对于post调用服务,Feign客户端的方法参数默认为body传值,body每次只能有一个值
        //2、如果有多个参数,则需要 @RequestParam 声明参数为请求行传值
        @PostMapping("order/add")
        public ResultVO addOrder(Order order,@RequestParam("str") String str);
    }
    

9.3.2 Get请求

Get请求调用服务,只能通过url传参

在Feign客户端的方法中,如果不指定参数的传值方式,则默认为body传参,Get请求也不列为,因此对于Get传递参数,必须通过@RequestParam注解声明

  • 服务提供者
@RestController
@RequestMapping("/order")
public class OrderController {

  @GetMapping("/get")
  public Order getOrder(String orderId){
    System.out.println(orderId);
    return new Order();
  }
}
  • 服务消费者(Feign客户端中)
@FeignClient("order-add")
public interface OrderAddClient {

  //必须加上 @RequestParam 注解才能传参
  @GetMapping("order/get")
  public Order getOrder(@RequestParam("orderId") String orderId);
}

十、服务注册与发现中心的可靠性和安全性

10.1 可靠性

在微服务的系统架构中,服务消费者是通过服务注册与发现中心发现服务、调用服务的,服务注册与发现中心服务器一旦挂掉,将会导致整个微服务架构系统的崩溃,如何保证Eureka的可靠性呢

  • 使用eureka集群

Eureka集群搭建

相互注册、相互发现

server:
  port: 8761

spring:
  application:
    name: service-eureka
eureka:
  client:
    service-url:
    	# 这里的 url 填写对方的url,就是把本Eureka搭建到对方的Eureka ,然后对方的 IP 写我的
      defaultZone: http://192.168.43.223:8761/eureka    

10.2 安全性

当完成 Eureka 的搭建之后,只要知道ip和端口就可以随意的注册服务、调用服务,这时不安全的,我们可以通过设置账号和密码来限制服务的注册及发现。

  • 在eureka中中和Spring Security安全框架实现账号和密码验证

10.2.1 添加SpringSecurity依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
  <version>2.7.3</version>
</dependency>

10.2.2 设置访问eureka的账号和密码

spring:
  security:
    user:
      name: luo
      password: 123456

10.2.3 配置Spring Security

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception{
    http.csrf().disable();

    //设置当前服务器的所有请求都要使用springsecurity的认证
    http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
  }
}

10.2.4 服务提供者和服务消费者连接到注册中心都要账号和密码

eureka:
  client:
    service-url:
      defaultZone: http://luo:123456@localhost:8761/eureka

十一、熔断器-Hystrix

服务故障的雪崩效应:当A服务调用B服务时,由于B服务的故障导致A服务处于阻塞状态,当量的请求可能会导致A服务因资源耗尽而出现故障

为了解决故障里的雪崩效应,出现了熔断器模型

在服务消费者A服务加入熔断器,如果B服务出现故障且频率达到一个特定的阈值,熔断器就断开,熔断器一但断开,服务消费者A服务在接收用户请求时将不在调用B服务,从而减少请求在A服务的阻塞

熔断器的作用:

  • 服务降级:用户请求A服务,A服务调用B服务,当B服务出现故障或者在特定的时间段内不能给A服务响应,为了避免A服务因等待B服务而产生阻塞,A服务就不等B服务的结果了,直接给用户一个降级响应
  • 服务熔断:用户请求A服务,A服务调用B服务,当B服务出现故障的频率过高达到特定阈值(5s 20次)时,当用户再请求A服务时,A服务将不再调用B服务,直接给用户一个降级响应

11.2 熔断器的原理

  1. 熔断器默认闭合(close)状态,当用户请求A服务时,A服务调用B服务,如果B服务在设定的时间不能给A服务响应,A服务则使用降级方案响应,同时记录B服务的故障
  2. 当B服务的故障率达到阈值(Hystrix默认 5s/20次),熔断器就会被断开,进入‘打开’状态
  3. 当熔断器为‘打开’状态时,用户请求A服务,A服务不在调用B服务,而是直接进行降级响应
  4. 状态为‘打开’状态的熔断器经过一个时间周期后会进入到‘半开’的状态
  5. 当熔断器为‘半开’状态时,当用户请求A服务时,A服务会对B服务进行一次调用,如果B成功响应A服务,熔断器则进入闭合状态,如果B服务响应失败,熔断器则回到‘打开’状态,再进入到下一个周期的熔断

11.3基于Feign服务调用的熔断使用

Feign是基于Ribbon和Hysgrix的封装

11.3.1 配置熔断器

  • 添加依赖
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>2.2.10.RELEASE</version>
</dependency>
  • 在application.yml启用熔断机制
feign:
  hystrix:
    enable: true
  • 在启动类中添加 @EnableHystrix 注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients

@EnableHystrix
public class ApiOrderAddFeignApplication {

  public static void main(String[] args) {
    SpringApplication.run(ApiOrderAddFeignApplication.class, args);
  }
}
  • 创建服务降级处理类
package com.luo.api.order.serice.fallback;

import com.luo.beans.Order;
import com.luo.vo.ResultVO;
import org.springframework.stereotype.Component;

@Component
public class OrderAddClientFallback {


    public ResultVO addOrder(Order order, String str) {
        System.out.println("--------------addOrder 的降级服务");
        return ResultVO.fail("调用失败",null);
    }

    public Order getOrder(String orderId) {
        System.out.println("--------------getOrder 的降级服务");

        return new Order();
    }
}
  • 在Feign客户端指定降级处理类 加上@FeignClient(value = “order-add”,fallback= OrderAddClientFallback.class)
@FeignClient(value = "order-add",fallback= OrderAddClientFallback.class)
public interface OrderAddClient {

  //1、对于post调用服务,Feign客户端的方法参数默认为body传值,body每次只能有一个值
  //2、如果有多个参数,则需要 @RequestParam 声明参数为请求行传值
  @PostMapping("order/add")
  public ResultVO addOrder(Order order,@RequestParam("str") String str);

  @GetMapping("order/get")
  public Order getOrder(@RequestParam("orderId") String orderId);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值