Eureka
Eureka Server 提供服务注册服务
Eureka Client 通过注册中心进行访问<br />Eureka 集群<br /> 相互注册,相互守望 对外暴露出一个整体<br /> eureka:<br /> instance:<br /> hostname: eureka7001.com #eureka服务端的实列名称<br /> client:<br />#表示自己就是注册中心<br /> fetch-registry: false<br /># 表示不向注册中心注册自己<br /> register-with-eureka: false<br /> service-url:<br />#设置与Eureka Server 交互的地址查询服务和注册服务需要依赖这个地址<br /> defaultZone: [http://eureka7002.com:7002/eureka](http://eureka7002.com:7002/eureka)
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
eureka的自我保护
一句话: 某时刻某一个微服务不可用了,Eureka 不会立刻删除,依旧会对该服务的信息进行保存<br /> 属于CAP里面的AP分支
zookeeper
服务节点是临时的<br /> 属于CAP里面的CP分支
<!--spring boot 整合zookeeper--><br /> <dependency><br /> <groupId>org.springframework.cloud</groupId><br /> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId><br /> <!-- 排除自带的zookeeper jar包--><br /> <exclusions><br /> <exclusion><br /> <groupId>org.apache.zookeeper</groupId><br /> <artifactId>zookeeper</artifactId><br /> </exclusion><br /> </exclusions><br /> </dependency><br /> <!-- 添加与服务器对应的 zookeeper 依赖--><br /> <dependency><br /> <groupId>org.apache.zookeeper</groupId><br /> <artifactId>zookeeper</artifactId><br /> <version>3.6.1</version><br /> </dependency>
# 将服务器别名 注册到zookeeper到注册中心名称<br /> spring:<br /> application:<br /> name: cloud-provider-payment<br /> cloud:<br /> zookeeper:<br /> connect-string: 192.168.10.129:2181
Consul
consul agent -dev 使用开发模式启动<br /> [http://localhost:8500](http://localhost:8500) consul的web管理页面
<dependency><br /> <groupId>org.springframework.cloud</groupId><br /> <artifactId>spring-cloud-netflix-turbine</artifactId><br /> </dependency><br /> <dependency><br /> <groupId>org.springframework.cloud</groupId><br /> <artifactId>spring-cloud-starter-consul-discovery</artifactId><br /> </dependency><br /> spring:<br /> application:<br /> name: cloud-provider-payment<br /> #consul注册中心<br /> cloud:<br /> consul:<br /> host: localhost<br /> port: 8500<br /> discovery:<br /> service-name: ${spring.application.name}<br /> #hostname: 127.0.0.1
三个注册中心的异同点
CAP原则 最多自能同时较好的满足两个
核心 : 一个分布式系统不可能同时满足一致性、可用性、分区容错性这三个需求<br /> ● 一致性 C<br /> ● 高可用(可用性) A<br /> ● 分区容忍性 P 分布式架构永远都要保证
Eureka java AP(高可用) 可配支持 HTTP 不会马上清除注册的服务
Consul go cp(数据一致) 支持 HTTP /DNS 服务节点是临时的(注册的服务一旦宕机、立马清除)
Zookeeper java cp(数据一致) 支持 客户端
Ribbon(负载均衡)
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用<br /> 负载均衡(LoadBalanced) 简单来说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)
Ribbon本地负载均衡客户端 比较 Nginx服务端负载均衡区别
Nginx是服务器负载均衡 ,客户端所有请求都会交给nginx,然后由nginx实现转发请求。<br />即负载均衡是由服务端实现的
Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表<br />之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术
集中式负载均衡LB
即在服务的消费方和提供方之间使用独立的LB设施(可用是硬件F5,也可以是软件nginx)由该设施负责把访问请求通过某种策略转发至服务的提供方;
进程内LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有那些地址可用,然后自己再从这些地址中选择出一个合适的服务器
ribbon就是属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来过去到服务提供方的地址<br /> ribbon 一句话就是 负载均衡+RestTemplate
ribbon
第一步选择EurekaServer ,它优先选择在同一区域内负责较少的server
第二步再用户指定的策略,在从server取到的服务注册列表中选择一个地址
其中ribbon提供了很多策略:比如轮询,随机,和根据响应时间加权
负载均衡的算法
rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务启动后rest接口计数从1开始
//获取服务器集群总数量 <br /> List<ServiceInstance>instances =discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
openFeign(服务接口绑定器) 接口+注解
微服务调用接口+@FeignClient
也是完成微服务之间的调用
Feign作用<br /> Feign旨在使编写Java Http客户端变得更加容易。<br /> 个人理解:声明式远程方法调用
OpenFeign默认等待一秒钟,超过后报错(time out)
Feign集成了Ribbon
利用Ribbon维护了 [payment]的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,简单而优雅的实现了服务调用。
Hystrix
分布式面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免失败
服务雪崩
多个微服务之间的调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。
如果扇出的链路上某个微服务的调用响应时间过长或者b不可用,对微服务A的调用就会占用越来越多的系统崩溃,所谓的“雪崩效应”
Hystrix
Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,<br /> 比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
断路器
断路器本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的,<br /> 可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、<br /> 不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
Hystrix能做什么
服务降级 fallback
服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好的提示 ++兜底方法!
服务熔断 break
类比保险丝 达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
服务的降级—->进而熔断—->恢复调用链路
服务限流 flowlimit 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
@HystrixCommand 报异常后如何处理
#开启<br /> feign:<br /> hystrix:<br /> enabled: true <br />全局兜底 没有使用精准打击的 就去使用全局兜底
熔断机制概述
熔断机制式应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,自动恢复调用链路。
熔断状态: 开启 关闭 半开启
在SpringCloud框架中,熔断机制通过Hystrix实现Hystrix会监控微服务间调用的状况。
当失败的调用到一定阈值,缺省时5秒内20此调用失败,就会启动熔断机制,熔断机制的注解是@HystrixCommand
//服务熔断
@HystrixCommand(fallbackMethod = “paymentCircuitBreaker_fallback”,commandProperties = {
@HystrixProperty(name = “circuitBreaker.enabled”,value = “true”), //是否开启断路器
@HystrixProperty(name = “circuitBreaker.requestVolumeThreshold”,value = “10”), //请求次数
@HystrixProperty(name = “circuitBreaker.sleepWindowInMilliseconds”,value = “10000”), //时间范围
@HystrixProperty(name = “circuitBreaker.errorThresholdPercentage”,value = “60”)}//失败率达到多少后跳闸
)
涉及到断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值
1、快照时间窗: 断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗、默认为最近的10秒
2、请求总数阀值:再快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,
如果该hystrix命令的调用次数不足20次即使所有的请求都超时或其他原因失败,断路器都不会打开。
3、错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,
有15次发生了超时异常,也即使超过了50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。
3.3 断路器开始或者关闭条件
• 当满足一定的阈值的时候(默认是10秒内超过20个请求次数)
• 当失败率达到一定的时候(默认10秒内超过50%的请求失败)
• 到达以上阈值,断路器将会开启
• 当开启的时候,所有的请求都不会进行转发。
• 一段时间后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发,如果成功,断路器关闭,如果失败,继续开启
断路器打开之后
1: 再有请求调用的时候,将不会调用主逻辑,而是直接调用降级的fallback方法,通过断路器,实现了自动的发现错误并将降级逻辑升级为主逻辑,减少响应延迟的效果。
2:原来的主逻辑要如何恢复?
• 对于这一问题mhystrix也为我们实现了自动恢复功能。
• 当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临
时的成为主逻辑。
• 当休眠时间窗到期,断路器将进入半开状态,释放给一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合。
• 主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。
HystrixDashboard
@EnableHystrixDashboard //开启Hystrix的监控页面 http://localhost:9001/hystrix
/*
此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
ServletRegistrationBean因为springboot的默认路径不是”/hystrix.stream”,
只要在自己的项目里配置上下面的servlet就可以了
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings(“/hystrix.stream”);
registrationBean.setName(“HystrixMetricsStreamServlet”);
return registrationBean;
}
server:<br /> port: 9001<br /> eureka:<br /> client:<br /> register-with-eureka: true<br /> fetch-registry: true<br /> service-url:<br /> defaultZone: [http://eureka7001.com:7001/eureka](http://eureka7001.com:7001/eureka)<br /> spring:<br /> application:<br /> name: could-consumer-hystrix-dashboard
GateWay (zuul) 服务网关
gateway皆在提供一种简单而有效的方式来对api进行路由,以及提供一些强大的过滤器功能,列如:熔断,限流,重试等
为了提升网关的性能SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty,
说穿了就是 SpringCloud Gateway是异步非阻塞式】
Gateway能干什么
• 反向代理<br /> • 鉴权<br /> • 流量控制<br /> • 熔断<br /> • 日志监控
SpringCloud Gateway具有的特征
• 基于Spring Frameword5 ,Project Reactor 和 SpringBoot 2.0进行构建;<br /> • 动态路由:能够匹配任何请求属性<br /> • 可以对路由指定Predicate(断言)和Filter(过滤器)<br /> • 集成Hystrix的断路器功能;<br /> • 集成Spring Cloud的服务发现功能<br /> • 易于编写的Predicate(断言)和Filter(过滤器)<br /> • 请求限流功能;<br /> • 支持路径重写
Zuul1.x 基于Servlet2.5使用阻塞架构它不支持任何长连接 (如WebSocket)
SpringCloud Gateway是异步非阻塞式
GateWay三大核心概念:
Route(路由)
路由时构建网关的基本模块,它由id,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate(断言)
开发人员可用匹配HTTP请求中的所有内容(列如请求头或请求参数) 如果请求与断言相匹配则进行路由
Filter(过滤器)
指的是spring框架中GatewayFilter的实列,使用过滤器,可用在请求中被路由前或者之后对请求进行修改
总结
• web 请求,通过一些匹配条件,定位到真正的服务节点,并在这个转发过程的前后,进行一些精细化控制
• predicate 就是我们的匹配条件
• filter:就可以理解为一个无所不能的拦截器,有了这两个元素,再加上目标的uri,就可以实现一个具体的路由了。
Predicate(断言)
Loaded RoutePredicateFactory [After] 之后 默认时区之后生效<br /> Loaded RoutePredicateFactory [Before] 之前 默认时区之前生效<br /> Loaded RoutePredicateFactory [Between] 之间 两个时间之前生效
Loaded RoutePredicateFactory [Cookie] <br />两个参数 一个cookieName 一个正则表达式- Cookie=username,zzyy<br /> curl [http://localhost:9527/payment/lb](http://localhost:9527/payment/lb) --cookie "username=zzyy"<br /> Loaded RoutePredicateFactory [Header] <br />两个参数 一个属性名称和一个正则表达式 - Header=X-Request-Id,\d+<br />curl [http://localhost:9527/payment/lb](http://localhost:9527/payment/lb) -H "X-Request-Id:1234"
Loaded RoutePredicateFactory [Host] <br />-Host=**.atguigu.com<br /> Loaded RoutePredicateFactory [Method] <br />- Method=GET<br /> Loaded RoutePredicateFactory [Path] <br />- Path=/payment/lb/** #断言,路径相匹配的进行路由<br /> Loaded RoutePredicateFactory [Query] <br />- Query=username, \d+ #要有参数名称并且是正整数才能路由<br /> curl [http://localhost:9527/payment/lb](http://localhost:9527/payment/lb) cmd测试
Filter(过滤器)
自定义全局GlobalFilter
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono
log.info(“* come in MyLogGateWayFilter”+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst(“uname”);
if (uname == null) {
log.info(“*用户名为null非法用户”);
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/**<br /> * 加载GlobalFilter 顺序 越小优先级越高<br /> * @return<br /> */<br /> @Override<br /> public int getOrder() {<br /> return 0;<br /> }<br /> }
Spring Cloud Config 服务配置中心
分布式系统面临的问题————配置问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置消息才能运行,所以一套集中式的、动态的配置管理设施时必不可少的。
是什么:
SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置
SpringCloud Config 分为服务端和客户端
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口
配置中心能干什么
• 集中管理配置文件
• 不同环境不同配置,动态化的配置更新,分环境部署比如 dev/test/prod/beta/release
• 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务回想配置中心统一拉去配置自己的信息。
• 当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置。
• 将配置信息以Rest接口的形式暴露。
配置中心服务端
远程仓库的配置文件读法
① 读取master分支
• http://localhost:3344/master/config-dev.yaml
② 读取dev分支<br /> • [http://localhost:3344/dev/config-dev.yaml](http://localhost:3344/dev/config-dev.yaml)
/{application}-{profile}[/{label}]<br /> 这样读取的是 JSON串<br /> • [http://localhost:3344/config/dev/master](http://localhost:3344/config/dev/master)
总结
• label:分支
• name[application]:服务名
• profiles:环境
配置中心 客户端
application.yml 是用户级的资源配置文件
bootstrap.yml 是系统级的,优先级更加高
出现的问题:
当GItHub 的配置文件内容被修改 刷新ConfigServer配置中心立刻响应 而ConfigClient客户端没有任何响应,ConfigClient客户端没有变化除非自己重启或者重新加载
配置中心动态刷新:避免GItHub 的配置文件内容被修改 每次都要重启ConfigClient客户端
@RefreshScope 配置上的注解 实现ConfigClient客户端动态刷新 在controller
通知以后 需要刷新一下
手动刷新 curl -X POST “http://localhost:3355/actuator/refresh”
虽然这种方式解决了不重启3355客户端的问题,但是如果有100个机器需要重新加载配置文件呢
所以这就需要使用 消息总线来进行广播。
Spring Cloud Bus 服务总线(消息总线)
Bus支持两种消息代理:RabbitMQ和Kafka
Spring Cloud Bus
是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能。
Spring Cloud Bus
能管理和传播分布式系统间的消息,就像一个分布式执行器,可用于广播状态更改,事件推送等,也可用当作微服务间的通信通道<br />
什么是总线
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实际都连接上来。由于该主题中产生的消息会被所有的实列监听和消息,所以称为消息总线。在总线上的各个实列,都可用方便地广播一些需要让其他连接在该主题上的实列都知道的消息<br />基本原理<br /> ConfigClient都监听MQ中同一个topic(默认是Spring Cloud Bus )。当一个服务刷新数据的时候,它会把这个消息放入到Topic中,这样其他监听同一个的服务就能得到通知,然后去更新自身的配置。
动态刷新全局广播
(配置在配置中心服务端)
配置中心服务端添加消息总线支持
rabbitmq:
username: root
password: root
port: 5672
host: 192.168.10.129
#rabbitMQ相关配置,暴露bus刷新配置的端点
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: ‘bus-refresh’
动态刷新定点通知
cmd中 精确通知
手动刷新curl -X POST “http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}”
destination: 微服务名称+端口号
只通知3355 不通知3366
curl -X POST “http://localhost:配置中心的端口号/actuator/bus-refresh/cloud-config-client:3355”
关于注解
@EnableDiscoveryClient //该注解 用于向使用consul 或者zookeeper作为注册中心时 注册服务
@LoadBalanced //该注解赋予了RestTemplate 负载均衡的能力
@EnableEurekaClient 开启eureka 客户端<br /> @EnableEurekaServer 开启eureka 服务器
@EnableFeignClients //启用Feign 激活并开启<br /> @FeignClient(value="暴露的服务名称(大写)") (openFeign) 微服务调用接口上<br /> @EnableHystrix //起用Hystrix
@EnableCircuitBreaker //Hystrix熔断机制的支持 在哪里用了降级 就在主启动类上加入这个注解 <br /> @HystrixCommand(fallbackMethod = "方法名") 一般放在客户端<br /> <br /> @DefaultProperties(defaultFallback = "方法名") 全局兜底 没有使用精准打击的 就去使用全局兜底<br /> <br /> @EnableHystrixDashboard //开启Hystrix的监控页面 [http://localhost:9001/hystrix](http://localhost:9001/hystrix) <br /> [http://localhost:8001/hystrix.stream](http://localhost:8001/hystrix.stream)
@RefreshScope 配置在controller上的注解 实现ConfigClient客户端动态刷新<br />