eureka 服务注册发现
1.spring Cloud 不能算是一门技术,他是一套解决微服务架构设计的方案,他包含了各种组件,比如注册中心,断路器,配置中心,集成路由等。
2.spring Cloud现在主流的三种生态主要是由,奈飞,阿里和spring官网分别针对不同的是同场景自研的一套工具。
3.spring Cloud是基于springBoot来使用的,在使用spring Cloud的时候不同的springBoot版本需要搭配不同的spring Cloud版本来使用,乱用版本的话可能会存在问题,一般是有一个对照表的,按照对照表来使用基本不会出现问题。
4.注册中心的设计满足cap原则
- c:可靠性:集群中主节点节挂掉了,整个集群都停止对外提供服务,一直到从新选出一个新的主节点,并且所有节点数据都同步完成才开始对外提供服务。
- a:可用性:集群中的主节点挂掉了不影响其它节点,其它节点还是正常运行,可能会存在节点数据不一致问题,但是这是可以接受的。
- p:区域安全隔离性:注册中心集群部署一主多从,写入数据直接写入主节点,读取的时候从节点读。主节点被写入数据后要需要同步给集群中的从节点,同步过程中会存在一定的延迟
一般注册中心的设计过程中至少要满足其中的两个,一般p是固定的一定会满足,剩下的就是c和a选其一,zookeeper他是满足cp的,eureka满足的是ap。
注册中心的作用:
集群中的服务注册与发现,服务提供者把服务注册等到注册中心,服务消费者到注册中心查找自己想要调用的服务,找到后拿到ip+port然后去调用自己需要调用的服务。
做一个注册中心的设计需要满足哪些条件?
- 注册中心要有一个容器(list)主要用来装注册的服务。
- 调用者服务需要把注册中心容器中保存的已经注册到注册中心的服务拉取到本地做缓存,这样就可以不用每次调用接口都到注册中心找地址。
- 注册中心不能无限期的保存所有的提供者的服务,需要定期的判断服务是否挂掉了,所以需要定期去检查服务的心跳,检查服务的健康情况。
- 注册中心定期检查已注册服务的心跳,如果长时间没有回应需要把服务从注册中心删除。
- 注册到注册中心的服务,需要定期的向注册中心发送心跳,防止注册中心把自己的服务给删除了
- 服务发送心跳的频率要高于注册中心的检查的频率,不然服务就会被注册中心删除
- 如果注册中心在一次检查服务心跳的时候发现大部分服务心跳都失效了,注册中心不会删除任何一个注册到注册中心的服务,因为eureka满足的是ap的原则,即可以容忍数据的不准确性,以可用性为主。
配置文件详解
- eviction-interval-timer-in-ms: 10000 #注册中心定期剔除服务列表中失效的服务地址
- enable-self-preservation: true # server自我保护机制,避免因为网络原因造成误删除
- renewal-percent-threshold: 0.85 # 如果在同一个机房中低于85%的服务没有正常运行(正常续约的服务小于85%)注册中心不会删除任何服务,保障其可用性
- renewal-percent-threshold应该是同一时间正常续约的服务低于85%,就启动自我保护机制,防止因为网络原因导致客户端续约失败,影响客户端之间相互的调用,因为为了保障其可用性,客户端会从注册中心定期拉取注册信息到客户端本地缓存。客户端有缓存地址的情况下只要注册中心不删除注册信息,等网络恢复后还可以继续用。这个也跟eureka的设计原则相关,因为eureka满足的是AP高可用性,宁愿提供错误的服务也要保障服务的可用性。
服务发现
spring cloud 是顶级社区,他提供了顶级接口,其它厂商都要按照他提供的接口标准去实现,这样的好处就是无论哪家厂商提供的框架和组件都可以构建相同的微服务架构,就算不同厂家混着用都可以。
服务发现的意思就是a服务从注册中心获取b服务的注册信息,并且缓存在本地随时可以找到b服务并且调用b服务的接口。
ribbon 客户端负载均衡
ribbon理解
- ribbon负责的是消费者端的负载均衡
- 消费者从注册中心获取provider的地址,并且缓存在本地
- consumer调用provider的请求会被ribbon拦截并且会做负载均衡。
- 负载均衡默认是轮询,也可以选择随机或者自定义负载均衡的规则
ribbon负载均衡和 nginx负载均衡的区别
如上图nginx负载均衡和ribbon的负载均衡的区别是,nginx是对外的,而ribbon相当于是spring cloud集群内部消费者客户端调用提供者的负载均衡,两个使用场景是不一样的。
hystrix
作用
hystrix断路器(熔断器),可以防止微服务集群雪崩,断路器打开访问服务提供者会直接快速返回不会真的访问,使用openfeign时请求会被hystrix代理,hystrix的本质就是代理对服务提供者的调用,因为只有代理请求才可以去做熔断。
手写断路器
思路
三种状态 开,关,半开
- 开:统计失败次数,失败次数到达阈值不在调用服务提供者
- 关:关闭状态不在调用直接返回
- 半开:时间窗口,处于关闭状态时开始即时到达窗口期,设置状态为半开,半开状态,设置20%的请求可以访问到提供者,如果访问成功修改状态为开。
hystrix 配置
配置解释
hystrix: #hystrix的全局控制
command:
default: #default是全局控制,也可以换成单个方法控制,把default换成方法名即可
circuitBreaker:
enabled: true #开启断路器
requestVolumeThreshold: 3 #失败次数(阀值) 20s内调用失败次数超过3次开启熔断器
sleepWindowInMilliseconds: 20000 #窗口时间 20s
errorThresholdPercentage: 60 #失败率 20s内调用失败率超过60%开启熔断器
execution:
isolation:
Strategy: thread #隔离方式 thread线程隔离集合和semaphore信号量隔离级别
thread:
timeoutInMilliseconds: 3000 #调用超时时长
fallback:
isolation:
semaphore:
maxConcurrentRequests: 1000 #信号量隔离级别最大并发数
隔离方式
- 隔离方式 两种隔离方式 thread线程池 按照group(10个线程)划分服务提供者,用户请求的线程和做远程的线程不一样
- 好处 当B服务调用失败了 或者请求B服务的量太大了 不会对C服务造成影响 用户访问比较大的情况下使用比较好 异步的方式
- 缺点 线程间切换开销大,对机器性能影响
- 应用场景 调用第三方服务 并发量大的情况下
- SEMAPHORE信号量隔离 每次请进来 有一个原子计数器 做请求次数的++ 当请求完成以后 --
- 好处 对cpu开销小
- 缺点 并发请求不易太多 当请求过多 就会拒绝请求 做一个保护机制
- 场景 使用内部调用 ,并发小的情况下
- 源码入门 HystrixCommand AbstractCommand HystrixThreadPool
Sleuth与Zipkin 分布式链路追踪
理论
- sleuth 收集微服务中接口调用的信息并且把信息上传到zipKin供zipKin分析接口的调用链路。
- zipKin 独立部署,提供可视化界面,可以在可视化界面中查看请求的调用链路信息,请求从客户端发起,经过了哪些服务,每个服务花费的时间等都可在可视化界面查看。收集过来的信息默认保存在内存中,也可通过配置把他保存在mysql,mongoDB等持久化存储数据库中。
- Sleuth与Zipkin主要作用是收集请求调用的链路(一个请求经过了几个微服务)信息,然后再把信息上传到zipKin,zipKin对这些数据进行保存,分析和展示。开发者可以根据zipKin上面保存的链路调用数据,分析请求在链路调用过程中的哪个环节花费的时间比较长,从而对其进行优化。
配置和集成
官方提供一键脚本
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
如果用 Docker 的话,直接
docker run -d -p 9411:9411 openzipkin/zipkin
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1 #配置采样率 默认的采样比例为: 0.1,即 10%,所设置的值介于 0 到 1 之间,1 则表示全部采集
rate: 10 #为了使用速率限制采样器,选择每秒间隔接受的trace量,最小数字为0,最大值为2,147,483,647(最大int) 默认为10。
springboot admin
- admin服务端可以从eureka上面拉取客户端的ip+port,从而建立和client端的心跳,保持对client服务的监听
- spring-boot-admin+spring-boot-actuator一块使用可以监听微服务集群中的每台服务的运行情况
gateway
网关作用
- 转发,前端请求都请求到网关,通过网关把接口转发到不同的服务。
- 保护安全,请求直接到网关可以不暴漏微服务集群中的服务的ip+port
- 负载均衡
- 网关就是一连串的过滤器来实现的,过滤器分为全局过滤器和局部过滤器
nginx和gateway使用场景
- 网关和nginx两个都是做请求转发的,nginx是服务器级别的请求转发,网关是程序级别的请求转发,网关的级别要比nginx级别低
- nginx是使用c语言写的网关底层是webflux做转发效率都很高,但是nginx的性能效率是强于网关的
- nginx可以给网关做负载均衡
- gateway高度集成eureka,和ribbon结合实现了负载均衡
- nginx做负载均衡每次都需要修改配置文件,gateway继承了eureka可以直接从注册中心拉取服务地址做负载均衡。
- nginx 级别最高可以给网关做负载均衡前端请求到了ng之后由ng来决定请求哪个网关。
- 网关级别第二可以给集群中的消费者类型的服务提供负载均衡,请求到了网关之后由网关决定调用哪个消费者服务。
- ribbon级别最低是给集群中的提供者提供负载均衡,请求到了消费者服务,由ribbon决定访问哪个提供者
gateway+eureka负载均衡实现原理
网关路由转发和负载均衡实现
- 直接再配置文件配置单服务的路由转发
spring:
application:
name: gate-server
cloud:
gateway:
enabled: true # =只要加了依赖 默认开启
routes: # 如果一个服务里面有100个路径 如果我想做负载均衡 ?? 动态路由
#方式一,配置单个的服务地址做路由转发
#请求方式 http://localhost/login
- id: login-service-route # 这个是路由的id 保持唯一即可
uri: http://localhost:8081 # uri统一资源定位符 url 统一资源标识符
predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
- Path=/login # 匹配规则 只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
- 在配置文件配置相同名称的多台服务的转发和负载均衡,要集成eureka从注册中心获取服务地址才可以做负载均衡
spring:
application:
name: gate-server
cloud:
gateway:
enabled: true # =只要加了依赖 默认开启
routes: # 如果一个服务里面有100个路径 如果我想做负载均衡 ?? 动态路由
# 方式二,通过配置lb协议和应用名称做路由转发和负载均衡
# 请求方式 http://localhost/testRibbonBalance
- id: provider-route # 这个是路由的id 保持唯一即可
uri: lb://provider # lb负载均衡协议,provider服务名称,通过网关访问provider服务的path会通过这个配置做负载均衡
predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
- Path=/** # 匹配规则 只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
- 开启动态代理访问的时候path一级路径加上服务名称就可实现eureka集群中所有服务的转发和负载均衡
spring:
application:
name: gate-server
cloud:
gateway:
enabled: true # =只要加了依赖 默认开启
# 方式三, 通过打开动态路由的配置来做路由转发和负载均衡
# 请求方式 http://localhost/provider/testRibbonBalance
discovery:
locator:
enabled: true # 开启动态路由 开启通用应用名称 找到服务的功能
lower-case-service-id: true # 开启服务名称小写
- 在代码中实现转发功能
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("guochuang-id",r->r.path("/guochuang").uri("https://www.bilibili.com/guochuang"))
.route("dance-id",r->r.path("/v/dance").uri("https://www.bilibili.com"))
.route("kichiku-id",r->r.path("/v/kichiku").uri("https://www.bilibili.com"))
.build();
}