微服务架构-SpringCloud

1. 微服务架构-springcloud

1.1 单体应用架构

单体应用架构是一种传统的软件架构模式,在这种模式下,整个应用程序被构建为一个单一的单元或组件。这意味着所有的功能模块(例如用户管理、订单处理等)都被打包在一起,并作为一个整体进行部署和扩展。

优点:

  1. 部署简单:由于是完整的结构体,可以直接部署在一个服务器上即可。
  2. 技术单一:项目不需要复杂的技术栈,往往一套熟悉的技术栈就可以完成开发。

缺点:

  1. 系统启动慢,一个进程包含了所有的业务逻辑,涉及到的启动模块过多,导致系统的启动、重启时间周期过长;
  2. 系统错误隔离性差、可用性差,任何一个模块的错误均可能造成整个系统的宕机;
  3. 可伸缩性差:系统的扩容只能只对这个应用进行扩容,无法结合业务模块的特点进行伸缩。
  4. 线上问题修复周期长:任何一个线上问题修复需要对整个应用系统进行全面升级。
  5. 跨语言程度差
  6. 不利于安全管理,所有开发人员都拥有全量代码。

1.2 微服务应用

微服务架构论文: Microservicesicon-default.png?t=N7T8https://martinfowler.com/articles/microservices.html

译文: 微服务译文理解_任何设计系统(广泛定义的)的组织将产生一种设计,他的结构就是该组织的通信结构-CSDN博客文章浏览阅读747次,点赞2次,收藏4次。微服务是什么?微服务详解在过去几年中,“微服务架构”这一术语如雨后春笋般涌现出来,它描述了一种将软件应用程序设计为一组可独立部署的服务的特定方式。虽然这种架构风格没有明确的定义,但在组织、业务能力上有一些共同的特征:自动化部署,端点智能化,语言和数据的去中心化控制。“微服务” - 软件架构拥挤大街上的有一个新术语。虽然我们自然的倾向是轻蔑的一瞥将它一带而过,然而我们发现这一术语描述了一种越来..._任何设计系统(广泛定义的)的组织将产生一种设计,他的结构就是该组织的通信结构https://blog.csdn.net/qq_42261668/article/details/102839758

原文:

In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.

译文:

简单来说,微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。

解读微服务特点:

  • 微服务是一种==项目架构思想==(风格)
  • 微服务架构是一系列小服务的组合(组件化与多服务)
  • 任何一个微服务,都是一个独立的进程(独立开发、独立维护、独立部署)
  • 轻量级通信http协议(跨语言,跨平台) [接口编写]
  • 服务粒度(围绕业务功能拆分-
  • 去中心化管理

1.3 微服务架构的优势

微服务架构是一种将单个应用程序开发为一组小型、独立的服务的方法,这些服务通过定义良好的API进行通信。以下是

1.易于开发和维护

  1. 一个微服务只关注一个特定的业务功能,所以它的业务清晰、代码量较少。
  2. 开发和维护单个微服务相对比较简单,整个应用是由若干个微服务构建而成,所以整个应用也会维持在可控状态。

部署麻烦----开发人员---容器化部署[docker]

⒉.单个微服务启动较快

  • 单个微服务代码量较少,所以启动会比较快;

3.局部修改容易部署

  1. 单体应用只要有修改,就要重新部署整个应用,微服务解决了这样的问题。
  2. 一般来说,对某个微服务进行修改,只需要重新部署这个服务即可;

4.技术栈不受限

  • 在微服务中,我们可以结合项目业务及团队的特点,合理地选择技术栈.

5.按需伸缩

  • 购物车---->购物车这个系统集群搭建

1.4 微服务架构的挑战

  • l 这么多小服务,如何管理他们? nacos
  • l 这么多小服务,他们之间如何通讯? openfeign
  • l 这么多小服务,客户端怎么访问他们? gateway
  • l 这么多小服务,一旦出现问题了,应该如何自处理?
  • l 这么多小服务,一旦出现问题了,应该如何排错?

相应的组件可以解决上面的相应的挑战。----把这些组件和在一起称为springcloud

1.5 SpringCloud与微服务关系

  • Springcloud为微服务思想提供了完美的解决方案

  • Springcloud是一些列框架的集合体(服务的注册与发现【注册中心】、服务间远程调用、服务降级、服务熔断、服务限流、分布式事务等)

  • springcloud就是一系列框架的集合,为了解决微服务的挑战。

注:springcloud有两个版本: springcloud netflix [停止更新] 和springcloud alibaba。

1.6 SpringBoot和SpringCloud关系

  • SpringBoot专注于快速方便的开发单个个体微服务。

  • SpringCloud是关注全局的微服务协调、整理、治理的框架,它将SpringBoot开发的单体整合并管理起来。

  • SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系。

2. 如何搭建微服务架构

2.1 创建一个父工程并引入依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--
        1. springboot的版本为2.3.12.RELEASE
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ykq</groupId>
    <artifactId>qy174-springcloud-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!--只要是父工程打包方式都是pom. 把src删除-->
    <packaging>pom</packaging>
    <name>qy174-springcloud-parent</name>
    <description>qy174-springcloud-parent</description>
    <!--定义版本号-->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!--springcloud的版本-->
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
        <!--阿里巴巴的版本  springboot springcloud  springcloudalibaba 他们的版本必须对应
        https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
        -->
        <spring-cloud-alibaba.version>2.2.8.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <!--
    dependencyManagement: 只负责jar的管理不负责jar的下载。
    -->
    <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>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

版本说明

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8Eicon-default.png?t=N7T8https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

2.2 创建一个公共模块

这个工具类主要放一些公共的,比如工具类,公共实体类【R】,实体类等,我这里创建的是一个普通的maven工程

实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tbl_product")
public class Product {
    @TableId(type= IdType.AUTO)
    private Integer pid;
    private String pname;
    private BigDecimal price;
    private Integer stock;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tbl_order")
public class Order {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String orderNo;
    private Integer productId;
    private BigDecimal price; //因为double存在精度丢失问题
    private String pname;
    private Integer num;

    private Integer userid;

    private Integer status;

    //订单创建时间--Date存在线程安全问题--默认按照驼峰命名
    private LocalDateTime createTime;
}

2.3 创建商品微服务

依赖:

    <dependencies>
         <!--公共依赖-->
         <dependency>
             <groupId>com.ykq</groupId>
             <artifactId>qy174-springcloud-common</artifactId>
             <version>0.0.1-SNAPSHOT</version>
         </dependency>
        <!--数据库的依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--springboot-web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

application.properties

# 商品微服务的端口8001~8009
server.port=8001

# 起服务名
spring.application.name=qy174-product

# 数据源
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud-product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#mysql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#mybatis映射文件
mybatis-plus.mapper-locations=classpath*:mapper/*.xml

主启动类

@SpringBootApplication
@MapperScan("com.ykq.product.mapper")
public class ProductApp {
    public static void main(String[] args) {
        SpringApplication.run(ProductApp.class,args);
    }
}

mapper

public interface ProductMapper extends BaseMapper<Product> {
}

service

public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;
    @Override
    public Product getById(Integer pid) {
        Product product = productMapper.selectById(pid);
        return product;
    }
}

controller

@RestController
@RequestMapping("/product")
public class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/getById/{pid}")
    public Product getById(@PathVariable Integer pid) {
        Product product = productService.getById(pid);
        return product;
    }
}

2.4 创建订单微服务

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping("/saveOrder")
    public Order saveOrder(Integer pid, Integer num) {
        Order order = new Order();
        order.setOrderNo(IdUtil.getSnowflakeNextIdStr());//订单编号: 时间戳+随机数  雪花算法: 生成一个唯一的id
        order.setNum(num);
        order.setStatus(0);
        order.setCreateTime(LocalDateTime.now());
        order.setUserid(1);

        order.setProductId(pid);
        //根据商品id查询商品信息---远程调用商品微服务的接口。
        // 基于Http协议调用。[1]可以自己封装HttpClient工具类【适合所有场景】 [2] spring框架提高了一个HttpClient的工具类【适合spring工程】RestTemplate。
        //String url, Class<T> responseType, Object... uriVariables
        Product product = restTemplate.getForObject("http://localhost:8001/product/getById/" + pid, Product.class);
        if(product==null||product.getStock()<num){
            throw new RuntimeException("商品不存在或库存不足");
        }
        order.setPname(product.getPname());
        order.setPrice(product.getPrice());
        Order order1 = orderService.createOrder(order);

        return order1;
    }
}
@Configuration
public class RestConfig {

    @Bean  //把方法的返回对象交于spring容器管理
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

3.Nacos Discovery--服务治理

3.1 服务治理介绍

*先来思考一个问题*

通过上一章的操作,我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址

(ip,端口)等硬编码到了代码中,这种做法存在许多问题:

l 一旦服务提供者地址变化,就需要手工修改代码

l 一旦是多个服务提供者,无法实现负载均衡功能

l 一旦服务变得越来越多,人工维护调用关系困难

那么应该怎么解决呢, 这时候就需要通过注册中心动态的实现服务治理

什么是服务治理

服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现

服务注册:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服

务的详细信息。并在注册中心形成一张服务的*清单*,服务注册中心需要以*心跳30s 90s*的方式去监测清单中 的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。

服务发现:服务调用方向服务注册中心咨询服务,并获取*所有服务*的实例清单,实现对具体服务实

例的访问。

通过上面的调用图会发现,除了微服务,还有一个组件是服务注册中心,它是微服务架构非常重要

的一个组件,在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能:

\1. 服务发现:

服务注册:保存服务提供者和服务调用者的信息

服务订阅:服务调用者订阅服务提供者的信息,注册中心向订阅者推送提供者的信息

\2. 服务配置:

配置订阅:服务提供者和服务调用者订阅微服务相关的配置

配置下发:主动将配置推送给服务提供者和服务调用者

\3. 服务健康检测

检测服务提供者的健康情况,如果发现异常,执行服务剔除

*常见的注册中心*

Zookeeper

zookeeper是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式

应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用

配置项的管理等。

Eureka ---

Eureka是Springcloud Netflix中的重要组件,主要作用就是做服务注册和发现。但是现在已经闭

源 ,停更不停用。

Consul

Consul是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现

和配置管理的功能。Consul的功能都很实用,其中包括:服务注册/发现、健康检查、Key/Value

存储、多数据中心和分布式一致性保证等特性。Consul本身只是一个二进制的可执行文件,所以

安装和部署都非常简单,只需要从官网下载后,在执行对应的启动脚本即可。

Nacos (服务治理 配置中心)

Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是 Spring

Cloud Alibaba 组件之一,负责服务注册发现和服务配置.

3.2 nacos实战入门

下载nacos的软件。

Releases · alibaba/nacos · GitHub

解压:

打开bin目录--修改startup.cmd文件---默认按照集群模式启动----修改为单机启动

启动nacos服务并访问nacos页面

http://localhost:8848/nacos

账号和密码: nacos

3.3 微服务接入到nacos上

引入nacos的jar包

      <!--nacos的jar包-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

在配置文件中指定nacos服务的地址

# 指定注册中心的地址--- 起名称 spring.cloud.nacos.discovery.server-addr=172.16.7.64:8848

修改订单微服务的代码

4. 负载均衡

通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。

4.1 手动实现负载均衡

手动实现负载均衡使用的策略:随机策略。 如果我想改变策略--修改源代码。第三方公司提高了一个组件。ribbon.

4.2 介绍ribbon

什么是Ribbon
是 Netflix 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中, nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从nacos中读 取到的服务信息,在调用服务节点提供的服务时,会合理(策略)的进行负载。 在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务。

ribbon是netflix公司的组件,作用自动从注册中心拉取服务器信息,并根据相应的策略完成负载均衡的调用。

4.3 使用ribbon

nacos依赖中自带了ribbon的jar包。

在RestTemplate所在的bean方法上加入一个注解。

修改OrderController类的代码

完成了负载均衡。---策略默认为轮询策略。

4.4 ribbon提供的负载均衡策略有哪些?

Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接口为

com.netflix.loadbalancer.IRule , 具体的负载策略如下图所示:

1.3 自定义ribbon负载均衡策略 - 盛开的太阳 - 博客园 (cnblogs.com)

第一种:局部使用

shop-product:  # 这里使用服务的名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #使用的的负载均衡策略
# 指定调用商品微服务使用的负载均衡的策略
qy174-product.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

第二种: 全局使用

5. Openfeign远程调用组件

之前我们使用RestTemplate+ribbon完成负载均衡。 语法不符合我们调用的习惯。

Controller----Service----->Dao.

@autoWire注入一个Service对象,对象调用类中的方法,习惯该方法需要什么参数就参数参数类型。

5.1 概述openfeign

OpenFeign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。 Nacos很好的兼容了OpenFeign, OpenFeign负载均衡默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。

5.2 使用openfeign

1.引入依赖

    <!--引入openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2. 创建一个接口

@FeignClient(value = "qy174-product")   //openfeign为该接口生成代理实现类。
public interface ProductFeign {
​
    //这里的方法的请求方式以及参数类型必须和提供者一致。
    @GetMapping("/product/getById/{pid}")
    public Product getById(@PathVariable Integer pid);
}

3.开启注解驱动

4.修改OrderController

  • 27
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值