init
This commit is contained in:
10
sentinel/sentinel-demo/README.md
Normal file
10
sentinel/sentinel-demo/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Sentinel Examples
|
||||
|
||||
The examples demonstrate:
|
||||
|
||||
- How to leverage basic features (e.g. flow control, circuit breaking, load protection) of Sentinel
|
||||
- How to use various data source extensions of Sentinel (e.g. file, Nacos, ZooKeeper)
|
||||
- How to use Dubbo with Sentinel
|
||||
- How to use Apache RocketMQ client with Sentinel
|
||||
- How to use Sentinel annotation support
|
||||
- How to add your own logic to Sentinel using Slot Chain SPI
|
||||
74
sentinel/sentinel-demo/pom.xml
Normal file
74
sentinel/sentinel-demo/pom.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-parent</artifactId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>sentinel-demo</name>
|
||||
|
||||
<modules>
|
||||
<module>sentinel-demo-basic</module>
|
||||
<module>sentinel-demo-dynamic-file-rule</module>
|
||||
<module>sentinel-demo-rocketmq</module>
|
||||
<module>sentinel-demo-dubbo</module>
|
||||
<module>sentinel-demo-nacos-datasource</module>
|
||||
<module>sentinel-demo-zookeeper-datasource</module>
|
||||
<module>sentinel-demo-apollo-datasource</module>
|
||||
<module>sentinel-demo-annotation-spring-aop</module>
|
||||
<module>sentinel-demo-parameter-flow-control</module>
|
||||
<module>sentinel-demo-slot-spi</module>
|
||||
<module>sentinel-demo-slotchain-spi</module>
|
||||
<module>sentinel-demo-cluster</module>
|
||||
<module>sentinel-demo-command-handler</module>
|
||||
<module>sentinel-demo-spring-webflux</module>
|
||||
<module>sentinel-demo-apache-dubbo</module>
|
||||
<module>sentinel-demo-apache-httpclient</module>
|
||||
<module>sentinel-demo-sofa-rpc</module>
|
||||
<module>sentinel-demo-spring-cloud-gateway</module>
|
||||
<module>sentinel-demo-zuul-gateway</module>
|
||||
<module>sentinel-demo-etcd-datasource</module>
|
||||
<module>sentinel-demo-spring-webmvc</module>
|
||||
<module>sentinel-demo-zuul2-gateway</module>
|
||||
<module>sentinel-demo-log-logback</module>
|
||||
<module>sentinel-demo-okhttp</module>
|
||||
<module>sentinel-demo-jax-rs</module>
|
||||
<module>sentinel-demo-quarkus</module>
|
||||
<module>sentinel-demo-annotation-cdi-interceptor</module>
|
||||
<module>sentinel-demo-motan</module>
|
||||
<module>sentinel-demo-transport-spring-mvc</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven.deploy.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-annotation-cdi-interceptor</artifactId>
|
||||
|
||||
<properties>
|
||||
<weld-se-shaded.version>3.1.4.Final</weld-se-shaded.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-annotation-cdi-interceptor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.weld.se</groupId>
|
||||
<artifactId>weld-se-shaded</artifactId>
|
||||
<version>${weld-se-shaded.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.cdi.interceptor;
|
||||
|
||||
import javax.enterprise.inject.se.SeContainer;
|
||||
import javax.enterprise.inject.se.SeContainerInitializer;
|
||||
|
||||
/**
|
||||
* @author sea
|
||||
*/
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SeContainerInitializer containerInit = SeContainerInitializer.newInstance();
|
||||
SeContainer container = containerInit.initialize();
|
||||
|
||||
TestService testService = container.select(TestService.class).get();
|
||||
|
||||
testService.test();
|
||||
|
||||
System.out.println(testService.hello(-1));
|
||||
System.out.println(testService.hello(1));
|
||||
|
||||
System.out.println(testService.helloAnother("bad"));
|
||||
|
||||
try {
|
||||
System.out.println(testService.helloAnother("foo"));
|
||||
} catch (IllegalStateException e) {
|
||||
System.err.println(e.getMessage());
|
||||
}
|
||||
|
||||
System.out.println(testService.helloAnother("weld"));
|
||||
|
||||
container.close();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.cdi.interceptor;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public final class ExceptionUtil {
|
||||
|
||||
public static void handleException(BlockException ex) {
|
||||
// Handler method that handles BlockException when blocked.
|
||||
// The method parameter list should match original method, with the last additional
|
||||
// parameter with type BlockException. The return type should be same as the original method.
|
||||
// The block handler method should be located in the same class with original method by default.
|
||||
// If you want to use method in other classes, you can set the blockHandlerClass
|
||||
// with corresponding Class (Note the method in other classes must be static).
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.cdi.interceptor;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public interface TestService {
|
||||
|
||||
void test();
|
||||
|
||||
String hello(long s);
|
||||
|
||||
String helloAnother(String name);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.cdi.interceptor;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.cdi.interceptor.SentinelResourceBinding;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class TestServiceImpl implements TestService {
|
||||
|
||||
@Override
|
||||
@SentinelResourceBinding(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
|
||||
public void test() {
|
||||
System.out.println("Test");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SentinelResourceBinding(value = "hello", fallback = "helloFallback")
|
||||
public String hello(long s) {
|
||||
if (s < 0) {
|
||||
throw new IllegalArgumentException("invalid arg");
|
||||
}
|
||||
return String.format("Hello at %d", s);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SentinelResourceBinding(value = "helloAnother", defaultFallback = "defaultFallback",
|
||||
exceptionsToIgnore = {IllegalStateException.class})
|
||||
public String helloAnother(String name) {
|
||||
if (name == null || "bad".equals(name)) {
|
||||
throw new IllegalArgumentException("oops");
|
||||
}
|
||||
if ("foo".equals(name)) {
|
||||
throw new IllegalStateException("oops");
|
||||
}
|
||||
return "Hello, " + name;
|
||||
}
|
||||
|
||||
public String helloFallback(long s, Throwable ex) {
|
||||
// Do some log here.
|
||||
return "Oops, error occurred at " + s + ", msg:" + ex.getMessage();
|
||||
}
|
||||
|
||||
public String defaultFallback() {
|
||||
System.out.println("Go to default fallback");
|
||||
return "default_fallback";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
|
||||
bean-discovery-mode="all">
|
||||
<interceptors>
|
||||
<class>com.alibaba.csp.sentinel.annotation.cdi.interceptor.SentinelResourceInterceptor</class>
|
||||
</interceptors>
|
||||
</beans>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-annotation-spring-aop</artifactId>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.0.5.RELEASE</spring.boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-annotation-aspectj</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.aop;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.aop.config;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
public class AopConfiguration {
|
||||
|
||||
@Bean
|
||||
public SentinelResourceAspect sentinelResourceAspect() {
|
||||
return new SentinelResourceAspect();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.aop.controller;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.annotation.aop.service.TestService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@RestController
|
||||
public class DemoController {
|
||||
|
||||
@Autowired
|
||||
private TestService service;
|
||||
|
||||
@GetMapping("/foo")
|
||||
public String apiFoo(@RequestParam(required = false) Long t) throws Exception {
|
||||
if (t == null) {
|
||||
t = System.currentTimeMillis();
|
||||
}
|
||||
service.test();
|
||||
return service.hello(t);
|
||||
}
|
||||
|
||||
@GetMapping("/baz/{name}")
|
||||
public String apiBaz(@PathVariable("name") String name) {
|
||||
return service.helloAnother(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.aop.service;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public final class ExceptionUtil {
|
||||
|
||||
public static void handleException(BlockException ex) {
|
||||
// Handler method that handles BlockException when blocked.
|
||||
// The method parameter list should match original method, with the last additional
|
||||
// parameter with type BlockException. The return type should be same as the original method.
|
||||
// The block handler method should be located in the same class with original method by default.
|
||||
// If you want to use method in other classes, you can set the blockHandlerClass
|
||||
// with corresponding Class (Note the method in other classes must be static).
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.aop.service;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public interface TestService {
|
||||
|
||||
void test();
|
||||
|
||||
String hello(long s);
|
||||
|
||||
String helloAnother(String name);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.annotation.aop.service;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Service
|
||||
public class TestServiceImpl implements TestService {
|
||||
|
||||
@Override
|
||||
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
|
||||
public void test() {
|
||||
System.out.println("Test");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SentinelResource(value = "hello", fallback = "helloFallback")
|
||||
public String hello(long s) {
|
||||
if (s < 0) {
|
||||
throw new IllegalArgumentException("invalid arg");
|
||||
}
|
||||
return String.format("Hello at %d", s);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback",
|
||||
exceptionsToIgnore = {IllegalStateException.class})
|
||||
public String helloAnother(String name) {
|
||||
if (name == null || "bad".equals(name)) {
|
||||
throw new IllegalArgumentException("oops");
|
||||
}
|
||||
if ("foo".equals(name)) {
|
||||
throw new IllegalStateException("oops");
|
||||
}
|
||||
return "Hello, " + name;
|
||||
}
|
||||
|
||||
public String helloFallback(long s, Throwable ex) {
|
||||
// Do some log here.
|
||||
ex.printStackTrace();
|
||||
return "Oops, error occurred at " + s;
|
||||
}
|
||||
|
||||
public String defaultFallback() {
|
||||
System.out.println("Go to default fallback");
|
||||
return "default_fallback";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
spring.application.name=sentinel-annotation-aspectj-example
|
||||
server.port=19966
|
||||
18
sentinel/sentinel-demo/sentinel-demo-apache-dubbo/README.md
Normal file
18
sentinel/sentinel-demo/sentinel-demo-apache-dubbo/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Sentinel Apache Dubbo Demo
|
||||
|
||||
This demo shows how to integrate Apache Dubbo **2.7.x or above version** with Sentinel
|
||||
using `sentinel-apache-dubbo-adapter` module.
|
||||
|
||||
## Run the demo
|
||||
|
||||
For the provider demo `FooProviderBootstrap`, you need to add the following parameters when startup:
|
||||
|
||||
```shell
|
||||
-Djava.net.preferIPv4Stack=true -Dproject.name=dubbo-provider-demo
|
||||
```
|
||||
|
||||
For the consumer demo `FooConsumerBootstrap`, you need to add the following parameters when startup:
|
||||
|
||||
```shell
|
||||
-Djava.net.preferIPv4Stack=true -Dproject.name=dubbo-consumer-demo
|
||||
```
|
||||
49
sentinel/sentinel-demo/sentinel-demo-apache-dubbo/pom.xml
Normal file
49
sentinel/sentinel-demo/sentinel-demo-apache-dubbo/pom.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-apache-dubbo</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<version>2.7.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo provides qos plugin and is enable by default. -->
|
||||
<!-- The dubbo-qos module is optional and it depends Netty 4.x, so add it explicitly -->
|
||||
<!-- @see http://dubbo.apache.org/zh-cn/docs/user/references/qos.html -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.31.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependency for Spring Context -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>5.1.5.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sentinel adapter and transport -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.ConsumerConfiguration;
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.FooServiceConsumer;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8721
|
||||
* -Dproject.name=dubbo-consumer-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooConsumerBootstrap {
|
||||
|
||||
private static final String INTERFACE_RES_KEY = FooService.class.getName();
|
||||
private static final String RES_KEY = INTERFACE_RES_KEY + ":sayHello(java.lang.String)";
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
|
||||
consumerContext.register(ConsumerConfiguration.class);
|
||||
consumerContext.refresh();
|
||||
initFlowRule(10, false);
|
||||
|
||||
FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Success: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// method flowcontrol
|
||||
Thread.sleep(1000);
|
||||
initFlowRule(20, true);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Success: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
System.out.println("fallback:" + service.doAnother());
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to result
|
||||
Thread.sleep(1000);
|
||||
registryCustomFallback();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Result: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
// fallback to exception
|
||||
Thread.sleep(1000);
|
||||
registryCustomFallbackForCustomException();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Result: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
registryCustomFallbackWhenFallbackError();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Result: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void registryCustomFallback() {
|
||||
DubboAdapterGlobalConfig.setConsumerFallback(
|
||||
(invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult("fallback", invocation));
|
||||
|
||||
}
|
||||
|
||||
public static void registryCustomFallbackForCustomException() {
|
||||
DubboAdapterGlobalConfig.setConsumerFallback(
|
||||
(invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult(new RuntimeException("fallback"), invocation));
|
||||
}
|
||||
|
||||
public static void registryCustomFallbackWhenFallbackError() {
|
||||
DubboAdapterGlobalConfig.setConsumerFallback(
|
||||
(invoker, invocation, ex) -> {
|
||||
throw new RuntimeException("fallback");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static void initFlowRule(int interfaceFlowLimit, boolean method) {
|
||||
FlowRule flowRule = new FlowRule(INTERFACE_RES_KEY)
|
||||
.setCount(interfaceFlowLimit)
|
||||
.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
List<FlowRule> list = new ArrayList<>();
|
||||
if (method) {
|
||||
FlowRule flowRule1 = new FlowRule(RES_KEY)
|
||||
.setCount(5)
|
||||
.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
list.add(flowRule1);
|
||||
}
|
||||
list.add(flowRule);
|
||||
FlowRuleManager.loadRules(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.ConsumerConfiguration;
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.FooServiceConsumer;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8721
|
||||
* -Dproject.name=dubbo-consumer-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Zechao zheng
|
||||
*/
|
||||
public class FooConsumerExceptionDegradeBootstrap {
|
||||
|
||||
private static final String INTERFACE_RES_KEY = FooService.class.getName();
|
||||
private static final String RES_KEY = INTERFACE_RES_KEY + ":sayHello(java.lang.String)";
|
||||
|
||||
public static void main(String[] args) throws InterruptedException, ExecutionException {
|
||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
|
||||
consumerContext.register(ConsumerConfiguration.class);
|
||||
consumerContext.refresh();
|
||||
|
||||
FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);
|
||||
initExceptionFallback(3);
|
||||
registryCustomFallback();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
String message = service.exceptionTest(true, false);
|
||||
System.out.println("Result: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
// sleep 3s to skip the time window
|
||||
initExceptionFallback(3);
|
||||
Thread.sleep(3000);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
String message = service.exceptionTest(false, true);
|
||||
System.out.println("Result: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
initExceptionFallback(3);
|
||||
Thread.sleep(3000);
|
||||
|
||||
try {
|
||||
// timeout to trigger the fallback
|
||||
CompletableFuture<String> completableFuture = RpcContext.getContext().asyncCall(() -> service.exceptionTest(false, true));
|
||||
System.out.println("Result: " + completableFuture.get());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
CompletableFuture<String> result = RpcContext.getContext().asyncCall(() -> service.exceptionTest(false, true));
|
||||
System.out.println("Result: " + result.get());
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void registryCustomFallback() {
|
||||
DubboAdapterGlobalConfig.setConsumerFallback(
|
||||
(invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult("fallback", invocation));
|
||||
|
||||
}
|
||||
|
||||
public static void initExceptionFallback(int timewindow) {
|
||||
DegradeRule degradeRule = new DegradeRule(INTERFACE_RES_KEY)
|
||||
.setCount(0.5)
|
||||
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||
.setTimeWindow(timewindow)
|
||||
.setMinRequestAmount(1);
|
||||
DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.provider.ProviderConfiguration;
|
||||
import com.alibaba.csp.sentinel.init.InitExecutor;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Provider demo for Apache Dubbo 2.7.x or above. Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8720
|
||||
* -Dproject.name=dubbo-provider-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooProviderBootstrap {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Users don't need to manually call this method.
|
||||
// Only for eager initialization.
|
||||
InitExecutor.doInit();
|
||||
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(ProviderConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
System.out.println("Service provider is ready");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public interface FooService {
|
||||
|
||||
String sayHello(String name);
|
||||
|
||||
String doAnother();
|
||||
|
||||
String exceptionTest(boolean biz, boolean timeout);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo.consumer;
|
||||
|
||||
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ConsumerConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
@DubboComponentScan
|
||||
public class ConsumerConfiguration {
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-consumer");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsumerConfig consumerConfig() {
|
||||
ConsumerConfig consumerConfig = new ConsumerConfig();
|
||||
// Uncomment below line if you don't want to enable Sentinel for Dubbo service consumers.
|
||||
// consumerConfig.setFilter("-sentinel.dubbo.consumer.filter");
|
||||
return consumerConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FooServiceConsumer annotationDemoServiceConsumer() {
|
||||
return new FooServiceConsumer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo.consumer;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooServiceConsumer {
|
||||
|
||||
@Reference(url = "dubbo://127.0.0.1:25758", timeout = 500)
|
||||
private FooService fooService;
|
||||
|
||||
public String sayHello(String name) {
|
||||
return fooService.sayHello(name);
|
||||
}
|
||||
|
||||
public String doAnother() {
|
||||
return fooService.doAnother();
|
||||
}
|
||||
|
||||
public String exceptionTest(boolean biz, boolean timeout) {
|
||||
return fooService.exceptionTest(biz, timeout);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo.provider;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Service
|
||||
public class FooServiceImpl implements FooService {
|
||||
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
return String.format("Hello, %s at %s", name, LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doAnother() {
|
||||
return LocalDateTime.now().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String exceptionTest(boolean biz, boolean timeout) {
|
||||
if (biz) {
|
||||
throw new RuntimeException("biz exception");
|
||||
}
|
||||
if (timeout) {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return "Success";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.dubbo.provider;
|
||||
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ProtocolConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
@DubboComponentScan
|
||||
public class ProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-provider");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ProtocolConfig protocolConfig() {
|
||||
ProtocolConfig protocolConfig = new ProtocolConfig();
|
||||
protocolConfig.setName("dubbo");
|
||||
protocolConfig.setPort(25758);
|
||||
return protocolConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-apache-httpclient</artifactId>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.1.3.RELEASE</spring.boot.version>
|
||||
<test.framework.version>4.3</test.framework.version>
|
||||
<apache.httpclient.version>4.5.6</apache.httpclient.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-apache-httpclient-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${apache.httpclient.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.httpclient;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author zhaoyuguang
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ApacheHttpClientDemoApplication implements CommandLineRunner {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ApacheHttpClientDemoApplication.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.apache.httpclient.controller;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.apache.httpclient.SentinelApacheHttpClientBuilder;
|
||||
import com.alibaba.csp.sentinel.adapter.apache.httpclient.config.SentinelApacheHttpClientConfig;
|
||||
import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.ApacheHttpClientResourceExtractor;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpRequestWrapper;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.protocol.BasicHttpContext;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author zhaoyuguang
|
||||
*/
|
||||
@RestController
|
||||
public class ApacheHttpClientTestController {
|
||||
|
||||
@Value("${server.port}")
|
||||
private Integer port;
|
||||
|
||||
@RequestMapping("/httpclient/back")
|
||||
public String back() {
|
||||
System.out.println("back");
|
||||
return "Welcome Back!";
|
||||
}
|
||||
|
||||
@RequestMapping("/httpclient/back/{id}")
|
||||
public String back(@PathVariable String id) {
|
||||
System.out.println("back");
|
||||
return "Welcome Back! " + id;
|
||||
}
|
||||
|
||||
@RequestMapping("/httpclient/sync")
|
||||
public String sync() throws Exception {
|
||||
SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
|
||||
config.setExtractor(new ApacheHttpClientResourceExtractor() {
|
||||
|
||||
@Override
|
||||
public String extractor(HttpRequestWrapper request) {
|
||||
String contains = "/httpclient/back/";
|
||||
String uri = request.getRequestLine().getUri();
|
||||
if (uri.startsWith(contains)) {
|
||||
uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
|
||||
}
|
||||
return request.getMethod() + ":" + uri;
|
||||
}
|
||||
});
|
||||
CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back");
|
||||
return getRemoteString(httpclient, httpGet);
|
||||
}
|
||||
|
||||
@RequestMapping("/httpclient/sync/{id}")
|
||||
public String sync(@PathVariable String id) throws Exception {
|
||||
SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
|
||||
config.setExtractor(new ApacheHttpClientResourceExtractor() {
|
||||
|
||||
@Override
|
||||
public String extractor(HttpRequestWrapper request) {
|
||||
String contains = "/httpclient/back/";
|
||||
String uri = request.getRequestLine().getUri();
|
||||
if (uri.startsWith(contains)) {
|
||||
uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
|
||||
}
|
||||
return request.getMethod() + ":" + uri;
|
||||
}
|
||||
});
|
||||
CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back/" + id);
|
||||
return getRemoteString(httpclient, httpGet);
|
||||
}
|
||||
|
||||
private String getRemoteString(CloseableHttpClient httpclient, HttpGet httpGet) throws IOException {
|
||||
String result;
|
||||
HttpContext context = new BasicHttpContext();
|
||||
CloseableHttpResponse response;
|
||||
response = httpclient.execute(httpGet, context);
|
||||
try {
|
||||
HttpEntity entity = response.getEntity();
|
||||
result = EntityUtils.toString(entity, "utf-8");
|
||||
EntityUtils.consume(entity);
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
httpclient.close();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
spring.application.name=sentinel-demo-apache-httpclient
|
||||
server.port=8083
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-apollo-datasource</artifactId>
|
||||
|
||||
<properties>
|
||||
<log4j2.version>2.17.0</log4j2.version>
|
||||
<slf4j.version>1.7.25</slf4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-apollo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.alibaba.csp.sentinel.demo.datasource.apollo;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* This demo shows how to use Apollo as the data source of Sentinel rules.
|
||||
* <br />
|
||||
* You need to first set up data as follows:
|
||||
* <ol>
|
||||
* <li>Create an application with app id as sentinel-demo in Apollo</li>
|
||||
* <li>
|
||||
* Create a configuration with key as flowRules and value as follows:
|
||||
* <pre>
|
||||
* [
|
||||
{
|
||||
"resource": "TestResource",
|
||||
"controlBehavior": 0,
|
||||
"count": 5.0,
|
||||
"grade": 1,
|
||||
"limitApp": "default",
|
||||
"strategy": 0
|
||||
}
|
||||
]
|
||||
* </pre>
|
||||
* </li>
|
||||
* <li>Publish the application namespace</li>
|
||||
* </ol>
|
||||
* Then you could start this demo and adjust the rule configuration as you wish.
|
||||
* The rule changes will take effect in real time.
|
||||
*
|
||||
* @author Jason Song
|
||||
*/
|
||||
public class ApolloDataSourceDemo {
|
||||
|
||||
private static final String KEY = "TestResource";
|
||||
|
||||
public static void main(String[] args) {
|
||||
loadRules();
|
||||
// Assume we config: resource is `TestResource`, initial QPS threshold is 5.
|
||||
FlowQpsRunner runner = new FlowQpsRunner(KEY, 1, 100);
|
||||
runner.simulateTraffic();
|
||||
runner.tick();
|
||||
}
|
||||
|
||||
private static void loadRules() {
|
||||
// Set up basic information, only for demo purpose. You may adjust them based on your actual environment.
|
||||
// For more information, please refer https://github.com/ctripcorp/apollo
|
||||
String appId = "sentinel-demo";
|
||||
String apolloMetaServerAddress = "http://localhost:8080";
|
||||
System.setProperty("app.id", appId);
|
||||
System.setProperty("apollo.meta", apolloMetaServerAddress);
|
||||
|
||||
String namespaceName = "application";
|
||||
String flowRuleKey = "flowRules";
|
||||
// It's better to provide a meaningful default value.
|
||||
String defaultFlowRules = "[]";
|
||||
|
||||
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ApolloDataSource<>(namespaceName,
|
||||
flowRuleKey, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
|
||||
}));
|
||||
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.datasource.apollo;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
|
||||
/**
|
||||
* Flow QPS runner.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
class FlowQpsRunner {
|
||||
|
||||
private final String resourceName;
|
||||
private final int threadCount;
|
||||
private int seconds;
|
||||
|
||||
public FlowQpsRunner(String resourceName, int threadCount, int seconds) {
|
||||
this.resourceName = resourceName;
|
||||
this.threadCount = threadCount;
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
private final AtomicInteger pass = new AtomicInteger();
|
||||
private final AtomicInteger block = new AtomicInteger();
|
||||
private final AtomicInteger total = new AtomicInteger();
|
||||
|
||||
private volatile boolean stop = false;
|
||||
|
||||
public void simulateTraffic() {
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread t = new Thread(new RunTask());
|
||||
t.setName("simulate-traffic-Task");
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
final class RunTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
|
||||
try {
|
||||
entry = SphU.entry(resourceName);
|
||||
// token acquired, means pass
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class TimerTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("begin to statistic!!!");
|
||||
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(seconds + " send qps is: " + oneSecondTotal);
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass
|
||||
+ ", block:" + oneSecondBlock);
|
||||
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration monitorInterval="60">
|
||||
<appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="[apollo-datasource-demo][%t]%d %-5p [%c] %m%n"/>
|
||||
</Console>
|
||||
<Async name="Async" includeLocation="true">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Async>
|
||||
</appenders>
|
||||
<loggers>
|
||||
<root level="INFO">
|
||||
<AppenderRef ref="Async"/>
|
||||
</root>
|
||||
</loggers>
|
||||
</configuration>
|
||||
13
sentinel/sentinel-demo/sentinel-demo-basic/pom.xml
Normal file
13
sentinel/sentinel-demo/sentinel-demo-basic/pom.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<artifactId>sentinel-demo-basic</artifactId>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.alibaba.csp.sentinel.AsyncEntry;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
/**
|
||||
* An example for asynchronous entry in Sentinel.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.0
|
||||
*/
|
||||
public class AsyncEntryDemo {
|
||||
|
||||
private void invoke(String arg, Consumer<String> handler) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
String resp = arg + ": " + System.currentTimeMillis();
|
||||
handler.accept(resp);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void anotherAsync() {
|
||||
try {
|
||||
final AsyncEntry entry = SphU.asyncEntry("test-another-async");
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
// Normal entry nested in asynchronous entry.
|
||||
anotherSyncInAsync();
|
||||
|
||||
System.out.println("Async result: 666");
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore.
|
||||
} finally {
|
||||
entry.exit();
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (BlockException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchSync() {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry("test-sync");
|
||||
} catch (BlockException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchSyncInAsync() {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry("test-sync-in-async");
|
||||
} catch (BlockException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void anotherSyncInAsync() {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry("test-another-sync-in-async");
|
||||
} catch (BlockException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void directlyAsync() {
|
||||
try {
|
||||
final AsyncEntry entry = SphU.asyncEntry("test-async-not-nested");
|
||||
|
||||
this.invoke("abc", result -> {
|
||||
// If no nested entry later, we don't have to wrap in `ContextUtil.runOnContext()`.
|
||||
try {
|
||||
// Here to handle the async result (without other entry).
|
||||
} finally {
|
||||
// Exit the async entry.
|
||||
entry.exit();
|
||||
}
|
||||
});
|
||||
} catch (BlockException e) {
|
||||
// Request blocked, handle the exception.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void doAsyncThenSync() {
|
||||
try {
|
||||
// First we call an asynchronous resource.
|
||||
final AsyncEntry entry = SphU.asyncEntry("test-async");
|
||||
this.invoke("abc", resp -> {
|
||||
// The thread is different from original caller thread for async entry.
|
||||
// So we need to wrap in the async context so that nested invocation entry
|
||||
// can be linked to the parent asynchronous entry.
|
||||
ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
|
||||
try {
|
||||
// In the callback, we do another async invocation several times under the async context.
|
||||
for (int i = 0; i < 7; i++) {
|
||||
anotherAsync();
|
||||
}
|
||||
|
||||
System.out.println(resp);
|
||||
|
||||
// Then we do a sync (normal) entry under current async context.
|
||||
fetchSyncInAsync();
|
||||
} finally {
|
||||
// Exit the async entry.
|
||||
entry.exit();
|
||||
}
|
||||
});
|
||||
});
|
||||
// Then we call a sync resource.
|
||||
fetchSync();
|
||||
} catch (BlockException ex) {
|
||||
// Request blocked, handle the exception.
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
initFlowRule();
|
||||
|
||||
AsyncEntryDemo service = new AsyncEntryDemo();
|
||||
|
||||
// Expected invocation chain:
|
||||
//
|
||||
// EntranceNode: machine-root
|
||||
// -EntranceNode: async-context
|
||||
// --test-top
|
||||
// ---test-sync
|
||||
// ---test-async
|
||||
// ----test-another-async
|
||||
// -----test-another-sync-in-async
|
||||
// ----test-sync-in-async
|
||||
ContextUtil.enter("async-context", "originA");
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry("test-top");
|
||||
System.out.println("Do something...");
|
||||
service.doAsyncThenSync();
|
||||
} catch (BlockException ex) {
|
||||
// Request blocked, handle the exception.
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
ContextUtil.exit();
|
||||
}
|
||||
|
||||
TimeUnit.SECONDS.sleep(20);
|
||||
}
|
||||
|
||||
private static void initFlowRule() {
|
||||
// Rule 1 won't take effect as the limitApp doesn't match.
|
||||
FlowRule rule1 = new FlowRule()
|
||||
.setResource("test-another-sync-in-async")
|
||||
.setLimitApp("originB")
|
||||
.as(FlowRule.class)
|
||||
.setCount(4)
|
||||
.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
// Rule 2 will take effect.
|
||||
FlowRule rule2 = new FlowRule()
|
||||
.setResource("test-another-async")
|
||||
.setLimitApp("default")
|
||||
.as(FlowRule.class)
|
||||
.setCount(5)
|
||||
.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
List<FlowRule> ruleList = Arrays.asList(rule1, rule2);
|
||||
FlowRuleManager.loadRules(ruleList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.authority;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
|
||||
|
||||
/**
|
||||
* Authority rule is designed for limiting by request origins. In blacklist mode,
|
||||
* requests will be blocked when blacklist contains current origin, otherwise will pass.
|
||||
* In whitelist mode, only requests from whitelist origin can pass.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class AuthorityDemo {
|
||||
|
||||
private static final String RESOURCE_NAME = "testABC";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========Testing for black list========");
|
||||
initBlackRules();
|
||||
testFor(RESOURCE_NAME, "appA");
|
||||
testFor(RESOURCE_NAME, "appB");
|
||||
testFor(RESOURCE_NAME, "appC");
|
||||
testFor(RESOURCE_NAME, "appE");
|
||||
|
||||
System.out.println("========Testing for white list========");
|
||||
initWhiteRules();
|
||||
testFor(RESOURCE_NAME, "appA");
|
||||
testFor(RESOURCE_NAME, "appB");
|
||||
testFor(RESOURCE_NAME, "appC");
|
||||
testFor(RESOURCE_NAME, "appE");
|
||||
}
|
||||
|
||||
private static void testFor(/*@NonNull*/ String resource, /*@NonNull*/ String origin) {
|
||||
ContextUtil.enter(resource, origin);
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(resource);
|
||||
System.out.println(String.format("Passed for resource %s, origin is %s", resource, origin));
|
||||
} catch (BlockException ex) {
|
||||
System.err.println(String.format("Blocked for resource %s, origin is %s", resource, origin));
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
ContextUtil.exit();
|
||||
}
|
||||
}
|
||||
|
||||
private static void initWhiteRules() {
|
||||
AuthorityRule rule = new AuthorityRule();
|
||||
rule.setResource(RESOURCE_NAME);
|
||||
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
|
||||
rule.setLimitApp("appA,appE");
|
||||
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
private static void initBlackRules() {
|
||||
AuthorityRule rule = new AuthorityRule();
|
||||
rule.setResource(RESOURCE_NAME);
|
||||
rule.setStrategy(RuleConstant.AUTHORITY_BLACK);
|
||||
rule.setLimitApp("appA,appB");
|
||||
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.degrade;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.Tracer;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker.State;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author jialiang.linjl
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class ExceptionRatioCircuitBreakerDemo {
|
||||
|
||||
private static final String KEY = "some_service";
|
||||
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger bizException = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
private static int seconds = 120;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
initDegradeRule();
|
||||
registerStateChangeObserver();
|
||||
startTick();
|
||||
|
||||
final int concurrency = 8;
|
||||
for (int i = 0; i < concurrency; i++) {
|
||||
Thread entryThread = new Thread(() -> {
|
||||
while (true) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||
pass.addAndGet(1);
|
||||
|
||||
// Error probability is 45%
|
||||
if (ThreadLocalRandom.current().nextInt(0, 100) > 55) {
|
||||
// biz code raise an exception.
|
||||
throw new RuntimeException("oops");
|
||||
}
|
||||
} catch (BlockException e) {
|
||||
block.addAndGet(1);
|
||||
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||
} catch (Throwable t) {
|
||||
bizException.incrementAndGet();
|
||||
// It's required to record exception here manually.
|
||||
Tracer.traceEntry(t, entry);
|
||||
} finally {
|
||||
total.addAndGet(1);
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
entryThread.setName("sentinel-simulate-traffic-task-" + i);
|
||||
entryThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerStateChangeObserver() {
|
||||
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
|
||||
(prevState, newState, rule, snapshotValue) -> {
|
||||
if (newState == State.OPEN) {
|
||||
System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
|
||||
TimeUtil.currentTimeMillis(), snapshotValue));
|
||||
} else {
|
||||
System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
|
||||
TimeUtil.currentTimeMillis()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initDegradeRule() {
|
||||
List<DegradeRule> rules = new ArrayList<>();
|
||||
DegradeRule rule = new DegradeRule(KEY)
|
||||
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
|
||||
// Set ratio threshold to 50%.
|
||||
.setCount(0.5d)
|
||||
.setStatIntervalMs(30000)
|
||||
.setMinRequestAmount(50)
|
||||
// Retry timeout (in second)
|
||||
.setTimeWindow(10);
|
||||
rules.add(rule);
|
||||
DegradeRuleManager.loadRules(rules);
|
||||
System.out.println("Degrade rule loaded: " + rules);
|
||||
}
|
||||
|
||||
private static void sleep(int timeMs) {
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(timeMs);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static void startTick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-tick-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("Begin to run! Go go go!");
|
||||
System.out.println("See corresponding metrics.log for accurate statistic data");
|
||||
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
long oldBizException = 0;
|
||||
while (!stop) {
|
||||
sleep(1000);
|
||||
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
long globalBizException = bizException.get();
|
||||
long oneSecondBizException = globalBizException - oldBizException;
|
||||
oldBizException = globalBizException;
|
||||
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", oneSecondTotal:" + oneSecondTotal
|
||||
+ ", oneSecondPass:" + oneSecondPass
|
||||
+ ", oneSecondBlock:" + oneSecondBlock
|
||||
+ ", oneSecondBizException:" + oneSecondBizException);
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total: " + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get() + ", bizException:" + bizException.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.degrade;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker.State;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
|
||||
/**
|
||||
* Run this demo, and the output will be like:
|
||||
*
|
||||
* <pre>
|
||||
* 1529399827825,total:0, pass:0, block:0
|
||||
* 1529399828825,total:4263, pass:100, block:4164
|
||||
* 1529399829825,total:19179, pass:4, block:19176 // circuit breaker opens
|
||||
* 1529399830824,total:19806, pass:0, block:19806
|
||||
* 1529399831825,total:19198, pass:0, block:19198
|
||||
* 1529399832824,total:19481, pass:0, block:19481
|
||||
* 1529399833826,total:19241, pass:0, block:19241
|
||||
* 1529399834826,total:17276, pass:0, block:17276
|
||||
* 1529399835826,total:18722, pass:0, block:18722
|
||||
* 1529399836826,total:19490, pass:0, block:19492
|
||||
* 1529399837828,total:19355, pass:0, block:19355
|
||||
* 1529399838827,total:11388, pass:0, block:11388
|
||||
* 1529399839829,total:14494, pass:104, block:14390 // After 10 seconds, the system restored
|
||||
* 1529399840854,total:18505, pass:0, block:18505
|
||||
* 1529399841854,total:19673, pass:0, block:19676
|
||||
* </pre>
|
||||
*
|
||||
* @author jialiang.linjl
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class SlowRatioCircuitBreakerDemo {
|
||||
|
||||
private static final String KEY = "some_method";
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
private static int seconds = 120;
|
||||
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
initDegradeRule();
|
||||
registerStateChangeObserver();
|
||||
startTick();
|
||||
|
||||
int concurrency = 8;
|
||||
for (int i = 0; i < concurrency; i++) {
|
||||
Thread entryThread = new Thread(() -> {
|
||||
while (true) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
pass.incrementAndGet();
|
||||
// RT: [40ms, 60ms)
|
||||
sleep(ThreadLocalRandom.current().nextInt(40, 60));
|
||||
} catch (BlockException e) {
|
||||
block.incrementAndGet();
|
||||
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
entryThread.setName("sentinel-simulate-traffic-task-" + i);
|
||||
entryThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerStateChangeObserver() {
|
||||
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
|
||||
(prevState, newState, rule, snapshotValue) -> {
|
||||
if (newState == State.OPEN) {
|
||||
System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
|
||||
TimeUtil.currentTimeMillis(), snapshotValue));
|
||||
} else {
|
||||
System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
|
||||
TimeUtil.currentTimeMillis()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initDegradeRule() {
|
||||
List<DegradeRule> rules = new ArrayList<>();
|
||||
DegradeRule rule = new DegradeRule(KEY)
|
||||
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||
// Max allowed response time
|
||||
.setCount(50)
|
||||
// Retry timeout (in second)
|
||||
.setTimeWindow(10)
|
||||
// Circuit breaker opens when slow request ratio > 60%
|
||||
.setSlowRatioThreshold(0.6)
|
||||
.setMinRequestAmount(100)
|
||||
.setStatIntervalMs(20000);
|
||||
rules.add(rule);
|
||||
|
||||
DegradeRuleManager.loadRules(rules);
|
||||
System.out.println("Degrade rule loaded: " + rules);
|
||||
}
|
||||
|
||||
private static void sleep(int timeMs) {
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(timeMs);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static void startTick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-tick-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("Begin to run! Go go go!");
|
||||
System.out.println("See corresponding metrics.log for accurate statistic data");
|
||||
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
|
||||
while (!stop) {
|
||||
sleep(1000);
|
||||
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass + ", block:" + oneSecondBlock);
|
||||
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total: " + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.flow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
/**
|
||||
* @author jialiang.linjl
|
||||
*/
|
||||
public class FlowQpsDemo {
|
||||
|
||||
private static final String KEY = "abc";
|
||||
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
|
||||
private static final int threadCount = 32;
|
||||
|
||||
private static int seconds = 60 + 40;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
initFlowQpsRule();
|
||||
|
||||
tick();
|
||||
// first make the system run on a very low condition
|
||||
simulateTraffic();
|
||||
|
||||
System.out.println("===== begin to do flow control");
|
||||
System.out.println("only 20 requests per second can pass");
|
||||
|
||||
}
|
||||
|
||||
private static void initFlowQpsRule() {
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule1 = new FlowRule();
|
||||
rule1.setResource(KEY);
|
||||
// set limit qps to 20
|
||||
rule1.setCount(20);
|
||||
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule1.setLimitApp("default");
|
||||
rules.add(rule1);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
}
|
||||
|
||||
private static void simulateTraffic() {
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread t = new Thread(new RunTask());
|
||||
t.setName("simulate-traffic-Task");
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void tick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("begin to statistic!!!");
|
||||
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(seconds + " send qps is: " + oneSecondTotal);
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass
|
||||
+ ", block:" + oneSecondBlock);
|
||||
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static class RunTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
// token acquired, means pass
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.flow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
/**
|
||||
* @author jialiang.linjl
|
||||
*/
|
||||
public class FlowThreadDemo {
|
||||
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
private static AtomicInteger activeThread = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
private static final int threadCount = 100;
|
||||
|
||||
private static int seconds = 60 + 40;
|
||||
private static volatile int methodBRunningTime = 2000;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(
|
||||
"MethodA will call methodB. After running for a while, methodB becomes fast, "
|
||||
+ "which make methodA also become fast ");
|
||||
tick();
|
||||
initFlowRule();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread entryThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
Entry methodA = null;
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(5);
|
||||
methodA = SphU.entry("methodA");
|
||||
activeThread.incrementAndGet();
|
||||
Entry methodB = SphU.entry("methodB");
|
||||
TimeUnit.MILLISECONDS.sleep(methodBRunningTime);
|
||||
methodB.exit();
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (methodA != null) {
|
||||
methodA.exit();
|
||||
activeThread.decrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
entryThread.setName("working thread");
|
||||
entryThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void initFlowRule() {
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule1 = new FlowRule();
|
||||
rule1.setResource("methodA");
|
||||
// set limit concurrent thread for 'methodA' to 20
|
||||
rule1.setCount(20);
|
||||
rule1.setGrade(RuleConstant.FLOW_GRADE_THREAD);
|
||||
rule1.setLimitApp("default");
|
||||
|
||||
rules.add(rule1);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
}
|
||||
|
||||
private static void tick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("begin to statistic!!!");
|
||||
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(seconds + " total qps is: " + oneSecondTotal);
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass
|
||||
+ ", block:" + oneSecondBlock
|
||||
+ " activeThread:" + activeThread.get());
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
if (seconds == 40) {
|
||||
System.out.println("method B is running much faster; more requests are allowed to pass");
|
||||
methodBRunningTime = 20;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.flow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* If {@link RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER} is set, incoming
|
||||
* requests are passing at regular interval. When a new request arrives, the
|
||||
* flow rule checks whether the interval between the new request and the
|
||||
* previous request. If the interval is less than the count set in the rule
|
||||
* first. If the interval is large, it will pass the request; otherwise,
|
||||
* sentinel will calculate the waiting time for this request. If the waiting
|
||||
* time is longer than the {@link FlowRule#maxQueueingTimeMs} set in the rule,
|
||||
* the request will be rejected immediately.
|
||||
*
|
||||
* This method is widely used for pulsed flow. When a large amount of flow
|
||||
* comes, we don't want to pass all these requests at once, which may drag the
|
||||
* system down. We can make the system handle these requests at a steady pace by
|
||||
* using this kind of rules.
|
||||
*
|
||||
* <p>
|
||||
* This demo demonstrates how to use {@link RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* {@link #initPaceFlowRule() } create rules that uses
|
||||
* {@code CONTROL_BEHAVIOR_RATE_LIMITER}.
|
||||
* <p>
|
||||
* {@link #simulatePulseFlow()} simulates 100 requests that arrives at almost the
|
||||
* same time. All these 100 request are passed at a fixed interval.
|
||||
*
|
||||
* <p/>
|
||||
* Run this demo, results are as follows:
|
||||
* <pre>
|
||||
* pace behavior
|
||||
* ....
|
||||
* 1528872403887 one request pass, cost 9348 ms // every 100 ms pass one request.
|
||||
* 1528872403986 one request pass, cost 9469 ms
|
||||
* 1528872404087 one request pass, cost 9570 ms
|
||||
* 1528872404187 one request pass, cost 9642 ms
|
||||
* 1528872404287 one request pass, cost 9770 ms
|
||||
* 1528872404387 one request pass, cost 9848 ms
|
||||
* 1528872404487 one request pass, cost 9970 ms
|
||||
* ...
|
||||
* done
|
||||
* total pass:100, total block:0
|
||||
* </pre>
|
||||
*
|
||||
* Then we invoke {@link #initDefaultFlowRule()} to set rules with default behavior, and only 10
|
||||
* requests will be allowed to pass, other requests will be rejected immediately.
|
||||
* <p/>
|
||||
* The output will be like:
|
||||
* <pre>
|
||||
* default behavior
|
||||
* 1530500101279 one request pass, cost 0 ms
|
||||
* 1530500101279 one request pass, cost 0 ms
|
||||
* 1530500101279 one request pass, cost 0 ms
|
||||
* 1530500101279 one request pass, cost 0 ms
|
||||
* 1530500101279 one request pass, cost 0 ms
|
||||
* 1530500101279 one request pass, cost 0 ms
|
||||
* 1530500101280 one request pass, cost 1 ms
|
||||
* 1530500101280 one request pass, cost 0 ms
|
||||
* 1530500101280 one request pass, cost 0 ms
|
||||
* 1530500101280 one request pass, cost 0 ms
|
||||
* done
|
||||
* total pass:10, total block:90 // 10 requests passed, other 90 requests rejected immediately.
|
||||
* </pre>
|
||||
*
|
||||
* @author jialiang.linjl
|
||||
*/
|
||||
public class PaceFlowDemo {
|
||||
|
||||
private static final String KEY = "abc";
|
||||
|
||||
private static volatile CountDownLatch countDown;
|
||||
|
||||
private static final Integer requestQps = 100;
|
||||
private static final Integer count = 10;
|
||||
private static final AtomicInteger done = new AtomicInteger();
|
||||
private static final AtomicInteger pass = new AtomicInteger();
|
||||
private static final AtomicInteger block = new AtomicInteger();
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
System.out.println("pace behavior");
|
||||
countDown = new CountDownLatch(1);
|
||||
initPaceFlowRule();
|
||||
simulatePulseFlow();
|
||||
countDown.await();
|
||||
|
||||
System.out.println("done");
|
||||
System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
|
||||
|
||||
System.out.println();
|
||||
System.out.println("default behavior");
|
||||
TimeUnit.SECONDS.sleep(5);
|
||||
done.set(0);
|
||||
pass.set(0);
|
||||
block.set(0);
|
||||
countDown = new CountDownLatch(1);
|
||||
initDefaultFlowRule();
|
||||
simulatePulseFlow();
|
||||
countDown.await();
|
||||
System.out.println("done");
|
||||
System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private static void initPaceFlowRule() {
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule1 = new FlowRule();
|
||||
rule1.setResource(KEY);
|
||||
rule1.setCount(count);
|
||||
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule1.setLimitApp("default");
|
||||
/*
|
||||
* CONTROL_BEHAVIOR_RATE_LIMITER means requests more than threshold will be queueing in the queue,
|
||||
* until the queueing time is more than {@link FlowRule#maxQueueingTimeMs}, the requests will be rejected.
|
||||
*/
|
||||
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
|
||||
rule1.setMaxQueueingTimeMs(20 * 1000);
|
||||
|
||||
rules.add(rule1);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
}
|
||||
|
||||
private static void initDefaultFlowRule() {
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule1 = new FlowRule();
|
||||
rule1.setResource(KEY);
|
||||
rule1.setCount(count);
|
||||
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule1.setLimitApp("default");
|
||||
// CONTROL_BEHAVIOR_DEFAULT means requests more than threshold will be rejected immediately.
|
||||
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
|
||||
|
||||
rules.add(rule1);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
}
|
||||
|
||||
private static void simulatePulseFlow() {
|
||||
for (int i = 0; i < requestQps; i++) {
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long startTime = TimeUtil.currentTimeMillis();
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
pass.incrementAndGet();
|
||||
long cost = TimeUtil.currentTimeMillis() - startTime;
|
||||
System.out.println(
|
||||
TimeUtil.currentTimeMillis() + " one request pass, cost " + cost + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(5);
|
||||
} catch (InterruptedException e1) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (done.incrementAndGet() >= requestQps) {
|
||||
countDown.countDown();
|
||||
}
|
||||
}
|
||||
}, "Thread " + i);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.flow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
/**
|
||||
* When {@link FlowRule#controlBehavior} set to {@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP}, real passed qps will
|
||||
* gradually increase to {@link FlowRule#count}, other than burst increasing.
|
||||
* <p/>
|
||||
* Run this demo, results are as follows:
|
||||
* <pre>
|
||||
* ...
|
||||
* 1530497805902, total:1, pass:1, block:0 // run in slow qps
|
||||
* 1530497806905, total:3, pass:3, block:0
|
||||
* 1530497807909, total:2, pass:2, block:0
|
||||
* 1530497808913, total:3, pass:3, block:0
|
||||
* 1530497809917, total:269, pass:6, block:263 // request qps burst increase, warm up behavior triggered.
|
||||
* 1530497810917, total:3676, pass:7, block:3669
|
||||
* 1530497811919, total:3734, pass:9, block:3725
|
||||
* 1530497812920, total:3692, pass:9, block:3683
|
||||
* 1530497813923, total:3642, pass:10, block:3632
|
||||
* 1530497814926, total:3685, pass:10, block:3675
|
||||
* 1530497815930, total:3671, pass:11, block:3660
|
||||
* 1530497816933, total:3660, pass:15, block:3645
|
||||
* 1530497817936, total:3681, pass:21, block:3661 // warm up process end, pass qps increased to {@link FlowRule#count}
|
||||
* 1530497818940, total:3737, pass:20, block:3716
|
||||
* 1530497819945, total:3663, pass:20, block:3643
|
||||
* 1530497820950, total:3723, pass:21, block:3702
|
||||
* 1530497821954, total:3680, pass:20, block:3660
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @author jialiang.linjl
|
||||
*/
|
||||
public class WarmUpFlowDemo {
|
||||
|
||||
private static final String KEY = "abc";
|
||||
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
|
||||
private static final int threadCount = 100;
|
||||
private static int seconds = 60 + 40;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
initFlowRule();
|
||||
// trigger Sentinel internal init
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
|
||||
//first make the system run on a very low condition
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Thread t = new Thread(new WarmUpTask());
|
||||
t.setName("sentinel-warmup-task");
|
||||
t.start();
|
||||
}
|
||||
Thread.sleep(20000);
|
||||
|
||||
/*
|
||||
* Start more thread to simulate more qps. Since we use {@link RuleConstant.CONTROL_BEHAVIOR_WARM_UP} as
|
||||
* {@link FlowRule#controlBehavior}, real passed qps will increase to {@link FlowRule#count} in
|
||||
* {@link FlowRule#warmUpPeriodSec} seconds.
|
||||
*/
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread t = new Thread(new RunTask());
|
||||
t.setName("sentinel-run-task");
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void initFlowRule() {
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule1 = new FlowRule();
|
||||
rule1.setResource(KEY);
|
||||
rule1.setCount(20);
|
||||
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule1.setLimitApp("default");
|
||||
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
|
||||
rule1.setWarmUpPeriodSec(10);
|
||||
|
||||
rules.add(rule1);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
}
|
||||
|
||||
static class WarmUpTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
// token acquired, means pass
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class RunTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("begin to statistic!!!");
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass
|
||||
+ ", block:" + oneSecondBlock);
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.alibaba.csp.sentinel.demo.flow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
|
||||
/**
|
||||
* When {@link FlowRule#controlBehavior} set to {@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER}, real passed
|
||||
* qps will gradually increase to {@link FlowRule#count}, other than burst increasing, and after the passed qps reaches
|
||||
* the threshold, the request will pass at a constant interval.
|
||||
* <p>
|
||||
* In short, {@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER} behaves like
|
||||
* {@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP} + {@link RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER}.
|
||||
* </p>
|
||||
*
|
||||
* <p/>
|
||||
* Run this demo, results are as follows:
|
||||
* <pre>
|
||||
* ...
|
||||
* 1541035848056, total:5, pass:5, block:0 // run in slow qps
|
||||
* 1541035849061, total:0, pass:0, block:0
|
||||
* 1541035850066, total:6, pass:6, block:0
|
||||
* 1541035851068, total:2, pass:2, block:0
|
||||
* 1541035852073, total:3, pass:3, block:0
|
||||
* 1541035853078, total:3361, pass:7, block:3354 // request qps burst increase, warm up behavior triggered.
|
||||
* 1541035854083, total:3414, pass:7, block:3407
|
||||
* 1541035855087, total:3377, pass:7, block:3370
|
||||
* 1541035856091, total:3366, pass:8, block:3358
|
||||
* 1541035857096, total:3259, pass:8, block:3251
|
||||
* 1541035858101, total:3066, pass:13, block:3054
|
||||
* 1541035859105, total:3042, pass:15, block:3026
|
||||
* 1541035860109, total:2946, pass:17, block:2929
|
||||
* 1541035861113, total:2909, pass:20, block:2889 // warm up process end, pass qps increased to {@link FlowRule#count}
|
||||
* 1541035862117, total:2970, pass:20, block:2950
|
||||
* 1541035863122, total:2919, pass:20, block:2899
|
||||
* 1541035864127, total:2903, pass:21, block:2882
|
||||
* 1541035865133, total:2930, pass:20, block:2910
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @author CarpenterLee
|
||||
* @see WarmUpFlowDemo
|
||||
* @see PaceFlowDemo
|
||||
*/
|
||||
public class WarmUpRateLimiterFlowDemo {
|
||||
private static final String KEY = "abc";
|
||||
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
|
||||
private static final int threadCount = 100;
|
||||
private static int seconds = 100;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
initFlowRule();
|
||||
// trigger Sentinel internal init
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
|
||||
//first make the system run on a very low condition
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Thread t = new Thread(new SlowTask());
|
||||
t.setName("sentinel-slow-task");
|
||||
t.start();
|
||||
}
|
||||
Thread.sleep(5000);
|
||||
|
||||
// request qps burst increase, warm up behavior triggered.
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread t = new Thread(new RunTask());
|
||||
t.setName("sentinel-run-task");
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void initFlowRule() {
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule1 = new FlowRule();
|
||||
rule1.setResource(KEY);
|
||||
rule1.setCount(20);
|
||||
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule1.setLimitApp("default");
|
||||
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER);
|
||||
rule1.setWarmUpPeriodSec(10);
|
||||
rule1.setMaxQueueingTimeMs(100);
|
||||
|
||||
rules.add(rule1);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
}
|
||||
|
||||
static class SlowTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
// token acquired, means pass
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class RunTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("begin to statistic!!!");
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass
|
||||
+ ", block:" + oneSecondBlock);
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.system;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.EntryType;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemRule;
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
|
||||
|
||||
/**
|
||||
* @author jialiang.linjl
|
||||
*/
|
||||
public class SystemGuardDemo {
|
||||
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
private static final int threadCount = 100;
|
||||
|
||||
private static int seconds = 60 + 40;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
tick();
|
||||
initSystemRule();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread entryThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry("methodA", EntryType.IN);
|
||||
pass.incrementAndGet();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
entryThread.setName("working-thread");
|
||||
entryThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void initSystemRule() {
|
||||
List<SystemRule> rules = new ArrayList<SystemRule>();
|
||||
SystemRule rule = new SystemRule();
|
||||
// max load is 3
|
||||
rule.setHighestSystemLoad(3.0);
|
||||
// max cpu usage is 60%
|
||||
rule.setHighestCpuUsage(0.6);
|
||||
// max avg rt of all request is 10 ms
|
||||
rule.setAvgRt(10);
|
||||
// max total qps is 20
|
||||
rule.setQps(20);
|
||||
// max parallel working thread is 10
|
||||
rule.setMaxThread(10);
|
||||
|
||||
rules.add(rule);
|
||||
SystemRuleManager.loadRules(Collections.singletonList(rule));
|
||||
}
|
||||
|
||||
private static void tick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
static class TimerTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("begin to statistic!!!");
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(seconds + ", " + TimeUtil.currentTimeMillis() + ", total:"
|
||||
+ oneSecondTotal + ", pass:"
|
||||
+ oneSecondPass + ", block:" + oneSecondBlock);
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
sentinel/sentinel-demo/sentinel-demo-cluster/pom.xml
Normal file
20
sentinel/sentinel-demo/sentinel-demo-cluster/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-cluster</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>sentinel-demo-cluster-embedded</module>
|
||||
<module>sentinel-demo-cluster-server-alone</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
# Sentinel Cluster Embedded Mode Demo
|
||||
|
||||
This demo demonstrates how to configure data source for cluster rules and configuration
|
||||
in **embedded mode**. You can start multiple `ClusterDemoApplication` instances and do cluster assignment in Sentinel dashboard or via dynamic data source.
|
||||
|
||||
See [DemoClusterInitFunc](https://github.com/alibaba/Sentinel/blob/master/sentinel-demo/sentinel-demo-cluster/sentinel-demo-cluster-embedded/src/main/java/com/alibaba/csp/sentinel/demo/cluster/init/DemoClusterInitFunc.java) for a sample of dynamic configuration.
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo-cluster</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-cluster-embedded</artifactId>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.0.5.RELEASE</spring.boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-parameter-flow-control</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-cluster-client-default</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-cluster-server-default</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos for dynamic data source -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- for a real web demo -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-annotation-aspectj</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public final class DemoConstants {
|
||||
|
||||
public static final String FLOW_POSTFIX = "-flow-rules";
|
||||
public static final String PARAM_FLOW_POSTFIX = "-param-rules";
|
||||
public static final String SERVER_NAMESPACE_SET_POSTFIX = "-cs-namespace-set";
|
||||
public static final String CLIENT_CONFIG_POSTFIX = "-cc-config";
|
||||
public static final String CLUSTER_MAP_POSTFIX = "-cluster-map";
|
||||
|
||||
private DemoConstants() {}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.app;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ClusterDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ClusterDemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.app.config;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* AOP config to enable annotation support for Sentinel.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
public class AopConfig {
|
||||
|
||||
@Bean
|
||||
public SentinelResourceAspect sentinelResourceAspect() {
|
||||
return new SentinelResourceAspect();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.app.controller;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.cluster.app.service.DemoService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@RestController
|
||||
public class ClusterDemoController {
|
||||
|
||||
@Autowired
|
||||
private DemoService service;
|
||||
|
||||
@GetMapping("/hello/{name}")
|
||||
public String apiHello(@PathVariable String name) throws Exception {
|
||||
return service.sayHello(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.app.service;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Service
|
||||
public class DemoService {
|
||||
|
||||
@SentinelResource(blockHandler = "sayHelloBlockHandler")
|
||||
public String sayHello(String name) {
|
||||
return "Hello, " + name;
|
||||
}
|
||||
|
||||
public String sayHelloBlockHandler(String name, BlockException ex) {
|
||||
// This is the block handler.
|
||||
ex.printStackTrace();
|
||||
return String.format("Oops, <%s> blocked by Sentinel", name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterGroupEntity {
|
||||
|
||||
private String machineId;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Set<String> clientSet;
|
||||
|
||||
public String getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setMachineId(String machineId) {
|
||||
this.machineId = machineId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getClientSet() {
|
||||
return clientSet;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setClientSet(Set<String> clientSet) {
|
||||
this.clientSet = clientSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterGroupEntity{" +
|
||||
"machineId='" + machineId + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", clientSet=" + clientSet +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.init;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
|
||||
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientAssignConfig;
|
||||
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfig;
|
||||
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfigManager;
|
||||
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
|
||||
import com.alibaba.csp.sentinel.demo.cluster.DemoConstants;
|
||||
import com.alibaba.csp.sentinel.demo.cluster.entity.ClusterGroupEntity;
|
||||
import com.alibaba.csp.sentinel.init.InitFunc;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
||||
import com.alibaba.csp.sentinel.util.AppNameUtil;
|
||||
import com.alibaba.csp.sentinel.util.HostNameUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class DemoClusterInitFunc implements InitFunc {
|
||||
|
||||
private static final String APP_NAME = AppNameUtil.getAppName();
|
||||
|
||||
private final String remoteAddress = "localhost:8848";
|
||||
private final String groupId = "SENTINEL_GROUP";
|
||||
|
||||
private final String flowDataId = APP_NAME + DemoConstants.FLOW_POSTFIX;
|
||||
private final String paramDataId = APP_NAME + DemoConstants.PARAM_FLOW_POSTFIX;
|
||||
private final String configDataId = APP_NAME + "-cluster-client-config";
|
||||
private final String clusterMapDataId = APP_NAME + DemoConstants.CLUSTER_MAP_POSTFIX;
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
// Register client dynamic rule data source.
|
||||
initDynamicRuleProperty();
|
||||
|
||||
// Register token client related data source.
|
||||
// Token client common config:
|
||||
initClientConfigProperty();
|
||||
// Token client assign config (e.g. target token server) retrieved from assign map:
|
||||
initClientServerAssignProperty();
|
||||
|
||||
// Register token server related data source.
|
||||
// Register dynamic rule data source supplier for token server:
|
||||
registerClusterRuleSupplier();
|
||||
// Token server transport config extracted from assign map:
|
||||
initServerTransportConfigProperty();
|
||||
|
||||
// Init cluster state property for extracting mode from cluster map data source.
|
||||
initStateProperty();
|
||||
}
|
||||
|
||||
private void initDynamicRuleProperty() {
|
||||
ReadableDataSource<String, List<FlowRule>> ruleSource = new NacosDataSource<>(remoteAddress, groupId,
|
||||
flowDataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
|
||||
FlowRuleManager.register2Property(ruleSource.getProperty());
|
||||
|
||||
ReadableDataSource<String, List<ParamFlowRule>> paramRuleSource = new NacosDataSource<>(remoteAddress, groupId,
|
||||
paramDataId, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
|
||||
ParamFlowRuleManager.register2Property(paramRuleSource.getProperty());
|
||||
}
|
||||
|
||||
private void initClientConfigProperty() {
|
||||
ReadableDataSource<String, ClusterClientConfig> clientConfigDs = new NacosDataSource<>(remoteAddress, groupId,
|
||||
configDataId, source -> JSON.parseObject(source, new TypeReference<ClusterClientConfig>() {}));
|
||||
ClusterClientConfigManager.registerClientConfigProperty(clientConfigDs.getProperty());
|
||||
}
|
||||
|
||||
private void initServerTransportConfigProperty() {
|
||||
ReadableDataSource<String, ServerTransportConfig> serverTransportDs = new NacosDataSource<>(remoteAddress, groupId,
|
||||
clusterMapDataId, source -> {
|
||||
List<ClusterGroupEntity> groupList = JSON.parseObject(source, new TypeReference<List<ClusterGroupEntity>>() {});
|
||||
return Optional.ofNullable(groupList)
|
||||
.flatMap(this::extractServerTransportConfig)
|
||||
.orElse(null);
|
||||
});
|
||||
ClusterServerConfigManager.registerServerTransportProperty(serverTransportDs.getProperty());
|
||||
}
|
||||
|
||||
private void registerClusterRuleSupplier() {
|
||||
// Register cluster flow rule property supplier which creates data source by namespace.
|
||||
// Flow rule dataId format: ${namespace}-flow-rules
|
||||
ClusterFlowRuleManager.setPropertySupplier(namespace -> {
|
||||
ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
|
||||
namespace + DemoConstants.FLOW_POSTFIX, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
|
||||
return ds.getProperty();
|
||||
});
|
||||
// Register cluster parameter flow rule property supplier which creates data source by namespace.
|
||||
ClusterParamFlowRuleManager.setPropertySupplier(namespace -> {
|
||||
ReadableDataSource<String, List<ParamFlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
|
||||
namespace + DemoConstants.PARAM_FLOW_POSTFIX, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
|
||||
return ds.getProperty();
|
||||
});
|
||||
}
|
||||
|
||||
private void initClientServerAssignProperty() {
|
||||
// Cluster map format:
|
||||
// [{"clientSet":["112.12.88.66@8729","112.12.88.67@8727"],"ip":"112.12.88.68","machineId":"112.12.88.68@8728","port":11111}]
|
||||
// machineId: <ip@commandPort>, commandPort for port exposed to Sentinel dashboard (transport module)
|
||||
ReadableDataSource<String, ClusterClientAssignConfig> clientAssignDs = new NacosDataSource<>(remoteAddress, groupId,
|
||||
clusterMapDataId, source -> {
|
||||
List<ClusterGroupEntity> groupList = JSON.parseObject(source, new TypeReference<List<ClusterGroupEntity>>() {});
|
||||
return Optional.ofNullable(groupList)
|
||||
.flatMap(this::extractClientAssignment)
|
||||
.orElse(null);
|
||||
});
|
||||
ClusterClientConfigManager.registerServerAssignProperty(clientAssignDs.getProperty());
|
||||
}
|
||||
|
||||
private void initStateProperty() {
|
||||
// Cluster map format:
|
||||
// [{"clientSet":["112.12.88.66@8729","112.12.88.67@8727"],"ip":"112.12.88.68","machineId":"112.12.88.68@8728","port":11111}]
|
||||
// machineId: <ip@commandPort>, commandPort for port exposed to Sentinel dashboard (transport module)
|
||||
ReadableDataSource<String, Integer> clusterModeDs = new NacosDataSource<>(remoteAddress, groupId,
|
||||
clusterMapDataId, source -> {
|
||||
List<ClusterGroupEntity> groupList = JSON.parseObject(source, new TypeReference<List<ClusterGroupEntity>>() {});
|
||||
return Optional.ofNullable(groupList)
|
||||
.map(this::extractMode)
|
||||
.orElse(ClusterStateManager.CLUSTER_NOT_STARTED);
|
||||
});
|
||||
ClusterStateManager.registerProperty(clusterModeDs.getProperty());
|
||||
}
|
||||
|
||||
private int extractMode(List<ClusterGroupEntity> groupList) {
|
||||
// If any server group machineId matches current, then it's token server.
|
||||
if (groupList.stream().anyMatch(this::machineEqual)) {
|
||||
return ClusterStateManager.CLUSTER_SERVER;
|
||||
}
|
||||
// If current machine belongs to any of the token server group, then it's token client.
|
||||
// Otherwise it's unassigned, should be set to NOT_STARTED.
|
||||
boolean canBeClient = groupList.stream()
|
||||
.flatMap(e -> e.getClientSet().stream())
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(e -> e.equals(getCurrentMachineId()));
|
||||
return canBeClient ? ClusterStateManager.CLUSTER_CLIENT : ClusterStateManager.CLUSTER_NOT_STARTED;
|
||||
}
|
||||
|
||||
private Optional<ServerTransportConfig> extractServerTransportConfig(List<ClusterGroupEntity> groupList) {
|
||||
return groupList.stream()
|
||||
.filter(this::machineEqual)
|
||||
.findAny()
|
||||
.map(e -> new ServerTransportConfig().setPort(e.getPort()).setIdleSeconds(600));
|
||||
}
|
||||
|
||||
private Optional<ClusterClientAssignConfig> extractClientAssignment(List<ClusterGroupEntity> groupList) {
|
||||
if (groupList.stream().anyMatch(this::machineEqual)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
// Build client assign config from the client set of target server group.
|
||||
for (ClusterGroupEntity group : groupList) {
|
||||
if (group.getClientSet().contains(getCurrentMachineId())) {
|
||||
String ip = group.getIp();
|
||||
Integer port = group.getPort();
|
||||
return Optional.of(new ClusterClientAssignConfig(ip, port));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private boolean machineEqual(/*@Valid*/ ClusterGroupEntity group) {
|
||||
return getCurrentMachineId().equals(group.getMachineId());
|
||||
}
|
||||
|
||||
private String getCurrentMachineId() {
|
||||
// Note: this may not work well for container-based env.
|
||||
return HostNameUtil.getIp() + SEPARATOR + TransportConfig.getRuntimePort();
|
||||
}
|
||||
|
||||
private static final String SEPARATOR = "@";
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.alibaba.csp.sentinel.demo.cluster.init.DemoClusterInitFunc
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo-cluster</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-cluster-server-alone</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-parameter-flow-control</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-cluster-server-default</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.alibaba.csp.sentinel.cluster.server.ClusterTokenServer;
|
||||
import com.alibaba.csp.sentinel.cluster.server.SentinelDefaultTokenServer;
|
||||
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||
|
||||
/**
|
||||
* <p>Cluster server demo (alone mode).</p>
|
||||
* <p>Here we init the cluster server dynamic data sources in
|
||||
* {@link com.alibaba.csp.sentinel.demo.cluster.init.DemoClusterServerInitFunc}.</p>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterServerDemo {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Not embedded mode by default (alone mode).
|
||||
ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
|
||||
|
||||
// A sample for manually load config for cluster server.
|
||||
// It's recommended to use dynamic data source to cluster manage config and rules.
|
||||
// See the sample in DemoClusterServerInitFunc for detail.
|
||||
ClusterServerConfigManager.loadGlobalTransportConfig(new ServerTransportConfig()
|
||||
.setIdleSeconds(600)
|
||||
.setPort(11111));
|
||||
ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton(DemoConstants.APP_NAME));
|
||||
|
||||
// Start the server.
|
||||
tokenServer.start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public final class DemoConstants {
|
||||
|
||||
public static final String APP_NAME = "appA";
|
||||
|
||||
public static final String FLOW_POSTFIX = "-flow-rules";
|
||||
public static final String PARAM_FLOW_POSTFIX = "-param-rules";
|
||||
|
||||
private DemoConstants() {}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.cluster.init;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
|
||||
import com.alibaba.csp.sentinel.demo.cluster.DemoConstants;
|
||||
import com.alibaba.csp.sentinel.init.InitFunc;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class DemoClusterServerInitFunc implements InitFunc {
|
||||
|
||||
private final String remoteAddress = "localhost:8848";
|
||||
private final String groupId = "SENTINEL_GROUP";
|
||||
private final String namespaceSetDataId = "cluster-server-namespace-set";
|
||||
private final String serverTransportDataId = "cluster-server-transport-config";
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
// Register cluster flow rule property supplier which creates data source by namespace.
|
||||
ClusterFlowRuleManager.setPropertySupplier(namespace -> {
|
||||
ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
|
||||
namespace + DemoConstants.FLOW_POSTFIX,
|
||||
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
|
||||
return ds.getProperty();
|
||||
});
|
||||
// Register cluster parameter flow rule property supplier.
|
||||
ClusterParamFlowRuleManager.setPropertySupplier(namespace -> {
|
||||
ReadableDataSource<String, List<ParamFlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
|
||||
namespace + DemoConstants.PARAM_FLOW_POSTFIX,
|
||||
source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
|
||||
return ds.getProperty();
|
||||
});
|
||||
|
||||
// Server namespace set (scope) data source.
|
||||
ReadableDataSource<String, Set<String>> namespaceDs = new NacosDataSource<>(remoteAddress, groupId,
|
||||
namespaceSetDataId, source -> JSON.parseObject(source, new TypeReference<Set<String>>() {}));
|
||||
ClusterServerConfigManager.registerNamespaceSetProperty(namespaceDs.getProperty());
|
||||
// Server transport configuration data source.
|
||||
ReadableDataSource<String, ServerTransportConfig> transportConfigDs = new NacosDataSource<>(remoteAddress,
|
||||
groupId, serverTransportDataId,
|
||||
source -> JSON.parseObject(source, new TypeReference<ServerTransportConfig>() {}));
|
||||
ClusterServerConfigManager.registerServerTransportProperty(transportConfigDs.getProperty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.alibaba.csp.sentinel.demo.cluster.init.DemoClusterServerInitFunc
|
||||
20
sentinel/sentinel-demo/sentinel-demo-command-handler/pom.xml
Normal file
20
sentinel/sentinel-demo/sentinel-demo-command-handler/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-command-handler</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.commandhandler;
|
||||
|
||||
import com.alibaba.csp.sentinel.init.InitExecutor;
|
||||
|
||||
/**
|
||||
* <p>To run this demo, we need to add the {@code sentinel-transport-simple-http} dependency.</p>
|
||||
* <p>
|
||||
* As soon as the CommandCenter has been initialized, we can visit {@code http://ip:commandPort/api}
|
||||
* to see all available command APIs (by default the port is 8719).
|
||||
* We can also visit our customized {@code /echo} command.
|
||||
* </p>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class CommandDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Only for demo. You don't have to do this in your application.
|
||||
InitExecutor.doInit();
|
||||
|
||||
System.out.println("Sentinel CommandCenter has been initialized");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.commandhandler;
|
||||
|
||||
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||
|
||||
/**
|
||||
* This class is a demo shows how to create and register a customized CommandHandler.
|
||||
*
|
||||
* <ul>
|
||||
* <li>1. Create a class which implements the {@link CommandHandler} SPI interface</li>
|
||||
* <li>2. Use a {@link CommandMapping} to specify the url and desc of your CommandHandler</li>
|
||||
* <li>3. Implement your own {@code handle} method </li>
|
||||
* <li>4. Add your CommandHandler in {@code com.alibaba.csp.sentinel.command.CommandHandler} file which is stored in
|
||||
* {@code resources/META-INF/services/} directory </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author houyi
|
||||
*/
|
||||
@CommandMapping(name = "echo", desc = "echo command for demo")
|
||||
public class EchoCommandHandler implements CommandHandler<String> {
|
||||
|
||||
@Override
|
||||
public CommandResponse<String> handle(CommandRequest request) {
|
||||
String name = request.getParam("name");
|
||||
if (name == null || name.trim().length() == 0) {
|
||||
return CommandResponse.ofSuccess("Tell us what's your name by submit a name parameter");
|
||||
}
|
||||
return CommandResponse.ofSuccess("Hello: " + name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.alibaba.csp.sentinel.demo.commandhandler.EchoCommandHandler
|
||||
112
sentinel/sentinel-demo/sentinel-demo-dubbo/README.md
Normal file
112
sentinel/sentinel-demo/sentinel-demo-dubbo/README.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Sentinel Dubbo Demo
|
||||
|
||||
Sentinel 提供了与 Dubbo 整合的模块 - Sentinel Dubbo Adapter,主要包括针对 Service Provider 和 Service Consumer 实现的 Filter。使用时用户只需引入以下模块(以 Maven 为例):
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-dubbo-adapter</artifactId>
|
||||
<version>x.y.z</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
引入此依赖后,Dubbo 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源,在配置了规则后就可以自动享受到 Sentinel 的防护能力。
|
||||
|
||||
> **注:若希望接入 Dashboard,请参考后面接入控制台的步骤。只引入 Sentinel Dubbo Adapter 无法接入控制台!**
|
||||
|
||||
若不希望开启 Sentinel Dubbo Adapter 中的某个 Filter,可以手动关闭对应的 Filter,比如:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public ConsumerConfig consumerConfig() {
|
||||
ConsumerConfig consumerConfig = new ConsumerConfig();
|
||||
consumerConfig.setFilter("-sentinel.dubbo.consumer.filter");
|
||||
return consumerConfig;
|
||||
}
|
||||
```
|
||||
|
||||
我们提供了几个具体的 Demo 来分别演示 Provider 和 Consumer 的限流场景。
|
||||
|
||||
## Service Provider
|
||||
|
||||
Service Provider 用于向外界提供服务,处理各个消费者的调用请求。为了保护 Provider 不被激增的流量拖垮影响稳定性,可以给 Provider 配置 **QPS 模式**的限流,这样当每秒的请求量超过设定的阈值时会自动拒绝多的请求。限流粒度可以是服务接口和服务方法两种粒度。若希望整个服务接口的 QPS 不超过一定数值,则可以为对应服务接口资源(resourceName 为**接口全限定名**)配置 QPS 阈值;若希望服务的某个方法的 QPS 不超过一定数值,则可以为对应服务方法资源(resourceName 为**接口全限定名:方法签名**)配置 QPS 阈值。有关配置详情请参考 [流量控制 | Sentinel](https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6)。
|
||||
|
||||
Demo 1 演示了此限流场景,我们看一下这种模式的限流产生的效果。假设我们已经定义了某个服务接口 `com.alibaba.csp.sentinel.demo.dubbo.FooService`,其中有一个方法 `sayHello(java.lang.String)`,Provider 端该方法设定 QPS 阈值为 10。在 Consumer 端在 1s 之内连续发起 15 次调用,可以通过日志文件看到 Provider 端被限流。拦截日志统一记录在 `~/logs/csp/sentinel-block.log` 中:
|
||||
|
||||
```
|
||||
2018-07-24 17:13:43|1|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String),FlowException,default,|5,0
|
||||
```
|
||||
|
||||
在 Provider 对应的 metrics 日志中也有记录:
|
||||
|
||||
```
|
||||
1532423623000|2018-07-24 17:13:43|com.alibaba.csp.sentinel.demo.dubbo.FooService|15|0|15|0|3
|
||||
1532423623000|2018-07-24 17:13:43|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)|10|5|10|0|0
|
||||
```
|
||||
|
||||
很多场景下,根据**调用方**来限流也是非常重要的。比如有两个服务 A 和 B 都向 Service Provider 发起调用请求,我们希望只对来自服务 B 的请求进行限流,则可以设置限流规则的 `limitApp` 为服务 B 的名称。Sentinel Dubbo Adapter 会自动解析 Dubbo 消费者(调用方)的 application name 作为调用方名称(`origin`),在进行资源保护的时候都会带上调用方名称。若限流规则未配置调用方(`default`),则该限流规则对所有调用方生效。若限流规则配置了调用方则限流规则将仅对指定调用方生效。
|
||||
|
||||
> 注:Dubbo 默认通信不携带对端 application name 信息,因此需要开发者在调用端手动将 application name 置入 attachment 中,provider 端进行相应的解析。Sentinel Dubbo Adapter 实现了一个 Filter 用于自动从 consumer 端向 provider 端透传 application name。若调用端未引入 Sentinel Dubbo Adapter,又希望根据调用端限流,可以在调用端手动将 application name 置入 attachment 中,key 为 `dubboApplication`。
|
||||
|
||||
在限流日志中会也会记录调用方的名称,如:
|
||||
|
||||
```
|
||||
2018-07-25 16:26:48|1|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String),FlowException,default,demo-consumer|5,0
|
||||
```
|
||||
|
||||
其中日志中的 `demo-consumer` 即为调用方名称。
|
||||
|
||||
## Service Consumer
|
||||
|
||||
> 对服务消费方的流量控制可分为**控制并发线程数**和**服务降级**两个维度。
|
||||
|
||||
### 并发线程数限流
|
||||
|
||||
Service Consumer 作为客户端去调用远程服务。每一个服务都可能会依赖几个下游服务,若某个服务 A 依赖的下游服务 B 出现了不稳定的情况,服务 A 请求服务 B 的响应时间变长,从而服务 A 调用服务 B 的线程就会产生堆积,最终可能耗尽服务 A 的线程数。我们通过用并发线程数来控制对下游服务 B 的访问,来保证下游服务不可靠的时候,不会拖垮服务自身。基于这种场景,推荐给 Consumer 配置**线程数模式**的限流,来保证自身不被不稳定服务所影响。限流粒度同样可以是服务接口和服务方法两种粒度。
|
||||
|
||||
采用基于线程数的限流模式后,我们不需要再显式地去进行线程池隔离,Sentinel 会控制资源的线程数,超出的请求直接拒绝,直到堆积的线程处理完成。
|
||||
|
||||
Demo 2 演示了此限流场景,我们看一下这种模式的效果。假设当前服务 A 依赖两个远程服务方法 `sayHello(java.lang.String)` 和 `doAnother()`。前者远程调用的响应时间 为 1s-1.5s之间,后者 RT 非常小(30 ms 左右)。服务 A 端设两个远程方法 thread count 为 5。然后每隔 50 ms 左右向线程池投入两个任务,作为消费者分别远程调用对应方法,持续 10 次。可以看到 `sayHello` 方法被限流 5 次,因为后面调用的时候前面的远程调用还未返回(RT 高);而 `doAnother()` 调用则不受影响。线程数目超出时快速失败能够有效地防止自己被慢调用所影响。
|
||||
|
||||
### 服务降级
|
||||
|
||||
当服务依赖于多个下游服务,而某个下游服务调用非常慢时,会严重影响当前服务的调用。这里我们可以利用 Sentinel 熔断降级的功能,为调用端配置基于平均 RT 的[降级规则](https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7)。这样当调用链路中某个服务调用的平均 RT 升高,在一定的次数内超过配置的 RT 阈值,Sentinel 就会对此调用资源进行降级操作,接下来的调用都会立刻拒绝,直到过了一段设定的时间后才恢复,从而保护服务不被调用端短板所影响。同时可以配合 fallback 功能使用,在被降级的时候提供相应的处理逻辑。
|
||||
|
||||
## Fallback
|
||||
|
||||
从 0.1.1 版本开始,Sentinel Dubbo Adapter 还支持配置全局的 fallback 函数,可以在 Dubbo 服务被限流/降级/负载保护的时候进行相应的 fallback 处理。用户只需要实现自定义的 [`DubboFallback`](https://github.com/alibaba/Sentinel/blob/master/sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallback.java) 接口,并通过 `DubboFallbackRegistry` 注册即可。默认情况会直接将 `BlockException` 包装后抛出。同时,我们还可以配合 [Dubbo 的 fallback 机制](http://dubbo.apache.org/#!/docs/user/demos/local-mock.md?lang=zh-cn) 来为降级的服务提供替代的实现。
|
||||
|
||||
Demo 2 的 Consumer 端提供了一个简单的 fallback 示例。
|
||||
|
||||
## Sentinel Dashboard
|
||||
|
||||
Sentinel 还提供 API 用于获取实时的监控信息,对应文档见[此处](https://github.com/alibaba/Sentinel/wiki/%E5%AE%9E%E6%97%B6%E7%9B%91%E6%8E%A7)。为了便于使用,Sentinel 还提供了一个控制台(Dashboard)用于配置规则、查看监控、机器发现等功能。
|
||||
|
||||
接入 Dashboard 的步骤(**缺一不可**):
|
||||
|
||||
1. 按照 [Sentinel 控制台文档](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0) 启动控制台
|
||||
2. 应用引入 `sentinel-transport-simple-http` 依赖,以便控制台可以拉取对应应用的相关信息
|
||||
3. 给应用添加相关的启动参数,启动应用。需要配置的参数有:
|
||||
- `-Dcsp.sentinel.api.port`:客户端的 port,用于上报相关信息
|
||||
- `-Dcsp.sentinel.dashboard.server`:控制台的地址
|
||||
- `-Dproject.name`:应用名称,会在控制台中显示
|
||||
|
||||
注意某些环境下本地运行 Dubbo 服务还需要加上 `-Djava.net.preferIPv4Stack=true` 参数。比如 Service Provider 示例的启动参数:
|
||||
|
||||
```bash
|
||||
-Djava.net.preferIPv4Stack=true -Dcsp.sentinel.api.port=8720 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=dubbo-provider-demo
|
||||
```
|
||||
|
||||
Service Consumer 示例的启动参数:
|
||||
|
||||
```bash
|
||||
-Djava.net.preferIPv4Stack=true -Dcsp.sentinel.api.port=8721 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=dubbo-consumer-demo
|
||||
```
|
||||
|
||||
这样在启动 Service Provider 和 Service Consumer 示例以后,就可以在 Sentinel 控制台中找到我们的服务了。可以很方便地在控制台中配置限流规则:
|
||||
|
||||

|
||||
|
||||
或者查看实时监控数据:
|
||||
|
||||

|
||||
53
sentinel/sentinel-demo/sentinel-demo-dubbo/pom.xml
Normal file
53
sentinel/sentinel-demo/sentinel-demo-dubbo/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-dubbo</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- Demo use Dubbo 2.6.x, since it supports JDK 1.7 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<version>2.6.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo provides qos plugin since 2.5.8 and is enable by default. -->
|
||||
<!-- The dubbo-qos module is optional and it depends Netty 4.x, so add it explicitly -->
|
||||
<!-- @see http://dubbo.apache.org/zh-cn/docs/user/references/qos.html -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.42.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- As demo use @DubboComponentScan to config, which is implemented in dubbo-config-spring module -->
|
||||
<!-- The dubbo-config-spring module is optional and it depends spring-context-support, so add it explicitly-->
|
||||
<!-- @see https://github.com/apache/incubator-dubbo/issues/2869 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.spring</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>1.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sentinel adapter and transport -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-dubbo-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public interface FooService {
|
||||
String sayHello(String name);
|
||||
|
||||
String doAnother();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.consumer;
|
||||
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ConsumerConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
@DubboComponentScan
|
||||
public class ConsumerConfiguration {
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-consumer");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsumerConfig consumerConfig() {
|
||||
ConsumerConfig consumerConfig = new ConsumerConfig();
|
||||
// Uncomment below line if you don't want to enable Sentinel for Dubbo service consumers.
|
||||
// consumerConfig.setFilter("-sentinel.dubbo.consumer.filter");
|
||||
return consumerConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FooServiceConsumer annotationDemoServiceConsumer() {
|
||||
return new FooServiceConsumer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.consumer;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.FooService;
|
||||
import com.alibaba.dubbo.config.annotation.Reference;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooServiceConsumer {
|
||||
|
||||
@Reference(url = "dubbo://127.0.0.1:25758", timeout = 3000)
|
||||
private FooService fooService;
|
||||
|
||||
public String sayHello(String name) {
|
||||
return fooService.sayHello(name);
|
||||
}
|
||||
|
||||
public String doAnother() {
|
||||
return fooService.doAnother();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo1;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration;
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer;
|
||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8721
|
||||
* -Dproject.name=dubbo-consumer-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooConsumerBootstrap {
|
||||
|
||||
public static void main(String[] args) {
|
||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
|
||||
consumerContext.register(ConsumerConfiguration.class);
|
||||
consumerContext.refresh();
|
||||
|
||||
FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Success: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo1;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.alibaba.csp.sentinel.init.InitExecutor;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8720
|
||||
* -Dproject.name=dubbo-provider-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooProviderBootstrap {
|
||||
|
||||
private static final String RES_KEY = "com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)";
|
||||
private static final String INTERFACE_RES_KEY = "com.alibaba.csp.sentinel.demo.dubbo.FooService";
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Users don't need to manually call this method.
|
||||
InitExecutor.doInit();
|
||||
|
||||
initFlowRule();
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(ProviderConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
System.out.println("Service provider is ready");
|
||||
}
|
||||
|
||||
private static void initFlowRule() {
|
||||
FlowRule flowRule = new FlowRule();
|
||||
flowRule.setResource(RES_KEY);
|
||||
flowRule.setCount(10);
|
||||
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
flowRule.setLimitApp("default");
|
||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo1;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.FooService;
|
||||
import com.alibaba.dubbo.config.annotation.Service;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Service
|
||||
public class FooServiceImpl implements FooService {
|
||||
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
return String.format("Hello, %s at %s", name, LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doAnother() {
|
||||
return LocalDateTime.now().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo1;
|
||||
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ProtocolConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
@DubboComponentScan("com.alibaba.csp.sentinel.demo.dubbo.demo1")
|
||||
public class ProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-provider");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ProtocolConfig protocolConfig() {
|
||||
ProtocolConfig protocolConfig = new ProtocolConfig();
|
||||
protocolConfig.setName("dubbo");
|
||||
protocolConfig.setPort(25758);
|
||||
return protocolConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo2;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboAdapterGlobalConfig;
|
||||
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration;
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.dubbo.rpc.RpcResult;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8721
|
||||
* -Dproject.name=dubbo-consumer-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooConsumerBootstrap {
|
||||
|
||||
private static final String RES_KEY = "com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)";
|
||||
private static final String INTERFACE_RES_KEY = "com.alibaba.csp.sentinel.demo.dubbo.FooService";
|
||||
|
||||
@SuppressWarnings("PMD.ThreadPoolCreationRule")
|
||||
private static final ExecutorService pool = Executors.newFixedThreadPool(10,
|
||||
new NamedThreadFactory("dubbo-consumer-pool"));
|
||||
|
||||
public static void main(String[] args) {
|
||||
initFlowRule();
|
||||
|
||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
|
||||
consumerContext.register(ConsumerConfiguration.class);
|
||||
consumerContext.refresh();
|
||||
|
||||
FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
String message = service.sayHello("Eric");
|
||||
System.out.println("Success: " + message);
|
||||
} catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
pool.submit(() -> System.out.println("Another: " + service.doAnother()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void initFlowRule() {
|
||||
FlowRule flowRule = new FlowRule();
|
||||
flowRule.setResource(RES_KEY);
|
||||
flowRule.setCount(5);
|
||||
flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
|
||||
flowRule.setLimitApp("default");
|
||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
}
|
||||
|
||||
private static void registerFallback() {
|
||||
// Register fallback handler for consumer.
|
||||
// If you only want to handle degrading, you need to
|
||||
// check the type of BlockException.
|
||||
DubboAdapterGlobalConfig.setConsumerFallback((a, b, ex) ->
|
||||
new RpcResult("Error: " + ex.getClass().getTypeName()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo2;
|
||||
|
||||
import com.alibaba.csp.sentinel.init.InitExecutor;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Please add the following VM arguments:
|
||||
* <pre>
|
||||
* -Djava.net.preferIPv4Stack=true
|
||||
* -Dcsp.sentinel.api.port=8720
|
||||
* -Dproject.name=dubbo-provider-demo
|
||||
* </pre>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FooProviderBootstrap {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Users don't need to manually call this method.
|
||||
InitExecutor.doInit();
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(ProviderConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
System.out.println("Service provider is ready");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo2;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.alibaba.csp.sentinel.demo.dubbo.FooService;
|
||||
import com.alibaba.dubbo.config.annotation.Service;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Service
|
||||
public class FooServiceImpl implements FooService {
|
||||
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
return String.format("Hello, %s at %s", name, LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doAnother() {
|
||||
return LocalDateTime.now().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.dubbo.demo2;
|
||||
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ProtocolConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Configuration
|
||||
@DubboComponentScan("com.alibaba.csp.sentinel.demo.dubbo.demo2")
|
||||
public class ProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-provider");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ProtocolConfig protocolConfig() {
|
||||
ProtocolConfig protocolConfig = new ProtocolConfig();
|
||||
protocolConfig.setName("dubbo");
|
||||
protocolConfig.setPort(25758);
|
||||
return protocolConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<artifactId>sentinel-demo-dynamic-file-rule</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-extension</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.file.rule;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
|
||||
import com.alibaba.csp.sentinel.property.PropertyListener;
|
||||
import com.alibaba.csp.sentinel.property.SentinelProperty;
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemRule;
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This Demo shows how to use {@link FileRefreshableDataSource} to read {@link Rule}s from file. The
|
||||
* {@link FileRefreshableDataSource} will automatically fetches the backend file every 3 seconds, and
|
||||
* inform the listener if the file is updated.
|
||||
* </p>
|
||||
* <p>
|
||||
* Each {@link ReadableDataSource} has a {@link SentinelProperty} to hold the deserialized config data.
|
||||
* {@link PropertyListener} will listen to the {@link SentinelProperty} instead of the datasource.
|
||||
* {@link Converter} is used for telling how to deserialize the data.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link FlowRuleManager#register2Property(SentinelProperty)},
|
||||
* {@link DegradeRuleManager#register2Property(SentinelProperty)},
|
||||
* {@link SystemRuleManager#register2Property(SentinelProperty)} could be called for listening the
|
||||
* {@link Rule}s change.
|
||||
* </p>
|
||||
* <p>
|
||||
* For other kinds of data source, such as <a href="https://github.com/alibaba/nacos">Nacos</a>,
|
||||
* Zookeeper, Git, or even CSV file, We could implement {@link ReadableDataSource} interface to read these
|
||||
* configs.
|
||||
* </p>
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FileDataSourceDemo {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
FileDataSourceDemo demo = new FileDataSourceDemo();
|
||||
demo.listenRules();
|
||||
|
||||
/*
|
||||
* Start to require tokens, rate will be limited by rule in FlowRule.json
|
||||
*/
|
||||
FlowQpsRunner runner = new FlowQpsRunner();
|
||||
runner.simulateTraffic();
|
||||
runner.tick();
|
||||
}
|
||||
|
||||
private void listenRules() throws Exception {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
String flowRulePath = URLDecoder.decode(classLoader.getResource("FlowRule.json").getFile(), "UTF-8");
|
||||
String degradeRulePath = URLDecoder.decode(classLoader.getResource("DegradeRule.json").getFile(), "UTF-8");
|
||||
String systemRulePath = URLDecoder.decode(classLoader.getResource("SystemRule.json").getFile(), "UTF-8");
|
||||
|
||||
// Data source for FlowRule
|
||||
FileRefreshableDataSource<List<FlowRule>> flowRuleDataSource = new FileRefreshableDataSource<>(
|
||||
flowRulePath, flowRuleListParser);
|
||||
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
|
||||
|
||||
// Data source for DegradeRule
|
||||
FileRefreshableDataSource<List<DegradeRule>> degradeRuleDataSource
|
||||
= new FileRefreshableDataSource<>(
|
||||
degradeRulePath, degradeRuleListParser);
|
||||
DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
|
||||
|
||||
// Data source for SystemRule
|
||||
FileRefreshableDataSource<List<SystemRule>> systemRuleDataSource
|
||||
= new FileRefreshableDataSource<>(
|
||||
systemRulePath, systemRuleListParser);
|
||||
SystemRuleManager.register2Property(systemRuleDataSource.getProperty());
|
||||
}
|
||||
|
||||
private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source,
|
||||
new TypeReference<List<FlowRule>>() {});
|
||||
private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source,
|
||||
new TypeReference<List<DegradeRule>>() {});
|
||||
private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source,
|
||||
new TypeReference<List<SystemRule>>() {});
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.file.rule;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
|
||||
import com.alibaba.csp.sentinel.init.InitFunc;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A sample showing how to register readable and writable data source via Sentinel init SPI mechanism.
|
||||
* </p>
|
||||
* <p>
|
||||
* To activate this, you can add the class name to `com.alibaba.csp.sentinel.init.InitFunc` file
|
||||
* in `META-INF/services/` directory of the resource directory. Then the data source will be automatically
|
||||
* registered during the initialization of Sentinel.
|
||||
* </p>
|
||||
*
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class FileDataSourceInit implements InitFunc {
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
// A fake path.
|
||||
String flowRuleDir = System.getProperty("user.home") + File.separator + "sentinel" + File.separator + "rules";
|
||||
String flowRuleFile = "flowRule.json";
|
||||
String flowRulePath = flowRuleDir + File.separator + flowRuleFile;
|
||||
|
||||
ReadableDataSource<String, List<FlowRule>> ds = new FileRefreshableDataSource<>(
|
||||
flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
|
||||
);
|
||||
// Register to flow rule manager.
|
||||
FlowRuleManager.register2Property(ds.getProperty());
|
||||
|
||||
WritableDataSource<List<FlowRule>> wds = new FileWritableDataSource<>(flowRulePath, this::encodeJson);
|
||||
// Register to writable data source registry so that rules can be updated to file
|
||||
// when there are rules pushed from the Sentinel Dashboard.
|
||||
WritableDataSourceRegistry.registerFlowDataSource(wds);
|
||||
}
|
||||
|
||||
private <T> String encodeJson(T t) {
|
||||
return JSON.toJSONString(t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.file.rule;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
|
||||
/**
|
||||
* Flow Rule demo.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
*/
|
||||
class FlowQpsRunner {
|
||||
private static final String KEY = "abc";
|
||||
|
||||
private static AtomicInteger pass = new AtomicInteger();
|
||||
private static AtomicInteger block = new AtomicInteger();
|
||||
private static AtomicInteger total = new AtomicInteger();
|
||||
|
||||
private static volatile boolean stop = false;
|
||||
|
||||
private static final int threadCount = 1;
|
||||
private static int seconds = 60 + 40;
|
||||
|
||||
public void simulateTraffic() {
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread t = new Thread(new RunTask());
|
||||
t.setName("simulate-traffic-Task");
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
Thread timer = new Thread(new TimerTask());
|
||||
timer.setName("sentinel-timer-task");
|
||||
timer.start();
|
||||
}
|
||||
|
||||
static final class RunTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop) {
|
||||
Entry entry = null;
|
||||
|
||||
try {
|
||||
entry = SphU.entry(KEY);
|
||||
// token acquired, means pass
|
||||
pass.addAndGet(1);
|
||||
} catch (BlockException e1) {
|
||||
block.incrementAndGet();
|
||||
} catch (Exception e2) {
|
||||
// biz exception
|
||||
} finally {
|
||||
total.incrementAndGet();
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class TimerTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println("begin to statistic!!!");
|
||||
|
||||
long oldTotal = 0;
|
||||
long oldPass = 0;
|
||||
long oldBlock = 0;
|
||||
while (!stop) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
long globalTotal = total.get();
|
||||
long oneSecondTotal = globalTotal - oldTotal;
|
||||
oldTotal = globalTotal;
|
||||
|
||||
long globalPass = pass.get();
|
||||
long oneSecondPass = globalPass - oldPass;
|
||||
oldPass = globalPass;
|
||||
|
||||
long globalBlock = block.get();
|
||||
long oneSecondBlock = globalBlock - oldBlock;
|
||||
oldBlock = globalBlock;
|
||||
|
||||
System.out.println(seconds + " send qps is: " + oneSecondTotal);
|
||||
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
|
||||
+ ", pass:" + oneSecondPass
|
||||
+ ", block:" + oneSecondBlock);
|
||||
|
||||
if (seconds-- <= 0) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
System.out.println("time cost: " + cost + " ms");
|
||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
||||
+ ", block:" + block.get());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.alibaba.csp.sentinel.demo.file.rule;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.datasource.FileInJarReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.property.PropertyListener;
|
||||
import com.alibaba.csp.sentinel.property.SentinelProperty;
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This Demo shows how to use {@link FileInJarReadableDataSource} to read {@link Rule}s from jarfile. The
|
||||
* {@link FileInJarReadableDataSource} will automatically fetches the backend file every 3 seconds, and
|
||||
* inform the listener if the file is updated.
|
||||
* </p>
|
||||
* <p>
|
||||
* Each {@link ReadableDataSource} has a {@link SentinelProperty} to hold the deserialized config data.
|
||||
* {@link PropertyListener} will listen to the {@link SentinelProperty} instead of the datasource.
|
||||
* {@link Converter} is used for telling how to deserialize the data.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link FlowRuleManager#register2Property(SentinelProperty)},
|
||||
* {@link DegradeRuleManager#register2Property(SentinelProperty)},
|
||||
* {@link SystemRuleManager#register2Property(SentinelProperty)} could be called for listening the
|
||||
* {@link Rule}s change.
|
||||
* </p>
|
||||
* <p>
|
||||
* For other kinds of data source, such as <a href="https://github.com/alibaba/nacos">Nacos</a>,
|
||||
* Zookeeper, Git, or even CSV file, We could implement {@link ReadableDataSource} interface to read these
|
||||
* configs.
|
||||
* </p>
|
||||
*
|
||||
* @author dingq
|
||||
*/
|
||||
public class JarFileDataSourceDemo {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
JarFileDataSourceDemo demo = new JarFileDataSourceDemo();
|
||||
demo.listenRules();
|
||||
|
||||
// Start to require tokens, rate will be limited by rule of FlowRule.json in jar.
|
||||
FlowQpsRunner runner = new FlowQpsRunner();
|
||||
runner.simulateTraffic();
|
||||
runner.tick();
|
||||
}
|
||||
|
||||
private void listenRules() throws Exception {
|
||||
// Modify the path with your real path.
|
||||
String jarPath = System.getProperty("user.dir") + "/sentinel-demo/sentinel-demo-dynamic-file-rule/target/"
|
||||
+ "sentinel-demo-dynamic-file-rule.jar";
|
||||
// eg: if flowRuleInJarName full path is 'sentinel-demo-dynamic-file-rule.jar!/classes/FlowRule.json',
|
||||
// your flowRuleInJarName is 'classes/FlowRule.json'
|
||||
String flowRuleInJarPath = "FlowRule.json";
|
||||
|
||||
FileInJarReadableDataSource<List<FlowRule>> flowRuleDataSource = new FileInJarReadableDataSource<>(
|
||||
jarPath,flowRuleInJarPath, flowRuleListParser);
|
||||
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
|
||||
}
|
||||
|
||||
private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source,
|
||||
new TypeReference<List<FlowRule>>() {});
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"resource": "abc0",
|
||||
"count": 20.0,
|
||||
"grade": 0,
|
||||
"passCount": 0,
|
||||
"timeWindow": 10
|
||||
},
|
||||
{
|
||||
"resource": "abc1",
|
||||
"count": 15.0,
|
||||
"grade": 0,
|
||||
"passCount": 0,
|
||||
"timeWindow": 10
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"resource": "abc",
|
||||
"controlBehavior": 0,
|
||||
"count": 20.0,
|
||||
"grade": 1,
|
||||
"limitApp": "default",
|
||||
"strategy": 0
|
||||
},
|
||||
{
|
||||
"resource": "abc1",
|
||||
"controlBehavior": 0,
|
||||
"count": 20.0,
|
||||
"grade": 1,
|
||||
"limitApp": "default",
|
||||
"strategy": 0
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"avgRt": 10,
|
||||
"highestSystemLoad": 5.0,
|
||||
"maxThread": 10,
|
||||
"qps": 20.0
|
||||
}
|
||||
]
|
||||
30
sentinel/sentinel-demo/sentinel-demo-etcd-datasource/pom.xml
Normal file
30
sentinel/sentinel-demo/sentinel-demo-etcd-datasource/pom.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-etcd-datasource</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-etcd</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.datasource.etcd;
|
||||
|
||||
|
||||
import io.etcd.jetcd.ByteSequence;
|
||||
import io.etcd.jetcd.Client;
|
||||
|
||||
/**
|
||||
* Etcd config sender for demo.
|
||||
*
|
||||
* @author lianglin
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class EtcdConfigSender {
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
|
||||
String rule_key = "sentinel_demo_rule_key";
|
||||
|
||||
Client client = Client.builder()
|
||||
.endpoints("http://127.0.0.1:2379")
|
||||
.user(ByteSequence.from("root".getBytes()))
|
||||
.password(ByteSequence.from("12345".getBytes()))
|
||||
.build();
|
||||
final String rule = "[\n"
|
||||
+ " {\n"
|
||||
+ " \"resource\": \"TestResource\",\n"
|
||||
+ " \"controlBehavior\": 0,\n"
|
||||
+ " \"count\": 5.0,\n"
|
||||
+ " \"grade\": 1,\n"
|
||||
+ " \"limitApp\": \"default\",\n"
|
||||
+ " \"strategy\": 0\n"
|
||||
+ " }\n"
|
||||
+ "]";
|
||||
client.getKVClient()
|
||||
.put(ByteSequence.from(rule_key.getBytes()), ByteSequence.from(rule.getBytes()));
|
||||
|
||||
System.out.println("setting rule success");
|
||||
Thread.sleep(10000);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.datasource.etcd;
|
||||
|
||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.etcd.EtcdConfig;
|
||||
import com.alibaba.csp.sentinel.datasource.etcd.EtcdDataSource;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lianglin
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class EtcdDataSourceDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
String rule_key = "sentinel_demo_rule_key";
|
||||
String yourUserName = "root";
|
||||
String yourPassWord = "12345";
|
||||
String endPoints = "http://127.0.0.1:2379";
|
||||
SentinelConfig.setConfig(EtcdConfig.END_POINTS, endPoints);
|
||||
SentinelConfig.setConfig(EtcdConfig.USER, yourUserName);
|
||||
SentinelConfig.setConfig(EtcdConfig.PASSWORD, yourPassWord);
|
||||
SentinelConfig.setConfig(EtcdConfig.CHARSET, "utf-8");
|
||||
SentinelConfig.setConfig(EtcdConfig.AUTH_ENABLE, "true");
|
||||
|
||||
ReadableDataSource<String, List<FlowRule>> flowRuleEtcdDataSource = new EtcdDataSource<>(rule_key, (rule) -> JSON.parseArray(rule, FlowRule.class));
|
||||
FlowRuleManager.register2Property(flowRuleEtcdDataSource.getProperty());
|
||||
List<FlowRule> rules = FlowRuleManager.getRules();
|
||||
System.out.println(rules);
|
||||
}
|
||||
|
||||
}
|
||||
49
sentinel/sentinel-demo/sentinel-demo-jax-rs/pom.xml
Normal file
49
sentinel/sentinel-demo/sentinel-demo-jax-rs/pom.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-jax-rs</artifactId>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.2.6.RELEASE</spring.boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-jax-rs-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-spring-boot-starter</artifactId>
|
||||
<version>4.5.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.jaxrs;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
/**
|
||||
* @author sea
|
||||
*/
|
||||
@Component
|
||||
@Provider
|
||||
@Priority(javax.ws.rs.Priorities.USER - 1)
|
||||
public class CustomExceptionMapper implements ExceptionMapper<Throwable> {
|
||||
@Override
|
||||
public Response toResponse(Throwable exception) {
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Unknown Server Error")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.jaxrs;
|
||||
|
||||
/**
|
||||
* @author sea
|
||||
*/
|
||||
public class HelloEntity {
|
||||
|
||||
Long id;
|
||||
|
||||
String msg;
|
||||
|
||||
public HelloEntity() {
|
||||
}
|
||||
|
||||
public HelloEntity(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public HelloEntity(Long id, String msg) {
|
||||
this.id = id;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HelloEntity{" +
|
||||
"id=" + id +
|
||||
", msg='" + msg + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.jaxrs;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* HelloResource
|
||||
* @author sea
|
||||
*/
|
||||
@Path("/hello")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Component
|
||||
public class HelloResource {
|
||||
|
||||
@GET
|
||||
public HelloEntity sayHello() {
|
||||
return new HelloEntity("hello");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public HelloEntity get(@PathParam(value = "id") Long id) {
|
||||
return new HelloEntity(id, "hello");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/list")
|
||||
public List<HelloEntity> getAll() {
|
||||
return IntStream.rangeClosed(1, 1000)
|
||||
.mapToObj(i -> new HelloEntity((long)i, "hello"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Path("/ex")
|
||||
@GET
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String exception() {
|
||||
throw new RuntimeException("test exception mapper");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.jaxrs;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.jaxrs.SentinelJaxRsClientTemplate;
|
||||
import com.alibaba.csp.sentinel.util.function.Supplier;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author sea
|
||||
*/
|
||||
public class JaxRsClientDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Client client = ClientBuilder.newBuilder()
|
||||
.connectTimeout(3, TimeUnit.SECONDS)
|
||||
.readTimeout(3, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
final String host = "http://127.0.0.1:8181";
|
||||
final String url = "/hello/1";
|
||||
String resourceName = "GET:" + url;
|
||||
Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
|
||||
|
||||
@Override
|
||||
public Response get() {
|
||||
return client.target(host).path(url).request()
|
||||
.get();
|
||||
}
|
||||
});
|
||||
System.out.println(response.readEntity(HelloEntity.class));
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.jaxrs;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* <p>Add the JVM parameter to connect to the dashboard:</p>
|
||||
* {@code -Dcsp.sentinel.dashboard.server=127.0.0.1:8080 -Dproject.name=sentinel-demo-jax-rs}
|
||||
*
|
||||
* @author sea
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class JaxRsDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(JaxRsDemoApplication.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.jaxrs;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.jaxrs.SentinelJaxRsProviderFilter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author sea
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SentinelJaxRsConfig {
|
||||
|
||||
@Bean
|
||||
public SentinelJaxRsProviderFilter sentinelJaxRsProviderFilter() {
|
||||
return new SentinelJaxRsProviderFilter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
server.port=8181
|
||||
45
sentinel/sentinel-demo/sentinel-demo-log-logback/pom.xml
Normal file
45
sentinel/sentinel-demo/sentinel-demo-log-logback/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-demo</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-demo-log-logback</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.stefanbirkner</groupId>
|
||||
<artifactId>system-rules</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.log.logback;
|
||||
|
||||
import com.alibaba.csp.sentinel.transport.log.CommandCenterLog;
|
||||
import com.alibaba.csp.sentinel.log.LogTarget;
|
||||
import com.alibaba.csp.sentinel.log.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class is a demo shows how to create a customized logger implementation.
|
||||
*
|
||||
* <ul>
|
||||
* <li>1. Create a class which implements the {@link Logger} SPI interface</li>
|
||||
* <li>2. Use a {@link LogTarget} to specify the log type</li>
|
||||
* <li>3. Implement your own method </li>
|
||||
* <li>4. Add your logger in {@code com.alibaba.csp.sentinel.log.Logger} file which is stored in
|
||||
* {@code resources/META-INF/services/} directory </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author xue8
|
||||
*/
|
||||
@LogTarget(value = CommandCenterLog.LOGGER_NAME)
|
||||
public class CommandCenterLogLoggerImpl implements Logger {
|
||||
|
||||
private final org.slf4j.Logger logger = LoggerFactory.getLogger(CommandCenterLog.LOGGER_NAME);
|
||||
|
||||
@Override
|
||||
public void info(String format, Object... arguments) {
|
||||
logger.info(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable e) {
|
||||
logger.info(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object... arguments) {
|
||||
logger.warn(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e) {
|
||||
logger.warn(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object... arguments) {
|
||||
logger.trace(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Throwable e) {
|
||||
logger.trace(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object... arguments) {
|
||||
logger.debug(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Throwable e) {
|
||||
logger.debug(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object... arguments) {
|
||||
logger.error(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable e) {
|
||||
logger.error(msg, e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.demo.log.logback;
|
||||
|
||||
import com.alibaba.csp.sentinel.log.LogTarget;
|
||||
import com.alibaba.csp.sentinel.log.Logger;
|
||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class is a demo shows how to create a customized logger implementation.
|
||||
*
|
||||
* <ul>
|
||||
* <li>1. Create a class which implements the {@link Logger} SPI interface</li>
|
||||
* <li>2. Use a {@link LogTarget} to specify the log type</li>
|
||||
* <li>3. Implement your own method </li>
|
||||
* <li>4. Add your logger in {@code com.alibaba.csp.sentinel.log.Logger} file which is stored in
|
||||
* {@code resources/META-INF/services/} directory </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author xue8
|
||||
*/
|
||||
@LogTarget(value = RecordLog.LOGGER_NAME)
|
||||
public class RecordLogLoggerImpl implements Logger {
|
||||
|
||||
private final org.slf4j.Logger logger = LoggerFactory.getLogger(RecordLog.LOGGER_NAME);
|
||||
|
||||
@Override
|
||||
public void info(String format, Object... arguments) {
|
||||
logger.info(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable e) {
|
||||
logger.info(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String format, Object... arguments) {
|
||||
logger.warn(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e) {
|
||||
logger.warn(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String format, Object... arguments) {
|
||||
logger.trace(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Throwable e) {
|
||||
logger.trace(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String format, Object... arguments) {
|
||||
logger.debug(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Throwable e) {
|
||||
logger.debug(msg, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String format, Object... arguments) {
|
||||
logger.error(format, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable e) {
|
||||
logger.error(msg, e);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user