当前位置: 首页 > 科技观察

程序员笔记-API网关如何实现服务离线的实时感知

时间:2023-03-20 17:54:29 科技观察

上篇文章《Eureka 缓存机制》介绍了Eureka的缓存机制。相信大家对Eureka有了更深入的了解。本文将详细介绍APIGateway是如何实现服务离线实时感知的。1.前言在基于云的微服务应用中,服务实例的网络位置是动态分配的。由于自动缩放、故障和升级,服务实例通常会动态变化。因此,客户端代码需要使用更复杂的服务发现机制。目前,服务发现主要有两种模式:客户端发现和服务端发现。服务器端发现:客户端通过负载均衡器向服务注册中心发起请求,负载均衡器查询服务注册中心并将每个请求路由到一个可用的服务实例。客户端发现:客户端负责确定集群中可用服务实例和负载均衡请求的网络地址。客户端访问服务注册中心,这是一个可用服务的数据库,然后客户端使用负载均衡算法选择一个可用的服务实例,然后发起请求。客户端发现和服务器端发现最大的区别在于客户端知道(缓存)可用的服务注册信息。如果客户端缓存没有从服务器及时更新,可能会导致客户端和服务器缓存数据不一致。2.Gateway和Eureka结合使用NetflixOSS提供了一个很好的客户端服务发现的例子。EurekaServer是注册中心。与EurekaServer相比,Zuul是EurekaClient。Zuul会在本地缓存EurekaServer服务列表,并以定时任务的形式更新服务列表。同时zuul通过本地列表发现其他服务,使用Ribbon实现客户端负载均衡。正常情况下,调用者向网关发起请求可以立即得到响应。但是当producer缩容、下线、升级时,由于Eureka的多级缓存设计结构和定时更新机制,导致LoadBalance端的服务列表B更新不及时(来自上篇文章《Eureka 缓存机制》可以看出,服务消费者最长的感知时间会接近240s),如果此时消费者向网关发起请求,LoadBalance会向一个已经不存在的服务发起请求,而请求会超时。3.解决方案3.1实现思路producer下线后,最后感知的是EurekaServer中的readWriteCacheMap,最后感知的是gatewaycore中的LoadBalance。但是loadBalance发现的生产者是在loadBalance本地维护的一个列表中。所以为了实现网关对生产者下线的实时感知,可以这样做:首先由生产者或者部署平台主动通知EurekaServer,然后跳过Eureka多级缓存之间的更新时间,直接通知Zuul中的EurekaClient,***将EurekaClient中的服务列表更新为Ribbon。但是,如果将离线通知的逻辑代码放在生产者中,会造成代码污染、语言差异等问题。借用一句名言:“计算机科学领域的任何问题都可以通过增加一个间接中间层来解决”。Gateway-SynchSpeed相当于一个代理服务,提供RESTAPI响应调用者的下线请求,并将生产者的状态同步到EurekaServer和网关核心,起到状态同步的作用和柔软的东西。思路:在producer缩容、下线、升级之前,spider平台(spider是容器管理平台)会主动通知Gateway-SynchSpeed一个producer的某个实例要下线,然后Gateway-SynchSpeed会通知EurekaServer生产者的一个实例下线;如果EurekaServer下线成功,Gateway-SynchSpeed会直接通知网关核心。设计特点无创且使用方便。调用者基于什么语言并不重要。调用方只需要向Gateway-SynchSpeed发起httprest请求即可。真正的实现逻辑不需要侵入调用者而是交给代理来实现。原子性。调用者先在EurekaServer下线,然后在所有相关的网关核心作为最小的工作执行单元下线。Gateway-SynchSpeed相当于一个“软东西”,一定程度上保证了服务下线的原子性。3.2实现步骤步骤描述步骤一:在生产者缩容、下线、升级之前,蜘蛛平台会以http请求的形式通知Gateway-SynchSpeed服务,通知的粒度为节点的IP服务实例所在的容器。第二步:Gateway-SynchSpeed收到请求后,首先检查IP是否可用,然后通知EurekaServer。第三步:EurekaServer设置Producer无效并返回处理结果(Eureka离线形式分为两种,一种是直接从服务注册列表中移除,第二种是状态offline,即Producer的状态设置为OUT_OF_SERVICE,如果是第一种形式下线,Spider平台发出下线请求后,不能保证Producer进程会立即被kill掉,如果在此期间Producer还有心跳同步到EurekaServer,则服务将重新注册到EurekaServer)。第四步:Gateway-SynchSpeed获取上一步的结果,如果结果成功,执行下一步;否则,停止。第五步:Gateway-SynchSpeed为EurekaClient。Gateway-SynchSpeed从IP到本地服务注册列表中获取Producer'sApplication-Name。第六步:Gateway-SynchSpeed通过Application-Name查询网关核心库中所有与离线服务相关的网关组名。第七步:Gateway-SynchSpeed通过网关组名在本地服务列表中查找该网关组下的所有服务地址ipAddress(ip:port)。第八步:Gateway-SynchSpeed异步通知所有相关网关节点。Step9:Gateway-Core收到通知后,将Producer下线,并将所有下线成功状态的实例信息记录到DownServiceCache中。第十步:Gateway-Core更新本地Ribbon服务列表。4.补偿机制Eureka提供了安全保护机制。EurekaClient在从EurekaServer更新服务列表之前,会验证相关的Hash值是否发生了变化(Client服务列表被修改,hash值会发生变化)。如果发生变化,则更新方式会从增量更新变为全量更新,(由《Eureka 缓存机制》可以看出30s内readOnlyCacheMap和readWriteCacheMap的数据可能不同),如果客户端缓存列表被readOnlyCacheMap覆盖,最终会导致Ribbon端服务列表和readWriteCacheMap数据不一致。针对Eureka机制,引入监听器EurekaEventListener作为补偿机制,监听EurekaClient的全拉事件,将缓存中未超过30s的服务状态重置为OUT_OF_SERVICE。5、API安全设计考虑了系统的安全性。如果被恶意访问,生产者可能会在EurekaServer中无缘无故下线,使消费者无法通过EurekaServer找到生产者。使用黑白名单进行安全过滤,基本流程如下:在Gateway-Synchspeed中设置白名单网段(IP网段)。在Gateway-Synchspeed中添加过滤器,以验证离线请求者的IP。如果请求者的IP在该网段内,则允许;否则,它将被过滤。6、日志回溯由于Gateway-SynchSpeed和Gateway-Core部署在Docker容器中,如果容器重启,所有日志文件都会丢失。因此需要将Gateway-SynchSpeed和Gateway-Core中的相关日志写入到Elasticsearch中,最后由Kibana负责查询Elasticsearch的数据并进行可视化展示。7.代码片段展示了Gateway-SynchSpeed用于状态同步。EurekaEventListener处理缓存的数据。8.补充说明目前网关使用Zuul和Eureka版本SpringCloudZuul1.3.6.RELEASE和SpringCloudEureka1.4.4.RELEASE实现服务离线的实时感知。目前网关实现对网关下游服务的实时感知,必须满足以下条件:生产者必须部署在kubernetes容器管理平台上。生产者执行正常的离线、升级或缩减操作。不支持容器资源不足导致服务宕机等异常下线服务。网关服务离线实时感知是网关提供给业务方的一个可选方案。蜘蛛平台默认不开启该功能。是否开启该功能由业务方根据自身系统需求决定。具体配置方法请参考API网关接入指南中的《网关实时感知在spider上配置文档说明》。【本文为栏目组织宜信科技学院微信公众号“宜信科技学院(id:CE_TECH)”原创文章】点此查看作者更多好文