Spring Cloud是什么
这里引用其他博主的说明
基于 Spring Boot 的 Spring 集成应用程序,它利用 Spring Boot 的开发便利性简化了分布式系统的开发,提供与外部系统的集成。 如服务注册与发现、配置中心、负载均衡、断路器、消息总线、数据监控等;换句话说:Spring Cloud 提供了构建分布式系统所需的“全家桶”。
Spring cloud Task,一个生命周期短暂的微服务框架,用于快速构建执行有限数据处理的应用程序。
个人理解:
springcloud是一种架构,一种思想,分布式,云架构,不专注于CRUD;springcloud就相当于乐高积木
————————————————
版权声明:本文为CSDN博主「小舟同学」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44021875/article/details/110948348
总的来说,SpringCloud做的就是协调各个微服务架构下的组件(如:服务注册中心,服务配置中心,服务间的远程调用,服务的负载均衡等等,这些组件可能都是由不同组织按照不同规范编写的,Spring Cloud做的就是让程序员可以不用在关注具体使用的哪个具体的组件,只需要遵照Spring Cloud提供的接口就可以搭建一套微服务架构的系统,而具体怎么去跟那些组件进行交互和协调,则交给SpringCloud),相对于Spring Cloud,Spring Cloud Alibaba在Spring Cloud的基础上融合了更多的微服务组件,让架构师在技术选型时有了更多可供选择的组件如Nacos,Sentinel等,同时也因为Spring Cloud Alibaba是在Spring Cloud基础上进行设计的,所以他也兼容Spring Cloud可以协调的所有组件。
微服务架构下的几个核心概念
(1)服务注册中心
微服务架构下,服务可能由几十上百个,这种情况下当然不能再由程序员来管理服务了,所以需要有一个注册中心用于给服务提供一个容器,服务提供者在启动时主动向服务提供者注册自己并提供自己的信息如ip端口服务名,而服务消费者则在需要调用远程服务时从注册中心拉取服务,通常会在本地有服务信息的缓存,再在固定时间反复从注册中心拉取服务信息覆盖缓存以提高系统性能。
服务的注册中心一般提供以下几个功能:服务的注册和发现,服务的健康检测,在服务出现宕机等问题时采取某种方式。
典型组件:Eureka、Nacos、Zookeeper
(2)服务配置中心
而当服务多了后,微服务的配置将会是个难题,假设某个配置可能在上线后修改,此时如果还是采用普通的本地配置方式,然后重新启动服务,效率将十分低下并且不平滑。所以采用服务的配置中心让服务可以实现从远程拉取配置并实现热更新。
典型组件: Nacos、Config
(3)服务远程调用
服务的远程调用是指当服务消费者通过服务注册中心获得到目标服务的ip和端口后,以何种协议发起调用(如http协议、dubbo协议),使用提供服务远程调用的框架可以屏蔽掉程序员对远程调用的感知,让开发更平滑规范。
典型组件:Dubbo、Feign、Ribbon+RestTemplate(Ribbon通过LoadBalancerInterceptor类实现对RestTemplate发送请求的拦截,获取到服务名后将服务名替换为ip端口然后替换)
(4)服务网关
在服务网关出现前,可能Nginx用的更多,但Nginx只能实现最基本的反向代理、负载均衡如果想要实现更多的功能如请求限流身份认证权限校验等功能则很麻烦,此时就可以通过服务网关(如Gateway),使用服务网关可以更好的进行拓展。
典型组件:Gateway
Spring Cloud版本选择
如图:SpringCloud的版本应该与SpringBoot的版本对应,否则可能会导致代码报错无法运行,
进行SpringCloud的微服务项目开发时,通常在父工程引入
<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帮我们进行包版本的管理,
为什么要让spring-cloud来帮我们管理?因为微服务的组件实在太多啦,而且每个组件又有很多个版本并且还在不断地更新迭代,可能突然出现一个新的feature又或者减少一个功能,更改一点协议,就导致无法兼容让spring-cloud无法正常完成协调工作,比如本人前两天尝试不用spring-cloud提供的依赖约束,自己去搭建一个微服务项目,报错一天也没解决,而spring-cloud-denpendencies存在的意义就是:”你用我这个版本,我包你能运行“,
点进去spring-cloud-dependencies这个依赖就可以看到,他提供了很多组件的版本约束
除了spring-cloud-dependencies依赖,不还有个spring-cloud-alibaba嘛,所以还有一个spring-cloud-alibaba-dependencies依赖,具体引入方式如下:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
点进去可以看到他也是做的一样的工作
Eureka的使用
Eureka服务端搭建
首先服务端只需要引入Eureka服务端的maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.1.7</version>
</dependency>
然后在在能被Spring扫描到的位置加入@EnableEurekaServer注解
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class,args);
}
}
yaml配置:
注:Eureka的服务端需要将自己也注册到服务端
server:
port: 10086
spring:
application:
name: eurekaserver #eureka自己也是个服务也要有名字
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka #eureka自己也是个服务所以会把自己也注册到eureka上
通过查看源码可以看到:service-url属性是一个Map对象
所以可以推断defaultZone代表的默认注册到的eureka服务端位置
Eureka客户端的使用
Eureka客户端的前置配置
搭建客户端只需要引入eureka的客户端starter依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
然后在yaml配置文件中添加Eureka的配置
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
可以看到,这跟服务端注册自己的配置是相同的,而如果要将该服务注册到多台eureka服务端上只需要用逗号隔开如:
在这里插入代码片
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka1.com:7001/eureka/,http://eureka2.com:7002/eureka/
而要实现eureka的集群,就是通过这种方式,具体可以参考
eureka集群搭建
在做完以上的配置后,一个最简单的使用远程调用的方式就是通过RestTemplate
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
RestTemplate是用于发送http请求并对请求结果进行反序列化的,
可以看到这里加了一个@LoadBalanced注解,直译过来就是负载均衡,
主要原理就是通过一个LoadBalancerInerceptor在RestTemplate发请求前进行拦截,点进LoadBalanced注解可以看到他是SpringCloud提供的注解
package org.springframework.cloud.client.loadbalancer;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
他会根据我们使用的服务注册中心的不同自动从不同的注册中心拉取服务,比如下文会用到Nacos,他就会自动从Nacos服务端去拉取服务,这也更好的应证了SpringCloud ”协调一切“”的特性 。
我现在所用的spring cloud版本(hoxton)使用的是ribbon的来实现负载均衡,通过查阅LoadBalancerInterceptor代码一路debug就可以找到,但貌似后面spring cloud默认不再使用ribbon。
同时,ribbon实现负载均衡的策略也是可以配置的,有一个IRule是所有负载均衡策略的父接口
使用RestTemplate发起远程调用
@GetMapping("/get")
public String get(){
return restTemplate.getForEntity("http://order-service/test/get",String.class).getBody();
}
可以看到,原先应填写ip端口的地方我填的服务名代替,spring-cloud会自动帮我完成对ip端口的获取以及对url的替换
配置ribbon负载均衡策略的方式
编程式配置
@Bean
public IRule rule(){
return new WeightedResponseTimeRule();
}
见名知意,这个Rule是通过权重和响应时间来决定选择哪个服务
配置文件配置
其中userservice代表当前服务的服务名
Ribbon开启饥饿加载
默认Ribbon是在第一次发起远程调用时采取拉取服务,可以通过配置开启项目启动时就拉取
关于Nacos
Nacos是阿里的一个开源产品,是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案。
通过这段介绍可以知道,Nacos既可以作为服务注册中心也可以作为配置中心。
Nacos-Discovery的基本使用
Nacos环境搭建
Nacos的项目搭建
首先要在父工程的pom文件中引入spring-cloud-alibaba的包管理依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
前文已说过具体的原因
然后在子模块引入nacos的discovery依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
接下来,我们只需要配置Nacos的address/username/password等基本信息,就可以搭建一个基于nacos作为服务注册中心的微服务项目
server:
port: 8082
spring:
application:
name: order-service
cloud:
nacos:
username: nacos
password: nacos
server-addr: localhost:8848
这里可以看到我将该服务订单服务名配置为order-service,端口配置为8082,并配置了nacos服务端的信息
其他的都保持刚刚eureka的配置,运行!
发现效果一样,成功实现了服务的远程调用,这也是spring-cloud强大的地方,使用spring-cloud可以很轻松的使用/更换一个微服务组件。
Nacos多级存储模型/优先调用同集群
Nacos不但提供了对服务的分类,还提供了对集群的分类,比如,可以将某一个服务的实例归类到SH(上海)的集群,再配置Nacos的负载均衡策略,就可以实现在远程调用时会优先调用当前集群的服务实例,具体配置方式如下
通过查看NacosRule所在的包,可以发现这也是spring-cloud-alibaba提供的
Nacos环境的隔离
nacos主要通过namespace和group来进行环境的隔离
Nacos-Config的基本使用
要使用Nacos的配置中心功能,需要先引入对应的maven依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
然后再resources下新建一个bootstrap.yml配置文件,这个配置文件会在application.yml之前被读取,所以说,我们需要把nacos的配置写到bootstrap.yml中,在这个文件中,我们需要配置nacos的信息以及项目的profile/service-name,还有对应配置文件的后缀
spring:
application:
name: user-service
cloud:
nacos:
username: nacos
password: nacos
config:
file-extension: yaml
server-addr: localhost:8848
profiles:
active: dev
通过这个,spring-cloud就可以知道我这个服务对应的dataId是user-service-dev.yaml
【Nacos配置中心的dataId默认格式是[服务名]-[profile].[后缀名]】
值得注意的是,spring-cloud除了会去获取dataId为user-service-dev.yaml的文件还会获取user-service.yaml这个配置文件,且user-service.yaml配置文件中的配置优先级更高。
而后,引入配置的方式有两种
引入配置的方式
直接使用Value注解
@Value("${user}")
private String c;
这样,在启动后Spring Cloud就会自动从nacos拉取配置并且填入
同时,如果使用这个方式,当Nacos上的配置修改的时候他不会自动更新,如果想让他自动更新,需要在类上增加一个RefreScope注解
如下:
@RestController
@RequestMapping("/test")
@RefreshScope
public class TestController {
@Resource
private RestTemplate restTemplate;
@Value("${user}")
private String c;
}
使用ConfigurationProperties注解
例子:
@ConfigurationProperties(prefix = "uu")
@Component
@Data
public class TestProperties {
private String name;
}
其中ConfigurationProperties的prefix代表属性的前缀
由此,name就会被赋值为对应配置文件下的uu.name属性
并且使用这种方式时,配置会自动热更新
Feign
Feign是什么
Feign也算是一个RPC框架,他默认基于JDK提供的URLConnection类发送HTTP请求,也因此,Feign也是基于http协议来实现远程调用的
Feign和RestTemplate的区别
那使用feign和使用之前用到的resttemplate有什么区别呢,如果单从效率来看,我认为没有多大区别,因为他俩都是基于http协议向服务提供方发送请求,本质都一样,但是Feign采用动态代理技术,直接封装一个个用于远程调用的对象给开发者,开发者可以直接通过调用接口的方法实现远程调用,在整个过程中,开发者是没有感知的,而反观RestTemplate:
这是十分丑陋的,并且程序员应更注重业务的开发而不是突然冒出来一个奇形怪状的url。
Feign的使用
首先需要导入Feign的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
导入依赖后,需要在使用一个EnableFeignClients注解,来开启对feignClient的扫描。
最后
我们只需要在一个接口上加上FeignClient注解,并在该注解里设置服务名
@FeignClient("order-service")
public interface TestFeignService {
@GetMapping("/test/testFeign")
public String testFeign(@RequestParam("data") String a);
}
然后spring-cloud就会帮我们把生成的代理对象注入到容器中,我们此时就可以从容器中获得这个TestFeignService对象并调用其中的方法来实现远程调用了。
并且,Spring Cloud很贴心的使用原有的GetMapping等注解来完成对这个请求的配置。
Feign的性能调优
Feign的主要有两个点可以优化
通过以上配置,我们可以将feign的底层http实现改为httpclient。