微服务(Erurka,Nacos)

274 阅读6分钟

SpringCloud

认识微服务

之前使用的都是单体架构\color{green}{单体架构}。也就是将所有功能集中在一个项目中开发,打包一个包部署
优点:架构简单,部署成本低
缺点:耦合度高,扩展性差


分布式架构\color{green}{分布式架构}:根据业务功能进行拆分,每个业务模块作为独立系统开发,成为一个服务。
优点:降低服务耦合,有利于服务升级扩展,架构复杂,难度大
缺点:

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

什么是微服务?

微服务是一种经过良好架构设计的分布式架构方案。

  • 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  • 面向服务:微服务对外暴露业务接口
  • 自治:团队独立、技术独立、数据独立、部署独立
  • 隔离性极强:服务调用做好隔离、容错、降级,避免出现级联问题

微服务:一种良好的分布式架构方案

  • 优点:拆分粒度更小、服务更独立、耦合度更低
  • 缺点:架构非常复杂,运维、监控、部署难度提高

微服务结构

image.png

微服务技术对比

image.png

企业需求

image.png

SpringCloud

image.png

SpringCloud 和 SpringBoot版本兼容关系

image.png

服务拆分

单一职责:不同微服务,不要重复开发相同业务
数据独立:不要访问其他微服务的数据库
将自己业务暴露为接口,供其他微服务调用

搭建cloud项目

父工程创建 maven 项目

配置父工程maven

<packaging>pom</packaging> 打包方式

<modules> 管理子模块
    <module>order-service</module>
    <module>user-service</module>
</modules>

子模块需要继承父模块

远程调用 RestTemplate

配置

// 注册 RestTemplate远程调用
@Bean
public RestTemplate restTemplate(){
    return new RestTemplate();
}

使用

@Override
public Order queryOrderById(Integer orderId) {
    Order order = orderDao.selectById(orderId);
    // 利用 RestTemplate 发起http请求获取User对象
    String url = "http://localhost:8080/user/" + order.getUserId();
    //获取User对象,自动反序列化,使用get请求
    User user = restTemplate.getForObject(url, User.class);
    order.setUser(user);
    return order;
}

提供者与消费者

服务提供者:一次业务中,被其他微服务调用的服务。(提供接口给其他微服务) 服务消费者:一次业务中,调用其他微服务的服务。(调用其他微服务提供的接口) 一个服务可以同时是提供者和消费者

Eureka 注册中心

下面这种方式,地址是硬编码的方式

String url = "http://localhost:8080/user/" + order.getUserId();

下面有几个问题?

  • 服务消费者如何获取服务提供者的地址信息?
    • 服务提供者启动时向Eureak注册自己信息,交给Eureka保存
    • 消费者根据服务名称向Eureka拉取提供者信息
  • 如果有多个服务提供者,消费者该如何选择?
    • 服务消费者利用负载均衡算法,从服务列表中挑选一个
  • 消费者如何得知服务者的健康状态,是否宕机?
    • 每隔30秒向EurekaServer发送心跳请求,检测是否还在运行
    • 如果已宕机就剔除

Eureka 作用

  • 服务启动时把接口信息在Eureka中注册,交给Eureka管理
  • 当消费者使用的时候从Eureka中要接口信息。拉取服务
  • Eureka 不会给他宕机的接口信息
  • Eureka每隔30秒检测接口信息是否宕机,宕机会踢掉这些信息 image.png Eureka架构服务角色分为两类:
    EureakServer:服务端,注册中心(记录服务信息,心跳监控)
    EurekaClient: 客户端
    • Provider:服务提供者(注册到EurekaServer,每隔30秒发送自己心跳)
    • consumer:服务消费者(拉取服务列表,基于服务做负载均衡,选中微服务发起远程调用)

Eureka 实践

父项目需要引入在 dependencyManagement

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Hoxton.SR10</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

新建一个项目叫 eureka-server

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

创建SpringBoot类,并且加上 @EnableEurekaServer

package com.example;

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

配置文件中配置Eureka信息
因为Eureka本身也是服务,所以需要配置自己的信息,加入自己\color{green}{因为Eureka本身也是服务,所以需要配置自己的信息,加入自己}

  • 比如我注册了三个Eureka,他们互相做注册,做数据交流
server:
  port: 10086 # 服务端口
spring:
  application:
    name: eurekaserver
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka #这里是多个,需要逗号分开  

遇到问题:表示当前 springCloud 版本和 SpringBoot 版本对应不上

Error creating bean with name 'configurationPropertiesBeans' defined in class path resource [org/springframework/cloud/autoconfigure/ConfigurationPropertiesRebinderAutoConfiguration.class]: Post-processing of merged bean definition failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [org.springframework.cloud.context.properties.ConfigurationPropertiesBeans] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b]

Eureka 页面

当打开页面后

image.png 最重要的地方就是这两个

Instances currently registered with Eureka
表示当前部署的服务有哪些

image.png 表示当前有一个服务名字叫做 eurekaserver 后面up是表示正在运行,再后面是地址

Eureka 服务的注册

在服务的项目中加入下面依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

配置当前服务信息,注册服务

spring:
  application:
    name: orderserver # 起服务名
eureka:
  client:
    service-url:
      # 注意这个10086一定要和前面Erueka对应
      defaultZone: http://127.0.0.1:10086/eureka

会发现下面图中多了两个,表示注册成功

image.png

启动两个实例

image.png

-Dserver.port=8082

image.png 可以看到下面已经出现两个了

image.png

Erueka 服务拉取(负载均衡)

负载均衡就是在并发量大的情况下,分配不同的服务器

消费者项目需要给RestTemplate加负载均衡 @LoadBalanced

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

消费者调用直接写服务名

@Override
public Order queryOrderById(Integer orderId) {
    Order order = orderDao.selectById(orderId);
    // 利用 RestTemplate 发起http请求获取User对象

    //实现负载均衡,下面 userserver 是在Eureka中配置的服务名
    String url = "http://userserver/user/" + order.getUserId();

    //获取User对象,自动反序列化,使用get请求
    User user = restTemplate.getForObject(url, User.class);
    order.setUser(user);
    return order;
}

Ribbon 负载均衡(原理)

Eureka 实现负载均衡使用的是 Ribbon

image.png

  1. 发起请求,请求Erueka,Erueka找到之后
  2. 返回给Ribbon,做负载均衡后,返回

添加 @LoadBalanced 注解之后
表示RestTemplate发起的请求,被Ribbon拦截并做处理

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

拦截原理

被 LoadBalancerInterceptor类所拦截,实现了 ClientHttpRequestInterceptor 拦截请求
接口中,下面的方法会拦截Http请求

ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;

实现类源代码

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI(); //拿到整个地址
        String serviceName = originalUri.getHost(); // 获的服务名称
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); //找Eruake,交给Ribbon处理
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

可以看到拿到地址了

image.png

负载均衡

image.png

跟入

会调用 this.execute

public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
}

继续跟入

  • serviceId 是服务的名称
  • ILoadBalancer对象的全名:DynamicServerListLoadBalancer(动态服务列表)
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
    ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
    Server server = this.getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    } else {
        RibbonServer ribbonServer = new RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
        return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
    }
}

流程

image.png

负载均衡策略(调整规则)

Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则:

image.png

内置负载均衡规则类规则描述
RoundRobinRule只做轮询,默认规则
ZoneAvoidanceRule以当前区域可用的服务器进行服务器选择,使用Zone对服务器进行分类,也就是给服务器进行地区标注,优先选择距离较近的(做轮询)
AvailabilityFilteringRule默认情况下:这台服务器如果连续三次失败,服务器会被标注为短路,短路持续30秒,如果再次连接失败,会几何级的增加短路时间
并发数过高的服务器如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit属性进行配置
WeightedResponseTimeRule为每个服务器增加权重值,服务器响应时间越长,权重就越小,影响服务器的选择
RandomRule随机选择一个可用的服务器。
RetryRule重试机制的选择逻辑

调整负载均衡规则
方式一:适用于Erueka 2.2.7.RELEASE

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
@Bean
public IRule rule(){
    return new RandomRule();
}

配置方式(只适合于 Erueka 2.2.7.RELEASE)

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡规则

懒加载配置(只适合于 Erueka 2.2.7.RELEASE)

Ribbon 是懒加载,第一次才会拉取服务,请求时间较长

配置饥饿加载是在项目创建时,启动创建,降低第一次访问耗时。

ribbon:
  eager-load:
    clients: userserver
    enabled: true

如果指定多个服务是这样写

ribbon:
  eager-load:
    clients: 
        - userserver
        - orderserver
    enabled: true

Nacos 注册中心

是 alibaba 的产 品 下载并解压,在bin里面,打开cmd进行启动

  • standalone 表示单机启动,还有集群启动

startup.cmd -m standalone

默认账号密码都是:nacos
导入依赖:注意不能和Eureka依赖同时存在
和Ribbon通用,但是2021版本已取消Ribbon 父工程

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.6.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

子工程

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

配置注册

application:
  name: userserver # user的服务名称
cloud:
  nacos:
    server-addr: localhost:8848 #nacos服务地址

分级存储模型(集群配置)

  • 服务调用尽可能选择本地的集群服务,因为跨集调用延迟较高
  • 只有本地集群不能使用的情况下,才能访问其他集群

image.png

spring:
  application:
    name: userserver #user的服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 #nacos服务地址
      discovery:
        cluster-name: HZ # 配置集群名称为杭州

可以在Nacos里面看到有集群

image.png

NacosRule 负载均衡

注意:下面服务名是根据服务定制的(谁调用给谁加)

userserver: # 服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则

访问流程,优先访问本集群,如果本集群挂掉再访问其他集群(跨集群),本集群多个随机

权重负载均衡(在Nacos里)

有时候,我们需要让好机器负载更多的请求,而性能差的负载较少的请求

这个时候就需要权重控制了(权重0~1,一般设置小数)

权重越高访问的越多\color{green}{权重越高访问的越多}

image.png

环境隔离-namespace(数据隔离)

首先在这里新建命名空间,ID可以不填写,会自动生产

image.png

在代码中, 配置好之后只有同空间中的才能访问

spring:
  application:
    name: orderserver
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务地址
      discovery:
        cluster-name: ShangHai
        # 把ID配置上去,表示当前服务在此空间中
        namespace: 3cb28592-a9fd-479c-b060-ca05f8db0f39 

总结:
不同namespace下的服务是不可见的
namespace有唯一的ID标识

Eureka 和 Nacos 区别(宕机)

Nacos 会把服务的提供者,划分为临时实例和非临时实例(默认都是临时实例)
临时实例:可以人为停止服务,用心跳检测,一段时间发一次心跳。宕机直接踢掉
非临时实例:Nacos,有Nacos主动发信息询问是否宕机,如果宕机了,会等它恢复健康

拉取也不一样,会每隔一段时间去pull和push,Erurka只有pull 如果有服务挂掉了,会主动push服务。

配置非临时实例

spring:
  application:
    name: orderserver
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务地址
      discovery:
        cluster-name: ShangHai
        namespace: 3cb28592-a9fd-479c-b060-ca05f8db0f39
        ephemeral: false # 修改为非临时实例

Nacos与eureka的共同点
- 都支持服务注册和服务拉取
- 都支持服务提供者心跳方式做健康检测
Nacos与Eureka的区别
- Nacos支持服务端主动检测提供者状态:
- 临时实例采用心跳模式
- 非临时实例采用主动检测模式
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

Nacos 配置管理

统一配置管理

首先添加

image.png

dataId:一般都是服务名 + 环境名 + 后缀(要唯一) Group:不用动 配置内容:只是有热更新需求的

image.png

获取配置文件步骤

graph LR
项目启动 --> 读取本地配置文件application.yml --> 创建spring容器 --> 加载Bean
  • 需要提前创建一个 bootstrap.yaml 文件 image.png

子模块引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

如果springBoot版本是2.6以上,加入以下注解

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

在 bootstrap.yaml 中加入以下内容

spring:
  application:
    name: userserver # 服务名
  profiles:
    active: dev # 生产环境
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # 地址
      config:
        file-extension: yaml # 后缀名

配置热更新(方式一)

上面只是获取,配置热更新还需要加 @RefreshScope

@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {

配置热更新(方式二推荐)

创建下面这个类

@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
}

实现它

// 创建刚刚的类
@Resource
private PatternProperties properties;

@GetMapping("/date")
public String query() {
    return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));
}

多环境配置共享

微服务启动时,会从Nacos读取多个配置文件
文件一:服务名-环境名.yaml
文件二:服务名.yaml

无论文件环境怎么变,文件二的绝对不变

创建此配置(Nacos里),无任何含义

启动dev会自动启动dev。

image.png

开启两个服务,dev和test。
dev 环境可以读取所有,test环境只能读取共享的属性

优先级问题
本地环境---最低
共享环境---中
当前环境配置---最高

Nacos 集群搭建

初始化数据库表

新建一个命名为nacos

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');

image.png

步骤一:Mysql搭建主从集群,因为主从比较复杂,这里用单点模式
集群几个系统就要存在几个Nacos(简称节点)

首先把 conf 中的 cluster.conf.example 的改为 cluster.conf

(打开)

#
# Copyright 1999-2018 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#it is ip
#example
# 这里是三个节点的地址
127.0.0.1:8845
127.0.0.1:8846
127.0.0.1:8847

打开 conf 中的 application.properties

(打开)

  1. 打开33行的数据源,表示用mysql集群
# spring.datasource.platform=mysql
spring.datasource.platform=mysql
  1. 打开36行,表示数据库的数量
# db.num=1
db.num=1
  1. 打开39行,配置数据库信息
### Connect URL of DB:
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# db.user.0=nacos
# db.password.0=nacos
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=1234

根据需求复制n份,修改端口,并启动

集群启动不需要加任何参数直接启动 startup.cmd

image.png

打开 nginx,config 里面 nginx.conf
在 server 上面加 upstream块

# upstream 的集群,有三个IP地址和端口号,和上面对应
upstream nacos-cluster {
    server 127.0.0.1:8845; #表示三个
    server 127.0.0.1:8846;
    server 127.0.0.1:8847;
}

# 反向代理
server {
    # 监听80端口,localhost
    listen       80;
    server_name  localhost;
    # /nacos,表示访问这个路径,代理到上面的集群去
    location /nacos {
        proxy_pass http://nacos-cluster;
    }

启动 nginx.exe 命令:start nginx.exe
关闭命令:taskkill /im nginx.exe /f

java 代码怎么配置?

spring:
  application:
    name: userserver
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: localhost:80 # 直接80
      config:
        file-extension: yaml

这个时候常常会遇到错误:failed to 400

failed to req API:/nacos/v1/ns/instance after all servers([localhost:80]) tried: ErrCode:400

解决方案1:在 nacos bin目录中 startup.cmd 中设置26行表示单机模式启动

set MODE="standalone"

解决方案2:因为端口和名字冲突的问题,在名字上多试几个新名字()

配置好之后,添加配置信息,会同步到数据库

image.png

image.png

下一篇:feign、Gateway