Java学习Day57:碧水金睛兽!(Spring Cloud微服务1.0)

1.微服务入门

(1).单体架构与分布式架构

单体架构: 将业务的所有功能集中在一个项目中开发,打成一个包部署
优点: 架构简单、部署成本低 ; 缺点: 耦合度
项目打包部署到Tomcat,用户直接访问。用户量增加后就多部署几台服务器形成集群。随着互联网发展、一个APP或Web通常都用有相当多的模块,因此出现了 分布式架构
分布式架构: 根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。
优点: 降低服务耦合、有利于服务升级拓展 ;

(2).微服务

微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:

单一职责: 微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发

面向服务: 微服务对外暴露业务接口

(由于不同模块部署在不同服务器、无法直接调用)

自治: 队独立、技术独立、数据独立、部署独立

隔离性强: 服务调用做好隔离、容错、降级,避免出现级联问题

(避免某个模块宕机造成影响)

单体架构特点?

简单方便,高度耦合,扩展性差,适合小型项目。例如: 学生管理系统

分布式架构特点?

松耦合,扩展性好,但架构复杂,难度大。适合大型互联网项目,例如:京东、淘宝

微服务:一种良好的分布式架构方案

优点: 拆分粒度更小、服务更独立、耦合度更低缺点:架构非常复杂,运维、监控、部署难度提高

2.服务拆分及远程调用

java 复制代码
1.不同微服务,不要重复开发相同业务
2.微服务数据独立,不要访问其它微服务的数据库
3.微服务可以将自己的业务暴露为接口,供其它微服务调用
css 复制代码
1.基于RestTemplate发起的http请求实现远程调用
2.http请求做远程调用是与语言无关的调用,只要知道对方的ip、端口、接口路径、请求参数即可。

(1).提供者与消费者

服务提供者: 一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
服务消费者: 一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)

一个服务既可以是提供者也可以是消费者,要根据具体的业务和情况来判断

我们服务在请求服务的时候,restTemplate访问的地址是固定的。 可在实际开发中通常都会有好几个环境,开发,测试等等环境。每个环境的地址都在变化 因此出现了几个问题:

1.服务消费者该如何获取服务提供者的地址信息?

2.如果有多个服务提供者,消费者该如何选择?

(2).微服务远程调用Demo

在父模块指定了父 POM

css 复制代码
<parent>
        <groupId>org.springframework.boot</groupId>
        <version>3.1.0</version>
        <artifactId>spring-boot-starter-parent</artifactId>
    </parent>
css 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2
    username: root
    password: 123456
mybatis:
  type-aliases-package: com.home.pojo
  configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

server:
  port: 8088

provider实现controller层,services层,和Mapper层,pojo

java 复制代码
@RestController
@RequestMapping("/user")
public class userController {
    @Autowired
    userServices userServices;
    @RequestMapping("/findAll")
    public usersss findall(){
        return userServices.findAll();
    }
}

consumr层只用实现controller层和pojo

java 复制代码
@RestController
@RequestMapping("/a")
public class usersssController {
    @Autowired
    RestTemplate restTemplate;
    @RequestMapping("/b")
    public usersss findAll(){
        usersss userssses= restTemplate.getForObject("http://localhost:8088/user/findAll",usersss.class);
        return userssses;
    }
}
复制代码
usersss userssses= restTemplate.getForObject("http://localhost:8088/user/findAll",usersss.class);

3.注册中心 Spring Cloud Eureka

Spirng Cloud Eureka使用Netflix Eureka来实现服务注册与发现(服务治理)。 它既包含了服务端组件,也包含了客户端组件,并且服务端与客户端均采用java编写,所以Eureka主要适用于通过java实现的分布式系统,或是JVM兼容语言构建的分布式系统。

**Eureka服务端组件:**即服务注册中心。它同其他服务注册中心一样,支持高可用配置。依托于强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。

**Eureka客户端组件:**主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。在应用程序启动时,Eureka客户端向服务注册中心注册自身提供的服务,并周期性的发送心跳来更新它的服务租约。同时,他也能从服务端查询当前注册的服务信息并把它们缓存到本地,并周期性的刷新服务状态。

注册中心保存提供者提供的服务

客户消费者定期拉去服务列表,需要的话就调用服务提供者,加入IP和端口变化,消费者再拉去一次新的信息即可;

对于注册中心来说,Client和Services都是我的客户端,但是等Client调用Services的时候,Services就是客户端,Client就是服务端;

心跳检测请求是注册中心用来检测服务提供端是否健在的主要依据

1. 整合注册中心Eureka

步骤分三步:

  • 第一步:搭建eureka服务,创建eureka_server工程

  • 第二步:服务提供者provider_service,注册到eureka注册中心

  • 第三步:服务消费者consumer_service,注册到eureka注册中心

4.NACOS

4.1 搭建eureka-server工程

1.创建eureka_server的springboot工程。

2.添加依赖

java 复制代码
<properties>
        <spring-cloud.version>2022.0.5</spring-cloud.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>eureka_server</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

3.在启动类EurekaServerApplication声明当前应用为Eureka服务使用@EnableEurekaServer注解

java 复制代码
@SpringBootApplication
@EnableEurekaServer
public class springBootEurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(springBootEurekaServer.class,args);
    }
}

4.编写配置文件application.yml

html 复制代码
server:
  port: 8080
spring:
  application:
    name: consumer
# 注册中心地址
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka
    registry-fetch-interval-seconds: 30

5.启动EurekaServerApplication

6.测试访问地址http://127.0.0.1:8761,如下信息代表访问成功

4.2 服务提供者-注册到eureka

复制代码
<properties>
    <spring-cloud.version>2022.0.5</spring-cloud.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
\<project.build.sourceEncoding\>UTF-8\</project.build.sourceEncoding\>
</properties>
复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        \<artifactId\>spring-cloud-starter-netflix-eureka-client\</artifactId\>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
       \<dependency\>
\<groupId\>org.springframework.cloud\</groupId\>
\<artifactId\>spring-cloud-dependencies\</artifactId\>
\<version\>${spring-cloud.version}\</version\>
\<type\>pom\</type\>
\<scope\>import\</scope\>
\</dependency\>
    </dependencies>
</dependencyManagement>
复制代码
@SpringBootApplication
@EnableDiscoveryClient
public class springBootProvider {
    public static void main(String[] args) {
        SpringApplication.run(springBootProvider.class,args);
    }
}
复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2
    username: root
    password: 123456
application:
name: providerServer
mybatis:
  type-aliases-package: com.home.pojo
  configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

server:
  port: 8088
#配置eureka注册中心的地址
# 注册中心地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka
# 租约续约间隔时间,默认30秒
  eureka:
    instance:
      lease-renewal-interval-in-seconds: 30

4.3服务消费者-注册到eureka

复制代码
<properties>
    <spring-cloud.version>2022.0.5</spring-cloud.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--当前的项目,是eureka的客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
<!--SpringCloud,BOM,依赖清单导入,所有依赖管理的坐标-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
复制代码
@SpringBootApplication
@EnableDiscoveryClient
public class springBootConsumerStarter {
    public static void main(String[] args) {
        SpringApplication.run(springBootConsumerStarter.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
复制代码
server:
  port: 8080
spring:
  application:
    name: consumer
# 注册中心地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka
registry-fetch-interval-seconds: 30

4.4消费者通过Eureka访问提供者

java 复制代码
@RestController
@RequestMapping("/a")
public class usersssController {
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/b")
    public usersss findAll(){
//discoveryClient 可以拉取注册中心中服务列表
        //getInstances(服务名),当前服务只有1个,返回值是List集合,获取0索引服务对象
        ServiceInstance instance = discoveryClient.getInstances("PROVIDERSERVER").get(0);
        //instance服务对象的实例。获取服务提供者的IP,端口号
        String host = instance.getHost();
        int port = instance.getPort();
        return restTemplate.getForObject("http://"+host+":"+port+"/user/findAll", usersss.class);
    }
}

租约续约间隔时间,默认30秒

eureka.instance.lease-renewal-interval-in-seconds: 30

每过30s注册中心查看服务端是否续租

每隔多久获取服务中心列表,(只读备份)

eureka.client.registry-fetch-interval-seconds: 30

每隔30s客户端拉去服务列表

5、SpringCloud Alibaba(Nacos)

5.1 Nacos和Eureka的特点

Eureka的优点包括:

1、简单易用:Eureka框架非常简单易用,便于快速上手和部署。

2、高可用性:Eureka支持多节点部署,并会自动将失效的节点剔除,确保整个系统的高可用性和弹性。

3、动态扩展性:Eureka可以根据实际需求进行扩展,通过添加新的服务提供者可以很容易地增加应用程序的处理能力。

4、易于集成:Eureka可以与Spring Cloud等流行的微服务框架进行无缝集成,从而提供更完善的微服务体系支持。

Eureka的不足之处:

1、Eureka Server 为单点故障问题,虽然可以通过多节点部署来优化和缓解,但是在高并发场景下仍可能成为限制系统扩展的瓶颈。

2、Eureka的服务注册中心本身也需要高可用环境,一旦出现问题,可能影响到整个微服务的正常运行。
Nacos的优点包括:

1、高可用性:Nacos支持多节点部署,通过选举算法实现了高可用和故障转移能力,在节点宕机或网络异常情况下仍能保证整个系统的稳定运行。

2、动态扩展性:Nacos可以根据实际需求进行快速扩展和缩容,支持集群、多数据中心、地域感知等特性。

3、完备的功能支持:Nacos支持服务注册与发现、配置管理、流量管理、DNS解析、存储KV对等功能,并且提供了Web界面和RESTful API等多种方式来使用这些功能。

4、易于集成:Nacos提供了多种语言和框架的集成方案,并且支持Spring Cloud等流行的微服务框架。

总的来说,Nacos是一个功能齐全、易于使用和高可用的分布式服务治理平台,可以为分布式系统提供高效、稳定的运行环境。

5.2 Nacos消费者

使用SpringBoot创建项目,搭建提供者服务(user-service)和消费者服务(consumer-service)。

  1. 创建项目user-service

    1. 执行创建数据库表,sql脚本

    2. 搭建三层架构Mapper、Service、Controller,创建根据id查询用户接口

    3. 配置user-service服务

    4. 启动2个端口9091、9092服务,并测试服务user-service

  2. 创建项目consumer-service

    1. 配置RestTemplate对象,注入Spring容器

    2. 搭建service层和controller层,通过RestTemplate对象发送请求访问提供者接口

    3. 测试消费者服务consumer-service

java 复制代码
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
java 复制代码
 <!--SpringCloud,BOM,依赖清单导入,所有依赖管理的坐标-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


        </dependencies>
    </dependencyManagement>
java 复制代码
@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("queryUserById")
    public User queryUserById(Integer id){
        return userService.queryUserById(id);
    }
}
java 复制代码
@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Override
    public User queryUserById(Integer id) {

        List<ServiceInstance> instances = discoveryClient.getInstances("provider_user");
        ServiceInstance serviceInstance = instances.get(0);
        String url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort();
        System.out.println("url = " + "http://"+url);

        User user = restTemplate.getForObject(url+"/user/queryUserById?id=" + id, User.class);
        return user;
    }
}
复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2
    username: root
    password: 123456
  application:
    name: providerNacos
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
mybatis:
  type-aliases-package: com.home.pojo
  configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5.3 Nacos服务者

复制代码
<properties>
    <spring-cloud.version>2022.0.5</spring-cloud.version>
    <spring.cloud.alibaba.version>2022.0.0.0</spring.cloud.alibaba.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
java 复制代码
@RestController
@RequestMapping("/a")
public class usersssController {
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/b/{id}")
    public usersss findAll(@PathVariable("id") Integer id){
//discoveryClient 可以拉取注册中心中服务列表
        //getInstances(服务名),当前服务只有1个,返回值是List集合,获取0索引服务对象
//        ServiceInstance instance = discoveryClient.getInstances("providerNacos").get(0);
        //instance服务对象的实例。获取服务提供者的IP,端口号
//        String host = instance.getHost();
//        int port = instance.getPort();
        return restTemplate.getForObject("http://providerNacos/user/findAll/"+id, usersss.class);
    }
}
复制代码
server:
  port: 8080
spring:
  application:
    name: consumerNacos
# 注册中心地址
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

6.负载均衡

将任务均匀分配

java 复制代码
     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

server:

port: ${port:9091}

构建集群

java 复制代码
@RestController
@RequestMapping("/user")
public class userController {
    @Autowired
    home.services.userServices userServices;
    @Value("${server.port}")
    private Integer port;
    @GetMapping("/findAll/{id}")
    public usersss findall(@PathVariable("id") Integer id){
        usersss usersss1= userServices.findAll(id);
        usersss1.setPort(port);
        return usersss1;
    }
}

6.1 修改负责均衡算法

public class CustomLoadBalancerConfiguration {

@Bean

ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {

String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);

}

}
@Configuration

@LoadBalancerClients(value = {

@LoadBalancerClient(name = "providerUser" , configuration = CustomLoadBalancerConfiguration.class) // 将负载均衡算法应用到指定的服务提供方中

})

public class RestTemplateConfiguration {

@Bean

@LoadBalanced // 让RestTemplate具有负载均衡的能力

public RestTemplate restTemplate() {

return new RestTemplate() ;

}

}

负载均衡算法可以改变调用顺序;

相关推荐
simple_ssn5 分钟前
汇编学习笔记
汇编·笔记·学习
van叶~5 分钟前
仓颉语言实战——2.名字、作用域、变量、修饰符
android·java·javascript·仓颉
张声录19 分钟前
【ETCD】【实操篇(十九)】ETCD基准测试实战
java·数据库·etcd
鱼香鱼香rose34 分钟前
面经hwl
java·服务器·数据库
新手小袁_J37 分钟前
java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigur
java·开发语言·spring·spring cloud·bootstrap·maven·mybatis
墨鸦_Cormorant37 分钟前
Java 创建图形用户界面(GUI)组件详解之下拉式菜单(JMenu、JMenuItem)、弹出式菜单(JPopupMenu)等
java·开发语言·gui
cccccc语言我来了38 分钟前
c++-----------------多态
java·开发语言·c++
南鸢1.040 分钟前
11张思维导图带你快速学习java
java·开发语言
墨鸦_Cormorant40 分钟前
JDK 8 升级 17 及 springboot 2.x 升级 3.x 指南
java·spring boot
ACGkaka_41 分钟前
IDEA 编译报错 “java: 常量字符串过长” 的解决办法
java·ide·intellij-idea