接下来对微服务相关技术做一个整理,并输出一个实践项目。
如果从服务构建到生产运营,包括的技术有:微服务框架,容器化,持续集成与发布,资源调度与服务编排,监控等一些大的范围。
这篇主要讲微服务框架,其中主要以Spring Cloud框架进行展开或举例,因为Spring Cloud作为微服务一个可行的落地方案,不仅服务治理功能齐全,也是目前的最佳实践之一。
首先,微服务之间要相互调用,那就从远程调用开始说起:
远程调用
调用类型 | 关系和特点 | 调用效果(同步,异步) | 调用形式 | 协议 | 常用 |
---|---|---|---|---|---|
socket远程发送 | client,server2点之间 | 原生异步 | ip+端口 | TCP/IP | Socket套接字编程 |
http远程发送 | Consumer - Provider 2点之间 | 同步调用 | IP+端口+服务url | http,https | HttpClient,Spring RestTemplate等工具 |
RPC框架 | Consumer - Provider 2点之间 | 同步,异步+回调,单播 | 本地接口 | Http, Https, http2, TCP自定义 | dubbo , GRPC等 |
MQ中间件 | Producer - Broker Server - Consumer 3点之间;服务调用 + 调用解耦 + 消息暂存(削峰平谷) | 同步,异步+回调,单播 | SDK接口 | TCP的自定义 | rocketMQ ,RabbitMQ , Kafka等 |
service mesh | client - client proxy - service proxy - service 4点,非侵入式框架 | 均可 | 本地调用 | Http,Https,http2,TCP的自定义 | Linkerd,Nginx,Envoy, Spring Cloud Sidecar, Consul等 |
RPC框架或叫服务框架开始,Socket IO 基本上已经采用异步非阻塞的方式,大部分底层使用了Netty的实现,在服务的调用方式上也普遍支持同步,异步有回调/无回调 等多种方式。接下来,也会支持反应式流的规范,提高服务调用之间的可靠性。(反应式可以参考上一篇文章)
服务注册发现
上面说的是服务之间远程调用的方式,接下来,我们每一个服务是分布部署在多台机器上的,而且基于集群的云服务器、虚拟机或容器环境,他们每次部署根据资源情况被编排到的虚拟机器的IP可能随时变化,那么,客户端需要知道当前调用的服务在哪些机器上,要对应哪些IP才能调用,所以,就需要引入实时的服务注册与发现。
- 作用 :解决服务名称和服务主机IP的对应关系,实现服务的实时注册,更新和查找
服务名:服务的名称,在该服务名称下注册服务实例的多个节点。
服务名可以简化客户端进行服务调用,一般需要通过负载均衡器,或DNS服务,根据相应的均衡算法策略,得到本次调用的服务名对应的节点IP。还有,我们要说的服务注册发现的方式。常用:Zookeeper,Etcd, Eureka(开源项目已暂停), Consul
服务注册与发现的产品特性:
Feature | Consul | zookeeper | etcd | euerka |
---|---|---|---|---|
编程语言 | Go | Java | Go | Java |
一致性 | Gossip(发现和协调),Raft(选举和多数派) | paxos | raft | — |
cap | Gossip-ap,Raft-cp | cp | cp | ap |
健康检查 | 支持 | 长连接,keepalive | 连接心跳 | 支持 |
多数据中心 | 支持 | — | — | — |
kv存储服务 | 支持 | 支持 | 支持 | — |
使用接口(多语言能力) | http和dns | 客户端 | http/grpc | http(sidecar) |
watch支持 | 全量/支持long polling | 支持 | 支持 long polling | 支持 long polling/大部分增量 |
自身监控 | metrics | — | metrics | metrics |
安全 | acl /https | acl | https支持(弱) | — |
spring cloud集成 | 支持 | 支持 | 支持 | 支持(项目停止) |
配置中心
作用:统一的配置Server,因为微服务粒度更小,数量更多,所以配置信息需要统一进行维护。另外,配置可以支持动态更新。
常用: Spring Cloud Config ,Spring Cloud Consul Config配置中心的产品特性:
Feature | Spring Cloud Config | Consul |
---|---|---|
存储 | git | consul server |
动态配置 | 依赖消息中间件 | 定时任务 |
配置增删改查 | rest api, git | rest api,命令,web console |
服务调用
服务调用需要关注哪些:
服务调用方式,负载均衡,超时与重试,熔断与降级,限流等服务框架一般提供了上面的解决方案,如Dubbo, GRPC, Spring Cloud。
服务调用方式
- 文章最开始介绍了远程调用的几种方式,当前微服务之间的主流方式,还是模拟本地接口的RPC调用方式
Spring Cloud 提供了OpenFeign组件, 来实现服务之间RPC的调用效果。
Feign 描述如下:
Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations.
参考:
https://github.com/spring-cloud/spring-cloud-openfeign
服务调用组件一般需要依赖:负载均衡 ,熔断降级 组件,对应Spring Cloud 的是 Ribbon , hystrix,并且,具有超时与重试的机制。
负载均衡:
- 将工作负载分布到多个服务器,提高性能和可靠性。在请求的每一个层次都有对应的负载均衡器。
客户端负载均衡
- 由客户端实现负载均衡策略,如:
Dubbo, spring cloud Ribbon
客户端负载均衡一般需要依赖服务注册中心,从注册中心获取服务的所有地址,并实现了不同的负载均衡算法,根据算法获得一个IP来路由转发。
服务器端负载均衡
服务器端负载均衡常用的有:
Dns server , LVS , Nginx 等服务端负载均衡一般有以下几种类型:
类型 | 特点 | 功能 | 常用 |
---|---|---|---|
DNS Server | 域名查找IP的服务 | DNS名字 配置多个IP,也支持基于地址的域名解析,解析成距离用户最近的服务器地址 | DNS服务商,内部DNS Server |
二层负载均衡 | MAC | 提供一个VIP(虚IP),集群中不同的机器采用相同IP地址,但是机器的MAC地址不一样,改写报文的目标MAC地址的方式将请求转发到目标机器实现负载均衡 | |
三层负载均衡 | VIP | 提供一个VIP(虚IP),但是集群中不同的机器采用不同的IP地址。根据不同的负载均衡算法,获得并转发至不同的真实服务器IP | LVS |
四层负载均衡 | TCP,UDP | 四层协议中除了包含源IP、目标IP以外,还包含源端口号及目的端口号。在三层负载均衡的基础上,用ip+port接收请求,再转发到对应的机器。 | F5硬件负载均衡,LVS,Haproxy |
七层负载均衡 | http,代理 | 应用层协议较多,常用http、radius、dns,根据请求内容负载均衡 | Nginx,Haproxy |
http重定向 | 302跳转 | 根据请求信息,下发一个新的地址,实现负载均衡 | 逻辑根据业务场景实现,一般用在CDN厂商文件下载,根据用户位置,CDN情况,文件热点等,动态的下发一个可用的CDN文件下载地址 |
- 其它
名称 | 类型 | 特点 | 建议 |
---|---|---|---|
全局负载均衡器GSLB | Http | 多数据中心支持 | 基于DNS、重定向、路由协议实现。用于CDN 就近性,健康检查策略来动态分配流量 |
数据层负载均衡 | 数据的均衡 | 均衡可以通过数据的均衡与请求的均衡实现 |
微服务有关的负载均衡
- 一般从请求入口到后台每一层用到的负载均衡:
类型 | 特点 | 建议 |
---|---|---|
DNS Server | 支持基于地址的域名解析,解析成距离用户最近的服务器地址 | 一般用作第一级负载均衡 |
TCP 负载均衡 (四层) | 海量流量转发 | LVS,一般作为前端接入的负载均衡 |
Http 负载均衡 (七层) | Http | Nginx负载均衡,可根据request head中Host配置路由规则(反向代理), 也可以和注册中心集成 |
微服务网关负载均衡 | Http | Spring Cloud Gateway:路由配置,限流,安全,熔断等,通过注册中心实现路由动态配置,并接入后端微服务 |
服务层负载均衡 | 客户端负载均衡 ; 或服务端负载均衡(dns,vip) | 和微服务框架有关 |
实际上服务之间(服务层)的负载均衡有几种实现方式:
类型 | 特点 | 常用 |
---|---|---|
集中式 | 由统一的负载均衡服务器来路由 | DNS Server->Load Balancer Server |
进程内 | 服务和负载均衡是一个进程,一般由服务框架提供的本地jar包实现 | Dubbo, spring cloud Ribbon |
独立进程 | 服务所在主机独立一个进程做负载均衡,也称作sidecar 或proxy模式负载均衡 | service mesh |
负载均衡算法
名称 | 说明 |
---|---|
轮询算法 | 顺序循环,DNS Server |
随机算法 | 随机分配,不适合机器配置不同的场景 |
加权算法 | 考虑到机器的差异性,分配给机器不同的权重;可以应用在轮询,随机,最少链接,Hash等算法。 |
哈希法 | 同一IP地址的请求,同一会话期内,转发到相同的服务器 |
一致性哈希 | 减少集群机器变化带来的影响 |
最少连接算法 | 优先选择连接数最少的服务器,动态分配,需要监控服务器请求连接数 |
超时与重试:
超时:
从服务调用的发展来看,或从基础到上层框架来看,有如下一些超时控制:
TCP超时有一系列控制,其中和连接,发送有关的是:
Connection-Establishment Timer 建立连接超时 Retransmission Timer 发送等待ACK,没有等到就会重传,重传到最大次数超时
Socket BIO,阻塞式IO:
连接 三次握手超时,connect(SocketAddress endpoint, int timeout) 写 缓冲区等待,TCP发送超时重传(超时时间操作系统可配置) 读 setSoTimeout,一次读取数据的等待超时时间
HttpClient:
老版本: setConnectTimeout:建立连接超时时间 setSocketTimeout: 读取数据的等待超时时间(或两个数据包之间的最大间隔时间),对应BIO- 新版本增加了: setConnectionRequestTimeout:从连接池获取可用连接的等待超时时间
Socket NIO:
连接,写,读 不需要阻塞,所以没有超时时间
Netty ,异步非阻塞IO ,框架层在NIO基础上增加了:
连接超时: Scheduled定时器,超时后关闭连接。 提供方法可以设置。
Dobbo 等RPC框架,在Netty基础上增加了:
同步发送并等待response数据的超时时间。并提供外部配置,以及超时后的重试次数。
Spring Cloud RPC Feign ,在Netty基础上主要提供了:连接,同步发送等待response返回的超时时间:
ConnectTimeout:请求连接的超时时间 ReadTimeout:请求处理的超时时间
Feign 可以单独设置 ,默认会读取ribbon的两个时间设置。建议用ribbon的。
重试
- 重试是配合调用超时,或网络抖动异常时,进行再一次的发送,一般可以配置重试的策略和次数
- Spring Cloud Ribbon:
超过最大重试还超时,则由框架抛出异常或进行熔断处理OkToRetryOnAllOperations:对所有操作请求都进行重试 MaxAutoRetriesNextServer:切换实例的重试次数 , 默认2次(不包括首次) MaxAutoRetries:对当前实例的重试次数
- 注意: 超时时间不能太短, 重试次数不能太多,不合理的设置会造成请求堆积不断增长,造成服务器雪崩
熔断与降级:
熔断
熔断器
断开保护开关,如果服务方已经不可用了,调用者默认的重试策略又增大了流量,导致资源瓶颈后调用者也不可用,最终导致了服务的雪崩效应。
熔断器的目的是让服务调用拥有自我保护和恢复的能力.资源隔离:
通过将每个依赖服务分配独立的资源(线程池,或信号量)进行资源隔离, 从而避免服务雪崩.熔断器模式:
- 当熔断器开关关闭时, 请求被允许通过熔断器. 如果当前健康状况高于设定阈值, 开关继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态.
- 当熔断器开关打开时, 请求被禁止通过,并进行降级处理。
- 经过一段时间后, 熔断开关为半打开状态,部分流量流入,当请求成功时,开关关闭。若该请求失败, 熔断器继续保持打开状态, 接下来的请求被禁止通过.
降级处理后,根据业务级别,在服务端恢复后,进行补偿逻辑处理。
- spring cloud:
hystrix : 熔断器 可以配置熔断超时时间 timeoutInMilliseconds
Hystrix 超时时间控制的是总的请求处理时间,所以Hystrix超时时间要包括 ribbon超时时间 * 重试次数 。
Hytrix,ribbon可以分服务单独设置timeout。
Circuit Breaker 断路器行为配置:
requestVolumeThreshold 滑动窗口的大小(检测的数据范围),默认为20
sleepWindowInMilliseconds 多久以后开始尝试是否恢复,默认为5000ms
errorThresholdPercentage 错误率,默认50%
Hystrix Metrics
Hystrix 提供了实时的监控,包括请求成功,失败(客户端抛出的异常),超时和线程拒绝。Hystrix Dashboard : Hystrix Metrics的展示
监控单实例服务,需要通过访问实例的/actuator/hystrix.stream接口来实现(依赖actuator)
监控集群服务,需要通过stream/mq 发送到Turbine进行聚合,再用Dashboard 进行统一展示。
降级:
降级方法: 当熔断器打开后,快速失败,进行降级处理。
比如: 非关键步骤可以跳过,或可以先保存下来,之后等到对方恢复了,再进行补偿。spring cloud:
hystrix可以配置 fallbackMethod 熔断后的降级方法。 @HystrixCommand(fallbackMethod = "") @FeignClient(value="", fallback = )
限流:
- 因为一切系统皆有瓶颈,所以首先要保证可以活下来。
服务进入的流量大小一般小于出口依赖服务的能力,大于则调用超时或者异常;多个调用则以最小的能力 为准;进入时和 出口的服务端流入时, 一般需要做限流;假如调用方 ,服务提供方数量会变化,那么 ,这种流量需要通过分布式限流来控制更准确;服务的调用方往往有多个,所以,服务端需要更精确的限流策略来分配流量。
限流算法:
固定、滑动时间窗口限流算法
令牌桶、漏桶限流算法
常用Google Guava提供的 RateLimit 工具分布式限流算法
一般采用redis计数器实现,需要注意:
数据一致性问题 , 超时问题 , 性能问题限流拒绝策略
拒绝
阻塞
降级等
限流规则配置
时间粒度
接口粒度
最大限流值
服务自身限流:
首先要保护自己,那么就要保证接入的流量在该应用-服务的最大tps,qps之内。一般采用单机限流算法就可以。
服务网关限流
外部过来的请求,因为网关多实例集群(因为网关实例也会发生变化),一般采用分布式限流策略。
Reactive Stream限流:
关于回压式流,可以参考上一篇“反应式”的文章。
服务网关
微服务的统一入口,是外部请求和内部微服务之间的桥梁。主要功能包括:
- 路由: 外部请求Path等规则到微服务的对应关系。一般包括请求规则断言和过滤器。
断言:匹配 HTTP 请求的任何内容,例如 headers 或参数。如果断言为真,则路由匹配。
过滤器:修改请求和响应。
路由的配置可以支持动态更新。 - 安全:
鉴权、脱敏,流量清洗,后端签名,黑名单等 - 限流:
因为微服务的数量会变化,所以,服务网关限流一般采用分布式限流算法。限流的粒度包括:
服务粒度
用户粒度,用户,IP
ORIGIN粒度
接口粒度
自由组合与自定义
与监控配合,进行限流操作 - 调用时的超时重试,熔断降级
- 日志记录,性能监控
灰度(请求规则和Ribbon规则匹配)
Spring Cloud Gateway
基于反应式的异步非阻塞网关
参考:
https://github.com/spring-cloud/spring-cloud-gateway
调用链
调用链介绍
服务网关接入微服务的一次请求调用,请求的这个微服务可能又依赖并调用了多个微服务,或中间件等。
调用链就是追踪上报收集服务调用过程中经历了哪些组件、哪些微服务、请求总时长、每个组件所花时长等信息。用于故障定位,统计分析和监控。
调用链属于APM (Application Performance Management) 即应用性能管理监控体系的一部分,并遵循分布式追踪OpenTracing标准,具体可以参考:
https://github.com/opentracing-contrib/opentracing-specification-zh/blob/master/specification.md
http://opentracing.io/documentation/pages/translations.html
调用链一般需要由以下组件构成:
数据埋点上报 - Spring Cloud Sleuth
数据收集,保存,提供查询API - Zipkin
查询展示 - Zipkin 或其它
其它开源框架还有:
Pinpoint, Skywalking, CAT, EgleEye
Spring Cloud
Sleuth
可用于跟踪集成的组件,埋点类型有:
Runnable and Callable
Hystrix
RxJava
HTTP integration
HTTP Client Integration
Feign
Asynchronous Communication
Messaging采样类型
AlwaysSampler
NeverSampler
IsTracingSampler
PercentageBasedSampler
常用的配置:spring.sleuth.sampler.probability=数据上报的2种方式:
- 通过http直接上报Zipkin
- 通过spring cloud stream 消息中间件发送Zipkin
具体可以参考官方文档:
https://cloud.spring.io/spring-cloud-sleuth/
Zipkin
- Zipkin Client:
zinkin埋点客户端如Sleuth,目前客户端官方及第三方提供的支持有java,C,python,JavaScript等 - Transport:
传输方式,http请求 或 消息中间件 - Database:
可以配置为mysql、elasticsearch或Cassandra持久化。 - Zipkin Server:
用于由Collector收集、存储、聚合及展示跟踪数据
一般也可以使用ELK,来收集和展示,便于个性化的需求扩展实现。
官方文档可以参考:
https://github.com/openzipkin/zipkin
微服务实践
最后,分享一个用Spring Cloud Finchley 搭建的微服务实践样例:
https://github.com/masenmiao/acloud-finchley-example