SpringCloud
一:微服务
-
微服务的4个核心问题:
- 服务很多,客户端如何访问:API网关
- 服务之间如何通信:HTTP、RPC
- 服务怎么管理:服务的注册于发现
- 服务挂了怎么办:熔断机制
-
解决方案:SpringCloud,是一个生态,SpringCloud基于SpringBoot
-
springcloud NetFlix:一站式解决方案
api网关,zuul组件
Feign,—HttpClines—Http通信方式,同步,阻塞
服务注册发现:Eureka
熔断机制:Hystrix
-
Apatch Dubbo Zookeeper:半自动,
API:无,找第三方组件,或者自己实现
Dubbo:是一个高性能的基于Java的RPC通信框架
zookeeper
无熔断机制,需要借助Hystrix
-
springcloud Alibaba:全新的一站式解决方案,更简单
-
-
新概念服务网格:Server Mesh
二:常见面试题
-
什么是微服务
微服务是近几年流行的一种架构思想,业界并没有一个统一的标准的定义,它提倡将单一的应用程序划分成一组小的服务,服务之间互相协调,互相配置,为用户最终价值。服务之间采用轻量级的通信机制互相沟通,每个业务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境中,另外应避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文选择合适的语言、工具对其进行架构,可以有一个非常轻量级的集中式管理来管理协调这些服务,可以使用不同的语言来编写服务,也可以用不同的数据存储。
微服务的核心就是将传统的一站式应用,根据业务拆分成一个个的服务,彻底的去耦合,每一个微服务提供单个的业务功能服务,一个服务做一件事情,从技术角度看就是一种小而独立的处理过程给,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。
-
微服务之间是如何独立通信的
-
springcloud和dubbo之间有哪些区别
-
对spring boot和springcloud的理解
-
什么是服务熔断,什么是服务降级
-
你所知道的微服务技术栈有哪些?请列举
-
eureka和zookeeper都可以提供注册与发现功能,请说说这两个的区别
-
微服务的优缺点是什么
三:微服务与微服务架构
四:入门概述
springcloud是基于spring boot提供的一套微服务解决方案,包括注册
五:编码步骤
-
创建一个普通的maven工程,并添加所需依赖
-
添加相关module,并进行编码
-
在模块的控制层添加
@RestController
、@PostMapping
、@GetMapping
注解,使用restful风格,让数据以json数据得以传输 -
在前端(客户端)模块,配置
RestTemplate
@Configuration public class ConfigBean { @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
@Autowired private RestTemplate restTemplate; private static final String REST_URL_PREFIX = "http://localhost:8001"; @RequestMapping("/dept/add") public boolean add(Dept dept){ return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class); } @RequestMapping("/dept/get/{id}") public Dept get(@PathVariable("id") Long id){ return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id,Dept.class); } @RequestMapping("/dept/list") public List<Dept> getAll(){ return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class); } }
六、Eureka
-
添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.6.RELEASE</version> </dependency>
-
配置
server: port: 7001 #Eureka eureka: instance: hostname: localhost #Eureka服务端的实例名称 client: register-with-eureka: false #是否向eureka注册中心注册, fetch-registry: false #如果为false,表示自己为注册中心 service-url: #监控页面 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
-
使用
@EnableEurekaServer
开启服务 -
为发布者添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--完善监控信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId>
-
添加配置
#Eureka eureka: client: service-url: defaultZone: http://localhost:7001/eureka/ instance: instance-id: springcloud-provider-dept8001 #通过此参数更改该服务在eureka上显示的名字 #监控info配置 info: app.name: kuangshen-springcloud company.name: blog.kuangstudy.con
-
开启服务
@EnableEurekaClient//在服务启动后自动注册到eureka @EnableDiscoveryClient//服务发现
-
获得Eureka相关信息
import org.springframework.cloud.client.discovery.DiscoveryClient; @Autowired private DiscoveryClient client; // @RequestMapping("/dept/discovery") public Object discovery(){ //获取微服务列表的清单 List<String> services = client.getServices(); System.out.println("discovery-->servicecs: " + services); //得到具体的微服务信息 List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT"); for (ServiceInstance instance : instances) { System.out.println( instance.getHost() + "\t" +instance.getPort() + "\t" +instance.getUri() + "\t" + instance.getServiceId() ); } return this.client; }
-
Eureka集群
配置与单个注册中心类似,只需在在其中一个注册中心挂载其他的注册中心即可
eureka: instance: hostname: localhost #Eureka服务端的实例名称 client: register-with-eureka: false #是否向eureka注册中心注册, fetch-registry: false #如果为false,表示自己为注册中心 service-url: #单机监控页面 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群:在其中一个注册中心挂其他的注册中心 defaultZone: http://localhost:7002/eureka/, http://localhost:7003/eureka/
-
在发布者配置文件中添加配置
#Eureka eureka: client: service-url: defaultZone: http://localhost:7001/eureka/, http://localhost:7002/eureka/, http://localhost:7003/eureka/ instance: instance-id: springcloud-provider-dept8001 #通过此参数更改该服务在eureka上显示的名字 #info配置 info: app.name: kuangshen-springcloud company.name: blog.kuangstudy.con
七、与zookeeper的区别
背景:
- ACID:RDBMS关系型数据库
- A:原子性
- C:一致性
- I:隔离性
- D:持久性
- CAP:NoSql
- C:强一致性
- A:可用性
- P:分区容错性
- CAP的三进二(CAP不可能全都满足):CA、AP、CP
- 根据CAP原理,将NoSql数据库分成了满足CA、AP、CP原则的三大类
作为服务注册中心,eureka比zookeeper好在哪里?
CAP理论指出,一个分布式系统不可能同时满足强一致性、可用性、分区容错性。由于分区容错性在分布式系统中是必须要保证的,因此我们只能在C和A之间权衡。
zookeeper保证的是CP,Eureka保证的是AP。
当向注册中心查询服务列表时,我们可以容忍返回的是几分钟之前的信息,但不能接受服务直接down掉不可用,也就是说服务注册功能对可用性的要求要高于一致性。当zookeeper的master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举,leader选举的时间太长,在30-120s,且在选举过程中整个zookeeper集群都是不可用的,这就导致选举期间注册服务瘫痪。而Eureka的各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余节点依然可以提供注册和查询服务,只不过查到的信息。除此之外,Eureka还有一种自我保护机制,如果15分钟内超过85%的节点都没有正常心跳,那么Eureka就会认为客户端与服务中心出现了网络故障,此时会出现以下几种情况:
- Eureka不在从注册列表中移除因长时间没有收到心跳而应该过期的服务
- Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他的节点上,(即保证当前节点依然可用)
- 当网络稳定后,当前实例新的注册信息会被同步到其他节点中
因此,Eureka可以很好的应对因网络故障而导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪
八:Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
算法:
- 轮询
- 随机
Ribbon:
- LB(load balance 负载均衡,简单来说就是将用户的请求平摊的分配到多个服务器上,从而达到系统的高可用),在微服务或分布式集群中常用的一种应用
- 常见的负载均衡软件有Nginx,Lvs等等
- dubbo、springcloud均提供了负载均衡,后者的负载算法可以自定义。
- 负载均衡简单分类
- 集中式LB
- 进程式LB
和Eureka整合:之后,客户端可以直接调用,不用关心IP地址和端口号
-
在客户端导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>
-
配置
#Eureka eureka: client: register-with-eureka: false #不向注册中心注册自己 service-url: defaultZone: http://localhost:7001/eureka/, http://localhost:7002/eureka/, http://localhost:7003/eureka/
-
配置,在启动类添加
@EnableEurekaClient
@Configuration public class ConfigBean { @Bean @LoadBalanced //配置负载均衡 public RestTemplate getRestTemplate(){ return new RestTemplate(); }
-
更改代码
//ribbon应该是一个变量,通过服务名来访问 //private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
使用ribbon实现负载均衡
配置多个服务提供者,这些服务提供者名称一致即可
自定义负载均衡算法
- IRule:接口
- AvailabilityFilteringRule:先过滤掉跳闸(访问故障)的服务,对剩下的服务进行轮询
- RondomRule:随机
- RoundRobinRule:轮询
- RetryRule:会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内重试
九:Feign负载均衡
- 简介
feign是声明式的web service 客户端, 它让微服务之间的调用变得更简单了, 类似controller调用service。 SpringCIoud 集成了Ribbon 和Eureka, 可在使用Feign时提供负载均衡的http客户端。丨
只需要创建一个接口, 然后添加注解即可!
feign,主要是社区,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法
1 . 微服务名字(Ribbon)
2 , 接口和注解(feign) - Feign 能干什么?
前面在使用Ribbon + RestTemplate 时, 利用RestTempIate 对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中, 由于对服务依赖的调用可能不止一处, 往往一个接口会被多处调用, 所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign 在此基础上做了进一步封装, 由他来帮助我们定义和实现依赖服务接口的定义, 在Feign 的实现下, 我们只需要创建一个接口并使用注解的方式来配置它( 类似于以前Dao接囗上标注Mapper 注解,现在是一个微服务接囗上面标注一个Feign注解即可。即可完成对服务提供方的接口绑定, 简化了使用SpringCIoud Ribbon时, 自动封装服务调用客户端的开发量。 - 可参照https://blog.csdn.net/shumeigang/article/details/93052619
十:Hystrix
服务熔断
服务端,某个服务超时或异常,引起熔断,
-
导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency>
-
在启动类上添加注解
//添加对熔断的支持 CircuitBreaker断路器 @EnableCircuitBreaker
-
编写熔断方法,添加注解
@GetMapping("/dept/get/{id}") @HystrixCommand(fallbackMethod = "hystrixGet") public Dept get(@PathVariable Long id){ Dept dept = deptService.queryById(id); if (dept == null) { throw new RuntimeException("id=>" + id + "不存在该用户,或者信息无法找到!"); } return dept; } //备选方法 @GetMapping("/dept/get/{id}") public Dept hystrixGet(@PathVariable Long id){ return new Dept().setDeptno(id) .setDname("id=>" + id + "没有对应信息,null--@Hystrix") .setDbSource("no this database in MySQL"); }
服务降级
客户端,一般从整体网站请求负载考虑,当某个服务熔断或关闭之后,服务将不再调用,此时在客户端,我们可以准备一个FallBackFactory,返回一个缺省值。
服务监控
-
导入依赖
<!--Hystrix依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.6.RELEASE</version> </dependency>
-
启动类上添加注解
@EnableHystrixDashboard
//开启监控 -
服务提供者添加hystrix依赖,若没有监控信息的依赖,添加
<!--完善监控信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
启动类增加
//增加一个servlet @Bean public ServletRegistrationBean hystrixMetricsStreamServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registrationBean.addUrlMappings("/actuator/hystrix/stream"); return registrationBean; }
十一:zuul
概述
zuul包含了对请求的路由和过滤两个功能以及代理功能。zuul和eureka进行整合,将zuul自身注册为eureka服务治理下的应用,同时从eureka中获取其他微服务的消息,实现其本身功能。
- 路由:负责将外部请求转发到具体的微服务实例上,实现外部访问统一入口的基础
- 过滤:负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础
步骤
-
导入依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.4.6.RELEASE</version> </dependency>
-
配置
server: port: 9527 spring: application: name: springcloud-zuul eureka: client: service-url: DEFAULT_ZONE: http://localhost:7001/eureka/, http://localhost:7002/eureka/, http://localhost:7003/eureka/ instance: instance-id: zuul9527.com prefer-ip-adress: true info: app-name: kuang-cloud company-name: www.kuangstudy.com ##zuul #隐藏项目名称 zuul: routes: mydept.serviceId: springclould-provider-dept mydept.path: /mydept/** ignored-services: pringclould-provider-dept #不能使用此路径访问,使用"*"来忽略全部 prefix: /kuang #公共的访问前缀
-
启动类添加注解
@EnableZuulProxy
-
进行访问
十二:config分布式配置
Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置,配置服务器为各个不同的微服务应用的所有环节提供了一个中心化的外部配置。分为服务端(分布式配置中心)和客户端两部分。配置服务器默认使用git来存储配置信息。
与Gitee整合
-
添加仓库
-
下载仓库到本地,可能需要公钥
-
添加yml文件,并将其上传至仓库
gary@Gary MINGW64 /d/oldComputer/idea/spring-cloud-git/springcloud-config (master) $ git add . gary@Gary MINGW64 /d/oldComputer/idea/spring-cloud-git/springcloud-config (master) $ git status On branch master Your branch is up to date with 'origin/master'. Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: application.yml $ git commit -m "init" #上传本地仓库 $ git push origin master #上传到远程仓库,origin,本用户;master:分支
-
创建server模块
-
添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
-
编写配置
server: port: 3344 spring: application: name: springcloud-config-server #连接远程仓库 cloud: config: server: git: uri: https://gitee.com/Ayeer/springcloud-config.git #http
-
添加
@EnableConfigServer//开启
注解,启动后即可访问到gitee仓库中的数据
-
-
client模块
-
添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>2.1.1.RELEASE</version> </dependency>
-
编写配置
client:bootstrap.yml系统级别的配置;application.yml:用户级别的访问
#bootstrap.yml spring: cloud: config: name: config-client #需要从git上获取的资源名称,不需要后缀 profile: test label: master uri: http://localhost:3344 #相当于http://localhost:3344/config-client/test #application.yml spring: application: name: springcloud-config-client-3355
然后在git上添加yml配置文件,然后,更改本地yml配置文件获取即可
-
主启动类启动
-
spring.cloud.config.name/profile/label/uri