preface

Spring Cloud: Spring Cloud: Spring Cloud

When we use Sentinel for fuses and flow limiting, some configurations are stored in the current server’s memory by default, which means they will disappear every time the service is restarted. We weren’t very friendly when we were building the microservices architecture for testing. It is well known that Sentinel provides several methods of persistence, such as persisting to Nacos and native JSON files. This method can solve the operation of persistence, but it cannot automatically synchronize the update, that is, the persistence configuration is written as it is, after the program is started, it cannot dynamically update to the persistent store! The ability to persist Nacos or native JSON would be great!

Sentinel dynamic push-pull data persistent synchronization to Nacos

This operation literally looks like just synchronization Nacos logic, but it is not. Synchronization Nacos is actually divided into normal service synchronization Nacos and Gateway synchronization Nacos. Because the pull and pull mechanisms of the Sentinel Datasource and our own service (gateway and others) are not the same, there are two logical things to do in this case!

Before writing the dynamic pull data persistence Nacos, ensure that the Sentinel service integration and Gateway integration Sentinel default flow can run first!

Persistent synchronization of Sentinel Dynamic Push-pull data to Nacos(Common Part)

1. Download Sentinel source code

Sentinel-GitHub

I said here the 1.7.1 version as a benchmark, to version, here I want to give a mouth, micro service architecture structures, the most disgusting I think is not the how hard it is to write code, are often the code will be a problem, always all versions of, this is a headache, but I’m here to provide a set of solutions, this version adaptation scheme is more accurate, Can help us determine a version of the version description between Spring Boot, Spring Cloud and Spring Cloud Alibaba under the payment request. I used Spring Boot 2.3.2.RELEASE, Spring Cloud Alibaba 2.2.5.RELEASE and Spring Cloud Hoxton.sr8 for the version of the entire microservice architecture

Without further ado, take it back and get back to the point of this article!

This is we want two open source, IDEA to open

2. Modified pom. XML

Modify the sentinel-datasource-nacos dependency in POM.xml to comment out test so it can be used in the main program.

<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <! --<scope>test</scope>--> </dependency>

3. Create the nacossync directory to write our binary code

The classes shown in NacosSync are the code we will write!

4.Naocs data synchronization Properties mapping class

This class is common to both Gateway binary synchronization and normal service binary

/** * @author TAO * @description: Naocs Data synchronization Properties Mapping class * @date 2021/5/1 22:36 */ @Component @ConfigurationProperties(prefix = "nacos.server") public class NacosConfigProperties { private String ip; private String port; private String namespace; private String groupId; public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getPort() { return port; } public void setPort(String port) { this.port = port; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getGroupId() { return groupId; } public void setGroupId(String groupId) { this.groupId = groupId; } public String getServerAddr() { return this.getIp() + ":" + this.getPort(); } @Override public String toString() { return "NacosConfigProperties [ip=" + ip + ", port=" + port + ", namespace=" + namespace + ", groupId=" + groupId + "]"; }}Copy the code

5.Nacos synchronization constant class

This class is optional, depending on the specification

/** * @author TAO * @description: Date 2021/5/6 23:19 */ public Final class NacosConfigConstant {public static final String FLOW_DATA_ID_POSTFIX = "-sentinel-flow"; // Universal sentinel persistence Nacos file suffix}Copy the code

6.Nacos synchronizes configuration classes

This class of words to write an empty class, behind the concrete implementation when we add corresponding code!

/** * @author TAO * @description: * @date 2021/5/6 23:19 */ @Configuration Public class NacosConfig {@autoWired Private NacosConfigProperties nacosConfigProperties; /** * TODO is the key to converting a FlowRuleEntity into a FlowRule. The following pairs are decoders for different scenarios. * TODO is actually parsing JSON in Nacos into the corresponding entity class. * @return FlowRule */ /TODO @Bean public ConfigService nacosConfigService() throws Exception { Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR, nacosConfigProperties.getServerAddr()); properties.put(PropertyKeyConst.NAMESPACE, nacosConfigProperties.getNamespace()); return ConfigFactory.createConfigService(properties); }}Copy the code

7. Application. Properties configuration file to add the Nacos configuration

Note that the namespace Nacos namespace can be omitted if it is published, and if it is any other self-created namespace it needs to be identified in addition to writing the namespace, which I didn’t go into

nacos.server.ip=nacos-ip
nacos.server.port=8848
nacos.server.namespace=
nacos.server.group-id=DEFAULT_GROUP
Copy the code

8. Add dependencies for our own service

<! --sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <! --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>Copy the code

9. Add some configuration for our own service

This configuration should have been written in Nacos persistence.

spring: application: name: yy-auth cloud: nacos: discovery: server-addr: nacos:8848 sentinel: transport: dashboard: Sentinel :9999 client-IP: 192.168.1.109 # Prevent sentinel from fetching virtual IP addresses port: 8719 Ds1: nacOS: server-addr: ds1: nacOS: server-addr: ds1: nacOS: server-addr nacos:8848 #namespace: sentinel dataId: yy-auth-sentinel-flow groupId: DEFAULT_GROUP data-type: json rule-type: flowCopy the code

At this point, the generic parts of the normal service and Gateway are written, and we’ll start writing the different code!

Persistent synchronization of Sentinel Dynamic Push-pull data to Nacos(Common service)

1. Write the pull Nacos configuration class

/** * @author TAO * @description: @Date 2021/5/6 23:18 */ @Component("flowRuleNacosProvider") public class flowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> { private static Logger logger = LoggerFactory.getLogger(FlowRuleNacosProvider.class); @Autowired private NacosConfigProperties nacosConfigProperties; @Autowired private ConfigService configService; @Autowired private Converter<String, List<FlowRuleEntity>> converter; @Override public List<FlowRuleEntity> getRules(String appName) throws Exception { Logger. info(" Current traffic limiting configuration file name pulled from Nacos :{}", appName + nacosConfigConstant.flow_data_ID_postfix); String rules = configService.getConfig(appName + NacosConfigConstant.FLOW_DATA_ID_POSTFIX, nacosConfigProperties.getGroupId(), 3000); Logger. info(" Pull traffic limiting information from Nacos :{}", rules); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return converter.convert(rules); }}Copy the code

2. Write push configuration to Nacos class

/** * @author TAO * @description: Nacos * @date 2021/5/6 23:19 */ @Component("flowRuleNacosPublisher") public class flowRuleNacosPublisher implements  DynamicRulePublisher<List<FlowRuleEntity>> { private static Logger logger = LoggerFactory.getLogger(FlowRuleNacosPublisher.class); @Autowired private NacosConfigProperties nacosConfigProperties; @Autowired private ConfigService configService; @Autowired private Converter<List<FlowRuleEntity>, String> converter; @Override public void publish(String app, List<FlowRuleEntity> rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } logger.info(" push to Nacos configuration :{}", rules); configService.publishConfig(app + NacosConfigConstant.FLOW_DATA_ID_POSTFIX, nacosConfigProperties.getGroupId(), converter.convert(rules)); }}Copy the code

3. Modify the redirect URL of the flow control rule

Find the resources/app/scripts/directives/sidebar sidebar. This code in the HTML:

<li ui-sref-active="active"> <a ui-sref="dashboard.flowV1({app: entry.app})"> <i class="glyphicon glyphicon-filter"></i>&nbsp; &nbsp; Flow control rules </a> </li>Copy the code

Is amended as:

<li ui-sref-active="active"> <a ui-sref="dashboard.flow({app: entry.app})"> <i class="glyphicon glyphicon-filter"></i>&nbsp; &nbsp; Flow control rules </a> </li>Copy the code

This will redirect to the FlowControllerV2 interface.

4. Add the corresponding Bean to the Nacos synchronization configuration class

Nacos@bean public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() { return rules -> JSON.toJSONString(rules.stream().map(FlowRuleEntity::toRule).collect(Collectors.toList()), true); } @Bean public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() { return s -> JSON.parseArray(s, FlowRuleEntity.class); }Copy the code

5. Replace flowRuleDefaultProvider and flowRuleDefaultPublisher with our own flowRuleNacosProvider and flowRuleNacosPublisher

Change the default DynamicRuleProvider and DynamicRulePublisher in FlowControllerV2 to:

@Autowired @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher; private void publishRules(/*@NonNull*/ String app) throws Exception { List<FlowRuleEntity> rules = repository.findAllByApp(app); rulePublisher.publish(app, rules); Logger. info(" Adding traffic limiting rules successfully {}", json.tojsonString (rules.stream().map(FlowRuleEntity::toRule).collect(Collectors. ToList ()), true)); }Copy the code

Restart the service! Note that I am directly modifying the jump URL of the navigation bar, so it is only valid at the corresponding location

Other entries need to be modified to take effect. I’m not going to show you any more!

Persistent Synchronization of Sentinel Dynamic Push-pull Data to Nacos(Gateway)

Gateway makes pushing and pulling persistence even easier! Don’t talk nonsense, just do it!

1. Write the pull nacos-gateway configuration

/** * @author TAO * @description: Pull Nacos - Gateway configuration * @ date 2021/5/6 "* / @ Component (" flowRuleNacosGatewayProvider") public class FlowRuleNacosGatewatProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> { private static Logger logger = LoggerFactory.getLogger(FlowRuleNacosGatewatProvider.class); @Autowired private NacosConfigProperties nacosConfigProperties; @Autowired private ConfigService configService; @Autowired private Converter<String, List<GatewayFlowRuleEntity>> converter; @Override public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception { Logger. info(" Current traffic limiting rule configuration file name for pulling Gateway from Nacos :{}", appName + nacosConfigConstant.flow_data_ID_postfix); String rules = configService.getConfig(appName + NacosConfigConstant.FLOW_DATA_ID_POSTFIX, nacosConfigProperties.getGroupId(), 3000); Logger. info(" Pull Gateway traffic limiting information from Nacos :{}", rules); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return converter.convert(rules); }}Copy the code

2. Write push configuration to nacos-gateway

/** * @author TAO * @description: Push configuration to Nacos - Gateway * @ date 2021/5/6 "* / @ Component (" flowRuleNacosGatewayPublisher") public class FlowRuleNacosGatewayPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> { private static Logger logger = LoggerFactory.getLogger(FlowRuleNacosGatewayPublisher.class); @Autowired private NacosConfigProperties nacosConfigProperties; @Autowired private ConfigService configService; @Autowired private Converter<List<GatewayFlowRuleEntity>, String> converter; @Override public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } logger.info(" push to gateway-nacOS configuration :{}", rules); configService.publishConfig(app + NacosConfigConstant.FLOW_DATA_ID_POSTFIX, nacosConfigProperties.getGroupId(), converter.convert(rules)); }}Copy the code

3.Nacos synchronizes configuration classes to add corresponding beans

Public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() { return rules -> JSON.toJSONString(rules); } @Bean public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() { return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class); }Copy the code

Complete code

4. Add corresponding dependencies to the Gateway service POM

<! --sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <! --sentinel-gateway--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> </dependency> <! --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>Copy the code

5. Add the Gateway service

spring: application: name: yy-gateway main: allow-bean-definition-overriding: true cloud: nacos: discovery: Server-addr: nacos:8848 sentinel: transport: dashboard: sentinel:9999 client-IP: 10.0.0.208 # 8719 datasource: # Note that although Sentinel is configured with synchronous NACOS extension and the data can be displayed synchronically on the console, the data is only read by the console, not by our own real service, so we need to write ds1: nacOS: server-addr: nacos:8848 #namespace: sentinel dataId: yy-gateway-sentinel-flow groupId: DEFAULT_GROUP data-type: json rule-type: gw-flowCopy the code

Note that the rule-type is not the same as the normal service, gW-flow. Restart the service.

conclusion

I have compiled a Spring Cloud related information document, Spring series of family drum, Java systematic information (including Java core knowledge, interview topics and the latest Internet real questions in 20 years, e-books, etc.), friends who need to pay attention to the public number [procedures yuan small wan] can obtain.