0%

Spring cloud微服务

Spring Cloud

微服务产生的背景

单体应用存在的问题

  • 随着业务的发展,开发变得越来越复杂。
  • 修改、新增某个功能,需要对整个系统进行测试,重新部署。
  • 一个模块出现问题,很可能导致整个系统崩溃。
  • 多团队同时对数据进行管理,容易产生安全漏洞。
  • 各个模块使用同一种技术框架,局限性太大,很难根据业务选择最适合的技术架构。
  • 模块内容太复杂,如果员工离职,可能需要很长时间才能完成任务交接。

为了解决上述问题,微服务架构应运而生,简单来说,微服务就是将一个单体应用拆分成若干个小型服务,协同完成系统功能的一种架构模式,在系统架构层面进行解耦合,将一个复杂问题拆分成若干个简单问题。
这样的好处是对于每一个简单问题,开发、维护部署的难度就降低了很多,可以实现自治,可以自主选择最适合的技术框架,提高了项目开发的灵活性。
微服务架构不仅是简单的拆分,拆分之后的各个微服务之间还要进行通信,否则就无法协同完成需求。
微服务之间只需要制定统一的协议即可,至于每个微服务使用什么技术框架来完成,统统不需要关心。
这种松耦合的方式使开发、部署都变得更加灵活,同时系统更容易拓展,降低了开发、运维的难度。

微服务的优点

  • 各个服务之间实现了松耦合,彼此之间不需要关注对方是用什么语言开发,什么技术开发,只需要保证自己的接口可以正常访问即可,通过标准协议访问其他接口即可。
  • 各个微服务之间独立自治,只需要专注于做好自己的业务,开发和维护不会影响到其他的微服务。
  • 微服务是一种去中心化的架构方式,相当于用零件拼接一台机器,如果某个零件出现问题,可以随时进行替换,从而保证机器的正常运行。

微服务的不足

  • 如果某个系统的远程调用出现问题,导致微服务不可用,就有可能产生级联反应,造成整个系统的崩溃。
  • 如果某个需求需要调用多个微服务,如何来保证数据的一致性。
  • 相比较与单体应用,微服务的学习难度会增加,对于新加入团队的员工来讲,如何快速掌握上手微服务架构,是一个问题。

微服务设计原则

从大到小,提炼出核心需求,搞清楚服务间的交互关系,先拆分成粒度较大的服务,然后再根据具体的业务需求逐步细化服务粒度,最终形成一套合理的微服务系统架构。

  • 服务粒度不能太小也不能太大,提炼核心需求,根据服务间的交互关系找到最合理的服务粒度。
  • 各个微服务的功能和职责尽量单一,避免出现多个服务处理同一个需求。
  • 各个微服务之间要相互独立、自治,自主开发、自主测试、自主部署、自主维护。
  • 保证数据的独立性,各个微服务独立管理其业务模型下的数据。
  • 使用RESTful协议完成微服务之间的写作任务,数据交互采用JSON格式,方便调用和整合。

微服务架构的核心组件

  • 服务治理
    • 服务注册
    • 服务发现

提供服务的叫做服务提供者。调用服务的叫做服务消费者。

  • 服务负载均衡
  • 服务网关
  • 微服务容错机制
  • 分布式配置
  • 服务监控

解决方案

Spring Cloud
微服务是一种分布式软件架构设计方式,具体的落地方案有很多,Dubbo、Spring Boot/Spring Cloud、Motan等等,Spring Cloud基于Spring Boot使得整体的开发、配置、部署都非常方便,可以快速搭建基于微服务的分布式应用,Spring Cloud相当于微服务各个组件的集大成者。

Spring Boot和Spring Cloud的关系

Spring Boot快速搭建基础系统,Spring Cloud在此基础上实现分布式系统中的公共组件,如服务注册、服务发现、配置管理、熔断器、控制总线等,服务调用方式是基于REST API。


搭建微服务系统的核心中枢

服务治理的核心组件:

  • 服务提供者
  • 服务消费者
  • 注册中心

分布式系统架构中,每个微服务在启动时,将自己的信息存储再注册中心,服务注册

服务消费者从注册中心查询服务提供者的网络信息,并通过此信息调用服务提供者的接口,服务发现

注册中心管理各个微服务:通过心跳机制,每隔一定的时间微服务会向注册中心进行汇报,如果注册中心长时间无法与某个微服务通信,就会自动销毁该服务。

当某个微服务的网络信息发生变化是,也会重新注册。

服务提供者、服务消费者、注册中心的关联:

  • 启动注册中心
  • 服务提供者启动时,在注册中心可注册一个可以提供服务的实例。
  • 服务消费者启动,在注册中心订阅需要调用的服务。
  • 注册中心将服务提供者的信息推送给服务消费者。
  • 服务消费者通过相关信息(IP、端口)调用服务提供者的服务。

注册中心核心模块

  • 服务注册表
  • 服务注册
  • 服务发现
  • 服务检查(通过心跳机制完成各个微服务之间的通信)

Spring Cloud的服务治理可以使用Eureka组件。

什么是Eureka?

Spring Cloud Eureka,提供服务注册和服务发现的功能。

Spring Cloud Eureka的组成

Eureka Server 服务端
Eureka Client 客户端

代码实现

  1. 创建Maven父工程,pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.sfx</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.1.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>
  1. 在父工程目录下创建Module,实现Eureka Server,pom.xml。
<dependencies>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

</dependencies>
  1. application.yml
server:
  port: 8761
eureka:
  client:
#    是否将当前的eureka服务作为客户端注册进去(是否注册自己)
    register-with-eureka: false
#    获取其他eureka数据信息
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/
  1. 创建启动类
package com.sfx;


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

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
}
  1. 启动,访问 http://localhost:8761 ,可以看到如下界面,启动成功。

注册第一个微服务

服务提供者和服务消费者都是通过Eureka Client连接到Eureka Server完成注册。

1.创建Modelu,实现Eureka Clinet。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

</dependencies>
  1. application.yml
server:
  port: 8010
spring:
  application:
    name: provider

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
instance:
#      是否注册ip地址
    prefer-ip-address: true
  1. 创建启动类
package com.sfx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}
  1. 创建实体类
package com.sfx.entity;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Student {
    private Integer id;
    private String name;
}
  1. 创建Repository

接口

package com.sfx.repository;

import com.sfx.entity.Student;

import java.util.Collection;

public interface StudentRepository {
    public Collection<Student> findAll();
    public Student findById(Integer id);
    public void saveOrUpdate(Student student);
    public void deleteById(Integer id);
}

实现类

package com.sfx.repository.impl;

import com.sfx.entity.Student;
import com.sfx.repository.StudentRepository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class StudentRepositoryImpl implements StudentRepository {

    private static Map<Integer,Student> map;
    static {
        map = new HashMap<>();
        map.put(1,new Student(1,"张三"));
        map.put(2,new Student(2,"李四"));
        map.put(3,new Student(3,"王五"));
    }

    @Override
    public Collection<Student> findAll() {
        return map.values();
    }

    @Override
    public Student findById(Integer id) {
        return map.get(id);
    }

    @Override
    public void saveOrUpdate(Student student) {
        map.put(student.getId(),student);
    }

    @Override
    public void deleteById(Integer id) {
        map.remove(id);
    }
}
  1. StudentHandler
package com.sfx.controller;

import com.sfx.entity.Student;
import com.sfx.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/provider")
public class StudentHandler {
    @Autowired
    private StudentRepository studentRepository;
    
    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return studentRepository.findAll();
    }
    
    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") Integer id){
        return studentRepository.findById(id);
    }
    
    
    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }
    
    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }
    
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        studentRepository.deleteById(id);
    }
}

接口测试


RestTemplate

通过RestTemplate可以实现不同微服务之间的调用。

RestTemplate是Spring框架提供的一种基于RESTful的服务组件,底层对HTTP请求及相应进行了封装,提供了很多访问远程REST服务的方法,可以简化代码的开发。

如何使用RestTemplate

  1. 创建Maven工程,pom.xml
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.7.3</version>
    </parent>
    
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        
    </dependencies>
  2. 创建User类