微服务
2021-04-14 09:56:58 9 举报
AI智能生成
微服务全解析,包括Eureka、OpenFeign、Ribbon、Hystrix、Apollo、Dubbo、ZooKeeper等
作者其他创作
大纲/内容
断路器:Hystrix
Hystrix能够保证在一个服务调用依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的容错能力
降级
(客户端)
(客户端)
当客户端请求服务器端的时候,防止由于服务端超时或者错误,导致客户端一直等待,直接返回一个友好的提示给客户端
哪些情况会触发服务降级?
程序异常、请求超时、服务熔断、线程池/信号量打满
扩展
fallback备选方案的返回值类型要和原方法保持一致
熔断
(服务端)
(服务端)
熔断机制
(断路器)
(断路器)
熔断机制是应对雪崩效应的一种微服务链路保护机制,当在一个统计时间范围内请求
失败数量达到设定值或当前的请求错误率达到设定的错误率阈值时开启断路,直接走
fallback降级逻辑,在指定时间后尝试恢复调用链路(最重要的是能恢复)
失败数量达到设定值或当前的请求错误率达到设定的错误率阈值时开启断路,直接走
fallback降级逻辑,在指定时间后尝试恢复调用链路(最重要的是能恢复)
简单来说熔断就是保险丝
服务降级 -> 服务熔断 -> 恢复调用链路
熔断类型
熔断打开
保险丝断了,此时服务处于不可用状态
熔断关闭
链路正常调通
熔断半开
放部分请求进来,观察调用状态
断路器如何工作?
概念
快照时间窗
统计一段时间内的错误数据,默认为最近的10秒
请求总数阈值
在时间窗内,必须达到请求数阈值才有资格熔断,默认20次
错误百分比
当请求总数在时间窗内超过了阈值,才会熔断,默认值是50%
熔断
默认10秒内总调用次数超过20次且有50%的请求调用失败才会打开断路器
在断路器打开期间,不会走主逻辑,而是走降级逻辑,减少延迟
在断路器打开期间,不会走主逻辑,而是走降级逻辑,减少延迟
恢复
一段时间后(默认是5秒)此时断路器半开,会转发一部分请求,若调用成功
则关闭断路器恢复链路,如果仍失败,则继续保持断开状态,重复此操作
则关闭断路器恢复链路,如果仍失败,则继续保持断开状态,重复此操作
隔离
服务隔离就是Hystrix为隔离的服务开启一个独立的线程池,这样在高并发的情况下不会影响其他服务
比如设置某块代码最多只能使用10个线程,限定资源的使用,避免有故障时出现资源被抢占光的情况
比如设置某块代码最多只能使用10个线程,限定资源的使用,避免有故障时出现资源被抢占光的情况
隔离方式
资源隔离
(线程)
资源隔离
(线程)
线程池隔离
为每个方法创建一个独立的线程池
信号量隔离
实现一个计数器来限制线程个数
限流
hystrix利用线程池的工作原理来进行限流
高并发流量进来,比如QPS突然飙升到100万,服务会崩溃,限流能让10万QPS进入系统,其他90万被拒绝
实时监控
dashboard
dashboard
监控+报警+优化。各种异常情况,有问题就及时报警,优化系统的配置和参数
监控页面一直显示loading?
@HystrixCommand注解和@EnableCircuitBreaker注解同时配置才会生效
服务网关:Gateway
为什么要使用网关?
统一接入、动态路由、权限认证、数据缓存
流量控制
熔断
降级
限流
性能监控、日志监控、灰度发布
安全防护
IP黑名单、URL黑名单
风控防刷、防恶意攻击
注意
底层基于 Netty,与 Servlet 不兼容,所以不要出现 Spring Web 的依赖
工作原理
原理
Route(路由):路由是网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成
Predicate(断言):规则判断,true还是false,如果断言为true则匹配该路由
Filter(过滤):可以在请求被路由前或者后对请求进行修改
限流
Gateway 官方提供了 RequestRateLimiter GatewayFilterFactory 过滤器工厂,使用 Redis 和 Lua 脚本
基于令牌桶算法,可分别进行 URI 限流、参数限流、IP限流
也可以整合Sentinel进行限流操作
GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则
ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合
鉴权
引入jjwt依赖,创建jwt工具类(生成秘钥、解析token)
创建全局过滤器,实现GlobalFilter, Ordered接口,编写过滤逻辑
如果是登陆请求则放行,否则获取请求头中的令牌进行解析
解析通过则根据权限放行,解析失败则组装报文返回
扩展:加密算法
不可逆加密
MD5 验签
可逆加密
对称加密(AES)加解密是同一把密钥,效率高,不安全
非对称加密(RSA)使用公钥加密,私钥解密,安全但效率低
组合使用:可通过非对称加密传递密钥,然后使用对称加密交互
路由规则
Path
http://localhost:9000/product/1
Query
http://localhost:9000/product/1?token=abc1
Method
Datetime
After|Before|Between
RemoteAddr
http://192.168.10.1:9000/product/1
Header
动态路由
动态获取URI
服务名称转发
http://localhost:9000/product-service/product/1
过滤器
网关过滤器
通过 spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上
通过 spring.cloud.default-filters 配置在全局,作用在所有路由上
全局过滤器
不需要在配置文件中配置,作用在所有的路由上
种类
Header、Parameter、Path、Body、Status、Session、Redirect、Retry、Ratelimiter 和 Hystrix
Path 过滤器
RewritePath GatewayFilter Factory
PrefixPath GatewayFilter Factory
StripPrefix GatewayFilter Factory
SetPath GatewayFilter Factory……
Parameter 参数过滤器
Status 状态过滤器
自定义网关过滤器
自定义网关过滤器需要实现以下两个接口:Gatewayfilter,Ordered
创建 MyFilter
绑定 Route
自定义全局过滤器(重点)
自定义全局过滤器需要实现以下两个接口:Globalfilter,Ordered
通过全局过滤器可以实现权限校验,安全性验证等功能
代码
使用它只需要加上@Component注解
限流
为什么需要限流?
用户增长过快
某个热点事件
竞争对手爬虫
恶意的请求
算法
计数器算法
固定窗口计数器
步骤
时间线划分为多个独立且固定大小窗口
落在每一个时间窗口内的请求就将计数器加 1
如果计数器超过了限流值,则后续落在该窗口的请求都会被拒绝
时间到达下一个时间窗口时,计数器会被重置为 0
缺陷
临界点问题:比如59秒时打满100个请求,60秒时重置,又打满100个请求,相当于1秒钟来了200个请求
资源浪费:我们希望100个请求可以均匀分在这一分钟内,但如果提前达到请求上限,剩余时间服务器就闲置了
滑动窗口计数器
步骤
将单位时间划分为多个区间,一般都是均分为多个小的时间段
每一个区间内都有一个计数器,有一个请求落在该区间内,则该区间内的计数器就会加一
每过一个时间段,时间窗口就会往右滑动一格,抛弃最老的一个区间,并纳入新的一个区间
计算整个时间窗口内的请求总数时会累加所有的时间片段内的计数器,总和超过了限制数,则拒绝接收请求
缺陷
时间区间的精度越高,算法所需的空间容量就越大
漏桶算法
步骤
将每个请求放入固定大小的队列进行存储
队列以固定速率向外流出请求,如果队列为空则停止流出
如队列满了则多余的请求会被直接拒绝
缺陷
当短时间内有大量的突发请求时,即使服务器负载不高,每个请求也都得在队列中等待一段时间才能被响应
令牌桶算法
以固定速率生成令牌并放入到令牌桶中
如果令牌桶满了则多余的令牌会直接丢弃
当请求到达时,会尝试从令牌桶中取令牌,取到了令牌的请求可以执行
如果桶空了,则拒绝该请求
实现
基于令牌桶
Gateway 官方提供了 RequestRateLimiter GatewayFilterFactory 过滤器工厂,使用 Redis 和 Lua 脚本
URI 限流
参数限流
IP 限流
整合Sentinal
https://github.com/alibaba/Sentinel/wiki/网关限流#spring-cloud-gateway
高可用
概念
对于大多数网站,2个9 是基本可用;3个9 是叫高可用;4个9 是拥有自动恢复能力的高可用
例如QQ的可用性是 4个9,就是说 QQ 能够保证在一年里99.99%的时间是可用的,只有0.01%不可用(大约53分钟)
总结
一个请求过来,首先经过 Nginx 的一层负载,到达网关,然后由网关负载到真实后端,若后端有问题,网关会进行重试访问,
多次访问后仍返回失败,可以通过熔断或降級立即返回结果。而且由于是负载均衡,网关重试时不ー定会访问到出错的后端
多次访问后仍返回失败,可以通过熔断或降級立即返回结果。而且由于是负载均衡,网关重试时不ー定会访问到出错的后端
配置中心:Apollo
Apollo
总体设计
总体设计
Config Service提供配置的读取、推送等功能,服务对象是 Apollo 客户端
Admin Service 提供配置的修改、发布等功能,服务对象是 Portal(管理界面)
Config Service 和 Admin Service 都是多实例、无状态部,所以需要将自己注册到 Eureka 中并保持心跳
在 Eureka 之上我们架了一层 Meta Server 用于封装 Eureka 的服务发现接口
Client 通过域名访问 Meta Server 获取 Config Service 服务列表(IP+Port),然后直接通过 IP + Port
访问服务,同时在 Client 侧会做 load balance、错误重试
访问服务,同时在 Client 侧会做 load balance、错误重试
Portait 通过域名访问 Meta Server 获取 Admin Service 服务列表(IP+Port),然后直接通过 IP + Port
访问服务,同时在 Portal 侧会做 load balance、错误重试
访问服务,同时在 Portal 侧会做 load balance、错误重试
为了简化部署,我们会把 Config Service、Eureka 和 Meta Server 三个逻辑角色部署在同一个 JVM 中
数据库
ConfigDB
Config Service
Admin Service
PortalDB
Portal
特性
统一管理不同环境、不同集群、不同命名空间的配置
通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置
同时还允许应用对共享的配置进行盖,配置界面支持多语言(中文,English)
配置修改实时生效(热发布)
用户在 Apollo 修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序
版本发布管理
所有的配置发布都有 版本 概念,从而可以方便的支持配置的 回滚
灰度发布
支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一酸时间没问题后再推给所有应用实例
权限管理、发布审核、操作审计
应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编和发布两个环节,从而减少人为的错误
所有的操作都有审计日志,可以方便的追踪可题
客户端配置信息监控
可以方便的看到配置在被哪些实例使用
部署简单
置中心作为基服务,可用性要求非常高,这就要求 Apollo)对外部依赖尽可能地少
目前唯一的外部依赖是 MySQL,所以部署非常简单,只要安装好 Java 和 MySQL 就可以让 Apollo 跑起来
Apollo 还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数
核心概念
application(应用)
实际使用配置的应用,Apollo需要根据具体应用获取对应的配置
每个引用都需要有唯一的身份标识(appId)
environment(环境)
Apollo运行时需要知道当前应用处于哪个环境,从而获取相应配置
环境默认是通过读取机器上的配置(server.properties中的env属性)指定的,
不过为了开发方便,也支持运行时通过system property指定
不过为了开发方便,也支持运行时通过system property指定
cluster(集群)
一个应用下不同实例的分组,比如按照数据中心分,把上海机房和北京机房的应用实例分组
对不同的分组(cluster)同一个配置可以有不一样的值(server.properties中的idc属性)
namespace(命名空间)
一个应用下不同配置的分组,比如数据库配置文件,RPC配置文件,应用自身配置文件等
各模块概要
Config Service
提供配置获取接口
提供配置更新推送接口(基于 http 长连接)
接口服务对象为Apollo客户端
Admin Service
提供配置管理接口
提供配置修改、发布等接口
接口服务对象为 Portal
Meta Server
- Portait 通过域名访问 Meta Server 获取 Admin Servicel 服务列表(IP+Port)
- Client 通过域名访问 Meta Server 获取 Config Service 服务列表(IP+Port)
- Meta Server,从 Eureka 获取 Config Service 和 Admin Service 的服务信息,相当于是一个 Eureka Client
- 増设一个 Meta Server 的角色主要是为了封装服务发现的细节,对 Portal 和 Client 而言,永远通过一个 Http
接口获取 Admin Service 和 Config Service 的服务信息,而不需要关心背后实际的服务注册和发现组件 - Meta Server 只是一个逻辑角色,在部署时和 Config Service 是在一个 JVM 进程中的(IP、Port 和 Config Service一致)
Eureka
基于 Eureka 和 Spring Cloud Netflix 提供服务注册和发现
Config Service 和 Admin Service 会向 Eureka 注册服务,并保持心跳
为了简单起见,目前 Eureka 在部署时和 Config Service 是在一个JVM进程中的(通过 Spring Cloud Netflix)
Portal
提供 Web 界面供用户管理配置
通过 Meta Server 获取 Admin Servicer 服务列表(IP+Pot),通过 IP+Port 访问服务
在 Portal 侧做 load balance、错误重试
Client
Apollo 提供的喜户端程序,为应用提供配置获取、实时更新等功能
通过 Meta Server 获取 Config Service 服务列表(IP+Port),通过 IP+Port 访问服务
在 Client 侧做 load balance、错误重试
服务端配置发布过程
用户在 Portal 操作配置发布
Portal 调用 Admin Service 的接口操作发布
Admin Service 发布配置后,发送 ReleaseMessages 给各个 Config Service
Config Service 收到 ReleaseMessage 后,通知对应的客户端
Apollo客户端实现原理
客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过 Http Long Pollings 实现)
客户端还会实时从 Apollo 配置中心服务端拉取应用的最新配置
这是一个 fallback 机制,为了防止推送机制失效导致配置不更新
客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取
的操作,服务端都会返回 304 - Not Modified
的操作,服务端都会返回 304 - Not Modified
定时频率默认为每 5 分钟拉取一次,客户端也可以通过在运行时指定
System Property: apollo. refreshInterval 来覆盖,单位为分钟
System Property: apollo. refreshInterval 来覆盖,单位为分钟
客户端从 Apollo 配置中心服务端获取到应用的最新配置后,会保存在内存中
客户端会把从服务端获取到的配置在本地文件系统存一份
在遇到服务不可用,或网络不通的时侯,依然能从本地恢复配置
应用程序可以从 Apollo 客户端获取最新的配置、订阅配置更新通知
Dubbo
实现原理
首先dubbo通过注册中心解决服务的注册和发现,消费者是有个动态代理的概念的,底层要走一个负载均衡,
按照指定的协议组织请求然后进行Request的封装,最后通过netty网络通信框架将请求序列化后发送出去
按照指定的协议组织请求然后进行Request的封装,最后通过netty网络通信框架将请求序列化后发送出去
服务提供者通过网络通信框架实现了一个server监听端口,收到请求后进行反序列化,然后进行Request和
Protocol的解析,最后将请求转交给动态代理调用接口的实现类
Protocol的解析,最后将请求转交给动态代理调用接口的实现类
10层模型:接口层、配置层、代理层、注册层、集群层、监控层、协议层、交换层、传输层、序列化层
SPI机制
基于SPI,我们可以很容易的对dubbo进行扩展,没有使用原生Java SPI,而是自己对其进行了增强
将实现类打成jar包
Java SPI
在jar包中resource/META-INF/services目录下放
一个跟目标接口同名的文件,内容是实现类的全类名
一个跟目标接口同名的文件,内容是实现类的全类名
缺点
一次性实例化扩展点所有实现,其中没用上也加载,很浪费资源
如果扩展点加载失败,就失败了,给用户没有任何通知
dubbo SPI
在jar包中resource/META-INF/dubbo目录下放一个
跟目标接口同名的文件,内容是key=实现类的全类名
跟目标接口同名的文件,内容是key=实现类的全类名
优点
解决了上述Java原生SPI的缺点
增加了对扩展点 IoC 和 AOP 的支持
应用场景
dubbo自身的协议类型,负载均衡扩展,序列化扩展等,都是基于 SPI 实现的
例如自定义负载均衡策略的实现:在dubbo工程中依赖生成的jar包,并配置<dubbo:protocol loadbalance="key"/>
通讯协议
dubbo协议(默认)
单一长连接,NIO异步通信,基于hessian序列化协议
dubbo协议位于TCP上层,基于Netty实现高性能网络通信
适合高并发小数据量(100k)的服务调用,消费者数量远大于提供者
rmi协议
多个短连接,支持Java二进制序列化,一般较少用
适合文件传输,消费者数量和提供者数量差不多
hessian协议
多个短连接,支持hessian序列化,一般较少用
适合文件传输,消费者数量小于提供者数量
http协议
支持json序列化,兼容性好,便于读写,占用带宽较大,传输效率较低
负载均衡策略
随机加权、轮询(存在慢服务器请求积累问题)、最少活跃数(解决)、一致性Hash
LoadBalance详情
Random
随机加权,按权重设置随机概率(默认)
RoundRobin
轮询,均匀的将流量打到各个机器上去,但是如果各个机器的性
能不同,容易导致性能差的机器负载过高,所以也需要配置权重
能不同,容易导致性能差的机器负载过高,所以也需要配置权重
LeastActive
最少活跃数,通过自动感知,给性能较差的机器分配更少的请求
ConstantHash
一致性Hash,使相同参数请求被分发到同一提供者,服务提供者
挂掉的时候,会根据虚拟节点均匀分配剩余流量,抖动不会太大
挂掉的时候,会根据虚拟节点均匀分配剩余流量,抖动不会太大
集群容错策略
失败重试(Failover)、快速失败(Failfast)、失败安全、失败自动恢复、并行调用、广播调用
如何选择?
读操作建议使用 Failover 失败自动切换,默认重试两次其他服务器,可配置retries(重试次数)
写操作建议使用 Failfast 快速失败,发一次调用失败就立即报错(适合非幂等接口)
重试机制:retries
指定重试次数,不包含第一次调用,通常配合集群容错策略使用
幂等性接口可以设置重试次数,非幂等接口不做
超时机制:timeout
服务消费者调用服务提供者,默认超过1000ms报错(服务调用超时)
dubbo针对超时做了比较精细化的支持,无论是消费端还是服务端,无论是接口级别还是方法级别都有支持
超时设置的优先级?
客户端 > 服务端|方法 > 接口|局部 > 全局
客户端方法级>服务端方法级>客户端接口级>服务端接口级>客户端全局>服务端全局
启动检查:check
消费者在启动时,如果注册中心没有提供者会启动失败
解决
方案一:在<dubbo:reference />标签中添加check="false"修改单个服务
方案二:在<dubbo:consumer />标签中添加check="false"统一管理所有服务
熔断降级
服务降级
比如服务A调用服务B,结果服务B挂了,服务A重试几次后还是不行,这时就会走一个备用的逻辑,给用户响应
解决
方案一:设置mock="true"然后在接口的同一路径下创建接口的实现类,命名
规则是接口名称+Mock后缀,然后在实现类中重写方法写自己的降级逻辑
规则是接口名称+Mock后缀,然后在实现类中重写方法写自己的降级逻辑
方案二:mock="return 123456..."或mock="return null"
服务容错
整合Hystrix
导入spring-cloud-starter-netflix-hystrix依赖,添加@EnableHystrix启用
在需要容错的方法上添加@HystrixCommand(fallbackMethod="XXX")
创建XXX方法并写容错逻辑,在目标方法报错后会走该方法的逻辑
在需要容错的方法上添加@HystrixCommand(fallbackMethod="XXX")
创建XXX方法并写容错逻辑,在目标方法报错后会走该方法的逻辑
配置集群容错方案
Zookeeper
核心
文件系统的数据结构
采用树状结构
/dubbo
/service
/provider
ip+port
/consumer
事件监听/通知机制
客户端会对某个节点建立一个 watcher 事件,当该节点发生变化时,这些客户端
会收到 zk 的通知,然后客户端可以根据节点变化来做出业务上的改变等
会收到 zk 的通知,然后客户端可以根据节点变化来做出业务上的改变等
ZAB原子广播协议
(fast paxos算法)
(fast paxos算法)
恢复模式(选主)
leader选举
启动选举
运行时选举
广播模式(同步)
写数据流程
client 向 zk 集群的 server1 发送了一个写请求
如果 server1 不是 leader 需要把写请求转发给 leader
leader 将写请求广播给各个 server,写成功后会通知leader
当 leader 收到过半的 server 写成功了就会通知 client 写操作完成
如果 server1 不是 leader 需要把写请求转发给 leader
leader 将写请求广播给各个 server,写成功后会通知leader
当 leader 收到过半的 server 写成功了就会通知 client 写操作完成
过半机制
保证一半以上的server同意这个proposal才会成功
保证了Zookeeper集群的数据一致性
保证了Zookeeper集群的数据一致性
集群中存在的问题
多台机器跑定时任务
问题产生
系统中会存在定时任务,当项目变成集群的时候,每台机器上都会有定时任务
这个定时任务会在多台机器上运行,会造成资源浪费和数据不一致的问题
解决方案:Master选举
在zookeeper中特定节点下创建临时无序节点,只有一台机器能创建成功
其他没有创建成功的机器,监听该临时节点的变化
集群间并发访问冲突
zookeeper实现分布式锁
集群
集群角色
Leader:负责进行投票决议,处理读写请求,更新状态
Follower:参与投票,处理读请求,转发写请求给leader
Observer:不参与投票,其他功能与follower相同
动态扩展zookeeper集群又不会降低写性能,
提高读取速度(写请求需要满足过半机制)
提高读取速度(写请求需要满足过半机制)
搭建集群
zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/temp/dataDir1
clientPort=2181
server.1=10.211.55.4:2888:3888
server.2=10.211.55.5:2888:3888
server.3=10.211.55.6:2888:3888
initLimit=10
syncLimit=5
dataDir=/usr/local/temp/dataDir1
clientPort=2181
server.1=10.211.55.4:2888:3888
server.2=10.211.55.5:2888:3888
server.3=10.211.55.6:2888:3888
高版本zk启动报错:FAILED TO START
解决
# 禁用 AdminServer 服务
admin.enableServer=false
或
# 修改端口 admin port
admin.serverPort=9000
admin.serverPort=9000
创建myid
echo 1 > dataDir1/myid
echo 2 > dataDir2/myid
echo 3 > dataDir3/myid
echo 2 > dataDir2/myid
echo 3 > dataDir3/myid
查看状态
nc 10.211.55.4 2181
stat
echo stat | nc 127.0.0.1 2181
sh zkServer.sh status
常见面试题
zk为什么要有主节点?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,
其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能
其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能
zk集群为什么是奇数台?
防止由脑裂造成的集群不可用
容灾能力相同的情况下,奇数更节省资源
如何保证事务的顺序一致性?
采用了全局递增的事务ID(zxid)来标识
应用场景有哪些?
注册中心、命名服务、分布式协调通知、分布式锁、分布式队列、高可用集群
zookeeper服务宕机对dubbo服务有没有影响?
没有影响,本地有缓存列表
注册中心:Eureka
服务注册与发现
使用注册中心管理每个服务与服务之间的依赖关系
服务提供者将自己暴露的地址注册到注册中心
服务消费者从注册中心拉取服务进行调用
注册表存储结构
采用内存的方式来管理服务信息
ConcurrentHashMap存储服务节点
服务注册:新增一个key-value的映射关系
服务发现:获取一个key-value的映射集合
组成结构
三大角色:Eureka Server、Service Provider、Service Consumer
提供服务的注册与发现,存key服务名,value服务地址
两个组件
Eureka Server:提供注册服务
Eureka Client
通过注册中心访问,客户端具备一个内置的使用轮询算法的负载均衡器
默认每30秒向注册中心发送心跳,超过90秒没有收到则移除节点
消费者获取调用地址后,底层使用HttpClient实现远程调用
actuator微服务信息完善
主机名称的修改
instance-id
左下角IP信息显示
prefer-ip-address
服务注册与发现
是怎么实现的?
是怎么实现的?
Eureka做了二级缓存
第一级叫做 ReadOnly 缓存,二级叫做 ReadWrite 缓存
客户端会直接从 ReadOnly 缓存中读取注册表信息
客户端会直接从 ReadOnly 缓存中读取注册表信息
ReadOnly缓存(定时同步)
ReadWrite缓存(立马同步)
定时任务会每30秒检查两个缓存的内容,不一致则将ReadWrite中的数据同步到ReadOnly
为什么要做二级缓存?
这么做的好处在于,优化并发读写的冲突
如果服务进行注册的时候,同时有服务来读去注册表信息,就会存在频繁的读写加锁的操作,
写的时候就不能读,导致性能下降,所以我们需要避免大量的读写都去操作一个表
写的时候就不能读,导致性能下降,所以我们需要避免大量的读写都去操作一个表
有了二级缓存,大部分的读操作都会走 ReadOnly 缓存,只需要定时同步就好了
自我保护机制
心跳检测
在应用启动后,节点们将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳
周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
自我保护
但是如果短时间内丢失了大量的服务实例心跳(80%),Eureka会触发自我保护机制,不踢除服务。
防止由于暂时的网络问题误删除健康的服务,是一种应对网络异常的安全措施
防止由于暂时的网络问题误删除健康的服务,是一种应对网络异常的安全措施
CAP
属于CAP里的AP分支,宁可保留错误的服务注册信息,也不盲目的注销任何可能健康的服务实例
如何关闭自我保护?
改为CP模式(不推荐)
改为CP模式(不推荐)
注册中心
eureka.server.enable-self-preservation: false
eureka.server.eviction-interval-timer-in-ms: 2000
服务端
eureka.instance.lease-renewal-interval-in-seconds: 1
心跳间隔(默认30)
eureka.instance.lease-espiration-duration-in-seconds: 2
超时时间(默认90)
如果Eureka不下
线服务怎么办?
线服务怎么办?
手动通知Eureka下线
格式:DELETE /eureka/apps/appID/instanceID
DELETE 127.0.0.1:8761/eureka/apps/EUREKACLIENT1/192.168.10.104:paymentServer:8765
通过运行指定的代码下线
在EurekaClient的代码中添加一个接口
集群
Eureka集群节点之间相互注册,相互监听,peer to peer(点对点)
集群中每个机器的地位是对等的,各个服务可以向任何一个Eureka实例注册,
集群中的任何一个Eureka实例接收到写请求后都会自动同步到其他所有实例
集群中的任何一个Eureka实例接收到写请求后都会自动同步到其他所有实例
对比ZooKeeper
Eureka保证的是AP
牺牲一致性,保证可用性和容错性
Eureka查到的信息可能不是最新的,但是每个节点都是平等的
ZooKeeper保证的是CP
牺牲可用性,保证一致性和容错性
服务down掉立即被踢出,master节点选举期间服务不可用
负载均衡:Ribbon
负载均衡:就是将用户的请求平摊到多个服务器上,从而达到系统的HA(高可用)
分类
服务端负载均衡,客户端所有请求都交给Nginx负载均衡服务器,然后由Nginx转发请求(集中式LB)
客户端负载均衡,先从注册中心获取服务列表,然后再通过Ribbon选择调用(进程式LB)
Ribbon
Ribbon有两个作用(负载均衡+服务调用)
客户端负载均衡机制(在配置RestTemplate时添加@LoadBalance注解)
Ribbon+RestTemplate通过【服务名】实现服务调用
工作流程
第一步:先选择EurekaServer ,它优先选择在同一个区域内负载较少的server
第二步:再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址
负载均衡策略
Ribbon提供了7种策略:轮询(默认)、随机、重试、根据响应时间加权、过滤跳闸、过滤故障、复合判断
Ribbon默认轮询负载均衡算法原理
调用次数对服务器个数取余,获取下标
服务重启后调用次数从1重新开始计数
核心组件-IRule
如何替换负载规则?
方法一
直接在消费方配置文件中指定规则
方法二
建一个规则包,不要放在@ComponentScan扫描的包下
创建规则配置类,添加@Configutation+@Bean注解
在启动类添加@RibbonClient注解,指定服务名和配置类
如何自定义规则?
注释掉@LoadBalance注解,使默认的规则失效,仿照源码编写
面向接口编程,新建负载均衡接口,定义获取所有服务列表的方法
定义实现类,编写负载均衡逻辑,返回计算后的服务器实例对象
在Controller中注入接口对象,调用接口对象中获取实例的方法
获取服务器实例对象的URL,通过RestTemplate或者Feign调用
远程调用:Feign
Feign
只需要写一个【接口】在接口上添加【注解】就可以完成【客户端】的服务调用
通过添加注解给接口生成动态代理,然后去调用方法的时候会生成http协议格式的请求
feign集成封装了ribbon,通过轮询实现了客户端的负载均衡,使服务调用更加简单
OpenFeign
服务调用
在接口上添加注解FeignClient(value="服务名"),将服务端Controller中
的方法头拷贝到接口中,在客户端Controller中注入接口实例,完成调用
的方法头拷贝到接口中,在客户端Controller中注入接口实例,完成调用
超时控制
openfeign底层是ribbon,客户端默认等待1秒钟
在application.yml中设置ribbon的超时等待时间
日志增强
Feign提供了日志打印功能,可以调整日志级别,对接口的调用情况进行监控
日志级别
NONE:【默认】不显示任何日志
BASIC:仅记录请求方法、URL、响应状态码及执行时间
HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息
FULL:除了BASIC中定义的信息之外,还有请求和响应的正文及元数据
代码实现
创建配置类
配置application.yml
0 条评论
下一页