SpringCloud
认识微服务
之前使用的都是。也就是将所有功能集中在一个项目中开发,打包一个包部署
优点:架构简单,部署成本低
缺点:耦合度高,扩展性差
:根据业务功能进行拆分,每个业务模块作为独立系统开发,成为一个服务。
优点:降低服务耦合,有利于服务升级扩展,架构复杂,难度大
缺点:
服务拆分粒度如何?
服务集群地址如何维护?
服务之间如何实现远程调用?
服务健康状态如何感知?
什么是微服务?
微服务是一种经过良好架构设计的分布式架构方案。
- 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
- 面向服务:微服务对外暴露业务接口
- 自治:团队独立、技术独立、数据独立、部署独立
- 隔离性极强:服务调用做好隔离、容错、降级,避免出现级联问题
微服务:一种良好的分布式架构方案
- 优点:拆分粒度更小、服务更独立、耦合度更低
- 缺点:架构非常复杂,运维、监控、部署难度提高
微服务结构
微服务技术对比
企业需求
SpringCloud
SpringCloud 和 SpringBoot版本兼容关系
服务拆分
单一职责:不同微服务,不要重复开发相同业务
数据独立:不要访问其他微服务的数据库
将自己业务暴露为接口,供其他微服务调用
搭建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秒检测接口信息是否宕机,宕机会踢掉这些信息
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,他们互相做注册,做数据交流
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 页面
当打开页面后
最重要的地方就是这两个
Instances currently registered with Eureka
表示当前部署的服务有哪些
表示当前有一个服务名字叫做 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
会发现下面图中多了两个,表示注册成功
启动两个实例
-Dserver.port=8082
可以看到下面已经出现两个了
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
- 发起请求,请求Erueka,Erueka找到之后
- 返回给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));
}
可以看到拿到地址了
负载均衡
跟入
会调用 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);
}
}
流程
负载均衡策略(调整规则)
Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则:
内置负载均衡规则类 | 规则描述 |
---|---|
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服务地址
分级存储模型(集群配置)
- 服务调用尽可能选择本地的集群服务,因为跨集调用延迟较高
- 只有本地集群不能使用的情况下,才能访问其他集群
spring:
application:
name: userserver #user的服务名称
cloud:
nacos:
server-addr: localhost:8848 #nacos服务地址
discovery:
cluster-name: HZ # 配置集群名称为杭州
可以在Nacos里面看到有集群
NacosRule 负载均衡
注意:下面服务名是根据服务定制的(谁调用给谁加)
userserver: # 服务名
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
访问流程,优先访问本集群,如果本集群挂掉再访问其他集群(跨集群),本集群多个随机
权重负载均衡(在Nacos里)
有时候,我们需要让好机器负载更多的请求,而性能差的负载较少的请求
这个时候就需要权重控制了(权重0~1,一般设置小数)
环境隔离-namespace(数据隔离)
首先在这里新建命名空间,ID可以不填写,会自动生产
在代码中, 配置好之后只有同空间中的才能访问
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 配置管理
统一配置管理
首先添加
dataId:一般都是服务名 + 环境名 + 后缀(要唯一) Group:不用动 配置内容:只是有热更新需求的
获取配置文件步骤
graph LR
项目启动 --> 读取本地配置文件application.yml --> 创建spring容器 --> 加载Bean
- 需要提前创建一个 bootstrap.yaml 文件
子模块引入依赖
<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。
开启两个服务,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');
步骤一: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
(打开)
- 打开33行的数据源,表示用mysql集群
# spring.datasource.platform=mysql
spring.datasource.platform=mysql
- 打开36行,表示数据库的数量
# db.num=1
db.num=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
打开 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:因为端口和名字冲突的问题,在名字上多试几个新名字()
配置好之后,添加配置信息,会同步到数据库