SpringCloud和Nacos的基础知识和使用

1.什么是SpringCloud

​   什么是微服务?

​   假如我们需要搭建一个网上购物系统,那么我们需要哪些功能呢?商品中心、订单中心和客户中心等。

​   当业务功能较少时,我们可以把这些功能塞到一个SpringBoot项目中来进行管理。但是随着业务越来越多,每个模块需要实现的功能越来越多时,每个模块需要的开发人员就越来越多,这时如果再是一个项目就不太合适了(耦合度太高,并且开发人员对同一个项目进行操作容易出现问题)。这就需要将原先的系统进行拆分,可以按照功能模块拆分成多个服务,这就引出了另一个问题,服务之间如何完成通信。

​   在实际的业务场景中,每个功能模块不可能是完全分离的,例如订单中心展示订单时可能需要获取商品的信息和客户的信息,这就需要调用商品中心模块和客户中心模块的接口。SpringCloud就支持我们将原有项目进行拆分,分成多个微服务,并支持微服务之间的通信。

1.1 SpringCloud简介

​   SpringCloud由五大组件构成:

1.注册中心Euraka(国内用的较多的是Nacos):负责服务注册和发现。
2.负载均衡Ribbon:负责服务实例的选择(同一个服务可能部署在多个服务器上)。
3.远程调用Feign:通过HTTP请求调用其他服务的接口。
4.熔断器Hystrix:容错管理工具,用于处理分布式系统中的延迟和故障。
5.API网关Zuul:用于路由、过滤和负载均衡。

​   这五大组件的工作流程如下(绕不开的八股):

1.服务注册:只有一个服务注册到注册中心,才可能被其他服务发现并调用;
2.服务发现:即一个服务通过注册中心发现了其他服务
3.负载均衡:客户端维护一份从注册中心获取的Provider列表清单,根据自己配置的Provider负载均衡选择算法在客户端进行请求的分发;
4.服务调用:一个服务对另一个服务进行调用;
5.隔离、熔断与降级:通过Hystrix的线程池去访问服务,不同的服务通过不同的线程池,实现了不同的服务调度隔离;如果服务出现故障,通过服务熔断,避免服务雪崩的问题 ;并且通过服务降级,保证可以手动实现服务正常功能;
6.网关路由:如果前端调用后台系统,统一从网关进入,通过网关转发请求给对应的服务;

在这里插入图片描述

1.2 Eureka

​   服务注册中心(Eureka server/Nacos server)像是整个微服务架构中的大脑,服务(Eureka client)需要注册到Eureka server以供其他服务(Eureka client)发现,如果要使用其他服务的功能也需要通过Eureka server来获得对应服务(Eureka client)的信息。

​   Eureka server的主要功能为服务注册表维护服务健康检查,Eureka client的主要功能为服务注册心跳续约健康状况查询。(是不是觉得很熟悉,有点像Redis的哨兵机制)

在这里插入图片描述

1.3 Ribbon

​   在实际的生产环境中,某些模块访问量较高,单个服务器可能无法承载这些访问请求,需要将这个微服务同时部署到多台服务器上,当有服务请求打到Eureka server上时,Eureka server会返回该服务类型对应的所有Eureka client实例。因此客户端会获得多个服务实例,Ribbon会选择哪个实例去处理请求,选择的方式有多种,轮询、随机、权重等,主要目的是避免多次请求均打到同一个服务实例上。Ribbon的作用是负载均衡。

​   Ribbon可以获取Provider清单,并且通过IPing实例定期(如每10秒)向每个Provider实例发送“ping”,并且根据Provider是否有响应来判断该Provider实例是否可用。如果该Provider的可用性发生了改变,或者Provider清单中的数量和之前的不一致,就从注册中心更新或者重新拉取Provider服务实例清单。每次RPC请求到来时,由Ribbon的IRule负载均衡策略接口的某个实现类来进行负载均衡。

1.4 Feign

​   在 Spring Cloud 中使用 Feign,可以做到使用 HTTP 请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问 HTTP 请求。Feign 整合了 Ribbon 和 Hystrix,具备负载均衡、隔离、熔断与降级功能。

1.5 Zuul

​   微服务网关是微服务架构中不可或缺的部分,它统一解决Provider路由、均衡负载、权限控制等功能。具体可以参考博客:https://blog.youkuaiyun.com/itigoitie/article/details/125895899?spm=1001.2014.3001.5502

1.6 Hystrix

​   隔离:通过Hystrix的线程池去访问服务,不同的服务通过不同的线程池,实现了不同的服务调度隔离;
​   熔断:分布式架构中的熔断器主要用于RPC接口上,为接口安装上“保险丝”,以防止RPC接口出现拥塞时导致系统压力过大而引起的系统瘫痪,当RPC接口流量过大或者目标Provider出现异常时,熔断器及时切断故障可以起到自我保护的作用。
​   降级:当服务不可用(服务正在等待、链接超时、网络延迟、服务器响应慢等),客户端一直等待时,调用fallback方法给客户端返回一个错误提示,不让客户端继续等待。

2.Nacos

​   Nacos是阿里的产品,它的功能要比Eureka更丰富,因此国内更倾向于使用Nacos,我们来简单介绍一下Nacos的安装和使用。

2.1 Nacos安装

​   Nacos官网:https://nacos.io/

在这里插入图片描述

在这里插入图片描述

​   将压缩包下载到本地并解压(避免中文路径),进入到bin目录:

在这里插入图片描述

​   接着在bin目录下打开cmd,输入如下命令来启动Nacos:

startup.cmd -m standalone

在这里插入图片描述

​   在浏览器中打开:http://192.168.239.1:8848/nacos/index.html

在这里插入图片描述

​   至此,Nacos安装就完成了,其实还挺简单的,接下来我们需要借助Nacos去搭建一个SpringCloud项目,下面将介绍如何单机搭建一个SpringCloud项目。

2.2 Nacos简单实践

2.2.1 IDEA搭建SpringCloud项目

2.2.1.1 数据库准备
CREATE TABLE USER (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
phone VARCHAR(15) NOT NULL,
address VARCHAR(50) NOT NULL
);

INSERT INTO USER VALUES (1, "ayanokoujimonki", 13299075426, "湖北省孝感市")
INSERT INTO USER(NAME, phone, address) VALUES ("二哈很六", 18834267011, "江苏省苏州市")
INSERT INTO USER(NAME, phone, address) VALUES ("陈大龟", 12481076533, "汉川市榔头村")
CREATE TABLE orders (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30) NOT NULL,
price INT NOT NULL,
user_id INT NOT NULL REFERENCES USER(id)
)

INSERT INTO orders VALUES (1, "可乐鸡翅", 32, 1);
INSERT INTO orders(NAME, price, user_id) VALUES("冰镇啤酒", 12, 1);
INSERT INTO orders(NAME, price, user_id) VALUES("草莓冰激凌", 8, 2);
INSERT INTO orders(NAME, price, user_id) VALUES("狼牙土豆", 10, 3);
2.2.1.2 创建父项目

​   1.首先创建父项目:

在这里插入图片描述

​   2.选择Spring Web依赖:

在这里插入图片描述

​   3.等到依赖下载好后,删除src目录及mvnw目录,正常情况下一般不会直接在父项目下直接编写代码:

在这里插入图片描述

​   4.修改pom文件,添加packaging标签和SpringCloud版本,并修改SpringBoot版本:

在这里插入图片描述

​   5.引入mysql和mybatis依赖:

在这里插入图片描述

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
<dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis</artifactId>
     <version>3.5.11</version>
</dependency>
<dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.3.2</version>
</dependency>

​   6.添加SpringCloud依赖库,后续子模块使用的时候就不需要再指定版本了

在这里插入图片描述

<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>2.2.9.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
2.2.1.3 创建子项目

  1.在父级项目上新建模块(user_client),并修改子项目的pom文件引入父项目的坐标

在这里插入图片描述

在这里插入图片描述

​   2.为了将子项目作为Nacos的client,需要引入如下依赖:

 <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.1.0</version>
</dependency>

在这里插入图片描述

​   3.编写application.yml文件

在这里插入图片描述

#服务端口,随便起
server:
  port: 8082
#服务名称
spring:
  application:
    name: userclient
  datasource:
    url: jdbc:mysql://localhost:3306/user
    username: root
    password: cmq123
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

​   4.同样的步骤创建另一个子项目(orders_client)

在这里插入图片描述

2.2.1.5 编写简单的业务代码

​   其实这时我们启动服务就可以看到服务注册到Nacos上了,只不过我们没有编写业务代码因此每个微服务不具备具体功能,为了将我们的服务能够被Nacos发现,需要在启动类上加上@EnableDiscoveryClient注解:

在这里插入图片描述

​   浏览器中打开Nacos地址就可以看到我们注册的实例了:http://192.168.239.1:8848/nacos/index.html

在这里插入图片描述

​   为了进一步验证服务之间能够通信,我们编写简单的业务代码,首先是userclient,我们编写pojo、controller、service和mapper:

在这里插入图片描述

​   其中UserService代码如下:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User findById(Integer id){
        System.out.println("UserService: "+ id);
        return userMapper.find(id);
    }
}

​   UserController代码如下:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;


    @GetMapping("/{id}")
    public User findUserById(@PathVariable("id") Integer id){
        return userService.findById(id);
    }

}

​   UserMapper代码如下:

@Mapper
public interface UserMapper {
    @Select("select * from user where id=#{id}")
    User find(Integer id);
}

​   User代码如下:

public class User {
    private int id;
    private String name;
    private String password;
    private String address;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

​   同理我们继续编写ordersclient的代码,项目结构保持相同:

在这里插入图片描述

​    User代码于userclient保持一致,Order代码如下:

public class Order {
    private int id;
    private String name;
    private int price;
    private int userId;
    private User user;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", userId=" + userId +
                ", user=" + user +
                '}';
    }
}

​   OrderMapper代码如下:

@Mapper
public interface OrderMapper {
    @Select("select * from orders where id= #{id}")
    Order find(Integer id);
}

OrderService代码如下:

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RestTemplate restTemplate;

    public Order findById(Integer id){
        Order order = orderMapper.find(id);
        String url = "http://userclient/user/" + order.getUserId();

        User user = restTemplate.getForObject(url, User.class);

        order.setUser(user);
        return order;
    }

}

​   OrderController代码如下:

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;
    @GetMapping("/{id}")
    public Order findById(@PathVariable("id") Integer id){
        Order byId = orderService.findById(id);
        return byId;
    }
}

​    启动类代码如下:

@EnableDiscoveryClient
@SpringBootApplication
public class OrdersClientApplication {

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

    /***
     * 定义一个RestTemplate Bean,用于发送HTTP请求
     * @return
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

​   为了将我们实体类和数据库中的字段对应,我们需要在application.yml文件中开启驼峰命名:

mybatis:
  type-aliases-package: com.ayanokouji.ordersclient.pojo.Order
  configuration:
    map-underscore-to-camel-case: true

​   我们再次启动这两个client,并在浏览器输入:localhost:8083/order/1

在这里插入图片描述

​   可以看到这两个服务确实完成了通信(虽然不是很优雅)。

​   这就是一个极致简单的SpringCloud项目,可以看到代码中我们并未显示地使用负载均衡,通信也是使用RestTemplate而不是Feign,关于负载均衡和Feign会在后面的博客中介绍(如果有时间的话,最近公司的活也有点多)。

参考博客

Nacos 注册中心下载到搭建详细步骤【微服务】_nacos下载-优快云博客

IDEA 搭建 SpringCloud 项目【超详细步骤】_idea创建springcloud工程-优快云博客

Spring Cloud 五大组件_springcloud五大组件-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值