前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >gateway nacos sentinel 三剑客强强组合

gateway nacos sentinel 三剑客强强组合

作者头像
kinbug [进阶者]
发布2020-05-07 12:00:04
4.1K0
发布2020-05-07 12:00:04
举报
文章被收录于专栏:IT进修之路IT进修之路

介绍

企业级微服务架构(源码地址),Gateway是很重要的组件之一

spring cloud gateway 响应式网关,基于nacos实现动态网关,基于sentinel实现动态限流,sentinel基于nacos数据持久化

软件架构

版本号:gateway、nacos、sentinel的版本号参考父级项目occo-parent

安装教程

  1. 启动注册中心和配置中心Nacos 文档地址:Nacos文档 下载地址:Nacos下载
  2. 启动限流服务Sentinel 文档地址:Sentinel文档 下载地址:Sentinel下载
  3. 启动网关
  • 下载occo-gateway启动项目
  • 启动gateway
  • 在nacos中建《路由》配置:
代码语言:javascript
复制
Data ID: gateway_router
Group:DEFAULT_GROUP  (默认的)
配置内容:[{"id":"user-server","uri":"lb://kb-user-center","order":0,"predicates":[{"args":{"pattern":"/user/**"},"name":"Path"}],"filters":[{"name":"StripPrefix","args":{"_genkey_0":"1"}}]},{"id":"sso-server","uri":"lb://kb-user-center","order":0,"predicates":[{"args":{"pattern":"/sso/**"},"name":"Path"}],"filters":[{"name":"StripPrefix","args":{"_genkey_0":"1"}}]}]    (JSON格式)
配置字段说明:       
       ①  id:路由的名字;
       ②  uri:路由的地址,lb表示去那儿一个服务,kb-user-center是nacos注册中心的服务名;
       ③  order:0 ,直接配置为0,为1是请求的url就会带服务名;
       ④  predicates:
            After路由匹配:匹配指定时间之后的请求:        name=After ,_genkey_0=2020-01-20T17:42:47.789-07:00[America/Denver]
            Before路由匹配:匹配指定时间之前的请求:      name=Before,_genkey_0=2020-01-20T17:42:47.789-07:00[America/Denver] 
            Between路由匹配:匹配指定时间区间的请求:     name=Before,_genkey_0=时间一 ,时间二         (PS:两个时间逗号隔开)
            Cookie路由匹配:匹配指定Cookie的值匹配请求:  name=Cookie, _genkey_0=chocolate, ch.p (PS:匹配cookie名为chocolate的值为ch.p的请求)
            Header路由匹配:匹配指定header的值匹配请求:  name=Header, _genkey_0=X-Request-Id, \d+ (PS:匹配头信息X-Request-Id的值匹配\d+的正则表达式)
            Host路由匹配:Host匹配设定的表达式:          name=Host, _genkey_0=**.fuse.org 
            Method路由匹配:匹配HttpMethod方法请求:      name=Method, _genkey_0=GET
            Path路由匹配:请求路径匹配设定表达式的请求:    name=Path, _genkey_0=/foo/{segment}    (PS:请求路径匹配路径匹配表达式/foo/{segment})
            Path路由匹配:请求路径匹配设定值的请求 :       name=Path, _genkey_0=/foo/**  (PS:请求路径匹配路径以/foo开头)
            Query路由匹配:请求参数匹配设定值或表达式的请求:name=Query, _genkey_0=baz   (PS:请求参数中包含baz参数)

4、发布gateway_router配置,每次重新启动gateway都要重新发布一下这个配置,才能被gateway获取到《路由》配置。 5、在nacos中建《限流》配置如下: Data ID: gateway-sentinel Group:DEFAULT_GROUP (默认的) 配置内容:[{"resource":"user-server","controlBehavior":0,"count":2,"grade":1,"limitApp":"default","strategy":0}] (JSON格式) 配置说明:

  • resource:资源名,即限流规则的作用对象
  • limitApp:流控针对的调用来源,若为 default 则不区分调用来源
  • grade:限流阈值类型(QPS 或并发线程数);0代表根据并发数量来限流,1代表根据QPS来进行流量控制
  • count:限流阈值
  • strategy:调用关系限流策略
  • controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
  • clusterMode:是否为集群模式

整合说明

1、GateWay支持跨域
代码语言:javascript
复制
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;

@Configuration
public class GatewayConfig {
	
	/**
	 * -跨域支持配置
	 */
	@Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
	
	/**
	 * -远程地址键解析器
	 */
	@Bean(value = "remoteAddrKeyResolver")
	public KeyResolver remoteAddrKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
	}
}
2、Gateway 整合Nacos

Ⅰ、整合需要的Jar

代码语言:javascript
复制
   <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>

		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>

Ⅱ、 Gateway获取Nacos的权重,在配置加入下面配置

代码语言:javascript
复制
    @Bean
	@Scope(value = "prototype")
	public IRule loadBalanceRule() {
		return new NacosRule();
	}

Ⅲ、动态获取nacos中gateway_router的路由配置

代码语言:javascript
复制
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

@Component
public class NacosDynamicRouteService implements ApplicationEventPublisherAware {

    private static String DATAID = "gateway_router";

    private static String GROUP = "DEFAULT_GROUP";

    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    private static final List<String> ROUTE_LIST = new ArrayList<>();

    @PostConstruct
    public void dynamicRouteByNacosListener() {
        try {
            ConfigService configService = NacosFactory.createConfigService(serverAddr);
            configService.getConfig(DATAID, GROUP, 5000);
            configService.addListener(DATAID, GROUP, new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    clearRoute();
                    try {
                    	System.err.println(configInfo);
                        List<RouteDefinition> gatewayRouteDefinitions = JSONObject.parseArray(configInfo, RouteDefinition.class);
                        for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
                            addRoute(routeDefinition);
                        }
                        publish();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    private void clearRoute() {
        for(String id : ROUTE_LIST) {
            this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        }
        ROUTE_LIST.clear();
    }

    private void addRoute(RouteDefinition definition) {
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            ROUTE_LIST.add(definition.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void publish() {
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
 3、Gateway整合sentinel

Ⅰ、需要的jar

代码语言:javascript
复制
        <dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.csp</groupId>
			<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
		</dependency>

Ⅱ、 注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例

代码语言:javascript
复制
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}

Ⅲ、官方指导地址(什么都还是官方靠谱)

https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81

4、Sentinel基于Nacos持久化

Ⅰ、添加jar

代码语言:javascript
复制
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

Ⅱ、添加配置

代码语言:javascript
复制
import java.util.List;
import java.util.Properties;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.api.PropertyKeyConst;

/**
 * sentinel数据持久化到nacos
 * @see https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95
 * @author kinbug
 */
@Component
public class SentinelDataSourceNacos {
	
	// nacos server addr
	@Value("${spring.cloud.nacos.config.server-addr}")
	private String serverAddr;

	// nacos group
	private static final String groupId = "DEFAULT_GROUP";
	// nacos dataId
	private static final String dataId = "gateway-sentinel";

	// if change to true, should be config NACOS_NAMESPACE_ID
	private static boolean isDemoNamespace = false;
	// fill your namespace id,if you want to use namespace. for example:
	// 0f5c7314-4983-4022-ad5a-347de1d1057d,you can get it on nacos's console
	private static final String NACOS_NAMESPACE_ID = "${namespace}";

	@PostConstruct
	public void initRules() {
		if (isDemoNamespace) {
			loadMyNamespaceRules();
		} else {
			loadRules();
		}
	}

	private void loadRules() {
		ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(serverAddr, groupId,
				dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
				}));
		FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
	}

	private void loadMyNamespaceRules() {
		Properties properties = new Properties();
		properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
		properties.put(PropertyKeyConst.NAMESPACE, NACOS_NAMESPACE_ID);

		ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(properties, groupId,
				dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
				}));
		FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
	}

}

Ⅲ、官方指导

https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
    • 软件架构
      • 安装教程
        • 整合说明
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档