微服务架构是一种架构风格和架构思想,它提倡将系统业务按照功能拆分为更加细粒度的服务,即每一个服务都是一个独立的应用。这些应用对外提供公共API
用于应用调度。本篇博客从服务治理、微服务网关、Netty
等方面介绍微服务。
分布式可参考我的博客溪源的Java笔记—分布式
服务注册发现
Service Provider
地址就行了。ZooKeeper
,Consul
,Nacos
, Eureka
等。分布式的服务治理,其背后的逻辑其实就是分布式数据一致性。
Eureka
Eureka
是一项基于REST
(代表性状态转移)的服务,主要在AWS
云中用于定位服务,以实现负载均衡和中间层服务器的故障转移。它是微服务框架中最核心和最基础的模块,它主要用来实现微服务实例的自动化注册与发现。
Eureka
由2个部分组成:服务端 和 客户端:
Eureka
的心跳检测是基于SpringBoot Actuator
来实现的。Rest
方式来实现调用。Eureka
的三种角色:服务注册中心、服务提供者、服务消费者,事实上一个结点既可以是服务提供者 、也可以是服务消费者。
微服务节点之间通过续约和续期地方式实现服务清单的一致性:
Eureka Client
会周期(默认30秒)地向Eureka Server
发送心跳以续约(Renew
)自己的信息。Eureka Server
会定期(默认60秒)执行一次失效服务检测功能,它一会检查超过一定时间(默认是60秒)没有续约的Eureka Client
,发现并注销该节点。Consul
Consul
是一个spring cloud
中集成好的开源的分布式的服务注册发现中心。
由Go
语言编写。支持健康检查,多数据中心还支持k-v
存储,采用RAFT
一致性算法,保证强一致性,可用性。并且和docker
完美兼容。
Consul
本身也是一种服务治理中心,相对于Eureka
而言:
Consul
牺牲了部分的性能,保证了服务的强一致性。Eureka
只要服务注册到主节点,就认为服务注册成功,不关其他节点是否可以正常调用。Nacos
Nacos
提供了四个主要功能
Nacos
使服务易于注册自己并通过DNS
或HTTP
接口发现其他服务。Nacos
还提供服务的实时运行状况检查,以防止向不正常的主机或服务实例发送请求。Nacos
消除了在更新配置时重新部署应用程序和服务的需求,这使配置更改更加有效和敏捷。Nacos
支持加权路由,使您可以更轻松地在数据中心内的生产环境中实施中间层负载平衡,灵活的路由策略,流控制和简单的DNS
解析服务。它可以帮助您轻松实现基于DNS
的服务发现,并防止应用程序耦合到特定于供应商的服务发现API
。Nacos
提供了易于使用的服务仪表板,可帮助您管理服务元数据,配置,kubernetes DNS
,服务运行状况和指标统计信息。Nacos 既支持AP也支持CP:
AP
模式,牺牲强一致性,从而保证存在节点宕机也不会影响正常的服务节点提供服务。CP
模式,牺牲数据可用性,确保分布式下配置参数的强一致性。网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能提供路由请求、鉴权、监控、缓存、限流等功能。
网关的存在体现了设计模式中的外观模式:
Facade
)对象进行。微服务使用网关的意义
不同的微服务一般会有不同的网络地址,而客户端可能需要调用多个服务接口才能完成一个业务需求,若让客户端直接与各个微服务通信,会有以下问题:
微服务网关介于服务端与客户端的中间层,所有外部服务请求都会先经过微服务网关客户只能跟微服务网关进行交互,无需调用特定微服务接口,使得开发得到简化。
微服务使用的网关主要有两种Zuul
和Gateway
,这里简单做一下对比:
Gateway
性能要好很多。从开发方面比较,Zuul1
编程模型简单,易于扩展;Gateway
编程模型稍难,代码阅读难度要比Zuul
高不少,扩展也稍复杂一些。BIO的阻塞问题
IO
请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU
。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block
状态。如果数据没有就绪,就会一直阻塞在read
方法。accept()
、read()
方法依旧会被阻塞。NIO同步非阻塞
NIO
本身采用的是多路复用IO
模型:通过一个线程不断去轮询多个 socket
的状态,只有当socket
真正有读写事件时,才真正调用实际的IO
读写操作。并且这种轮询是采用内核的方式,效率比直接使用用户线程高很多。IO
基于字节流和字 符流进行操作,而 NIO
基于 Channel
和 Buffer
(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。NIO的非阻塞性
线程通常将非阻塞IO
的空闲时间用于在其它通道上执行IO
操作,所以一个单独的线程现在可以管理多个输入和输出通道。
Channel通道
Channel
通道,是用于应用程序与操作系统进行交互的渠道。
NIO
的Channel
的是主要实现类:
IO
的通道UDP
数据的通道SocketChannel
来与服务器建立连接ServerSocketChannel
来等待客户端的连接通道类似于流,但是有区别:
Buffer缓冲区
缓冲区,实际上是一个容器,是一个连续数组。Channel
提供从文件、 网络读取数据的渠道,但是读取或写入的数据都必须经由 Buffer
。
Selector
Selector
能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。selector
进行select()
操作可能会产生阻塞,但是可以设置阻塞时间,并且可以用wakeup()
唤醒selector
,所以NIO
是非阻塞IO
。SelectionKey
键表示了一个特定的通道对象和一个特定的选择器对象之间的注册关系。AIO异步非阻塞
异步的体现:
AIO
在数据准备完成后,会主动通知”客户端“AIO与NIO的区别:
Netty
Netty
是一个NIO
客户端服务器框架:
TCP
和UDP
套接字服务器。Future-Listener
机制,用户可以方便的主动获取或者通过通知机制获得IO
操作结果。Netty
采用了串行无锁化设计,在 IO
线程内部进行串行操作,避免多线程竞争导致的性能下降。Netty线程模型
Netty
的线程模型是基于NIO
的Selector
构建的,纯粹的selector
存在半包问题。
半包问题
BIO
中在读取不到数据时会发生阻塞,但是NIO
不会。为了解决NIO
的半包问题,Netty
提供了两种方式解决闭包问题: 包定长FixedLengthFrameDecoder
和包分隔符DelimiterBasedFrameDecoder
。Netty模型Reactor模式
Reactor
模式(反应器模式)是一种处理一个或多个客户端并发交付服务请求的事件设计模式。当请求抵达后,服务处理程序使用I/O多路复用策略,然后同步地派发这些请求至相关的请求处理程序。
Reactor模式又可以被细分为:
Reactor单线程模型
Reactor
单线程模型,指的是所有的 IO
操作都在同一个NIO
线程上面完成,Reactor
模式使用的是异步非阻塞IO
,所有的IO
操作都不会导致阻塞,理论上一个线程可以独立处理所有IO
相关的操作,这些操作包括:
TCP
连接Reactor多线程模型
Reactor
多线程模型与单线程模型大的区别就是有一组 NIO
线程处理 IO操作:
NIO
线程Acceptor
线程用于监听服务端,接收客户端的TCP连接请求。NIO
线程池:处理请求,负责消息的读取、解码、编码和发送等。主从Reactor多线程模型
接收客户端连接的不再是个1个单独的 NIO
线程,而是一个独立的 NIO
线程池,即mainReactor
线程池。
主从Reactor
多线程模型可以理解为是一种"boss接活,让work干
"的模式:
mainReactor
线程池用来接收请求,与客户端进行握手验证subReactor
线程池用来处理请求,不直接与客户端进行连接mainReactor
池接受到完整的数据后,subReactor
池才会处理,这样就避免了半包的问题。Dubbo与Spring Cloud的差异:
Dubbo
是一个分布式服务框架,致力于提供高性能和透明化的 RPC
远程服务调用方案,以及 SOA
服务治理方案。Spring Cloud
基于 Spring Boot
,为微服务体系开发中的架构问题,提供了一整套的解决方案:包括服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。Dubbo性能优于 Spring Cloud 的原因:
Dubbo
采用单一长连接和 NIO
异步通讯(保持连接/轮询处理),使用自定义报文的 TCP
协议。Hessian2
框架,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况,但不适用于传输大数据的服务调用。Dubbo
的兼容性比较好,可以根据实际业务选择其他的通讯协议或序列化协议。Spring Cloud
直接使用 HTTP
协议的REST
。(REST
为表述性状态传递)。SpringCloud的子项目
1.Spring Cloud Starters:Spring Cloud
的基础组件。
2.Spring Cloud Config:配置管理工具,支持使用Git
存储配置内容,可以使用它实现应用配置的外部化存储, 支持客户端配置信息刷新、加密和解密等配置内容
3.Spring Clond Netflix:其中包括了:
Eureka 服务发现框架(服务治理)
Eureka
高可用注册中心
单节点时注册中心不需要注册自己,但是高可用注册中心,节点要向出自己以外的服务中心进行注册
不需要重新创建新项目 只要多配制application.properties
运行时 java -jar xxx.jar--spring.profiles.active=ek8761
(命令行配置优先级最高)
Eureka
客户端的实现
@EnableEurekaClient
中的@EnableDiscoveryClient
用来实现发现服务,帮助与Eureka Server
相互协作Region
,接着会加载Zone
,一个应用只有一个Region
,但是可以有多个Zone
(适用于跨机房、跨地区配置)Ribbon
的默认策略会优先访问通客户端处于一个Zone
中的服务端实例,只有当同一个Zone
中没有可用服务端实例才会访问其他Zone
的实例Eureka框架与负载均衡
Ribbon
是一个基于HTTP
和TCP
的客户端负载均衡器:
ribbon
时需要在客户端配置ribbonServerList
服务端列表去轮询以达到负载均衡的作用。Eureka
结合,扩展成从Eureka
注册中心获取服务端列表。ribbon
将确认服务端是否启动的职责委托给Eureka
。Eureka
服务端中保存着所有的服务的实例清单,当新的客户端进行注册时,会从服务端获取该份清单。我们通常所说的服务端负载均衡(硬件负载均衡和软件负载均衡)和客户端负载均衡的差异就在于这份清单的存储位置:
nginx
),而客户端负载均衡(ribbon
)每一个客户端组件都保存完整的服务清单。通过设置nginx.conf
的服务器端负载均衡的弊端在于:
Eureka
注册服务,服务的调用可以通过向服务名发起请求而实现。RestTemplate
Ribbon
的自动化配置,同时通过配置@LoadBalanced
还能开启客户端负载均衡。@LoadBalanced
会使用拦截器的方式来实现其负载均衡,如getForEntity
(url
,body
类型,参数)会通过url
从服务清单中获取服务节点GET请求
getForEntity
(url
,body
类型,参数)ResponseEntity
,该对象是Spring
对Http
请求响应的封装,它包括:http
请求状态、请求头、请求体对象POST请求
postForEntity
(url
,参数,返回对象类型)PUT请求
put
(url
,参数,序列号)DELETE请求
delete
(url
,序列号)Spring Eureka保护机制、重试机制
Eureka
保护机制
Eureka
会在超过85%的实例失去心跳而出发保护机制,注册中心会保留此时的所有节点,以实现服务间依然可以相互调用的场景,即时其中有部分故障节点,但这样可以继续保障绝大数服务可以正常使用。重试机制在请求超时后进行重试:
Spring Retry
实现重试Ribbon
实现重试Zuul
实现重试Feign
实现重试Spring Cloud Hystrix 熔断机制
Spring Cloud Hystrix
,该框架的使用目标在于通过控制那些访问远程系统、服务和 第三方库的节点,从而对延迟和故障提供更强大的容错能力。
Hystrix
具有服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。@EnableCircuitBreaker
来开启熔断器功能Hystrix的工作流程
HystrixCommand
(单个结果)或HystrixObservableCommand
(多个结果)对象Observable
事件源对象、返回多个Observable
事件源对象这四种事件源通常会被订阅者所监控(这里的设计是观察者-订阅者模式)Observable
事件源对象fallback
方法Hystrix
的线程池设计采用了“舱壁模式”HystrixObservableCommand.construct()
返回多个结果 或HystrixCommand.run()
返回单一的结果计算断路器的健康程度fallback
处理:当服务执行失败时,“服务降级”,执行fallback
函数Hystrix
命令执行成功之后,它会将处理结果直接返回或者以Obervable
的形式返回。断路器健康程度
熔断器熔断服务的决定因素:
当前服务健康状态=请求失败数/请求总数 A设定阈值 当前请求数B
服务降级
fallback
方法,进入fallback
方法fallback
给用户一个友好的提示结果“舱壁模式”
“舱壁模式”:Hystrix
使用该模式实现线程池的隔离:
Hystrix的请求缓存
@HystrixCommand
注解结合使用KEY
来设定@CacheRemove(commadKey="请求的函数名")
key
值,如果没有标注则会使用所有的参数。Key
生成方式 优先级高于CacheKey
请求合并
Hystrix
提供了HystrixCollapser
来实现请求的合并,以减少通讯的消耗好线程的占用。HystrixCollapser
将使用一个合并处理器,将处于一个很短的时间窗(默认10毫秒)内对同一依赖服务的多个请求进行整合并以批量的方式发起请求的功能。使用场景:
@HystrixCollapser(batchMethod = "helloService",collapserProperties = {
@HystrixProperty(name ="timerDelayInMilliseconds",value = "100")})
@HystrixCommand
@Override public List<User> helloService(List<String> ids) {
ResponseEntity<List> responseEntity =restTemplate.getForEntity("http://springcloud-eureka-client-user/hello?id={1}",List.class,StringUtils.join(ids,","));
return responseEntity.getBody();
}
Hystrix配置
Hystrix根据不同业务场景提供了非常丰富和灵活的配置方法。@HystrixCommand(commandProperties = {@HystrixProperty(name="属性1",value = "值1"),@HystrixProperty(name="属性名2",value = "值2")})
提供了5类配置属性:
HystrixCommand.run()
的执行。HystrixCommand.getFallback()
的执行。这些属性同时适用于线程池的信号量的隔离策略。HystrixCircuitBreaker
的行为。HystrixCommand
和HystrixObservableCommand
执行中的指标信息。HystrixCommand
使用的HystrixRequestContext
的设置。声明式服务调用:Spring Cloud Feign
Feign
整合了Spring Cloud Ribbon
与Spring Cloud Hystrix
,同时提供了一种声明式的Web
服务客户端定义方式。
所有通过Feign
我们可以通过注解的方式 快速的调用服务,并且自动回开启客户端负载均衡。
简单地说 Feign
能够对RestTemplate
进行进步封装。
Dubbo
来自于阿里巴巴,它是一个分布式服务框架,致力于提供高性能和透明化的PRC
远程调用服务调用方案。
Dubbo的的特点
spring
配置的方式即可完成服务化,对于应用无入侵。(SpringCloud
有一定的入侵)maven
的install &deploy
命令把interface
和Model
层发布到仓库中,服务调用方只需要依赖interface和model层即可。GateWay
前置网关(Spring Cloud
使用Zuul
实现负载均衡将请求转向Eureka服务器)隔绝外部直接调用原子服务的风险Dubbo SPI
来实现的,其基本原理是Java SPI
机制。Dubbo支持的通信协议和序列化协议
通讯协议:(10种)
NIO
异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。Java REST API
实现的REST
调用支持Hessian
协议用于集成 Hessian
的服务,Hessian
底层采用 Http
通讯,采用Servlet
暴露服务,Dubbo
缺省内嵌 Jetty
作为服务器实现JS
使用的服务。json-rpc
是基于json
的跨语言远程调用协议RMI
协议采用 JDK
标准的 java.rmi.*
实现,采用阻塞式短连接和 JDK
标准序列化方式。Thrift
实现PRC
协议redis
实现RPC
协议Memcached
实现RPC
协议序列化协议:(6种)
hessian
的一个 Apache Dubbo
私有版本Java
自带的序列号工具Java
版本内的 JSON
解析器/生成器Java
序列化工具Java
版本的快速有效的二进制对象序列化框架Dubbo 核心部件:
Docker
容器)zookeeper
)dubbo
的控制台页面中可以显示,目前只有一个简单版本)Dubbo调用的流程
Provider
start
启动服务。register
注册服务到注册中心。Consumer
subscribe
向注册中心订阅服务,只订阅使用到的服务。notify
当服务发生变化时,获取最新的服务列表,更新本地缓存。invoke调用
Consumer
直接发起对 Provider
的调用,无需经过注册中心。而对多个 Provider
的负载均衡,Consumer
通过cluster
组件实现。count监控
Consumer
和 Provider
都异步通知监控中心。dubbo与Apache Thrift的区别
dubbo
本身是一个综合的SOA
解决方案,thrift
仅是一个rpc
服务框架;
dubbo
当前主要用作java
, thrift
可以用作目前所熟知的各种语言;
dubbo
可以使用thrift
作为rpc
服务组件,dubbo
也有自带的rpc
组件
Dubbo服务高可用机制
Dubbo
容错机制
容错机制值得是服务容忍错误的能力,当系统出现网络延迟、网络中断、服务异常等原因,造成当前服务暂时不可用,Dubbo
提供了容错机制来优雅地帮助服务调用者处理这类错误。
Dubbo默认提供了6种容错模式
retries=2
可以修改次数,但是重试次数增加会带来更长的响应延迟。(这种容错模式通常用于读操作)Failover Cluster retries=0
)forks=2
来设置最大并行数。(这种模式要保证请求的幂等性)服务调用者容错机制的配置方式容错机制既可以在服务调用者中配置或在服务提供者中配置
Dubbo 负载均衡机制
在Dubbo
提供了4种负载均衡策略,分别是:
Random LoadBalance随机算法(默认):可以针对性能较好的服务器设置较大的权重值,权重值越大,随机的概率越大。
RoundRobin LoadBalance轮询:安装公约后的权重设置轮询比例。
LeastActive LoadBalance最少活跃调用数:处理较慢的节点将会收到更少的请求。
ConsistentHash LoadBalance一致性Hash:相同参数的请求总是发送到同一个服务提供者。
Dubbo服务降级机制
服务降级是一种系统保护策略,当服务器访问压力较大时,可以根据当前业务情况对不重要的服务降级,以保证核心服务的正常进行。服务降级可以分为两类:
Dubbo
提供了Mock
配置来实现服务降级,它会在一下情况触发:
Dubbo
服务者不提供服务Dubbo
服务超时Mock
本身是一种模拟失败的行为。服务降级mock
的级别:
mock
服务mock
服务。mock
服务。Mock
服务(不管服务能否调用成功)。Spring Cloud Alibaba
主要为微服务开发提供一站式的解决方案,使开发者通过SpringCloud
编程模型轻松地解决微服务架构下的
各种问题。
Sentinel
进行流量控制,断路和系统自适应保护Alibaba Nacos
上注册,客户可以使用Spring
管理的bean
发现实例。通过Spring Cloud Netflix
支持Ribbon
,客户端负载均衡器Nacos
作为数据存储Spring Cloud Stream RocketMQ Binder
连接的高度可扩展的事件驱动微服务Spring Cloud Bus RocketMQ
链接分布式系统的节点Seata
分布式事务解决方案Apache Dubbo RPC
扩展Spring Cloud
服务间调用的通信协议