Skip to content

Commit

Permalink
feat: Sentinel 示例
Browse files Browse the repository at this point in the history
  • Loading branch information
dunwu committed Feb 27, 2024
1 parent bbed14d commit 6b003ce
Show file tree
Hide file tree
Showing 16 changed files with 2,051 additions and 17 deletions.
3 changes: 1 addition & 2 deletions codes/distributed/ratelimit/sentinel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
(2)启动

```shell
java -jar sentinel-dashboard.jar -Dproject.name=sentinel-dashboard --server.port=18080
java -jar sentinel-dashboard2.jar -Dproject.name=sentinel-dashboard --server.port=18080
```

### 启动 Provider 服务
Expand Down Expand Up @@ -105,4 +105,3 @@ java -jar sentinel-dashboard.jar -Dproject.name=sentinel-dashboard --server.port
}
}
```

54 changes: 54 additions & 0 deletions codes/distributed/ratelimit/sentinel/basic/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>

<groupId>io.github.dunwu.spring</groupId>
<artifactId>spring-distributed-ratelimit-sentinel-basic</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Spring::分布式::流量控制::Sentinel::Basic</name>

<properties>
<java.version>1.8</java.version>
<resource.delimiter>@</resource.delimiter>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>1.8.7</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -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 example.spring.ratelimit.sentinel;

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;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
* 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);
}
}
Original file line number Diff line number Diff line change
@@ -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 example.spring.ratelimit.sentinel.authority;

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;

import java.util.Collections;

/**
* 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));
}
}
Loading

0 comments on commit 6b003ce

Please sign in to comment.