SpringCloud深度学习(在更)

微服务简介

微服务是什么?

微服务是一种架构风格,将一个大型应用程序拆分为一组小型、自治的服务。每个服务都运行在自己独立的进程中,使用轻量级的通信机制(通常是HTTP或消息队列)进行相互之间的通信。这种方式使得每个服务可以独立开发、部署和扩展,同时也降低了整个应用程序的复杂性。微服务架构可以提高系统的可伸缩性、灵活性和可维护性,使得团队可以更快地开发和交付新的功能。

微服务项目结构图

SpringCloud深度学习(在更)_第1张图片

单体的Java项目和分布式的Java项目的区别

  单体项目

  • 优点:发布简单,开发时无需考虑接口暴露问题。
  • 缺点:项目耦合度会随着代码量的增大而提高,可读性底。
  • 作用域:面向使用人群小的项目,开发成本底。(个人系统,个人博客,等等)

微服务项目

  • 优点:大大降低耦合度,业务模块分布清楚,可读性高。
  • 缺点:开发成本远远大于单体项目,需要考虑接口暴露问题。
  • 作用域:面向使用人群大的项目。(电商项目,等等) 

SpringCloud深度学习(在更)_第2张图片

 微服务结构

SpringCloud深度学习(在更)_第3张图片

 微服务对比

SpringCloud深度学习(在更)_第4张图片

学习环境

 jdk1.8,。

springboot版本为:2.3.9.RELEASE。

springcloud版本为:Hoxton.SR10。

eureka 

eureka的作用:作为服务中心。

SpringCloud深度学习(在更)_第5张图片

SpringCloud深度学习(在更)_第6张图片 eureka的使用

1.创建eureka的注册中心

导入依赖


            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server

在application.yml中配置对应的注册信息

#在注册中心中的名字
spring:
  application:
    name: eurekaService
对应的服务端口
server:
  port: 10086

因为eureka作为服务注册中心,所以也需要将自己注册到服务中心中
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka

在启动类上添加注解驱动 @EnableEurekaServer 

对应的效果图

SpringCloud深度学习(在更)_第7张图片 2.将服务端和消费端都注册到eureka中。

此时服务端和客户端需要添加的依赖为下


    org.springframework.cloud
    spring-cloud-starter-netflix-eureka-client

 在application.yml编写注册信息

#要注册到的注册中心位置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka
 
spring:
  application:
    name: ”对应名字“

在restTemplate中将原本对应的地址位置修改为在eureka中的要调用的服务名字

SpringCloud深度学习(在更)_第8张图片

注册中心效果图为下:

SpringCloud深度学习(在更)_第9张图片

在未来我们的某个模块不一定只有一个,它可能是多个相同的模块,防止因为宕机的缘故导致服务无法使用。

这里我们就复制一个相同的服务

SpringCloud深度学习(在更)_第10张图片 在对用的restTemplate的配置类添加 @LoadBalanced

 进行测试,在调用两次接口后发现两个服务都被调用了一次,说明实现了负载均衡。

SpringCloud深度学习(在更)_第11张图片

SpringCloud深度学习(在更)_第12张图片  Ribbon

Ribbon流程

SpringCloud深度学习(在更)_第13张图片

 Ribbon负载均衡流程源码

SpringCloud深度学习(在更)_第14张图片

在LoadBalancerInterceptor类中会调用intercept方法,其会获取对应的host名字,通过这个host去注册中心中查找对应的服务地址。

SpringCloud深度学习(在更)_第15张图片

效果图为下: 

SpringCloud深度学习(在更)_第16张图片 获得到的serverName=user-service。

通过后序loadBalancer的execute方法,其会调用实现类下的execute方法,也就是RibbonLoadBalancerClient下的execute方法

SpringCloud深度学习(在更)_第17张图片

 通过getServer方法去eureka中拉去对应的名字的服务,可以得到user-service的实例,这里就是两个user-service实例。

 在getServer方法中最终会调用到rule.choose方法

SpringCloud深度学习(在更)_第18张图片

 在该方法的作用就是选择对应的负载均衡的策略

SpringCloud深度学习(在更)_第19张图片

总共有四大种策略,默认使用轮番查询策略,也就是 RoundRobinRule。

最终只要通过添加@LoadBalanced就可以实现负载均衡。

负载均衡策略 

SpringCloud深度学习(在更)_第20张图片

 设置策略的方法

1. 通过@Bean配置对应的策略,其作用域为全局。

    @Bean
    //设置为随机策略
    public IRule getIRule() {
        return new RandomRule();
    }

2.通过在application.yml中进行配置,此方法的优点就是作用域小,可以只作用在某个服务模块上。

#对应要设置策略的服务名
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

 饥饿加载

在默认情况下,只有当消费端访问对用的服务端时,服务端才会进行加载,所以在第一次访问服务端的耗时会很长。

为了提高访问效率,我们可以在项目启动时提前加载好对应的服务端,这里就可以使用饥饿加载。

配置方法为下:

ribbon:
  eager-load:
    enabled: true
    #clients是个列表,所以可以设置多个
    clients: 
      - user-service

这样在消费端第一次访问对应的服务端时就会大大减少消耗的时间。

nacos

nacos安装 

 下载并解压对应的nacos文件后,通过cmd进入nacos的bin目录,执行以下指令进行启动。

startup.cmd -m standalone

SpringCloud深度学习(在更)_第21张图片

此时我们就可以访问localhost:8848/nacos,在该界面中的用户名和密码都是:nacos。

将对应的服务端和消费端的注册中心都改为nacos。

1.导入依赖

在父目录中导入的依赖为下:


    com.alibaba.cloud
    spring-cloud-alibaba-dependencies
    2.2.5.RELEASE
    pom
    import

 在服务端和消费端导入的依赖为下:



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery

在服务端中的application.yml中配置为下:

spring:
  cloud:
    nacos:
      server-addr: localhost:8848

启动微服务,效果图为下:

SpringCloud深度学习(在更)_第22张图片

 nacos服务分级存储模型

实现方法就是:将每个服务分布到不同的集群,这样就可以保证在某个集群失效时不会影响服务的使用。

例子:将所有的user-service设置到集群HZ,将order-service设置到集群BJ。
在application.yml的设置为下:

spring:
  cloud:
    nacos:
      discovery:
        #设置对应的集群名称
        cluster-name: BJ

实现效果为下:

SpringCloud深度学习(在更)_第23张图片

SpringCloud深度学习(在更)_第24张图片

 服务实例的权重设置

权重范围为:0~1,数字越大权重就越大。

在nacos中的是设置方式为下:

SpringCloud深度学习(在更)_第25张图片

权重的使用的特殊情况。

当我们需要对某个模块进行升级时,我们不再需要重新发布项目,而是将当前服务的权重设置为0,这样用户访问是就不会调用当前的服务模块,用户对访问到项目功能的其他模块。

nacos设置负载均衡

 在application.yml中配置以下信息:

#对应要设置策略的服务名
user-service:
  ribbon:
    #设置的哦负载均衡的策略
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

该策略为:存在多个拥有同样功能的集时,我们会先去访问,距离我们更近的集群,当该集群宕机时,才会访问其他相同功能的模块。

nacos环境隔离

SpringCloud深度学习(在更)_第26张图片在nacos中新建一个环境的方式。

SpringCloud深度学习(在更)_第27张图片

 id不设置的话,就会通过UUID自动生成。

SpringCloud深度学习(在更)_第28张图片

在代码application.tml中设置服务的环境空间。

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: BJ
        namespace: 419f5dac-5806-4e04-9017-6f7bf726ba41

 注意:不同环境间的服务模块是无法相互调用的,所以如果出现500异常可能就是跨环境的错误。

nacos和eureka的区别

SpringCloud深度学习(在更)_第29张图片

nacos设置非临时实例的设置为下:

spring:
  cloud:
    nacos:
      discovery:
        #设置为非临时实例
        ephemeral:true

nacos配置管理

在nacos中配置对应的application.yml。

配置文件的名字的格式为:[服务名]-[对应的环境名].[文件格式]。(userservice-dev.yaml)

 编写效果为下: 

SpringCloud深度学习(在更)_第30张图片

为了配合使用线上的配置文件,所以我们需要在springboot说明服务模块对应的线上的配置文件名。

需要在对应的服务模块引入对应的依赖



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-config

在对应的服务上创建bootstrap.yaml 文件,在该文件中配置对应的线上配置文件信息。

spring:
  application:
    name: orderservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev
  cloud:
    nacos:
      server-addr: localhost:8848 # Nacos地址
      config:
        file-extension: yaml # 文件后缀名
#      discovery:
#        namespace: 419f5dac-5806-4e04-9017-6f7bf726ba41

在controller类中编写对应的属性

  

启动测试。

SpringCloud深度学习(在更)_第31张图片

确实读到线上的配置,但此时我们在去更改线上的配置,发现获取的name还是历史版本的值,需要我们重启对应的服务模块才会进行更新,为了实现热更新,我们提供了两种解决方案。

热更新
1. 在属性对应的类上使用就注解:@RefreshScope。

SpringCloud深度学习(在更)_第32张图片

 进行测试,效果图为下:

更改前:

SpringCloud深度学习(在更)_第33张图片

更新后:

SpringCloud深度学习(在更)_第34张图片

 2.创建对用的属性类,将该属性类交给spring容器管理,实现热更新。

创建对用的属性类:OrderProperties

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("com")
@Data
public class OrderProperties {
    private String name;
}

在controller层中注入OrderProperties

import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.OrderProperties;
import cn.itcast.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

   @Autowired
   private OrderService orderService;
    @Autowired
    OrderProperties orderProperties;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }
    @GetMapping("/test")
    public String test1() {
        System.out.println("线上对应的名字为:" + orderProperties.getName());
        return orderProperties.getName();
    }
}

测试结果和方案一效果相同。

配置共享

在某个服务模块中,该模块中会存在多个环境: dev, pro, test,这些环境的配置在nacos中都是相互隔离的,为使得各个模块都可以读到某个配置,我们可以在nacos中创建一个配置共享文件。

 测试环境就是:

orderservice-dev.yaml, orderservice-pro.yaml, orderservice-test.yaml。

我们可以创建一个配置文件,该文件的名字是固定的 ,[spring.application.name].yaml。

进行测试。

让orderservice服务去读取线上模块的共享配置。

SpringCloud深度学习(在更)_第35张图片

 修改对应的OrderProperties。

SpringCloud深度学习(在更)_第36张图片

 测试结果为下:

SpringCloud深度学习(在更)_第37张图片

 搭建nacos集群

集群结构

SpringCloud深度学习(在更)_第38张图片

 搭建步骤为下:

1.在本地数据库中创建nacos需要的数据库信息。

创建一个名字为 nacos的数据库,然后导入对应的sql。

CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(64) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `src_user` text,
  `src_ip` varchar(50) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE `users` (
	`username` varchar(50) NOT NULL PRIMARY KEY,
	`password` varchar(500) NOT NULL,
	`enabled` boolean NOT NULL
);

CREATE TABLE `roles` (
	`username` varchar(50) NOT NULL,
	`role` varchar(50) NOT NULL,
	UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);

CREATE TABLE `permissions` (
    `role` varchar(50) NOT NULL,
    `resource` varchar(255) NOT NULL,
    `action` varchar(8) NOT NULL,
    UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

下载对应的nacos压缩包,解压后将conf/cluster.conf.example文件重命名为cluster.conf。

在cluster.conf中怕配置各个 nacos的地址。

startup.cmd

修改/conf/application.properties中的mysql信息

SpringCloud深度学习(在更)_第39张图片复制三份nacos,并在application.properties中配置对应的端口,启动这些nacos。

启动指令为下:

startup.cmd 

2. 配置nginx进行负载均衡操作了。

修改/conf/nginx.conf的配置。

 #配置对应的nacos集群的地址
    upstream nacos-cluster {
    server 127.0.0.1:8841;
	server 127.0.0.1:8842;
	server 127.0.0.1:8843;
    }
    #配置代理
    server {
        listen       80;
        server_name  localhost;

        location /nacos {
            proxy_pass http://nacos-cluster;
        }
    }

启动nginx,在我们使用项目的配置中nacos的地址就是localhost:80,80端口就是nginx代理后的结果。

Feign

feign的使用 

在对应的服务模块引入依赖 


    org.springframework.cloud
    spring-cloud-starter-openfeign

 在启动类上夹feign的注解驱动:  @EnableFeignClients

在对用服务模块中创建被调用服务对应的feign 接口

import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("userservice")//被调用模块的名称
public interface orderFeignClient {
    @GetMapping("/user/{id}")
    public User queryOrderByUserId(@PathVariable("id") Long id);
}

将调用服务的模块中controller的代码为下

import cn.itcast.order.FeignClient.UserFeignClient;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@Service
public class OrderService {

    @Resource
    private OrderMapper orderMapper;
   @Autowired
    UserFeignClient userFeignClient;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        //通过获取的userId,调用userService获取对应的信息
        User user = userFeignClient.queryOrderByUserId(order.getUserId());
        System.out.println(user);
        order.setUser(user);
        // 4.返回
        return order;
    }
}

测试效果图为下

SpringCloud深度学习(在更)_第40张图片

feign自定义配置

SpringCloud深度学习(在更)_第41张图片

配置我们做的配置一般也就是 feign.logger.level。

logger的等级为下:

  • NONE:不记录任何日志信息,这是默认值。

  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间

  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息

  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。  

logger的配置为下:

feign:
  client:
    config:
      default: #如果是default表示全局配置,如果是对应的服务名,也就是作用在对应的服务模块
      loggerLevel: FULL
      

使用java代码实现logger等级的配置

创建一个类进行配置。

import feign.Logger;
import org.springframework.context.annotation.Bean;

public class orderConfiguration {
    @Bean
    public Logger.Level loginLevel() {
        return Logger.Level.BASIC;
    }
}

如果需要作用在全局,那么就在启动类上进行配置。

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = orderConfiguration.class)
public class OrderApplication {

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

}

如果需要作用在对用的服务上,我们只需要在对应服务的FeignClient接口上配置即可。

@FeignClient(value = "userservice", configuration = orderConfiguration.class)//被调用模块的名称
public interface UserFeignClient {
    @GetMapping("/user/{id}")
    public User queryOrderByUserId(@PathVariable("id") Long id);
}

feign使用优化

Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:

•URLConnection:默认实现,不支持连接池

•Apache HttpClient :支持连接池

•OKHttp:支持连接池

因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。  

实现方法为下:

引入对应的依赖



    io.github.openfeign
    feign-httpclient

 在application.yml中配置对应的信息

feign:
  httpclient:
    enabled: true #开启feign对httpClient的支持
    max-connections: 200 #最大的连接数
    max-connections-per-route: 50 #每个路径找到的连接数

使用优化的方案

1.日志级别尽量用basic,保证日志的输出最少。

2.使用HttpClient或OKHttp代替URLConnection

① 引入feign-httpClient依赖

② 配置文件开启httpClient功能,设置连接池参数

最佳实现方案

1.继承方式。

一样的代码可以通过继承来共享:

1)定义一个API接口,利用定义方法,并基于SpringMVC注解做声明。

2)Feign客户端和Controller都集成改接口

SpringCloud深度学习(在更)_第42张图片

优点:

  • 简单。

  • 实现了代码共享。

缺点:

  • 服务提供方、服务消费方紧耦合

  • 参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解。  

 2.将Feign单独抽取成一个包,在未来需要使用时直接导入包即可。

 SpringCloud深度学习(在更)_第43张图片

方案二实现步骤 

创建对应的Fiegn包,将相关的feign接口和pojo,配置类都抽取到此包。

SpringCloud深度学习(在更)_第44张图片

在对应的服务模块中引入feign-api包。

    
            cn.itcast.demo
            feign-api
            1.0
        

将对应的配置进行导包,我们此时运行项目会发现userFeignClient在spring容器中找不到,这是因为Feign接口没有被项目在开始时扫描到,是可以为了让其扫描到,我们需要添加一些配置。

在@EnableFeignClients中配置配置扫描的包

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(basePackages = "com.huang.FeignClient")
 //如果需要指定某个class的话就使用{}进行指定

public class OrderApplication {

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

}

 进行测试,测试结果为下:

SpringCloud深度学习(在更)_第45张图片

Gateway

 什么是Gateway: 

Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

Gateway的使用

 创建一个新得模块,用于创建gateway。

导入相应得依赖。



    org.springframework.cloud
    spring-cloud-starter-gateway



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery

在applicatino.yml中配置规则

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**

测试结果为下:

SpringCloud深度学习(在更)_第46张图片

断言规则

SpringCloud深度学习(在更)_第47张图片

gateway过滤器 

过滤器的作用

SpringCloud深度学习(在更)_第48张图片 过滤器存在很多个。

名称 说明
AddRequestHeader 给当前请求添加一个请求头
RemoveRequestHeader 移除请求中的一个请求头
AddResponseHeader 给响应结果中添加一个响应头
RemoveResponseHeader 从响应结果中移除有一个响应头
RequestRateLimiter 限制请求的流量

测试:在此我们测试AddRequestHeader过滤器,也就是添加请求头过滤器。

 在application.yml配置过滤器

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
          filters:
            #添加对应的请求头, 此时请求头的名字为hello,值为:ostkaka!
            - AddRequestHeader=hello, ostkaka!

进行测试。

在controller层中编写代码

 @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId, @RequestHeader(value = "hello", required = false) String str) {
        // 根据id查询订单并返回
        System.out.println("请求头的信息未为:" + str);
        return orderService.queryOrderById(orderId);
    }

在我们访问orderservice模块时,就会出现以下效果图

如果需要将该请求头设置作用在所有的服务模块上,我们可以使用default-filters

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters: #默认的过滤器配置,作用在全局
      - AddRequestHeader=hello, ostkaka! 

进行测试,和之前效果用于,在其他服务模块也可以获得对用的请求头。

全局过滤器

不同于default-filters,全局过滤器可以自定义过滤方式。

自定义步骤为下:

创建个类,用于实现GlobalFilter接口。

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
@Order(0)//设置权重
public class GlobalFilterImpl implements GlobalFilter {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap queryParams = request.getQueryParams();
        List name = queryParams.get("name");
        if(name.equals("admin")) {
            //说明name = admin
            //放行
            return chain.filter(exchange);
        }
        //不符合条件,不放行
        exchange.getResponse().setStatusCode(HttpStatus.valueOf(401));
        //直接完成就不向下放行
        return exchange.getResponse().setComplete();
    }
}

该过滤器会直接在ioc容器中创建,直接作用在全局。

效果图为下:

SpringCloud深度学习(在更)_第49张图片

 过滤器的执行顺序

SpringCloud深度学习(在更)_第50张图片 网关解决跨域问题

 在网关模块中的application.yml中配置即可

spring:
  cloud:
    gateway:
      # 。。。
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

后续使用CV即可。

Sentinel

雪崩问题

SpringCloud深度学习(在更)_第51张图片 如果其中有个服务发生故障时,会导致关联的所有模块发生故障。

解决雪崩问题方案

1.超时处理

设置访问服务的超时时间,请求超过一定时间就返回错误信息,不会进行永久等待。

SpringCloud深度学习(在更)_第52张图片

2.仓壁模式

SpringCloud深度学习(在更)_第53张图片 

 船舱都会被隔板分离为多个独立空间,当船体破损时,只会导致部分空间进入,将故障控制在一定范围内,避免整个船体都被淹没。

于此类似,我们可以限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。

SpringCloud深度学习(在更)_第54张图片

分配线程给对应的服务,如果对应二点线程耗尽后,也不会占用其他的线程,保证项目的其他模块正常运行。

 3.断路器模式

断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。(也就是我们未来最常使用的解决方案)

SpringCloud深度学习(在更)_第55张图片

 当发现对应的服务模块的异常比例过高时,断路器就会执行熔断操作,就直接无法访问异常的服务模块,直接返回错误信息,保证其他服务模块的正常运行。

限流

流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

SpringCloud深度学习(在更)_第56张图片

 熔断技术的对比

SpringCloud深度学习(在更)_第57张图片

 sentinel整合springboot

1.运行sentinel。

2.引入依赖(springcloud对应的版本为:Hoxton.SR8)



    com.alibaba.cloud 
    spring-cloud-starter-alibaba-sentinel

3.在application.yml中配置sentinel的配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel的面板地址

访问对应的模块,进行测试

SpringCloud深度学习(在更)_第58张图片

sentine就在实时监测对应模块的并发和异常情况。

 

你可能感兴趣的:(SpringBoot,分布式,spring,cloud,spring,后端)