This commit is contained in:
shuhongfan
2023-09-04 16:40:17 +08:00
commit cf5ac25c14
8267 changed files with 1305066 additions and 0 deletions

View 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

View 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>

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}

View File

@@ -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";
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}

View File

@@ -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";
}
}

View File

@@ -0,0 +1,2 @@
spring.application.name=sentinel-annotation-aspectj-example
server.port=19966

View 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
```

View 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>

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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");
}
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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";
}
}

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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) {
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,2 @@
spring.application.name=sentinel-demo-apache-httpclient
server.port=8083

View File

@@ -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>

View File

@@ -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());
}
}

View File

@@ -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);
}
}
}

View File

@@ -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>

View 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>

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View 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>

View File

@@ -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.

View File

@@ -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>

View File

@@ -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() {}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 +
'}';
}
}

View File

@@ -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 = "@";
}

View File

@@ -0,0 +1 @@
com.alibaba.csp.sentinel.demo.cluster.init.DemoClusterInitFunc

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -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() {}
}

View File

@@ -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());
}
}

View File

@@ -0,0 +1 @@
com.alibaba.csp.sentinel.demo.cluster.init.DemoClusterServerInitFunc

View 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>

View File

@@ -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");
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
com.alibaba.csp.sentinel.demo.commandhandler.EchoCommandHandler

View 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 控制台中找到我们的服务了。可以很方便地在控制台中配置限流规则:
![规则配置](http://dubbo.incubator.apache.org/img/blog/sentinel-dashboard-view-rules.png)
或者查看实时监控数据:
![秒级实时监控](http://dubbo.incubator.apache.org/img/blog/sentinel-dashboard-metrics.png)

View 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>

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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));
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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()));
}
}

View File

@@ -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");
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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>>() {});
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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>>() {});
}

View File

@@ -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
}
]

View File

@@ -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
}
]

View File

@@ -0,0 +1,8 @@
[
{
"avgRt": 10,
"highestSystemLoad": 5.0,
"maxThread": 10,
"qps": 20.0
}
]

View 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>

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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>

View File

@@ -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();
}
}

View File

@@ -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 + '\'' +
'}';
}
}

View File

@@ -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");
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1 @@
server.port=8181

View 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>

View File

@@ -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);
}
}

View File

@@ -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