技术标签: SpringCloudAlibaba 分布式
版本兼容参考: alibaba/spring-cloud-alibaba
Spring Cloud: https://spring.io/projects/spring-cloud#overview
Spring Cloud Alibaba Version | Sentinel Version | Nacos Version | RocketMQ Version | Dubbo Version | Seata Version |
---|---|---|---|---|---|
2.2.5.RELEASE | 1.8.0 | 1.4.1 | 4.4.0 | 2.7.8 | 1.3.0 |
2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE | 1.8.0 | 1.3.3 | 4.4.0 | 2.7.8 | 1.3.0 |
2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE | 1.7.1 | 1.2.1 | 4.4.0 | 2.7.6 | 1.2.0 |
2.2.0.RELEASE | 1.7.1 | 1.1.4 | 4.4.0 | 2.7.4.1 | 1.0.0 |
2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE | 1.7.0 | 1.1.4 | 4.4.0 | 2.7.3 | 0.9.0 |
2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE | 1.6.3 | 1.1.1 | 4.4.0 | 2.7.3 | 0.7.1 |
Spring Cloud Version | Spring Cloud Alibaba Version | Spring Boot Version |
---|---|---|
Spring Cloud Hoxton.SR8 | 2.2.5.RELEASE | 2.3.2.RELEASE |
Spring Cloud Greenwich.SR6 | 2.1.3.RELEASE | 2.1.13.RELEASE |
Spring Cloud Hoxton.SR3 | 2.2.1.RELEASE | 2.2.5.RELEASE |
Spring Cloud Hoxton.RELEASE | 2.2.0.RELEASE | 2.2.X.RELEASE |
Spring Cloud Greenwich | 2.1.2.RELEASE | 2.1.X.RELEASE |
Spring Cloud Finchley | 2.0.3.RELEASE | 2.0.X.RELEASE |
Spring Cloud Edgware | 1.5.1.RELEASE(停止维护,建议升级) | 1.5.X.RELEASE |
服务治理概念
在RPC远程调用过程中,服务与服务之间依赖关系非常大,服务Url地址管理非常复杂,所以这时候需要对我们服务的url实现治理,通过服务治理可以实现服务注册与发现、负载均衡、容错等。
服务注册中心的概念
微服务调用接口常用名词
服务发现
Nacos的基本的介绍
Nacos可以实现分布式服务注册与发现/分布式配置中心框架。
官网的介绍: https://nacos.io/zh-cn/docs/what-is-nacos.html
windows安装nacos
首先去NACOS官网 下载相关jar,这里使用的是最新版本1.4.1
Nacos端口为8848
http://127.0.0.1:8848/nacos/#/login 账号密码nacos naocs
nacos可以支持分布式配置中心和服务注册与发现
首先要有一个SpringBoot项目,微服务项目是基于SpringBoot项目的,主要是由于SpringBoot项目可以不用写太多繁琐的配置文件,写过SSM的都体验过,那滋味。。。。
注意事项:必须先启动nacos,才能启动cloud的项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version> <!-- Spring Boot 版本 -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 子模块 -->
<modules>
<module></module>
</modules>
<groupId>com.cp</groupId>
<artifactId>springcloud-father</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-father</name>
<description>Demo project for Spring Boot</description>
<!-- 统一版本号 -->
<properties>
<java.version>1.8</java.version>
<spring.cloud-version>Hoxton.SR8</spring.cloud-version>
<spring.cloud.alibaba-version>2.2.5.RELEASE</spring.cloud.alibaba-version>
</properties>
<!--统一依赖-->
<dependencyManagement>
<dependencies>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这里我们现在Maven创建子模块,也可以使用SpringBoot创建子模块
使用SpringBoot 可以不用手动创建主启动类等一些文件
使用Maven 创建的子项目pom文件内容简短,方便建立父子模块关系
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //添加注解,实现服务注册
public class SpringCloudProviderApplication {
public static void main(String [] args){
SpringApplication.run(SpringCloudProviderApplication.class,args);
}
}
server:
port: 9000
spring:
application:
name: springcloud-provider #服务名称,微服务项目中必须设计服务名称
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
package com.cp.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-06 10:08
**/
@RestController
public class ProviderController {
@GetMapping("/index")
public String index(){
return "Hello word";
}
}
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
注意事项:必须先启动nacos,才能启动cloud的项目
访问地址:http://localhost:8848/nacos
启动完成后去nacos服务注册中心看看,发现provider生产者已经注册到了nacos,说明生产者已经搭建完成。
访问地址:http://localhost:9000/index ,如图所示,生产者已经搭建完成
创建消费者,步骤和创建生产者一样,修改一下端口号和服务名称
server:
port: 9001
spring:
application:
name: springcloud-consumer #服务名称,微服务项目中必须设计服务名称
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
注意事项:必须先启动nacos,才能启动cloud的项目
访问地址:http://localhost:8848/nacos
启动完成后nacos注册服务中心可以看到消费者服务已经注册
/**
* 服务发现
*/
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/instances")
public List<ServiceInstance> instances(){
List<ServiceInstance> instances = discoveryClient.getInstances("springcloud-consumer");
return instances;
}
注意事项:必须先启动nacos,才能启动cloud的项目
访问地址:http://localhost:9001/instances,如图所示:
消费者已经搭建完成并得到了注册信息
LB(Load Balance,负载均衡)是一种集群技术,它将特定的业务(网络服务、网络流量等)分担给多台网络设备(包括服务器、防火墙等)或多条链路,从而提高了业务处理能力,保证了业务的高可靠性。
负载均衡是一种基础的网络服务,核心原理是按照指定的负载均衡算法,将请求分配到后端服务集群上,从而为系统提供并行处理和高可用的能力。
负载均衡一般分为以下两种:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8AoPG0X-1616120955070)(https://images1.freesion.com/158/2a/2a380343a1444f63155c1499761c494e.png)]
客户端发送请求到负债均衡器,负载均衡器根据相关的负载均衡算法(随机、轮询、加权)选择其中一台服务器,将请求转发到服务器上。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8Z9QJXe-1616120955070)(https://images2.freesion.com/499/b0/b06eaa2e8cf41870af8b798bcf6f48f3.png)]
如上图所示,和集中式负载均衡的不同是,客户端负载均衡器需要自己维护服务实例的信息,然后通过相关的负载均衡算法(随机、轮询、加权)从实例中选取一个实例,直接进行访问。
Ribbon 默认采用轮询策略
这里我们实现消费者(consumer)调用提供者(provider)
在提供者(provider)定义方法
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-06 10:08
**/
@RestController
public class ProviderController {
//获取端口号
@Value("${server.port}")
private String port;
@GetMapping("/echo")
public String echo(){
//打印当前端口号
return "Hello word ------->"+port;
}
}
修改消费者(consumer)主启动类
添加@LoadBalanced注解
/**
* @LoadBalanced
* 实现赋值均衡
* 使用的是轮询策略
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
在消费者(consumer)定义service层
/**
* 调用provider模块中的方法
* @return String
*/
String echo();
@Autowired
private RestTemplate restTemplate;
@Override
public String echo() {
/**
* 第一个参数获取路径
* 第二个参数是那边接口返回的类型
* springcloud-provider 是提供者模块yml配置的名称
* index 是提供者里有的提供方法
*/
String s = restTemplate.getForObject("http://springcloud-provider/index", String.class);
return s;
}
在消费者(consumer)定义Controller层
@Autowired
private CousmerService cousmerService;
/**
* 调用生产者提供的方法
* @return
*/
@GetMapping("/echo")
public String echo(){
return cousmerService.echo();
}
注意事项:必须先启动nacos,才能启动cloud的项目
访问地址:http://localhost:9001/echo,如图所示
修改消费者(consumer)模块中的配置
#springcloud-provider 是你提供者(provider)模块名称
springcloud-provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
在消费者(consumer)添加NacosWeightLoadBalancerRule类
package com.cp.config;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 基于Nacos权重的负载均衡
*
* @Author Administrator
*/
@Slf4j
public class NacosWeightLoadBalancerRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
// 读取配置文件,并初始化NacosWeightLoadBalancerRule
}
@Override
public Server choose(Object o) {
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
// 请求的微服务名称
String applicationName = loadBalancer.getName();
try {
// nacos 通过基于权重的负载均衡算法,算出一个健康的服务实例以供调用
Instance instance = nacosDiscoveryProperties.namingServiceInstance().selectOneHealthyInstance(applicationName);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("获取服务实例异常:{}", e.getMessage());
}
return null;
}
}
添加依赖
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
配置文件
#springcloud-provider 是你提供者(provider)模块名称
springcloud-provider:
ribbon:
NFLoadBalancerRuleClassName: com.cp.config.NacosWeightLoadBalancerRule #刚刚创建类的路径
OpenFeign是一个声明式的Web服务客户端、让编写Web服务客户端变得更加容易只需要创建一个接口然后添加上注解即可,同时,它集成了Ribbon,可以轻松实现负载均衡的效果。
Feign和OpenFeign的区别:
这里我们对消费者(consumer)调用提供者(provider)进行优化
在消费者(consumer)模块中添加依赖
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在消费者(consumer)的主启动类添加注解
//支持 OpenFeign 组件的使用
@EnableFeignClients
修改消费者(consumer) service层
package com.cp.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @FeignClient(value = "springcloud-provider") 声明要访问的服务
* value = 需要访问的服务名称
* @GetMapping("/echo") 声明要调用的方法
* /echo 必须是访问服务里拥有的方法接口
**/
@FeignClient(value = "springcloud-provider")
public interface ConsumerService {
@GetMapping("/echo")
String echo();
}
定义后可以不用编写实现类可直接通过Controller层(不需要改动)进行调用
注意事项:必须先启动nacos,才能启动cloud的项目
访问地址:http://localhost:9001/echo,如图所示
在分布式系统中,由于网络原因或者自身的原因,服务一般无法保证100%可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况。此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。
由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩效应”。
服务雪崩效应是一种因 服务提供者 的不可用导致 服务调用者 的不可用,并将不可用 逐渐放大 的过程.如果所示:
上图中, A为服务提供者, B为A的服务调用者, C和D是B的服务调用者. 当A的不可用,引起B的不可用,并将不可用逐渐放大C和D时, 服务雪崩就形成了
我把服务雪崩的参与者简化为 服务提供者 和 服务调用者, 并将服务雪崩产生的过程分为以下三个阶段来分析形成的原因:
服务雪崩的每个阶段都可能由不同的原因造成, 比如造成 服务不可用 的原因有:
针对造成服务雪崩的不同原因, 可以使用不同的应对策略:
Sentinel 具有以下特征:
Sentinel 的主要特性:
Sentinel 的开源生态:
Sentinel 分为两个部分:
在提供者(provider)添加依赖
<!-- sentinel 服务容错 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 服务监控器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在提供者(provider)添加YAML配置
spring:
cloud:
# 服务容错
sentinel:
transport:
dashboard: localhost:8080
management:
endpoints:
web:
exposure:
include: '*'
提供者(provider) YAML 完整配置
server:
port: 9000
spring:
application:
# 服务名称
name: springcloud-provider #服务名称,微服务项目中必须设计服务名称
cloud:
# 服务注册
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
# 服务容错
sentinel:
transport:
dashboard: localhost:8080
management:
endpoints:
web:
exposure:
include: '*'
注意:运行项目前先启动本地的sentinel-dashboard-1.8.0.jar
包
打开控制台启动命令:
java -jar sentinel-dashboard-1.8.0.jar
启动成功后访问: http://localhost:8080;如图所示
账号密码sentinel sentinel
进入控制台后需要先访问一下接口进行监控
流控是Sentinel核心功能之一,流控指的是流量控制。
点击簇点链路后进行操作
表示1秒内查询2次就是OK,若超过次数2,就直接失败-快速失败,报默认错误。
连续快速访问:
当A接口访问到达指定的值,将B接口进行限流
在提供者(provider)定义方法
/**
* 测试关联限流
* @return
*/
@GetMapping("/show")
public String show(){
return "2333333";
}
目前提供者(provider)所拥有的方法
package com.cp.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-06 10:08
**/
@RestController
public class ProviderController {
/**
* 获取端口号
*/
@Value("${server.port}")
private String port;
/**
* 被消费者进行调用并输出当前端口号
* @return
*/
@GetMapping("/echo")
public String echo(){
return "Hello word ------->"+port;
}
/**
* 测试关联限流
* @return
*/
@GetMapping("/show")
public String show(){
return "2333333";
}
}
编写测试类频繁访问提供者(provider)接口 来测试限流
package com.cp;
import org.springframework.web.client.RestTemplate;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-08 14:46
**/
public class ProviderTest {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
for (int i = 0; i < 500; i++) {
String forObject = restTemplate.getForObject("http://localhost:9010/show", String.class);
try {
//0.1秒延迟
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
通过关联/show接口;当接口每秒访问超过2时,/echo接口限流
添加限流规则后去确定测试类进行测试
访问结果:
B和C都访问A接口,当B或C其中一个接口到达限流要求后将A接口限流
在提供者(provider)添加依赖
<!-- 链路限流所需以下三个依赖 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version> <!-- 通过版本统一可以忽略版本号 -->
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
在提供者(provider) YMAL 中配置添加
spring:
cloud:
sentinel:
filter:
enabled: false
提供者(provider) YAML 完整配置
server:
port: 9000
spring:
application:
# 服务名称
name: springcloud-provider #服务名称,微服务项目中必须设计服务名称
cloud:
# 服务注册
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
# 熔断器
sentinel:
transport:
dashboard: localhost:8080
filter:
enabled: false
management:
endpoints:
web:
exposure:
include: '*'
在提供者(provider)添加配置类
package com.cp.config;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-10 09:35
**/
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean registrationBean(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new CommonFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false");
registrationBean.setName("sentinelFilter");
return registrationBean;
}
}
提供者(provider) 添加 ProviderServiceImpl 类
package com.cp.service.impl;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-10 07:56
**/
@Service
public class ProviderServiceImpl {
//必须添加 @SentinelResource 才有流控效果
@SentinelResource("/link")
public String link(){
return "链路访问结果";
}
}
在提供者(provider) ProviderController 添加方法
@Autowired
private ProviderServiceImpl providerService;
/**
* 链路限流测试
* @return
*/
@GetMapping("/link1")
public String link1(){
providerService.link();
return "link1";
}
@GetMapping("/link2")
public String link2(){
providerService.link();
return "link2";
}
打开Sentinel 控制台,查看相关链路
进行链路限流
选择好资源名后,流控模式选择链路
根据自己选择的资源名查看他的拥有哪些入口资源,添加一个入口资源,可添加多个用逗号隔开
当入口资源达到自己定义的阈值后选择的资源进行限流
修改之前编写过的测试类进行测试
package com.cp;
import org.springframework.web.client.RestTemplate;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-08 14:46
**/
public class ProviderTest {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
for (int i = 0; i < 500; i++) {
String forObject = restTemplate.getForObject("http://localhost:9000/link2", String.class);
try {
//0.5秒延迟
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行测试类后访问/link1得到结果
资源成功的被限流了
消息队列概述
消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ
Linux 配置环境:传送门
JDK: jdk-8u271-linux-x64.tar.gz
RocketMQ: rocketmq-all-4.7.1-bin-release
RocketMQ控制台: rocketmq-externals
pom.xml 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
创建 Order 类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Integer id;
private String buyerName;
private String buyerTel;
private String address;
private Date createDate;
}
提供者(provider)添加依赖
<dependency>
<groupId>com.cp</groupId>
<artifactId>dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Spring Boot Rocketmq -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Rocketmq 可视化连接 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.1</version>
</dependency>
提供者(provider)目前依赖
<dependency>
<groupId>com.cp</groupId>
<artifactId>dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- sentinel 服务容错 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 服务监控器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 链路限流所需以下三个依赖 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
<!-- Spring Boot Rocketmq -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Rocketmq 可视化连接 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.1</version>
</dependency>
提供者(provider) 添加 application.yml 配置
rocketmq:
name-server: 192.168.64.135:9876
producer:
group: myprovider
提供者(provider) 现在 YAML 配置
server:
port: 9000
spring:
application:
# 服务名称
name: springcloud-provider #服务名称,微服务项目中必须设计服务名称
cloud:
# 服务注册
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
# 熔断器
sentinel:
transport:
dashboard: localhost:8080
filter:
enabled: false
management:
endpoints:
web:
exposure:
include: '*'
rocketmq:
name-server: 192.168.64.135:9876
producer:
group: myprovider
在提供者(provider) 控制器中 定义方法
@Autowired
private RocketMQTemplate rocketMQTemplate;
@GetMapping("/create")
public Order create(){
Order order = new Order(
1,
"张三",
"123123",
"软件园",
new Date()
);
this.rocketMQTemplate.convertAndSend("orderTopic",order);
return order;
}
目前提供者(provider) 控制器所拥有的方法
package com.cp.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-06 10:08
**/
@RestController
public class ProviderController {
/**
* 获取端口号
*/
@Value("${server.port}")
private String port;
/**
* 被消费者进行调用并输出当前端口号
* @return
*/
@GetMapping("/echo")
public String echo(){
return "Hello word ------->"+port;
}
/**
* 测试关联限流
* @return
*/
@GetMapping("/show")
public String show(){
return "2333333";
}
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 消息队列进行消息发送
*/
@GetMapping("/create")
public Order create(){
Order order = new Order(
1,
"张三",
"123123",
"软件园",
new Date()
);
this.rocketMQTemplate.convertAndSend("orderTopic",order);
return order;
}
}
启动前要保证nacos、ES、以及 [服务器/虚拟机] 端口号开放和打开
访问: http://localhost:9000/create 得到结果
消费者(consumer) 模块添加依赖和提供者(provider)添加依赖一致
<dependency>
<groupId>com.cp</groupId>
<artifactId>dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Spring Boot Rocketmq -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Rocketmq 可视化连接 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.1</version>
</dependency>
消费者(consumer) 目前拥有的依赖
<dependency>
<groupId>com.cp</groupId>
<artifactId>dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Boot Rocketmq -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Rocketmq 可视化连接 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.1</version>
</dependency>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
消费者(consumer) 添加 application.yml 配置
rocketmq:
name-server: 192.168.64.138:9876
消费者(consumer) 现在 YAML 配置
spring:
application:
name: springcloud-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
server:
port: 9001
rocketmq:
name-server: 192.168.64.135:9876
消费者(consumer) 创建 ConsumeService 类 进行消息消费
消费者(consumer)会实时监控提供者(provider)是否产生消息来通过消费
package com.cp.service;
import com.cp.enitiy.Order;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* @author : CP
* @version: 1.0
* @program : spring-cloud-alibaba
* @description :
* @date : 2021-03-16 20:13
**/
@Slf4j
@Service
@RocketMQMessageListener(consumerGroup = "myConsumer",topic = "orderTopic")
public class ConsumeService implements RocketMQListener<Order> {
@Override
public void onMessage(Order order) {
log.info("新订单{},发短信",order);
}
}
无论先启动提供者(provider)还是消费者(consumer)都没有关系
提供者(provider) 用于提供消息
消费者(consumer)实时监控提供者(provider)
启动前要保证nacos、ES、以及 [服务器/虚拟机] 端口号开放和打开
每次刷新提供者提供消息的接口,消费者都会立刻进行消费
打开 RocketMQ控制台也可以查看消费记录
java -jar rocketmq-console-ng-1.0.0.jar 启动jar包 访问自己定义的端口号
不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
以上这些问题可以借助网关解决。
客户端向Spring Cloud GateWay发出请求,然后在GateWay Handler Mapping中找到与请求相匹配的路由,将其发送到GateWay Web Handler;Handler再通过指定的过滤器链来将请求发送到我们实际的服务执⾏业务逻辑,然后返回。过滤器之
间⽤虚线分开是因为过滤器可能会在发送代理请求之前(pre)或者之后(post)执⾏业务逻辑。
Filter在“pre”类型过滤器中可以做参数校验、权限校验、流量监控、⽇志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改、⽇志的输出、流量监控等。
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
特别注意
Spring Cloud Gateway 不使用 Web 作为服务器,而是 使用 WebFlux 作为服务器,Gateway 项目已经依赖了 starter-webflux
,所以这里千万不要依赖starter-web
package com.cp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author : CP
* @version: 1.0
* @program : spring-cloud-alibaba
* @description :
* @date : 2021-03-19 09:35
**/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class,args);
}
}
在resources创建YAML文件
server:
port: 9010
spring:
application:
# 服务名称
name: springcloud-gateway #服务名称,微服务项目中必须设计服务名称
cloud:
gateway:
# 开启本地能使用服务访问路由
discovery:
locator:
enabled: true
routes:
#springcloud-provider 提供者模块
- id: SPRINGCLOUD-PROVIDER
uri: lb://springcloud-provider
predicates:
- Method=GET,POST #请求方式
#springcloud-consumer 消费者模块
- id: SPRINGCLOUD-CONSUMER
uri: lb://springcloud-consumer
predicates:
- Method=GET,POST
#其他服务可继续添加
传送门: 官方文档
启动 Gateway 模块、提供者(provider)模块、消费者(consumer)模块
访问提供者(provider)模块
访问消费者(consumer)模块
添加后访问必须携带请求头token才能进行访问
package com.cp.filter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Map;
/**
* 鉴权过滤器
*/
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (token == null || token.isEmpty()) {
ServerHttpResponse response = exchange.getResponse();
// 封装错误信息
Map<String, Object> responseData = Maps.newHashMap();
responseData.put("code", 401);
responseData.put("message", "非法请求");
responseData.put("cause", "Token is empty");
try {
// 将信息转换为 JSON
ObjectMapper objectMapper = new ObjectMapper();
byte[] data = objectMapper.writeValueAsBytes(responseData);
// 输出错误信息到页面
DataBuffer buffer = response.bufferFactory().wrap(data);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return chain.filter(exchange);
}
/**
* 设置过滤器的执行顺序
* @return
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
我们应用程序在运行过程中需要读取一切配置信息,这些信息会伴随程序的整个生命周期。例如:数据库的配置
随着微服务的兴起,配置文件也随之增加并且分散冗余,配置中心就是将配置文件从应用中剥离出来进行统一的管理,不需要我们的服务自己去管理配置。
目前市面上用的比较多的配置中心有:Spring Cloud Config、Apollo(携程)和Nacos(阿里)等。
对比项目 | Spring Could Confi | Apollo | Nacos |
---|---|---|---|
配置实时推送 | 支持(Spring Cloud Bus) | 支持(HTTP长轮询1s内) | 支持(HTTP长轮询1s内) |
版本管理 | 支持(Git) | 支持 | 支持 |
配置回滚 | 支持(Git) | 支持 | 支持 |
灰度发布 | 支持 | 支持 | 不支持 |
权限管理 | 支持(依赖Git) | 支持 | 不支持 |
多集群 | 支持 | 支持 | 支持 |
多环境 | 支持 | 支持 | 支持 |
监听查询 | 支持 | 支持 | 支持 |
多语言 | 只支持Java | 主流语言,提供了Open API | 主流语言,提供了Open API |
配置格式校验 | 不支持 | 支持 | 支持 |
单机读(QPS) | 7(限流所致) | 9000 | 15000 |
单击写(QPS) | 5(限流所致) | 1100 | 1800 |
3节点读 (QPS) | 21(限流所致) | 27000 | 45000 |
3节点写 (QPS) | 5(限流所致) | 3300 | 5600 |
发布配置
1、需要在 Nacos Server 中创建配置文件,采用YAML的方式部署配置文件,操作流程如下:
浏览器打开 http://127.0.0.1:8848/nacos,访问 Nacos Server
2、修改提供者(provider) resources 目录下的配置文件
添加bootstrap.properties
# 这里的应用名对应 Nacos Config 中的 Data ID,实际应用名称以配置中心的配置为准
spring.application.name=springcloud-provider-config
# 指定查找名为 nacos-provider-config.yaml 的配置文件
spring.cloud.nacos.config.file-extension=yaml
# Nacos Server 的地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
为了避免出现问题将提供者(provider)application.yml删除或注释
3、修改提供者(provider) ProviderController 类
在类上添加@RefreshScope可以达到服务端修改配置后立刻得到反应
注入ConfigurableApplicationContext方式将要以applicationContext.getEnvironment().getProperty(“user.name”);来取值
package com.cp.controller;
import com.cp.service.impl.ProviderServiceImpl;
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.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-06 10:08
**/
@RefreshScope //范围刷新
@RestController
public class ProviderController {
@Autowired
private ProviderServiceImpl providerService;
/**
* 获取端口号
*/
@Value("${server.port}")
private String port;
/**
* 获取自定义名称
*/
@Value("${user.name}")
private String name;
/**
* 被消费者进行调用并输出当前端口号
* @return
*/
@GetMapping("/echo")
public String echo(){
return "Hello word ------->"+port;
}
/**
* 测试关联限流
* @return
*/
@GetMapping("/show")
public String show(){
return "2333333";
}
/**
* 链路限流测试
* @return
*/
@GetMapping("/link1")
public String link1(){
providerService.link();
return "link1";
}
@GetMapping("/link2")
public String link2(){
providerService.link();
return "link2";
}
// /**
// * 注入配置文件上下文
// */
// @Autowired
// private ConfigurableApplicationContext applicationContext;
@GetMapping("/getName")
public String getName(){
// return applicationContext.getEnvironment().getProperty("user.name");
return name;
}
}
ableApplicationContext方式将要以applicationContext.getEnvironment().getProperty(“user.name”);来取值
package com.cp.controller;
import com.cp.service.impl.ProviderServiceImpl;
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.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : CP
* @version: 1.0
* @program : springcloud-father
* @description :
* @date : 2021-03-06 10:08
**/
@RefreshScope //范围刷新
@RestController
public class ProviderController {
@Autowired
private ProviderServiceImpl providerService;
/**
* 获取端口号
*/
@Value("${server.port}")
private String port;
/**
* 获取自定义名称
*/
@Value("${user.name}")
private String name;
/**
* 被消费者进行调用并输出当前端口号
* @return
*/
@GetMapping("/echo")
public String echo(){
return "Hello word ------->"+port;
}
/**
* 测试关联限流
* @return
*/
@GetMapping("/show")
public String show(){
return "2333333";
}
/**
* 链路限流测试
* @return
*/
@GetMapping("/link1")
public String link1(){
providerService.link();
return "link1";
}
@GetMapping("/link2")
public String link2(){
providerService.link();
return "link2";
}
// /**
// * 注入配置文件上下文
// */
// @Autowired
// private ConfigurableApplicationContext applicationContext;
@GetMapping("/getName")
public String getName(){
// return applicationContext.getEnvironment().getProperty("user.name");
return name;
}
}
Base64只是一个固定的转码,不安全的,是完全不安全的,只是将内容不能使肉眼辨认内容而已 String str="测试数据"; //转码Base64 Stringencode=Base64.getEncoder().encodeToString(str.getBytes()); System.out.println(encode); //解码Base64 byte[] decode = Base64.ge._base64 末尾是固定的吗
在阅读完《深入理解计算机系统》第一章(计算机系统漫游)、第七章(链接)以及第十章(虚拟存储器)和《程序员的自我修养——链接、装载与库》后,历时悠久的梦想终于要实现了。开篇之初,首先提出一个迷惑了很久的一个问题:什么是虚拟存储器?它跟进程的虚拟地址空间有什么关系?虚拟存储器是建立在主存--辅存物理结构基础上,有附加的硬件装置及操作系统存储管理软件组成的一种存储体系。
现如今DevOps已经深入人心,在这个大量数据中心建设加速的时代,运维部门都在高度强调自动化,而自动化的关键即DevOps。但是,大家在推进DevOps的过程中却发现其前途坎坷。 一种方案是建设自己的开发队伍从头开始,做CMDB、做监控、做自动化、做流程、做服务目录、做大屏展现,这种造轮子方法需要强大持续的研发投入,成本极高;第二种方案则是寻找开源产品改造,以适合自己,如CMDBBuil_统一运维平台选型对比
原标题:大神教你如何用C语言实现科学计算器用C实现的科学计算器使用C语言写的科学计算器,可以实现四则运算、三角函数运算、指对数运算;优先级正确;能智能屏蔽空格,能识别输入错误和运算错误,能实现继续运算、清空运算结果和有效退出的功能 附上代码#include #include #include #define INPUT_MAX 1000#define NODE_MAX 500#define NUM...
计算机组成原理全套教案 (12页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!9.9 积分计算机组成原理第1章概论一、 教学目标掌握:存储程序的概念、计算机系统的组成、计算机的工作过程、计算机的主要性能指 标。了解:电子计算机的发展简史、存储程序的概念、计算机系统的组成、计算机的工作过 程、计算机的主要性能指标。二、 课时分配本章安排6课时。其中,理论..._计算机组成教学教案
初学VC写了一个简单的编译器界面,请各位大佬赐教!1、工程代码块:2、系统主界面3、读取文件,编辑文件,复制,剪切,粘贴等小功能实现4、显示/隐藏工具栏目前还在完善中,有啥改进意见的我们可以一起讨论哦~~..._vb编译器
文章目录多任务的任务类型多任务的设置多任务的任务类型Normal:普通任务Semistatic:半静态任务,热启动后,任务从main程序起点开始重新执行。Static:静态任务,热启动后,任务从当前指针位置执开始行。多任务的设置虚拟示教器的控制面板页面虚拟示教器的配置——配置系统参数 ==>> 主题——controller选择Task后,点击显示全部选择添加,进入新建task页面,设置task类型(TYPE)和task的值(建议根据自己要实现的task功能定义_abbpcinterface
英特尔最近宣布针对英特尔主动管理技术(AMT),英特尔标准可管理系统(ISM)和英特尔小型企业技术固件,从版本6至11.6中的漏洞进行固件升级。该漏洞多年来一直存在于英特尔芯片组中,特别是管理引擎(ME)。 ME可以像DRM(数字版权管理)一样运行,可以让TPM(可信平台模块)和AMT一样工作。关于AMTAMT使系统管理员可以通过远程连接重新映像裸机。为了实现这一点,AMT需要开启许多权限,...
一般来说,同一个波特率可以对应多组参数,但是要让通信更稳定,则需要选择采样点尽量靠近CIA推荐值的那一组CIA推荐采样点波特率采样点【sample point】<=500K87.5%>500K80%>800K75%波特率计算公式:波特率 = 频率/(CAN_BS1+CAN_BS2+1)/CAN_Prescaler采样点计算方式:smp = (1+CAN_BS1)/(1+CAN_BS1+CAN_BS2)以上内容如有错误或描述不合理的地方_stm32can波特率设置
参考windows安装MPICH但安装时出错如下:运行exe文件时要加./表示当前目录,OK!某教程提及,故为方便使用,添加了个环境变量。_mpiexec2 安装
数据结构Java语言数据库GCsocket小细节算法题_查漏补缺自我总结
完全搬运,原文请猛戳NVIDIA 对开源驱动开发的支持之差从 Linus Torvalds 那句著名的“FuckNVIDIA”就可见一斑——几乎没有提供任何开发文档,开源驱动的开发基本要通过逆向工程进行。因而,想要获得较好的 3D 加速性能、VDPAU 硬件解码功能、完整的多头显示支持等等,你必须使用 NVIDIA闭源驱动。不过闭源驱动的一大问题就是文档匮乏、过时,一大堆神奇设置(不少还是隐藏的)...