其他分享
首页 > 其他分享> > AlibabaCloud 核⼼组件服务治理 Nacos 实战

AlibabaCloud 核⼼组件服务治理 Nacos 实战

作者:互联网

使用 Maven 聚合工程创建微服务架构

maven 聚合工程 xdclass-cloud,包含以下四个子项目

创建聚合工程(记得删除聚合工程 src 目录)

<modelVersion>4.0.0</modelVersion>

<groupId>net.xdclass</groupId>
<artifactId>xdclass-cloud</artifactId>
<version>1.0-SNAPSHOT</version>

<modules>
    <module>xdclass-common</module>
    <module>xdclass-order-service</module>
    <module>xdclass-user-service</module>
    <module>xdclass-video-service</module>
</modules>

<!-- 一般来说父级项目的packaging都为pom,packaging默认类型jar类型-->
<packaging>pom</packaging>

<properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencyManagement>
    <dependencies>
        <!--https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies/2.3.3.RELEASE-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.3.3.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!--https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies/Hoxton.SR8-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!--https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-dependencies/2.2.1.RELEASE-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.3.5.RELEASE</version>
            <configuration>
                <fork>true</fork>
                <addResources>true</addResources>
            </configuration>
        </plugin>
    </plugins>
</build>
聚合工程pom.xml

四个子项目都是普通的 Maven 项目,xdclass-common 是公共项目,用来存放实体类等其他作用

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>net.xdclass</groupId>
        <artifactId>xdclass-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>
子项目pom.xml

基本的项目结构就是这样,我们来打通 Mybatis 连接 Mysql 数据库

创建 common 包实体类

public class User {
    private Integer id;
    private String name;
    private String pwd;
    private String headImg;
    private String phone;
    private Date createTime;
    private String wechat;
    //省略getter/setter方法
}
​
public class Video {
    private Integer id;
    private String title;
    private String summary;
    private String coverImg;
    private Integer  price;
    private Date createTime;
    private Double point;
    //省略getter/setter方法
}
​
public class VideoOrder {
    private Integer id;
    private String outTradeNo;
    private Integer state;
    private Date createTime;
    private  Integer totalFee;
    private Integer videoId;
    private String videoTitle;
    private String videoImg;
    private Integer userId;
    //省略getter/setter方法
}
实体类

Maven 项目创建时没有像 SpringBoot 创建时已经创建好包结构,需要自己手动创建

xdclass-video-service 项目 pom 文件新增依赖(子项目没有指明依赖版本号就是使用父项目一样的版本)

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
xdclass-video-service项目pom文件

application.yml

server:
  port: 9000

spring:
  application:
    name: xdclass-video-service

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/cloud_video?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456


mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
application.yml

VideoApplication.java

@SpringBootApplication
@MapperScan("net.xdclass.dao")
public class VideoApplication {
    public static void main(String [] args){
        SpringApplication.run(VideoApplication.class,args);
    }
}
VideoApplication.java

VideoMapper.java

@Repository
public interface VideoMapper {
    @Select("select * from video where id=#{videoId}")
    Video findById(@Param("videoId") int videoId);
}
VideoMapper.java

 

服务直接怎么调用

RPC:

Rest(Http):

我们看一个 RestTemplate 的例子

OrderController.java

@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/save")
    public Object save(int videoId) {

        Video video = restTemplate.getForObject("http://localhost:9000/api/v1/video/find_by_id?videoId=" + videoId, Video.class);

        VideoOrder videoOrder = new VideoOrder();
        videoOrder.setVideoId(video.getId());
        videoOrder.setVideoTitle(video.getTitle());
        videoOrder.setCreateTime(new Date());
        return videoOrder;
    }
}
OrderController.java

OrderApplication.java

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

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
OrderApplication.java

application.yml

server:
  port: 8000

spring:
  application:
    name: xdclass-order-service

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/cloud_order?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: xdclass.net

# 控制台输出sql、下划线转驼峰
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
application.yml

存在的问题:

既然存在这些问题,解决问题的方案也呼之欲出:注册中心

注册中心

什么是注册中心(服务治理)

为什么要用

主流的注册中心:zookeeper、Eureka、consul、etcd、Nacos

nacos下载和启动官网上有很清楚的介绍

通过注册中心解决第一个问题:服务之间的 IP 信息写死

视频服务集成Nacos

添加依赖

<!--添加nacos客户端-->
<dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
nacos依赖

配置 Nacos 地址

server:
  port: 9000
​
spring:
  application:
    name: xdclass-video-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
Nacos地址

启动类增加注解

@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

订单服务集成和用户服务集成 Nacos 都是一样的套路

服务之间的调用,这样可以获得所有服务集合,我们可以访问任意一个服务

@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/save")
    public Object save(int videoId) {

        //Video video = restTemplate.getForObject("http://localhost:9000/api/v1/video/find_by_id?videoId=" + videoId, Video.class);

        List<ServiceInstance> list = discoveryClient.getInstances("xdclass-video-service");
        ServiceInstance serviceInstance = list.get(0);
        Video video = restTemplate.getForObject("http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() +
                "/api/v1/video/find_by_id?videoId=" + videoId, Video.class);

        VideoOrder videoOrder = new VideoOrder();
        videoOrder.setVideoId(video.getId());
        videoOrder.setVideoTitle(video.getTitle());
        videoOrder.setCreateTime(new Date());
        return videoOrder;
    }
}

第一个问题解决了,现在看看第二个问题

负载均衡

什么是负载均衡(Load Balance)

软硬件角度负载均衡的种类

从端的角度负载均衡有两种

常见的负载均衡策略(看组件的支持情况)

集成 Ribbon 实现负载均衡

什么是 Ribbon?

订单服务增加 @LoadBalanced 注解

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

调用方式改造,注意红色字体

@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/save")
    public Object save(int videoId) {

        //Video video = restTemplate.getForObject("http://localhost:9000/api/v1/video/find_by_id?videoId=" + videoId, Video.class);

        //List<ServiceInstance> list = discoveryClient.getInstances("xdclass-video-service");
        //ServiceInstance serviceInstance = list.get(0);
        //Video video = restTemplate.getForObject("http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() +"/api/v1/video/find_by_id?videoId=" + videoId, Video.class);

        Video video = restTemplate.getForObject("http://xdclass-video-service/api/v1/video/find_by_id?videoId=" + videoId, Video.class);

        VideoOrder videoOrder = new VideoOrder();
        videoOrder.setVideoId(video.getId());
        videoOrder.setVideoTitle(video.getTitle());
        videoOrder.setCreateTime(new Date());
        return videoOrder;
    }
}

自定义 Ribbon 负载均衡策略

分析源码得知 Ribbon 支持多种负载均衡策略

Ribbon 支持的负载均衡策略介绍

负载均衡策略调整

订单服务增加配置
​
xdclass-video-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

策略选择: 

  1. 如果每个机器配置一样,则建议不修改策略 (推荐) 
  2. 如果部分机器配置强,则可以改为WeightedResponseTimeRule

 

现在解决第三个问题:多个服务直接关系调用维护复杂

Feign 介绍

原先 Ribbon 代码存在的问题:不规范,风格不统一,维护性比较差

什么是Feign:

官方文档(版本 2.2.5)

Nacos 支持 Feign,可以直接集成实现负载均衡的效果 

使用 Feign 步骤

加入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
openfeign依赖

启动类增加注解 @EnableFeignClients

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

订单服务增加接口,服务名称记得和 nacos 保持一样

@FeignClient(name="xdclass-video-service")
public interface VideoService {

    @GetMapping(value = "/api/v1/video/find_by_id")
    Video findById(@RequestParam("videoId") int videoId);
}

调用方进行改造

@RestController
@RequestMapping("api/v1/video_order")
public class OrderController {

    @Autowired
    private VideoService videoService;

    @RequestMapping("/save")
    public Object save(int videoId) {

        Video video = videoService.findById(videoId);

        VideoOrder videoOrder = new VideoOrder();
        videoOrder.setVideoId(video.getId());
        videoOrder.setVideoTitle(video.getTitle());
        videoOrder.setCreateTime(new Date());
        return videoOrder;
    }
}

订单服务项目结构

POST 方式提交怎么做?

//订单服务service
@PostMapping(value = "/api/v1/video/save")
Video saveVideo(@RequestBody Video video);
​
​//视频服务controller
@PostMapping("save")
public Object save(@RequestBody Video video){
  System.out.println(video.getTitle());
  return  video;
}

注意:

Ribbon 和 Feign 两个的区别和选择

 

CAP理论知识

CAP 定理:指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition Tolerance(分区容错性),三者不可同时获得。

CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡。

原因:

注册中心选择:

结论:

分布式系统中P,肯定要满足,所以只能在 C 和 A 中二选一。没有最好的选择,最好的选择是根据业务场景来进行架构设计,如果要求一致性,则选择 Zookeeper,如金融行业;如果要去可用性,则 Eureka,如电商系统。

 NacosEurekaConsulZookeeper
一致性协议 CP+AP AP CP CP
健康检查 TCP/HTTP/MYSQL/Client Beat 心跳 TCP/HTTP/gRPC/Cmd Keep Alive
雪崩保护
访问协议 HTTP/DNS HTTP HTTP/DNS TCP
SpringCloud集成 支持 支持 支持 支持

 

 

 

 

 

 

 

 

BASE理论

什么是 BASE 理论

Basically Available(基本可用)

Soft state(软状态)

Eventually consistent(最终一致性)

 

标签:class,Nacos,private,videoId,xdclass,video,组件,public,AlibabaCloud
来源: https://www.cnblogs.com/jwen1994/p/13952688.html