Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >线上SpringCloud网关调用微服务跨机房了,咋整?

线上SpringCloud网关调用微服务跨机房了,咋整?

作者头像
猿天地
发布于 2020-03-11 01:45:26
发布于 2020-03-11 01:45:26
1.5K00
代码可运行
举报
文章被收录于专栏:猿天地猿天地
运行总次数:0
代码可运行

作者:东升的思考

转自:Java爱好者社区

前言

公司内考虑到服务器资源成本的问题,目前业务上还在进行服务的容器化改造和迁移,计划将容器化后的服务,以及一些中间件(MQ、DB、ES、Redis等)尽量都迁移到其他机房。

那你们为什么不用阿里云啊,腾讯云啊,还用自己的机房?

的确是这样,公司内部目前还是有专门的运维团队。也是因为历史原因,当时业务发展比较迅猛,考虑到数据的安全性也是自建机房的。对于中小型公司这样做,显然成本太高了,所以一般都用阿里云。对于中大型企业或者对数据安全性要求高的公司,自建机房维护的也不再少数。

对于中间件来说,比如 Redis 缓存,有的业务也是因为历史原因,当时上线后都是单独申请,并部署的一套集群,但是量并不是很大,所以类似这种情况的,可以考虑跟其他项目使用的集群合并为一个,这样就可能节省了一部分服务器资源。

现在大多数企业都已经微服务化,容器化了。

所以,将非容器化的业务要求都迁移到容器中,这里的容器基本都是指 Kubernetes 平台了,通过容器发布调度服务,对于运维来说,维护变得更加便捷,高效。

对于研发来说,业务需要部署服务,不再需要重新提 JIRA 工单,走一系列审核流程,最后给到你的可能还是一台虚拟机,依赖的软件单独安装部署。用了容器,只要在 集装箱 中提前安装好所需软件环境,按照发布规范打好镜像,发布服务的过程一路就是 点点点...

线上业务场景介绍

继续来说今天的主题。

有一个项目是 SpringCloud 架构的,其中使用到了 网关 Zuul,并且也使用了到了 Eureka 作为注册中心。

因为该项目提前已经迁移到北京机房节点部署的容器环境,我们最终目标是迁移到其他机房(如:天津机房)。

北京有两个机房:A机房、B机房,因为都在北京,所以两个机房之间的 网络延时 是可以接受的。

微服务也同样在这两个机房之间都有部署。

此时,如果只是将微服务部署到 天津机房,会变成如下图所示的关系:

问题很明显,就是网关服务只有北京的,而微服务新增了天津机房的,此时会导致 跨机房调用,即北京网关调用到了天津微服务。

尽管北京到天津 ping 的网络延时仅有 3 毫秒 之差,但是服务与服务之间的调用,可就不止这 3 毫秒了。

其中包括服务器与服务器之间 TCP连接的建立、数据传输的网络开销,如果数据包过大,跨机房访问耗时就会很明显了。

所以呢,尽量避免跨机房访问,当然要将网关也要迁移到天津机房。

但是,大家看 粉红色粗体 的线条,仍然存在跨机房调用,天津网关调用到北京微服务。

对于线上并发访问量稍微大点,或者有些接口响应体大的,又或者网络抖动等场景下,可能就会导致接口响应时间变长了。

如何解决呢?

因大部分业务都部署到天津,可以将天津机房的服务权重调高

SLB配置 (类Nginx):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
upstream {
    server 北京机房网关IP  20;
    server 天津机房网关IP  80}

网关与微服务之间,都是通过 Eureka 注册中心媒介来沟通,即 注册服务 拉取服务

仅仅在网关层配置好权重还不够,此时还会存在天津网关路由到北京微服务上。

Eureka 内部是基于 Ribbon 实现负载均衡的,自行实现按权重的负载均衡策略,Eureka做一点改造,界面上支持权重的修改。

下图截图了部分示例:

IP后面的就是权重值,可以在界面上输入权重值进行调整。

我们可以将北京微服务权重调低,天津微服务权重调高。

相当于网关以及微服务两侧都是通过基于 权重 的负载均衡算法来尽量减少跨机房调用的,但是无法避免跨机房调用。

使用 Eureka 的分区改进

上面描述的方案对于 20% 的流量仍然存在跨机房访问,我们能不能做到先访问同一机房的服务,如果同一机房的服务都不可用了,再访问其他机房的呢?

答案是 可以的

我们可以借助于 Eureka 注册中心里提供了 regionzone 的概念来实现。

regionzone 两个概念均来自亚马逊的 AWS:

region:简单理解为地理上的分区,比如亚洲地区,或者华北地区等等,没有具体大小的限制。根据项目情况,自行合理划分 region。

zone:简单理解为 region 内的具体机房,比如说 zone 划分为北京、天津,且北京有两个机房,就可以在 region 内划分为三个zone,北京划分为zone1、zone2,天津为zone3。

结合上面的示例,假设仅设置一个 region 为京津地区。

然后我们给这个区域下的网关服务、微服务打上 zone 机房标签,在系统运维上将机房也称作 IDC 数据中心

网关服务打上zone标签:

微服务打上zone标签:

这个功能都是在 Eureka注册中心 上实现的,在给服务配置 zone 前,调用路径如下所示:

给服务配置 zone 之后,框架内部的路由机制的实现下,调用路径如下所示:

当前使用的 Eureka 是部署在北京,如果想让服务在注册续约拉取 动作时也能实现 就近机房访问,部署架构就变成如下这个样子:

北京区域不同机房假设认为网络延时小,所以北京两个机房可以使用同一个 Eureka 集群;天津可以单独再部署一套 Eureka 集群,这样就可以实现优先路由到同机房访问。

服务注册的关键配置

基本原理就是这样,贴上一段 Eureka 使用 regionzone 的配置供大家参考:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring:
  application:
    name: mananger

server:
  port: ${EUREKA_SERVER_PORT:8011}

eureka:
  instance:
    # 全网服务实例唯一标识
    instance-id: ${EUREKA_SERVER_IP:127.0.0.1}:${server.port}
    # 服务实例的meta数据键值对集合,可由注册中心进行服务实例间传递
    metadata-map:
      # [HA-P配置]-当前服务实例的zone
      zone: ${EUREKA_SERVER_ZONE:tz-1}
      profiles: ${spring.profiles.active}
    # 开启ip,默认为false=》hostname
    prefer-ip-address: true
    ip-address: ${EUREKA_SERVER_IP:127.0.0.1}
    # [HA-P配置]-当前服务实例的region
client:
    region: ${EUREKA_SERVER_REGION:cn-bj}
    # [HA-P配置]-开启当前服务实例优先发现同zone的注册中心,默认为true
    prefer-same-zone-eureka: true
    # [服务注册]-允许当前服务实例注册,默认为true
    register-with-eureka: true
    # [服务续约]-允许当前服务实例获取注册信息,默认为true
    fetch-registry: true
    # [HA-P配置]-可用region下zone集合
        availability-zones:
      cn-bj: ${eureka.instance.metadata-map.zone},zone-bj,zone-tj
   service-url:
      # [HA-P配置]-各zone下注册中心地址列表
       zone-bj: http://BJIP1:8011/eureka,http://BJIP2:8012/eureka
       zone-tj: http://TJIP1:8013/eureka,http://TJIP2:8014/eureka

prefer-same-zone-eureka :

默认就为true,首先会通过 region 找到 availability-zones 内的第一个 zone,然后通过这个 zone 找到 service-url 对应该机房的注册中心地址列表,并向该列表内的 第一个URL 地址发起注册和心跳,不会再向其它的URL地址发起操作。只有当第一个URL地址注册失败的情况下,才会依次向其它的URL发起操作,重试一定次数仍然失败,会间隔一段心跳时间继续重试。

eureka.instance.metadata-map.zone:

服务提供者和消费者都要配置该参数,表示自己属于哪一个机房的。网关服务也属于消费者,从注册中心拉取到注册表之后会根据这个参数中指定的 zone 进行过滤,过滤后向同 zone 内的服务会有多个实例 ,通过 Ribbon 来实现负载均衡调用。如果同一 zone 内的所有服务都不可用时,会其他 zone 的服务发起调用。

另外注意一点 availability-zones 下 region 的配置是 ${eureka.instance.metadata-map.zone},... 这样配置的好处是,你只要指定好了 eureka.instance.metadata-map.zone,优先会将这个参数放到可用分区下作为第一个 zone 来访问。

Zuul 网关路由分区源码分析

网关使用的 zuul,其内部也是通过 ribboneureka 的结合来实现服务之间的调用,因为网关实际也是个服务消费者,同样会注册到 eureka 上,被网关拉取过来的注册表里的服务,作为服务提供者,同样会注册到eureka上。

通过一张图把控整个请求的大致脉络:

上述图示中部分核心源码如下所示:

PollServerListUpdater#start(final UpdateAction action) 启动后会每隔30秒(默认)去Eureka注册中心拉取一次注册表信息,更新本地缓存的数据结构

调用到了DyamicServerListLoadBalancer匿名实现类中。

通过DyamicServerListLoadBalancer类调用了 updateListOfServer() 方法更新服务列表,serverListImpl的实现是DiscoveryEnabledNIWSServerList类

在DiscoveryEnabledNIWSServerList类内部会调用 obtainServersViaDiscovery() 方法,其内部通过 EurekaClient 来实现从 Eureka 注册中心拉取服务列表。

过滤器内部获取同一机房(zone)的服务列表,先后会调用 ZonePreferenceServerListFilterZoneAffinityServerListFilter 两个过滤器实现 zone 的过滤。

最开始获取的Servers一共是有4条记录,根据调试的代码看,我们是为了获取 zone 为2的服务,所以得到的结果是一条,即 zone = "2",说明找到了同 zone 服务。

请求接口后会调用到 LoadBalancerContext#getServerFromLoadBalancer(...),内部会调用到ILoadBalancer 具体实现的 chooseServer() 方法,最终会获取到 zone="2" 里的一个Server。

那么这里是如何选择的Server呢?

本地调试时,只配置了已给可用的zone,所以这里条件满足会直接调用 super.chooseServer(key) 父类的方法:

BaseLoadBalancer#chooseServer(...) 父类的选择Server的方法,其内部通过 IRule#choose(key) 会调用到具体的负载均衡器的实现:

上述截图中,能看到 MetadataWeightedRule ,这个类是我们自行基于权重负载均衡实现。

该实现类是继承了 ZoneAviodanceRule ,目的就是利用了 zone 的概念,所重写的 choose(Object key) 方法,调用了 this.getPredicate().getEligibleServers(...) 会走同样的过滤规则获取到同一机房(zone)下的所有服务列表,然后在基于每个服务配置的权重筛选一个Server。

获取到 Server 后,拼接接口的URI请求地址 http://IP:PORT/api/.../xxx.json ,通过底层的 OkHttp 实现完成 Http 接口的调用过程。

好了,到此基本就分析完了,从网关请求,通过 ribbon 组件从 eureka 注册中心拉取服务列表,如何基于 zone 分区来实现多数据中心的访问。

对于 服务注册,要保证服务能注册到同一个 zone 内的注册中心,如果跨 zone 注册,会导致网络延时较大,出现拉取注册表,心跳超时等问题。

对于 服务调用,要保证优先调用同一个 zone 内的服务,当无法找到同 zone 或者 同 zone 内的服务不可用时,才会转向调用其他 zone 里的服务。

本文提到的只是网关到微服务之间的调用,实际项目中,微服务还会调用其他第三方的服务,也要同时考虑到跨机房调用的问题,尽量都让各服务之间在同机房调用,减少网络延时,提高服务的稳定性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 猿天地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SpringCloud微服务之初识微服务01
随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢?
Maynor
2021/12/06
3470
SpringCloud微服务之初识微服务01
微服务SpringCloudday1 认识微服务与服务注册(Eureka与nacos)
随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢?
小小程序员
2023/07/01
2680
微服务SpringCloudday1 认识微服务与服务注册(Eureka与nacos)
微服务架构的服务与发现-Spring Cloud
简单来说,服务化的核心就是将传统的一站式应用根据业务拆分成一个一个的服务,而微服务在这个基础上要更彻底地去耦合(不再共享DB、KV,去掉重量级ESB),并且强调DevOps和快速演化。这就要求我们必须采用与一站式时代、泛SOA时代不同的技术栈,而Spring Cloud就是其中的佼佼者。
java思维导图
2018/07/26
4480
微服务架构的服务与发现-Spring Cloud
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
【基础的内容考察 ——回答原则:简单的问题不能答错(一道面试题就能淘汰一个人),新手和老手都要注意】
寻求出路的程序媛
2024/08/05
2310
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud真不难—Eureka注册中心、Ribbon负载均衡、Nacos注册中心
随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢?
陶然同学
2023/02/27
5700
SpringCloud真不难—Eureka注册中心、Ribbon负载均衡、Nacos注册中心
微服务架构-实现技术之具体实现工具与框架5:Spring Cloud Feign与Ribbon原理与注意事项
二、FeignClent注解剖析+Spring Cloud Feign基本功能配置解读
全栈程序员站长
2022/08/11
4050
微服务架构-实现技术之具体实现工具与框架5:Spring Cloud Feign与Ribbon原理与注意事项
SpringCloud之eureka
随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢?
roydonGuo
2023/02/03
3210
微服务学习计划——SpringCloud
在学习并掌握了众多基础框架之后,我们的项目繁杂且难以掌握,那么我们就需要开启一门新的课程,也就是我们常说的微服务架构
秋落雨微凉
2023/03/08
6720
微服务学习计划——SpringCloud
微服务架构SpringCloud
努力,不是为了要感动谁,也不是要做给某些人看,而是有能力跳出自己厌恶的圈子,并拥有自己选择的权力,用自己喜欢的方式,过一生。
凹谷
2020/04/11
6920
微服务 eureka_变压吸附的原理
随着互联网技术的发展,系统用户量的增长,很多系统都采用了分布式的方式进行部署。这个固然大大提高了系统的性能和可用性,但是分布式部署导致各种服务数量大增,这给我们进行服务治理和运维带来了困扰。
全栈程序员站长
2022/08/02
2580
微服务 eureka_变压吸附的原理
【微服务】134:SpringCloud
我们使用的就是SpringCloud,不用多说,看名称都知道又是Spring旗下的一个项目。
刘小爱
2020/08/28
3520
Ribbon和 Nacos服务注册中心
上一节我们学习了 SpringCloud 的核心组件 Eureka ,但是它逐渐被 Nacos 替代
程序员Leo
2023/08/07
4550
Ribbon和 Nacos服务注册中心
05-面试必会-SpringBoot&SpringCloud
1.在 SpringBoot 项目的启动引导类上都有一个注解@SpringBootApplication
捞月亮的小北
2023/12/01
2120
05-面试必会-SpringBoot&SpringCloud
SpringBoot+SpringCloud面试题整理
什么是SpringBoot? 1、用来简化spring初始搭建和开发过程使用特定的方式进行配置(properties或者yml文件) 2、创建独立的spring引用程序main方法运行 3、嵌入Tomcat无需部署war包,直接打成jar包nohup java -jar – & 启动就好 4、简化了maven的配置 4、自动配置spring添加对应的starter自动化配置 SpringBoot常用的starter: 1、spring-boot-starter-web(嵌入Tomcat和web开发需要的servlet和jsp支持) 2、spring-boot-starter-data-jpa(数据库支持) 3、spring-boot-starter-data-Redis(Redis支持) 4、spring-boot-starter-data-solr(solr搜索应用框架支持) 5、mybatis-spring-boot-starter(第三方mybatis集成starter) SpringBoot自动配置原理: 1、@EnableAutoConfiguration这个注解会”猜”你将如何配置spring,前提是你已经添加了jar依赖项,如果spring-boot-starter-web已经添加Tomcat和SpringMVC,这个注释就会自动假设您在开发一个web应用程序并添加相应的spring配置,会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建spring容器中bean 2、在main方法中加上@SpringBootApplication和@EnableAutoConfiguration SpringBoot starter工作原理: 1、SpringBoot在启动时扫描项目依赖的jar包,寻找包含spring.factories文件的jar 2、根据spring.factories配置加载AutoConfigure 3、根据@Conditional注解的条件,进行自动配置并将bean注入到Spring Context SpringBoot的优点: 1、减少开发、测试时间和努力 2、使用JavaConfig有助于避免使用XML 3、避免大量的maven导入和各种版本冲突 4、提供意见发展方法 5、通过提供默认值快速开始开发 6、没有单独的web服务器需要,这就意味着不再需要启动Tomcat、Glassfish或其他任何东西 7、需要更少的配置,因为没有web.xml文件。只需添加用@Configuration注释的类,然后添加用@Bean注释的方法,Spring将自动加载对象并像以前一样对其进行管理。甚至可以将@Autowired添加到bean方法中,以使用Spring自动装入需要的依赖关系中 Springcloud解决那些问题: 配置管理、(注册中心eureka、zk)、服务发现、服务注册、断路器、路由策略、全局锁、分布式会话、客户端调用、接口网关(zuul)、服务管理系统 SpringBoot与Springcloud: 1>、SpringBoot简化了xml配置,快速整合框架 2>、Springcloud是一套微服务解决方案—RPC远程调用 3>、关系Springcloud依赖与SpringBoot(web组件用的SpringMVC),为什么Springcloud会依赖与SpringBoot?因为Springcloud写接口就是SpringMVC接口 4>、SpringBootproperties和yml中可以使用${random}设置一些随机值 服务的调用: rest、feign(均使用httpclient技术),负载均衡ribbon 服务调用的原理: 服务首先注册到注册中心eureka中(注册一个名字通过名字调用) 负载均衡 ribbon,先去注册中心取到对应的服务,然后交给我ribbon 配置详解: 1>、eureka.client.register-with-eureka:是否向注册中心注册自己,注册为true反之为false 2>、eureka.client.fetch-registry: 是否需要去检索服务,检索为true反之为false 3>、eureka.client.serviceUrl.defaultZone : 指定服务注册中心的地址 Eureka: 1>、eureka可分为三个角色:服务发现者、服务注册者、注册发现中心,但是这三个角色并不和实际部署的模型是一对一的关系 2>、所有的网络通信都是基于http(s)协议的 3>、Eureka和AWS是紧密结合的,无论是配置还是源码,比如Region、zone…,Region可以通过
全栈程序员站长
2022/09/07
2740
你都用过SpringCloud的哪些组件,它们的原理是什么?
看到文章的题目了吗?就是这么抽象和笼统的一个问题,确实是我面试中真实被问到的,某共享货车平台的真实面试问题。 SpringCloud确实是用过,但是那是三四年前了,那个时候SpringCloud刚开始流行没多久,我们技术总监让我们调研一下,然后算上我在内的三个同事就一人买了一本SpringCloud的书籍,开始看,开始研究,正好那个时候DDD也比较火,然后我们就一边研究的SpringCloud一边按照DDD的模型搭建自己的项目。 但是这个项目最后做了三个月,才完成了一期。后面二期还没开始,我就撤了。所以SpringCloud总共的使用时间就两三个月,所以对这部分知识掌握的并不扎实,而且入职了新公司之后,都是使用公司自己封装的框架,也已经三年没有用过SpringCloud了,这次是要面试换工作了,所以决定将这方面的知识,总结一下。
纪莫
2021/01/21
7420
微服务:Nacos注册中心
Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层的隔离。
.29.
2024/04/25
1960
微服务:Nacos注册中心
SpringCloud微服务如何优雅停机及源码分析
本文主要讨论的是微服务注册到Eureka注册中心,并使用Zuul网关负载访问的情况,如何停机可以使用户无感知。
Bug开发工程师
2019/05/15
2K0
深入理解 Spring Cloud 核心组件 底层原理
之前一直在看 Spring Cloud 及微服务架构 对 Spring Cloud 的主要组件的原理有了更深入一点的理解,特地做一下总结。
搜云库技术团队
2019/11/18
1.5K0
基于SpringCloud的微服务架构分析,神仙框架!
Spring Cloud是一个相对比较新的微服务框架,2016年才推出1.0的release版本. 虽然Spring Cloud时间最短, 但是相比Dubbo等RPC框架, Spring Cloud提供的全套的分布式系统解决方案。
搜云库技术团队
2021/10/20
1.5K0
基于SpringCloud的微服务架构分析,神仙框架!
Spring Cloud核心组件详解
1)、Eureka服务端:也称服务注册中心,同其他服务注册中心一样,支持高可用配置。如果Eureka以集群模式部署,当集群中有分片出现故障时,那么Eureka就转入自我保护模式。它允许在分片故障期间继续提供服务的发现和注册,当故障分片恢复运行时,集群中其他分片会把它们的状态再次同步回来
全栈程序员站长
2022/09/14
1.7K0
Spring Cloud核心组件详解
推荐阅读
相关推荐
SpringCloud微服务之初识微服务01
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验