• Spring Cloud Gateway整合Nacos实现服务路由及集群负载均衡


    目录

    一、序言

    我们都知道Spring Cloud Gateway是一个基于Spring BootSpring WebFluxProject Reactor构建的高性能网关,旨在提供简单、高效的API路由。

    Spring Cloud Gateway基于Netty运行,因此在传统Servlet容器中或者打成war包是不能正常运行的。


    二、代码示例

    这里我们注册中心选型的是Nacos,如果还没有安装Nacos,请参考:Nacos快速安装部署

    1、父工程spring-cloud-gateway-learning

    	
    	        spring-cloud-api-gateway
    	        spring-cloud-user-service
    	        spring-cloud-message-service
    	
    
        
            8
            8
            UTF-8
            2.3.7.RELEASE
            Hoxton.SR12
            2.2.6.RELEASE
            3.12.0
        
    
        
            
                org.projectlombok
                lombok
            
            
                org.apache.commons
                commons-lang3
                ${commons.lang3.version}
            
        
    
        
            
                
                    org.springframework.boot
                    spring-boot-starter-parent
                    ${spring.boot.version}
                    pom
                    import
                
    
                
                    org.springframework.cloud
                    spring-cloud-dependencies
                    ${spring.cloud.version}
                    pom
                    import
                
                
                    com.alibaba.cloud
                    spring-cloud-alibaba-dependencies
                    ${spring.cloud.alibaba.version}
                    pom
                    import
                
            
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    备注:具体Spring Cloud各版本说明请参考Spring Cloud Alibaba版本说明

    2、子工程spring-cloud-api-gateway

    (1) pom.xml

    
            com.universe
            spring-cloud-gateway-learning
            1.0-SNAPSHOT
    
    
    
            
                org.springframework.cloud
                spring-cloud-starter-gateway
            
            
                com.alibaba.cloud
                spring-cloud-starter-alibaba-nacos-discovery
            
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (2) 配置文件和代码示例

    1. bootstrap.yml

      spring:
      application:
      name: api-gateway
      server:
      port: 9000

    2. application.yml

      spring:
      cloud:
      gateway:
      routes:
      - id: user-service
      uri: lb://user-service
      predicates:
      - Path=/user/**
      - id: message-service
      uri: lb://message-service
      predicates:
      - Path=/message/**
      nacos:
      discovery:
      server-addr: localhost:8848

    如果URI以lb开头,比如如上配置中的lb://user-serviceSpring Cloud Gateway会用ReactiveLoadBalancerClientFilter 解析服务名为user-service的实例对应的实际host和端口,并做集群负载均衡

    这项功能通过全局过滤器ReactiveLoadBalancerClientFilter 实现,官网描述如下:
    在这里插入图片描述

    1. RouteRecordGlobalFilter

      @Slf4j
      @Component
      public class RouteRecordGlobalFilter implements GlobalFilter, Ordered {

      @Override
      public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      	// RouteToRequestUrlFilter会把实际路由的URL通过该属性保存
      	URI proxyRequestUri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
      	long start = System.currentTimeMillis();
      
      	return chain.filter(exchange).then(Mono.fromRunnable(() -> {
      		long end = System.currentTimeMillis();
      		log.info("实际调用地址为:{},调用耗时为:{}ms", proxyRequestUri, (end - start));
      	}));
      }
      
      @Override
      public int getOrder() {
      	// 优先级设为最低,先让RouteToRequestUrlFilter先调用
      	return Ordered.LOWEST_PRECEDENCE;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      }

    RouteRecordGlobalFilter 这个全局过滤器我们主要用来记录路由后的实际代理地址,以及调用耗时。

    我们看下RouteToRequestUrlFilter的描述会发现实际路由地址会通过ServerWebExchange中名为ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的属性保存。

    在这里插入图片描述

    关于RouteToRequestUrlFilter的部分源码如下:

    @Override
    	public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    		Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    		if (route == null) {
    			return chain.filter(exchange);
    		}
    		log.trace("RouteToRequestUrlFilter start");
    		URI uri = exchange.getRequest().getURI();
    		boolean encoded = containsEncodedParts(uri);
    		URI routeUri = route.getUri();
    
    		if (hasAnotherScheme(routeUri)) {
    			// this is a special url, save scheme to special attribute
    			// replace routeUri with schemeSpecificPart
    			exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR,
    					routeUri.getScheme());
    			routeUri = URI.create(routeUri.getSchemeSpecificPart());
    		}
    
    		if ("lb".equalsIgnoreCase(routeUri.getScheme()) && routeUri.getHost() == null) {
    			// Load balanced URIs should always have a host. If the host is null it is
    			// most
    			// likely because the host name was invalid (for example included an
    			// underscore)
    			throw new IllegalStateException("Invalid host: " + routeUri.toString());
    		}
    
    		URI mergedUrl = UriComponentsBuilder.fromUri(uri)
    				// .uri(routeUri)
    				.scheme(routeUri.getScheme()).host(routeUri.getHost())
    				.port(routeUri.getPort()).build(encoded).toUri();
    		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);
    		return chain.filter(exchange);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    备注:更多关于全局过滤器的介绍请参考 Spring Cloud Gateway全局过滤器

    3、子工程spring-cloud-user-service

    (1) pom.xml

    
            com.universe
            spring-cloud-gateway-learning
            1.0-SNAPSHOT
    
    
    
            
                org.springframework.boot
                spring-boot-starter-web
            
            
                com.alibaba.cloud
                spring-cloud-starter-alibaba-nacos-discovery
            
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (2) 配置文件

    1. bootstrap.yml

      spring:
      application:
      name: user-service
      server:
      servlet:
      context-path: /user


      spring:
      profiles: user-service-master
      server:
      port: 9091


      spring:
      profiles: user-service-slave
      server:
      port: 9092

    2. application.yml

      spring:
      cloud:
      nacos:
      discovery:
      server-addr: localhost:8848

    3. UserController

      @RestController
      public class UserController {

      @GetMapping("/info")
      public Map getUserInfo() {
      Random random = new Random();
      	int waitTime = random.nextInt(1000);
      	LockSupport.parkNanos(1000 * 1000 * waitTime);
      	
      	Map result = new HashMap<>();
      	result.put("name", "Nick");
      	result.put("age", 25);
      	return result;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      }

    4、子工程spring-cloud-message-service

    (1) pom.xml

    
            com.universe
            spring-cloud-gateway-learning
            1.0-SNAPSHOT
    
    
    
            
                org.springframework.boot
                spring-boot-starter-web
            
            
                com.alibaba.cloud
                spring-cloud-starter-alibaba-nacos-discovery
            
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (2) 配置文件和代码示例

    1. bootstrap.yml

      spring:
      application:
      name: message-service
      server:
      servlet:
      context-path: /message


      spring:
      profiles: message-service-master
      server:
      port: 9093


      spring:
      profiles: message-service-slave
      server:
      port: 9094

    2. application.yml

      spring:
      cloud:
      nacos:
      discovery:
      server-addr: localhost:8848

    3. MessageController

      @RestController
      public class MessageController {

      @GetMapping("/info")
      public Map getMessageInfo() {
      Random random = new Random();
      	int waitTime = random.nextInt(1000);
      	LockSupport.parkNanos(1000 * 1000 * waitTime);
      
      	Map result = new HashMap<>();
      	result.put("id", 1);
      	result.put("title", "我爱中国");
      	return result;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      }


    三、测试结果

    分别启动api-gateway、指定概要文件启动两个user-service服务实例、和两个message-service服务实例,查看Nacos控制台。
    在这里插入图片描述

    可以看到,api-gateway启动了一个服务实例,user-service和message-service都启动了两个服务实例。

    备注:IDEA运行时指定Active Profiles即可。

    1、集群负载均衡测试

    连续访问http://localhost:9000/user/info,可以看到user-service集群服务实例被轮询调用。
    在这里插入图片描述

    2、服务路由测试

    分别访问 http://localhost:9000/user/infohttp://localhost:9000/message/info,我们可以看到基于路径匹配的服务路由分发是成功的。
    在这里插入图片描述

    **加粗样式**

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    错误未找到concrt140.dll最详细的解决方法与修复教程
    【JavaScript】js判断一个变量是数组
    019-JAVA访问权限、封装详细讲解
    蓝牙资讯|苹果新款AirPods Pro支持Vision Pro无损音频和IP54防水防尘
    html实现图片裁剪处理(附源码)
    ModStartBlog 现代化个人博客系统 v5.2.0 主题开发增强,新增联系方式
    动态数据模型分析与应用
    2173. 最多连胜的次数
    【设计模式】Java 语言不同的编程范式-第1章
    windows11使用docker部署安装minio
  • 原文地址:https://blog.csdn.net/asdfadafd/article/details/126114125