Springcloud-实用篇-1

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: Springcloud-实用篇-1

一、微服务

1.1 微服务技术栈

  • 服务集群:将单独的每一个功能,独立开发,独立部署,最后形成一个单独的服务,一旦这样的服务越来越多,就会形成一个服务集群。


注册中西:记录每个服务的ip、端口、以及每个服务的实现功能,多个单体服务之间的信息直接从注册中心进行拉取。

配置中心:当服务集群越来越多,就需要到配置中心,当需要修改某个服务时,只需要到配置中心进行修改即可,一旦配置中心更新,就会通知对应的单体服务进行热更新。

服务网关:可以对用户进行身份校验,统一的请求路由,然后在服务器上查询数据库,查到则返回给用户

分布式缓存:一种将数据存储在内存中的缓存技术,它可以存储一些用户经常需要用的数据,以提高访问速度。

分布式搜索:将搜索服务拆分成多个服务,将搜索结果集合并后返回给客户端,从而满足大量查询和高并发请求的需求。

消息队列:是分布式系统中常见的数据结构,它可以存储和转发消息,处理服务间的异步通信。因为微服务通常是独立部署的小型服务,它们需要通过消息队列来进行通信。

例如,一个服务可能需要将某些任务交给另一个服务来处理。在这种情况下,它可以将任务发送到消息队列中,并且另一个服务可以异步地从队列中消费这些任务

使用消息队列好处,包括解耦、异步和削峰。

消息队列可以用于解耦服务间的通信,使得服务能够独立进化。

通过异步通信,一个服务不需要等待另一个服务完成它的工作,从而提高了整个系统的响应速度和吞吐量。

对于请求流量的突发性增加,消息队列还可以用于削峰,使得系统能够更好地处理请求。

分布式日志服务:将分散在不同服务中产生的日志(运行日志、报错日志等)收集到一个中心化的地方进行存储和管理,以便于应用开发人员快速检索和定位问题。

系统监控链路追踪:针对分布式系统下的调用链路进行的监控。它能够跟踪系统中各个服务之间的调用,记录下每个服务的处理时间、请求状态,以及请求具体到达哪台机器上等信息。通过链路追踪,我们可以更好地了解整个服务调用的流程,快速定位问题,并对服务进行优化。链路追踪工具有很多,如Zipkin、Skywalking等。

Jenkins是一个开源的自动化服务器,它可以帮助软件开发人员自动化构建、测试和部署等与软件开发相关的流程,从而实现持续集成和持续交付。它是一个基于服务器的系统,可以运行在像Apache Tomcat这样的servlet容器中。

1.3 微服务技术栈分类

二、微服务架构

2.1 微服务架构的演变

2.1.1 单体架构

所有功能集中在一个项目种开发,打包部署

优点:

  • 架构简单
  • 部署成本低

缺点:

  • 耦合度高,模块关联太多

2.1.2 分布式架构


根据业务功能对系统进行拆分,每个业务模块单独开发

优点:

  • 降低服务耦合
  • 有利于服务升级扩展

缺点:

  • 服务拆分粒度如何?
  • 服务集群地址如何维护?
  • 服务之间如何实现远程调用?
  • 服务健康状态如何感知?



7680b75228d74ae5fc04655590be42b8.png



2.1.3 微服务


分布式架构的优化设计方案

  • 单一职责:拆分粒度更小,每一个服务对应唯一的业务能力
  • 面向服务:微服务对外的业务接口
  • 自治:团队独立、技术独立、数据独立、部署独立
  • 隔离性强:服务调用做好隔离、容错、降级、避免出现级联问题
  • 架构赋值、运维、监控、部署难度提高


2.2 微服务技术对比


2.2.1 技术选择

三、Springcloud

官网


SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配

SpringCloud与Springboot版本兼容

3.1 服务拆分及远程调用


3.1.1 拆分原则

  • 不同微服务,不要重复开发相同业务
  • 微服务数据独立,不要访问到其他微服务的数据库
  • 暴露自己的业务接口,让其他微服务调用


2884ea614bdc73f35f2c15c48aee1fd6.png


3.1.2 案例说明

项目结构:

将demo跑起来


3.2 拆分总结

  1. 微服务需要根据业务模块拆分,做到单一职责,不要重复开发相同业务
  2. 微服务可以将业务暴露为接口,供其它微服务使用
  3. 不同微服务都应该有自己独立的数据库


3.3 案例:根据订单id查询订单功能

需求:根据订单id查询订单的同时,把订单所属的用户信息一起返回

目前情况:


  • 订单信息只能查询到订单数据库信息
  • 用户信息只能查询到用户数据库信息
  • 两者之间毫无关联

3.4 远程调用方式


使用远程调用方式查询到用户信息

可以使用RestTemplate发送请求, RestTemplate 是发送各种HTTP请求,那么就可以使用 RestTemplate 发起远程http请求:

order_service 模块中的启动配置类中:

    /**
     * 在启动配置类注入 RestTemplate bean容器
     * @return
     */
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


修改查询实现方法:

    @Autowired
    private RestTemplate restTemplate;
    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2利用RestTemplate发送Http请求,查询用户
        // 2.1 url的地址为user-service模块启动的端口,因为是向user-service发送请求
        String url = "http://localhost:8081/user/" + order.getUserId();
        // 发送请求,完成远程调用
        User user = restTemplate.getForObject(url, User.class);
        // 封装user
        order.setUser(user);
        // 4.返回
        return order;
    }
}



3.4.1 消费者与提供者


提供者:一次业务种,被其他微服务调用的服务 (提供接口给其他微服务,接口被调用了)


消费者:一次业务种,调用其他微服务的服务(调用其他微服务提供的接口,调用别人的接口)


上面的demo中,user就是服务提供者(接口被调用),order就是服务消费者(调用了别人的接口)


e841671550f00e97b576baf729943230.png


思考:服务A调用服务B,服务B调用服务C,那么服务B是什么角色?主要是要看怎么调用

  1. 如果是服务B调用了服务C,那么服务B就是服务消费者
  2. 如果是服务B被服务A调用了,那么服务B就是服务提供者


3.5 总结

服务调用关系

  • 服务提供者:暴露接口给其它微服务调用
  • 服务消费者:调用其它微服务提供的接口
  • 提供者与消费者角色其实是相对
  • 一个服务可以同时是服务提供者和服务消费者


四、Eureka

4.1 demo案例存在调用服务问题

  1. 服务消费者该如何获取服务提供者的地址信息?
  2. 如果有多个服务提供者,消费者该如何选择?
  3. 消费者如何得知服务提供者的健康状态?

4.2 Eureka注册中心

4.2.1 Eureka的作用


服务注册和发现:Eureka Server用于接收各个微服务实例的注册信息,并存储在自己的注册表中。Eureka Client用于将自身服务实例注册到注册表中,并从注册表中获取其他微服务实例的信息。这样,当一个微服务需要调用其他微服务时,只需要从注册表中获取对应的微服务实例的地址即可。

负载均衡:Eureka Client内置了一个轮询负载均衡器,每次从注册表中获取所有同名服务实例的地址列表,通过轮询算法选择其中一个地址进行调用。这样,就能够实现基于客户端的负载均衡。

举例说明:假设在一个电商网站中,商品微服务需要调用支付微服务进行交易。如果没有Eureka,商品微服务将无法直接找到支付微服务的实例地址。但是,如果使用了Eureka,支付微服务实例会将自己的信息注册到Eureka Server的注册表中,商品微服务在调用支付微服务时,只需要从注册表中获取支付微服务实例的地址列表,然后通过轮询算法选择其中一个进行调用,就能够顺利地完成交易操作。


以下是对上面的demo进行分析:


a6752bd38cd1e8628f87db8b021dd1db.png

再来回答上面第一部分的遗留问题:


消费者该如何获取服务提供者具体信息?


服务提供者启动时向eureka注册自己的信息


eureka保存这些信息


消费者根据服务名称向eureka拉取提供者信息


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


服务消费者利用负载均衡算法,从服务列表中挑选一个

消费者如何感知服务提供者健康状态?


服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态


eureka会更新记录服务列表信息,心跳不正常会被剔除


消费者就可以拉取到最新的信息

4.3 Euraka注册中心总结


在Eureka架构中,微服务角色有两类:


EurekaServer:服务端,注册中心

记录服务信息

心跳监控

EurekaClient:客户端

Provider:服务提供者,例如案例中的 user-service

注册自己的信息到EurekaServer

每隔30秒向EurekaServer发送心跳

consumer:服务消费者,例如案例中的 order-service

根据服务名称从EurekaServer拉取服务列表

基于服务列表做负载均衡,选中一个微服务后发起远程调用

4.4 Eureka 搭建

4.4.1 搭建Eureka注册中心

  1. 创建一个单独的 Eureka 项目
  2. 导入组件:
<!--eureka服务端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>


  1. 添加Eureka注解 @EnableEurekaServer
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}


  1. 配置信息
server:
  port: 8083 # 服务端口
spring:
  application:
    name: eurekaserver # eureka的服务名称
eureka:
  client:
    service-url:  # eureka的地址信息
      defaultZone: http://localhost:8083/eureka


4.4.2 服务注册(user-server)

  1. 引入pom.xml
<dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>


配置文件种,引入客户端配置

eureka:
  client:
    service-url:  # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

将一个服务启动多次(如下图所示),但是端口不能一样

4.4.3 服务发现

在order-service完成服务拉取

服务拉取是基于服务名称获取服务列表,然后在对服务列表做负载均衡

  1. 修改OrderService的代码,修改访问的url路径,用服务名代替ip、端口:
// 2.1 url的地址为user-service模块启动的端口,因为是向user-service发送请求
String url = "http://userserver/user/" + order.getUserId();


  1. 在order-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}


然后访问 order 服务订单:

http://localhost:8082/order/102


五、Ribbon 负载均衡

5.1 负载均衡流程


可以使用之前的demo,说明负载均衡流程:

5.2 负载均衡策略


IRule接口:

5.3 修改负载均衡规则

通过定义IRule实现可以修改负载均衡规则,有两种方式:

  1. 代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:
@Bean
public IRule randomRule(){
    return new RandomRule();
}

配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则

userserver:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


5.4 饥饿机制

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时。

通过下面配置开启饥饿加载:(在order-service中)


5.5 负载均衡总结


Ribbon负载均衡规则

规则接口是IRule

默认实现是ZoneAvoidanceRule,根据zone选择服务列表,然后轮询

负载均衡自定义方式

代码方式:配置灵活,但修改时需要重新打包发布

配置方式:直观,方便,无需重新打包发布,但是无法做全局配置

饥饿加载

开启饥饿加载

指定饥饿加载的微服务名称

六、Nacos注册中心

Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。


6.1 Windows11安装Nacos

下载地址:NacosGithub (不建议安装最新版本)

启动方式:

  1. 单机启动:
startup.cmd -m standalone


集群启动,在bin目录下启动多个

startup.cmd


运行效果如下:点击链接会跳转到对应的界面

6.2 Nacos 服务注册

  1. 在cloud-demo父工程中添加spring-cloud-alilbaba的管理依赖
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba</artifactId>
                <version>2.2.5.RELEASE</version>
            </dependency>


在user-service工程下导入配置文件

<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>

修改配置文件

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: userserver # user服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务地址


6.3 Nacos服务分级存储模型

将一个服务分级存储部署



6.3.1 服务跨集群调用

  • 服务调用尽可能选择本地集群的服务,跨集群调用延迟较高
  • 本地集群不可访问时,再去访问其它集群


6.4 服务集群配置

增加服务集群配置,name随便命名:

在nacos控制台就会看到两个集群的地方



4bfef480b1b25e4c0bf53715522ecfe9.png

6.4.1 Nacos服务分级总结


Nacos服务分级存储模型


一级是服务,例如userservice


二级是集群,例如GX或BJ


三级是实例,例如GX机房的某台部署了userservice的服务器


如何设置实例的集群属性


修改application.yml文件,添加spring.cloud.nacos.discovery.cluster-name属性即可

6.5 Nacos负载均衡

将以上的配置进行配置之后,就会优先选择本地集群查询,本地没有才回去访问其他的服务集群

① 优先选择同集群服务实例列表

② 本地集群找不到提供者,才去其它集群寻找,并且会报警告

③ 确定了可用实例列表后,再采用随机负载均衡挑选实例

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
5月前
|
消息中间件 NoSQL Java
Spring Cloud项目实战Spring Cloud视频教程 含源码
Spring Cloud项目实战Spring Cloud视频教程 含源码
96 1
|
16天前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
29 0
|
2月前
|
Java Spring
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
|
2月前
|
Java Spring 容器
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
|
2月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
|
2月前
|
SQL Java 数据库连接
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
|
2月前
|
Java 开发工具 Spring
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
|
2月前
|
NoSQL Java Redis
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
|
2月前
|
Java Spring
【Azure 应用服务】记一次Azure Spring Cloud 的部署错误 (az spring-cloud app deploy -g dev -s testdemo -n demo -p ./hellospring-0.0.1-SNAPSHOT.jar --->>> Failed to wait for deployment instances to be ready)
【Azure 应用服务】记一次Azure Spring Cloud 的部署错误 (az spring-cloud app deploy -g dev -s testdemo -n demo -p ./hellospring-0.0.1-SNAPSHOT.jar --->>> Failed to wait for deployment instances to be ready)
|
2月前
|
Java Maven Python
【Azure Spring Cloud】部署Azure spring cloud 失败
【Azure Spring Cloud】部署Azure spring cloud 失败