微服务架构就是将单体的应用程序分成多个应用程序,这多个应用程序就成为微服务,每个微服务运行在自己的进程中,并使用轻量级的机制通信。这些服务围绕业务能力来划分,并通过自动化部署机制来独立部署。这些服务可以使用不同的编程语言,不同数据库,以保证最低限度的集中式管理
同步(REST HTTP协议,RPC TCP 协议)
异步(消息中间件,例如Kafka、ActiveMQ、RabbitMQ、RocketMQ)
REST HTTP 协议(编写restful风格接口,调用接口)(springcloud使用REST通信)
REST 请求在微服务中是最为常用的一种通讯方式,它依赖于 HTTP\HTTPS 协议。RESTFUL 的特点是:
每一个 URI 代表 1 种资源
客户端使用 GET、POST、PUT、DELETE 4 个表示操作方式的动词对服务端资源进行操作:GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源
通过操作资源的表现形式来操作资源
资源的表现形式是 XML 或者 HTML
客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息
举例,有一个服务方提供了如下接口:另外一个服务需要去调用该接口,调用方只需要根据 API 文档发送请求即可获取返回结果。通过这样的方式可以实现服务之间的通讯。
spingboot简省xml、springmvc、mybatis错综复杂的配置
springcloud基于spingboot的优雅简洁,基于SpringBoot把市场上优秀的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理
什么叫做开箱即用?即使是当年的黄金搭档dubbo+zookeeper下载配置起来也是颇费心神的!而springcloud完成这些只需要一个jar的依赖就可以了!
springcloud大多数子模块都是直击痛点,像zuul解决的跨域,fegin解决的负载均衡,hystrix的熔断机制等等等等
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
优点:
缺点:
总的来说优点大过于缺点,目前看来Spring Cloud是一套非常完善的分布式框架
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
(1)服务调用方式:dubbo是RPC ,springcloud 是Rest Api
(2)注册中心:dubbo 是zookeeper, springcloud是eureka,也可以是zookeeper
(3)服务网关,dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。
传统架构 → 分布式架构 → SOA架构 → 微服务架构
分布式架构就是将传统结构按照模块进行拆分,不同的人负责不同的模块,不会产生代码冲突问题,方便开发。
SOA架构就是将业务逻辑层提取出来,将相似的业务逻辑形成一个服务,提供外部访问接口,服务之间访问通过RPC调用实现。
微服务类似于SOA架构,但是比SOA架构粒度更细,更轻量。
SOA基于WebService和ESP实现,底层基于HTTP协议和使用XML方式传输,XML在网络传输过程中会产生大量冗余。微服务由SOA架构演变而来,继承了SOA架构的优点,同时对SOA架构缺点进行改善,数据传输采用JSON格式,相比于XML更轻量和快捷,粒度更细,更加便于敏捷开发。SOA数据库会存在共享,微服务提倡每个服务连接独立的数据库。
为什么需要服务注册与发现?
在服务启动时,服务提供者会向注册中心注册服务,暴露自己的地址和端口等,注册中心会更新服务列表。服务消费者启动时会向注册中心请求可用的服务地址,并且在本地缓存一份提供者列表,这样即便注册中心宕机了,仍然可以正常调用服务。
如果提供者集群发生变更,注册中心会将变更推送给服务消费者,更新可用的服务地址列表
建立各个服务之间联系的纽带
典型的服务发现组件
Zookeeper(雅虎Apache)
Eureka(Netfix)
Nacos(Alibaba)
Consul(Google)
为什么要将服务注册到nacos?(为了更好的查找这些服务)
在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
服务启动时如何找到服务启动注册配置类?(NacosNamingService)
服务消费方是如何调用服务提供方的服务的?(RestTemplate)
传统项目处理配置的问题
为什么要用配置中心
因此,我们需要配置中心来统一管理配置!把业务开发者从复杂以及繁琐的配置中解脱出来,只需专注于业务代码本身,从而能够显著提升开发以及运维效率。
市场上主流配置中心有Apollo(携程开源),nacos(阿里开源),Spring Cloud Config(Spring Cloud 全家桶成员),nacos,此组件不仅提供了注册中心,还具备配置中心的功能。
配置中心修改配置文件后的反应
外界修改配置文件后,服务器内部会有感应,但是外界无法获取这种感应,因为服务器启动创建对象后只读取一次配置文件内容,我们获取的属性值是第一次创建服务器对象的配置属性,如果外界要实时获取配置中心对配置文件的修改,需要实时创建服务器对象,此时需要在调取配置文件的类上添加@RefreshScope注解,该注解会实时感应变化,当有变化时,其会在缓存中创建一个代理对象,而每次配置文件变化则会刷新这个对象,则配置文件的属性值也会实时刷新。
@RefreshScope注解是spring管理的依据标准参数以外的参数变化在新的Spring Context容器中比较后,对有变化的参数创建新的Bean对象
nacos配置中心的GROUP
每个GROUP可以指定给多个服务对象,每个服务对象也可以设置多个GROUP,但默认使用DEFAULT_GROUP。
nacos配置中心的命名空间
可以创建多个每个命名空间,进行配置隔离,⽐如隔离开发环境和⽣产环境,默认使用无名空间,也可以在服务器中配置文件通过命名空间的码指定命名空间。
nacos配置中心的共享配置
共享配置只能在同一个命名空间下共享不同data-id(服务器)的配置
spring:
cloud:
nacos:
config:
server-addr: localhost:8848//指定的配置中心地址
namespace: 83ed55a5-1dd9-4b84-a5fe-a734e4a6ec6d //指定的命名空间
file-extension: yml
shared-configs[0]: //第一个共享配置
data-id: app-public.yml //制定命名空间下的目标服务的配置
refresh: true //指定实时共享配置
优点:
Spring Cloud官方自己提供的客户端负载均衡器, 用来替代Ribbon。
Spring官方提供了两种负载均衡的客户端:
RestTemplate
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。默认情况下,RestTemplate默认依赖jdk的HTTP连接工
//引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
//配置文件
spring:
application:
name: mall-user-loadbalancer-demo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 不使用ribbon
loadbalancer:
ribbon:
enabled: false
//使用@LoadBalanced注解配置RestTemplate
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
//使用
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/findOrderByUserId/{id}")
public R findOrderByUserId(@PathVariable("id") Integer id) {
String url = "http://mall-order/order/findOrderByUserId/"+id;
R result = restTemplate.getForObject(url,R.class);
return result;
}
}
WebClient
WebClient是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。它的响应式编程的基于Reactor的。WebClient中提供了标准Http请求方式对应的get、post、put、delete等方法,可以用来发起相应的请求。
等于RestTemplate loadBalancedRestTemplate =new RestTemplate();将这个对象交给spring管理,并且由于@LoadBalanced的存在,在使用RestTempalte进行服务调用时,这个调用过程会被@LoadBalanced的一个拦截器LoadBalancerInterceptor进行拦截,然后在拦截器内部,启动负载均衡策略。
@LoadBalanced注解属于Spring,而不是Ribbon的,他们都使用了Irule接口下的规则。
负载均衡怎么写:根据irule接口实现 client
在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel
核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。
服务器中引入依赖作为Sentinel的核心库和客户端,其中包含拦截器interceptor组件。
当服务触发时拦截器会从Sentinel的控制台调取设置的限流规则,当触发规则时,会反馈给用户控制台对请求者设置的限流提示信息。
Sentinel控制台对被访问服务器设置限流(流控)操作
选择要限流的簇点链路,添加流控规则,单机阈值为单台客户端每秒最多提交请求。
直接限流模式:只限制对本服务器的访问
关联限流模式:如果触发第一个服务器限流规则,就对第二个服务器进行限流。
链路限流模式:
需要关闭URL PATH聚合,否则入口只能指定为默认的聚合的URL入口为:sentinel_spring_web_context: web-context-unify: false
需要指定服务名: @SentinelResource(“doGetResource”)//指定资源名
链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。
此时限流会报500异常。
处理500异常:
Sentinel控制台对被访问服务器设置降级(熔断)操作
慢调用比例方式:
最大rt(响应时间):该值为允许的最长延时响应,超过这个响应时间将被统计
比例阈值:超过响应时间的操作超过该比例的将被统计
熔断时长:触发熔断降级操作的将被降级的时长
最小请求数:统计时间内的请求数超过这个数的将被统计
统计时长:以上操作需要在这个时间内,会触发降级
异常比例:
以比例统计异常,类似于慢调用比例,将统计所有异常。
异常数:
以数量统计异常
Sentinel控制台对被访问服务器设置热点限流操作
热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
指定服务和资源名
@GetMapping(“/sentinel/findById”)
@SentinelResource(“resource”) //指定自原名
public String doFindById(@RequestParam(“id”) Integer id){
return "resource id is "+id;
}
Sentinel控制台对被访问服务器设置系统限流操作
Sentinel控制台对被访问服务器设置黑白名单限流操作
网关作用: 统一管理微服务请求,权限控制、负载均衡、路由转发、监控、安全控制黑名单和白名单等
面对互联网复杂的业务系统,大致分成两类:流量网关和业务网关
流量网关:跟具体的后端业务系统和服务完全无关的部分,比如安全策略、全局性流控策略、流量分发策略等。流量网关的功能跟 Web 应用防火墙(WAF)非常类似。WAF一般是基于 Nginx/OpenResty 的 ngx_lua 模块开发的 Web 应用防火墙。
业务网关:针对具体的后端业务系统,或者是服务和业务有一定关联性的部分,并且一般被直接部署在业务服务的前面。业务网关一般部署在流量网关之后,业务系统之前,比流量网关更靠近系统。我们大部分情况下说的 API 网关,狭义上指的是业务网关。并且如果系统的规模不大,我们也会将两者合二为一,使用一个网关来处理所有的工作
服务网关 = 路由转发 + 过滤器
● 请求接入:作为所有 API 接口服务请求的接入点,管理所有的接入请求;
● 业务聚合:作为所有后端业务服务的聚合点,所有的业务服务都可以在这里被调用;
● 中介策略:实现安全、验证、路由、过滤、流控,缓存等策略,进行一些必要的中介处理;
● 统一管理:提供配置管理工具,对所有 API 服务的调用生命周期和相应的中介策略进行统一管理。
Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
解释1:客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则将其发送到网关 Web 处理程序,此处理程序运行特定的请求过滤器链。过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求之前或之后执行逻辑。所有 “pre” 过滤器逻辑先执行,然后执行代理请求,代理请求完成后,执行 “post” 过滤器逻辑。
解释2:Gateway网关自带拦截器
有Filter过滤器,因此可以在“pre”类型的Filter中自行实现计数器算法、漏桶算法、令牌桶算法三种过滤器。
计数器算法:
当限流qps为100,如果设定单位时间内累加请求的数量达到了100,那么后续的请求就会被全部拒绝。这种现象称为“突刺现象”。
漏桶算法:
为了消除"突刺现象",规定请求出口为匀速,无论多少请求出口依旧按规定速度处理,请求入口不同于计数器算法超过限流数马上抛弃,而是存于类似于桶的容器中,当集中的请求过后慢慢处理。但容器也有上限。
令牌桶算法:
令牌桶算法是对漏桶算法的一种改进,漏桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。令牌桶中的令牌是匀速产生的,既然是桶其也有上限。
如服务器处理能力为10万次每秒,计数器规定10秒内可访问10万次,多余的抛弃,当有漏桶算法时多余的将被存储,然后规定每秒处理1万次,此时如果第一秒就出现10万次访问时,将出现拥堵,所以令牌桶算法排上用处,其规定每秒产生1万个令牌,所以当之前十秒没有访问时就可以产生10万令牌,突发出现的10万请求将获取令牌被处理,此后继续产生令牌。
在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用(RPC)。为了保证其高可用,单个服务有必须集群部署。由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务累计,导致服务瘫痪,甚至导致服务“雪崩”。为了解决这个问题出现了短路器,相当于现实生活中的保险丝。
多个服务之间调用的时候,假设服务A调用服务B和服务C,服务B和服务C又调用其他的服务,这就是所谓的“扇出”。如果“扇出”的链路上某个服务调用响应时间过长或者不可用,对服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的 “ 雪崩效应 ”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接受流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫 雪崩。
要避免这样的级联故障,就需要有一种链路中断的方案:
服务降级、服务熔断
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,已提高分布式系统的弹性。
“ 断路器 ” 本身是一种开关装置,当某个服务单元发送故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
服务降级:
服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback
哪些情况会发出降级?
服务熔断
类似保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
服务限流
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
Hystrix实现服务降级的功能是通过重写HystrixCommand中的getFallback()方法,当Hystrix的run方法或construct执行发生错误时转而执行getFallback()方法
配置项目
//在启动类配置的注解
@EnableHystrix
//业务代码
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallBackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
return paymentHystrixService.paymentInfo_TimeOut(id);
}
//配置文件application.yml
feign:
hystrix:
enabled: true
一般都是在消费端配置断路器,因为不用来回传值
用于传播集群状态变化的消息总线,使用轻量级消息代理链接分布式系统中的节点,可以用来动态刷新集群中的服务配置。