From 2f0ce2ef7ea075ba0f816266e2d9a6bd5eb8180e Mon Sep 17 00:00:00 2001 From: xiaolongzuo <150349407@qq.com> Date: Tue, 18 Dec 2018 14:53:16 +0800 Subject: [PATCH 1/8] Add SchedulerX readme doc. --- README-zh.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README-zh.md b/README-zh.md index 219a9e51..f308f309 100644 --- a/README-zh.md +++ b/README-zh.md @@ -13,6 +13,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。 * **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。 * **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。 * **阿里云对象存储**:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。 +* **分布式任务调度**:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。 更多功能请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 @@ -29,6 +30,8 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。 **[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 +**[Alibaba Cloud SchedulerX](https://help.aliyun.com/document_detail/43136.html?spm=a2c4g.11186623.6.709.baef7da9QVICiD)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。 + 更多组件请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 ## 如何构建 @@ -96,6 +99,8 @@ Example 列表: [Alibaba Cloud ACM Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/acm-example/acm-local-example/readme-zh.md) +[Alibaba Cloud SchedulerX Example](https://github.com/xiaolongzuo/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/readme-zh.md) + ## 版本管理规范 项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从0开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用0,即版本号为 0.x.x 的格式。 From d204a54b760d719fc195de261496ee81dc0ac8b9 Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Tue, 18 Dec 2018 17:35:45 +0800 Subject: [PATCH 2/8] Optimize Sentinel RestTemplate url resource --- .../src/main/asciidoc-zh/sentinel.adoc | 2 +- spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc | 2 +- .../cloud/alibaba/cloud/examples/ExceptionUtil.java | 8 +++++++- .../src/main/resources/flowrule.json | 4 ++-- .../sentinel/custom/SentinelProtectInterceptor.java | 4 ++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc index 0d54a60f..5d106bd3 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc @@ -185,7 +185,7 @@ Sentinel RestTemplate 限流的资源规则提供两种粒度: * `schema://host:port`:协议、主机和端口 -NOTE: 以 `https://www.taobao.com/test` 这个 url 为例。对应的资源名有两种粒度,分别是 `https://www.taobao.com:80` 以及 `https://www.taobao.com:80/test` +NOTE: 以 `https://www.taobao.com/test` 这个 url 为例。对应的资源名有两种粒度,分别是 `https://www.taobao.com` 以及 `https://www.taobao.com/test` ### 动态数据源支持 diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc index a604c3e7..40478e4b 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc @@ -187,7 +187,7 @@ Sentinel RestTemplate provides two granularities for resource rate limiting: * `schema://host:port`: Protocol, host and port -NOTE: Take `https://www.taobao.com/test` as an example. The corresponding resource names have two levels of granularities, `https://www.taobao.com:80` and `https://www.taobao.com:80/test`. +NOTE: Take `https://www.taobao.com/test` as an example. The corresponding resource names have two levels of granularities, `https://www.taobao.com` and `https://www.taobao.com/test`. ### Dynamic Data Source Support diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java index 3b8349fc..94ef5dde 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java @@ -1,5 +1,9 @@ package org.springframework.cloud.alibaba.cloud.examples; +import org.springframework.cloud.alibaba.sentinel.rest.SentinelClientHttpResponse; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; + import com.alibaba.csp.sentinel.slots.block.BlockException; /** @@ -7,8 +11,10 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; */ public class ExceptionUtil { - public static void handleException(BlockException ex) { + public static SentinelClientHttpResponse handleException(HttpRequest request, + byte[] body, ClientHttpRequestExecution execution, BlockException ex) { System.out.println("Oops: " + ex.getClass().getCanonicalName()); + return new SentinelClientHttpResponse("custom block info"); } } diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json index 679dff4a..d798f805 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json @@ -16,9 +16,9 @@ "strategy": 0 }, { - "resource": "abc", + "resource": "http://www.taobao.com", "controlBehavior": 0, - "count": 1, + "count": 0, "grade": 1, "limitApp": "default", "strategy": 0 diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java index a1a26f6c..f21da49b 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java @@ -58,8 +58,8 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { URI uri = request.getURI(); - String hostResource = uri.getScheme() + "://" + uri.getHost() + ":" - + (uri.getPort() == -1 ? 80 : uri.getPort()); + String hostResource = uri.getScheme() + "://" + uri.getHost() + + (uri.getPort() == -1 ? "" : ":" + uri.getPort()); String hostWithPathResource = hostResource + uri.getPath(); Entry hostEntry = null, hostWithPathEntry = null; ClientHttpResponse response; From 4a16533d1300c4113373f9d9389575099458ba6d Mon Sep 17 00:00:00 2001 From: flystar32 Date: Tue, 18 Dec 2018 20:10:58 +0800 Subject: [PATCH 3/8] add doc author , --- .../src/main/asciidoc/spring-cloud-alibaba.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/spring-cloud-alibaba.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/spring-cloud-alibaba.adoc index bbcae98b..5018c2ca 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/spring-cloud-alibaba.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/spring-cloud-alibaba.adoc @@ -1,6 +1,6 @@ [[spring-cloud-alibaba-reference]] = Spring Cloud Alibaba Reference Documentation -xiaojing; xiaolongzuo; jim fang; bingting peng +xiaojing; xiaolongzuo; jim fang; bingting peng; wangyuxin :doctype: book :toc: :toclevels: 4 From 89178bc913d03b92a03561dee18ff03b07b8edb0 Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Tue, 18 Dec 2018 21:36:14 +0800 Subject: [PATCH 4/8] update docs --- .../sentinel-core-example/readme-zh.md | 28 ++++++++++--------- .../sentinel-core-example/readme.md | 8 ++++-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md index af535e6d..bfdc599b 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md @@ -122,28 +122,30 @@ ## 自定义限流处理逻辑 -1. URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。 +* 默认限流异常处理 + +URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。 如果需要自定义处理逻辑,实现的方式如下: - ```java - public class CustomUrlBlockHandler implements UrlBlockHandler { - @Override - public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException { - // todo add your logic - } - } +```java +public class CustomUrlBlockHandler implements UrlBlockHandler { + @Override + public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException { + // todo add your logic + } +} - WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler()); - ``` +WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler()); +``` -2. 自定义限流触发后,默认的处理逻辑是抛出异常。 +* 使用 `@SentinelResource` 注解下的限流异常处理 如果需要自定义处理逻辑,填写 `@SentinelResource` 注解的 `blockHandler` 属性(针对所有类型的 `BlockException`,需自行判断)或 `fallback` 属性(针对熔断降级异常),注意**对应方法的签名和位置有限制**,详情见 [Sentinel 注解支持文档](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3)。示例实现如下: ```java public class TestService { - // blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制. + // blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制. @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class}) public void test() { System.out.println("Test"); @@ -172,7 +174,7 @@ public final class ExceptionUtil { } ``` -一个简单的示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。 +一个简单的 `@SentinelResource` 示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。 ## Endpoint 信息查看 diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md index e3135729..eb9ca2e0 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md @@ -108,7 +108,9 @@ The screenshot belows shows invoke success: ## Customize Flow Control Logic -1. When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)". +* Flow control exception handle by default + +When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)". If you want to customize your flow control logic, see the code below: @@ -123,7 +125,9 @@ The screenshot belows shows invoke success: WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler()); -2. When a custom resource is blocked by Sentinel, the default logic is throw BlockException. +* Flow control exception handle by using `@SentinelResource` + +When a custom resource is blocked by Sentinel, the default logic is throw BlockException. If you want to customize your flow control logic, implement interface `SentinelExceptionHandler`, set @SentinelResource's blockHandler() and blockHandlerClass(). See the code below: From ba101f479ed6330371f11e04807a96c22786ce1c Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Tue, 18 Dec 2018 22:20:52 +0800 Subject: [PATCH 5/8] calculate exception ratio in Sentinel RestTemplate --- .../custom/SentinelProtectInterceptor.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java index f21da49b..2bfb39e3 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java @@ -33,6 +33,7 @@ import org.springframework.util.ClassUtils; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.SphU; +import com.alibaba.csp.sentinel.Tracer; import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; @@ -69,16 +70,24 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor hostEntry = SphU.entry(hostResource); response = execution.execute(request, body); } - catch (BlockException e) { - try { - return handleBlockException(request, body, execution, e); + catch (Throwable e) { + if (!BlockException.isBlockException(e)) { + Tracer.trace(e); + throw new IllegalStateException(e); } - catch (Exception ex) { - if (ex instanceof IllegalStateException) { - throw (IllegalStateException) ex; + else { + try { + return handleBlockException(request, body, execution, + (BlockException) e); + } + catch (Exception ex) { + if (ex instanceof IllegalStateException) { + throw (IllegalStateException) ex; + } + throw new IllegalStateException( + "sentinel handle BlockException error: " + ex.getMessage(), + ex); } - throw new IllegalStateException( - "sentinel handle BlockException error: " + ex.getMessage(), ex); } } finally { From 46e4d71b22c2e6baf3613fc0fd977faeea8baf7c Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Tue, 18 Dec 2018 23:00:55 +0800 Subject: [PATCH 6/8] remove duplicate entry when request path is empty --- .../sentinel/custom/SentinelProtectInterceptor.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java index 2bfb39e3..18a895de 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java @@ -62,11 +62,17 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor String hostResource = uri.getScheme() + "://" + uri.getHost() + (uri.getPort() == -1 ? "" : ":" + uri.getPort()); String hostWithPathResource = hostResource + uri.getPath(); + boolean entryWithPath = true; + if (hostResource.equals(hostWithPathResource)) { + entryWithPath = false; + } Entry hostEntry = null, hostWithPathEntry = null; ClientHttpResponse response; try { - ContextUtil.enter(hostWithPathResource); - hostWithPathEntry = SphU.entry(hostWithPathResource); + ContextUtil.enter(hostResource); + if (entryWithPath) { + hostWithPathEntry = SphU.entry(hostWithPathResource); + } hostEntry = SphU.entry(hostResource); response = execution.execute(request, body); } From 179a517e2d00b14ff79c5d07cf426cc37b47ee6b Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Tue, 18 Dec 2018 23:27:31 +0800 Subject: [PATCH 7/8] using resource with path in Context --- .../alibaba/sentinel/custom/SentinelProtectInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java index 18a895de..a1ab9e22 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java @@ -69,7 +69,7 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor Entry hostEntry = null, hostWithPathEntry = null; ClientHttpResponse response; try { - ContextUtil.enter(hostResource); + ContextUtil.enter(hostWithPathResource); if (entryWithPath) { hostWithPathEntry = SphU.entry(hostWithPathResource); } From 452fa5c5643dcbdcc58d92103dab95fb038985bd Mon Sep 17 00:00:00 2001 From: flystar32 Date: Wed, 19 Dec 2018 15:38:50 +0800 Subject: [PATCH 8/8] update ACM listener logic and publish a refresh event instead of invoke refresh method --- .../acm/refresh/AcmContextRefresher.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmContextRefresher.java b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmContextRefresher.java index a6115912..617c8806 100644 --- a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmContextRefresher.java +++ b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/refresh/AcmContextRefresher.java @@ -25,11 +25,14 @@ import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository; -import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource; import org.springframework.cloud.alicloud.context.acm.AcmIntegrationProperties; import org.springframework.cloud.context.refresh.ContextRefresher; +import org.springframework.cloud.endpoint.event.RefreshEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; import org.springframework.util.StringUtils; @@ -43,7 +46,8 @@ import com.alibaba.edas.acm.listener.ConfigChangeListener; * * @author juven.xuxb, 5/13/16. */ -public class AcmContextRefresher implements ApplicationListener { +public class AcmContextRefresher + implements ApplicationListener, ApplicationContextAware { private Logger logger = LoggerFactory.getLogger(AcmContextRefresher.class); @@ -53,6 +57,8 @@ public class AcmContextRefresher implements ApplicationListener listenerMap = new ConcurrentHashMap<>(16); @@ -74,19 +80,10 @@ public class AcmContextRefresher implements ApplicationListener