diff --git a/README.md b/README.md index cbd11f8d..89729d08 100755 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ try { } ``` -So far the code modification is done. +So far the code modification is done. We also provide [annotation support module](https://github.com/alibaba/Sentinel/blob/master/sentinel-extension/sentinel-annotation-aspectj/README.md) to define resource easier. ### 3. Define Rules @@ -93,6 +93,8 @@ rules.add(rule); FlowRuleManager.loadRules(rules); ``` +For more information, please refer to [How To Use](https://github.com/alibaba/Sentinel/wiki/How-to-Use). + ### 4. Check the Result After running the demo for a while, you can see the following records in `~/logs/csp/${appName}-metrics.log`. @@ -144,3 +146,12 @@ These are only part of the companies using Sentinel, for reference only. If you ![Taiping Renshou](http://www.cntaiping.com/tplresource/cms/www/taiping/img/home_new/tp_logo_img.png) ![Shunfeng Technology](https://user-images.githubusercontent.com/9434884/48463502-2f48eb80-e817-11e8-984f-2f9b1b789e2d.png) ![Mandao](https://user-images.githubusercontent.com/9434884/48463559-6cad7900-e817-11e8-87e4-42952b074837.png) +![每日优鲜](https://home.missfresh.cn/statics/img/logo.png) +![二维火](https://user-images.githubusercontent.com/9434884/49358468-bc43de00-f70d-11e8-97fe-0bf05865f29f.png) +![文轩在线](http://static.winxuancdn.com/css/v2/images/logo.png) +![客如云](https://www.keruyun.com/static/krynew/images/logo.png) +![亲宝宝](https://stlib.qbb6.com/wclt/img/home_hd/version1/title_logo.png) +![杭州光云科技](https://www.raycloud.com/images/logo.png) +![金汇金融](https://res.jinhui365.com/r/images/logo2.png?v=1.527) +![Vivo](https://user-images.githubusercontent.com/9434884/49355264-c6f87600-f701-11e8-8109-054cf91df868.png) +![闪电购](http://cdn.52shangou.com/shandianbang/official-source/3.1.1/build/images/logo.png) diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java index 76b25381..f24bbe55 100755 --- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java +++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java @@ -46,17 +46,23 @@ import com.alibaba.csp.sentinel.util.StringUtil; */ public class CommonFilter implements Filter { + private final static String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY"; + private final static String COLON = ":"; + private boolean httpMethodSpecify = false; + @Override public void init(FilterConfig filterConfig) { - + httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter(HTTP_METHOD_SPECIFY)); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - HttpServletRequest sRequest = (HttpServletRequest)request; + throws IOException, ServletException { + HttpServletRequest sRequest = (HttpServletRequest) request; Entry entry = null; + Entry methodEntry = null; + try { String target = FilterUtil.filterTarget(sRequest); // Clean and unify the URL. @@ -73,9 +79,16 @@ public class CommonFilter implements Filter { ContextUtil.enter(target, origin); entry = SphU.entry(target, EntryType.IN); + + // Add method specification if necessary + if (httpMethodSpecify) { + methodEntry = SphU.entry(sRequest.getMethod().toUpperCase() + COLON + target, + EntryType.IN); + } + chain.doFilter(request, response); } catch (BlockException e) { - HttpServletResponse sResponse = (HttpServletResponse)response; + HttpServletResponse sResponse = (HttpServletResponse) response; // Return the block page, or redirect to another URL. WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); } catch (IOException e2) { @@ -88,6 +101,9 @@ public class CommonFilter implements Filter { Tracer.trace(e4); throw e4; } finally { + if (methodEntry != null) { + methodEntry.exit(); + } if (entry != null) { entry.exit(); } diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java index 2602f17d..14e8b2a1 100644 --- a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java +++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilterTest.java @@ -171,6 +171,6 @@ public class CommonFilterTest { @After public void cleanUp() { FlowRuleManager.loadRules(null); - ClusterBuilderSlot.getClusterNodeMap().clear(); + ClusterBuilderSlot.resetClusterNodes(); } } diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/CommonFilterMethodTest.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/CommonFilterMethodTest.java new file mode 100644 index 00000000..3df4c7d5 --- /dev/null +++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/CommonFilterMethodTest.java @@ -0,0 +1,133 @@ +/* + * 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.adapter.servletmethod; + +import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; +import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; +import com.alibaba.csp.sentinel.node.ClusterNode; +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.slots.clusterbuilder.ClusterBuilderSlot; +import com.alibaba.csp.sentinel.util.StringUtil; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.Collections; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * @author Roger Law + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +public class CommonFilterMethodTest { + + private static final String HELLO_STR = "Hello!"; + + private static final String HELLO_POST_STR = "Hello Post!"; + + private static final String GET = "GET"; + + private static final String POST = "POST"; + + private static final String COLON = ":"; + + @Autowired + private MockMvc mvc; + + private void configureRulesFor(String resource, int count) { + configureRulesFor(resource, count, "default"); + } + + private void configureRulesFor(String resource, int count, String limitApp) { + FlowRule rule = new FlowRule() + .setCount(count) + .setGrade(RuleConstant.FLOW_GRADE_QPS); + rule.setResource(resource); + if (StringUtil.isNotBlank(limitApp)) { + rule.setLimitApp(limitApp); + } + FlowRuleManager.loadRules(Collections.singletonList(rule)); + } + + @Test + public void testCommonFilterMiscellaneous() throws Exception { + String url = "/hello"; + this.mvc.perform(get(url)) + .andExpect(status().isOk()) + .andExpect(content().string(HELLO_STR)); + + ClusterNode cnGet = ClusterBuilderSlot.getClusterNode(GET + COLON + url); + assertNotNull(cnGet); + assertEquals(1, cnGet.passQps()); + + + ClusterNode cnPost = ClusterBuilderSlot.getClusterNode(POST + COLON + url); + assertNull(cnPost); + + this.mvc.perform(post(url)) + .andExpect(status().isOk()) + .andExpect(content().string(HELLO_POST_STR)); + + cnPost = ClusterBuilderSlot.getClusterNode(POST + COLON + url); + assertNotNull(cnPost); + assertEquals(1, cnPost.passQps()); + + testCommonBlockAndRedirectBlockPage(url, cnGet, cnPost); + + } + + private void testCommonBlockAndRedirectBlockPage(String url, ClusterNode cnGet, ClusterNode cnPost) throws Exception { + configureRulesFor(GET + ":" + url, 0); + // The request will be blocked and response is default block message. + this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isOk()) + .andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); + assertEquals(1, cnGet.blockQps()); + + // Test for post pass + this.mvc.perform(post(url)) + .andExpect(status().isOk()) + .andExpect(content().string(HELLO_POST_STR)); + + assertEquals(2, cnPost.passQps()); + + + FlowRuleManager.loadRules(null); + WebServletConfig.setBlockPage(""); + } + + + @After + public void cleanUp() { + FlowRuleManager.loadRules(null); + ClusterBuilderSlot.resetClusterNodes(); + } +} diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/FilterMethodConfig.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/FilterMethodConfig.java new file mode 100644 index 00000000..d2c9d21f --- /dev/null +++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/FilterMethodConfig.java @@ -0,0 +1,25 @@ +package com.alibaba.csp.sentinel.adapter.servletmethod; + +import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author: Roger Law + **/ +@Configuration +public class FilterMethodConfig { + + @Bean + public FilterRegistrationBean sentinelFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new CommonFilter()); + registration.addUrlPatterns("/*"); + registration.addInitParameter("HTTP_METHOD_SPECIFY", "true"); + registration.setName("sentinelFilter"); + registration.setOrder(1); + + return registration; + } +} diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/TestApplication.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/TestApplication.java new file mode 100644 index 00000000..745d79a0 --- /dev/null +++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/TestApplication.java @@ -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.adapter.servletmethod; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author Eric Zhao + */ +@SpringBootApplication +public class TestApplication { + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } +} diff --git a/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/TestMethodController.java b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/TestMethodController.java new file mode 100644 index 00000000..04b08b40 --- /dev/null +++ b/sentinel-adapter/sentinel-web-servlet/src/test/java/com/alibaba/csp/sentinel/adapter/servletmethod/TestMethodController.java @@ -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.adapter.servletmethod; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Roger Law + */ +@RestController +public class TestMethodController { + + @GetMapping("/hello") + public String apiHello() { + return "Hello!"; + } + + @PostMapping("/hello") + public String apiHelloPost() { + return "Hello Post!"; + } + +} diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterTokenClient.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterTokenClient.java new file mode 100644 index 00000000..6a230c07 --- /dev/null +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterTokenClient.java @@ -0,0 +1,32 @@ +/* + * 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.cluster; + +/** + * Token client interface for distributed flow control. + * + * @author Eric Zhao + * @since 1.4.0 + */ +public interface ClusterTokenClient extends TokenService { + + /** + * Get descriptor of current token server. + * + * @return current token server + */ + TokenServerDescriptor currentServer(); +} \ No newline at end of file diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/TokenClientProvider.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/TokenClientProvider.java new file mode 100644 index 00000000..592046c9 --- /dev/null +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/TokenClientProvider.java @@ -0,0 +1,61 @@ +/* + * 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.cluster; + +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +import com.alibaba.csp.sentinel.log.RecordLog; + +/** + * Provider for a universal {@link ClusterTokenClient} instance. + * + * @author Eric Zhao + * @since 1.4.0 + */ +public final class TokenClientProvider { + + private static ClusterTokenClient client = null; + + private static final ServiceLoader LOADER = ServiceLoader.load(ClusterTokenClient.class); + + static { + // Not strictly thread-safe, but it's OK since it will be resolved only once. + resolveTokenClientInstance(); + } + + public static ClusterTokenClient getClient() { + return client; + } + + private static void resolveTokenClientInstance() { + List clients = new ArrayList(); + for (ClusterTokenClient client : LOADER) { + clients.add(client); + } + + if (!clients.isEmpty()) { + // Get first. + client = clients.get(0); + RecordLog.info("[TokenClientProvider] Token client resolved: " + client.getClass().getCanonicalName()); + } else { + RecordLog.warn("[TokenClientProvider] No existing token client, resolve failed"); + } + } + + private TokenClientProvider() {} +} diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/log/ClusterStatLogUtil.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/log/ClusterStatLogUtil.java new file mode 100644 index 00000000..16f914c6 --- /dev/null +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/log/ClusterStatLogUtil.java @@ -0,0 +1,59 @@ +/* + * 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.cluster.log; + +import java.io.File; + +import com.alibaba.csp.sentinel.eagleeye.EagleEye; +import com.alibaba.csp.sentinel.eagleeye.StatLogger; +import com.alibaba.csp.sentinel.log.LogBase; + +/** + * @author jialiang.linjl + * @author Eric Zhao + * @since 1.4.0 + */ +public final class ClusterStatLogUtil { + + private static final String FILE_NAME = "sentinel-cluster.log"; + + private static StatLogger statLogger; + + static { + String path = LogBase.getLogBaseDir() + FILE_NAME; + + statLogger = EagleEye.statLoggerBuilder("sentinel-cluster-record") + .intervalSeconds(1) + .entryDelimiter('|') + .keyDelimiter(',') + .valueDelimiter(',') + .maxEntryCount(5000) + .configLogFilePath(path) + .maxFileSizeMB(300) + .maxBackupIndex(3) + .buildSingleton(); + } + + public static void log(String msg) { + statLogger.stat(msg).count(); + } + + public static void log(String msg, int count) { + statLogger.stat(msg).count(count); + } + + private ClusterStatLogUtil() {} +} diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/Node.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/Node.java index f836ae0b..edf9be03 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/Node.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/Node.java @@ -26,6 +26,7 @@ import com.alibaba.csp.sentinel.node.metric.MetricNode; * @author qinan.qn * @author leyou * @author Eric Zhao + * @author leitao */ public interface Node { @@ -147,7 +148,7 @@ public interface Node { void increaseThreadNum(); /** - * Increase current thread count. + * Decrease current thread count. */ void decreaseThreadNum(); diff --git a/sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/metric.js b/sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/metric.js index ebb810f8..7986d2f6 100755 --- a/sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/metric.js +++ b/sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/metric.js @@ -68,7 +68,7 @@ app.controller('MetricCtl', ['$scope', '$stateParams', 'MetricService', '$interv forceFit: true, width: 100, height: 250, - padding: [10, 30, 70, 30] + padding: [10, 30, 70, 50] }); var maxQps = 0; for (var i in metric.data) { diff --git a/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.js b/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.js index 45ed9fab..ce1a9030 100755 --- a/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.js +++ b/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.js @@ -33,16 +33,14 @@ angular.module('sentinelDashboardApp') // toggle side bar $scope.click = function ($event) { - let element = angular.element($event.target); let entry = angular.element($event.target).scope().entry; - entry.active = !entry.active; + entry.active = !entry.active;// toggle this clicked app bar - if (entry.active === false) { - element.parent().children('ul').hide(); - } else { - element.parent().parent().children('li').children('ul').hide(); - element.parent().children('ul').show(); - } + $scope.apps.forEach(function (item) {// collapse other app bars + if (item != entry) { + item.active = false; + } + }); }; /** diff --git a/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/transport/config/TransportConfig.java b/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/transport/config/TransportConfig.java index 5f934a98..ab150175 100755 --- a/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/transport/config/TransportConfig.java +++ b/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/transport/config/TransportConfig.java @@ -16,6 +16,8 @@ package com.alibaba.csp.sentinel.transport.config; import com.alibaba.csp.sentinel.config.SentinelConfig; +import com.alibaba.csp.sentinel.util.HostNameUtil; +import com.alibaba.csp.sentinel.util.StringUtil; /** * @author leyou @@ -25,6 +27,7 @@ public class TransportConfig { public static final String CONSOLE_SERVER = "csp.sentinel.dashboard.server"; public static final String SERVER_PORT = "csp.sentinel.api.port"; public static final String HEARTBEAT_INTERVAL_MS = "csp.sentinel.heartbeat.interval.ms"; + public static final String HEARTBEAT_CLIENT_IP = "csp.sentinel.heartbeat.client.ip"; private static int runtimePort = -1; @@ -66,4 +69,18 @@ public class TransportConfig { public static void setRuntimePort(int port) { runtimePort = port; } + + /** + * Get heartbeat client local ip. + * If the client ip not configured,it will be the address of local host + * + * @return the local ip. + */ + public static String getHeartbeatClientIp() { + String ip = SentinelConfig.getConfig(HEARTBEAT_CLIENT_IP); + if (StringUtil.isBlank(ip)) { + ip = HostNameUtil.getIp(); + } + return ip; + } } diff --git a/sentinel-transport/sentinel-transport-common/src/test/java/com/alibaba/csp/sentinel/transport/config/TransportConfigTest.java b/sentinel-transport/sentinel-transport-common/src/test/java/com/alibaba/csp/sentinel/transport/config/TransportConfigTest.java new file mode 100644 index 00000000..d35c77fa --- /dev/null +++ b/sentinel-transport/sentinel-transport-common/src/test/java/com/alibaba/csp/sentinel/transport/config/TransportConfigTest.java @@ -0,0 +1,25 @@ +package com.alibaba.csp.sentinel.transport.config; + +import com.alibaba.csp.sentinel.config.SentinelConfig; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class TransportConfigTest { + + @Test + public void getClientIp() { + //config heartbeat client ip + System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP, "10.10.10.10"); + String ip = TransportConfig.getHeartbeatClientIp(); + + assertNotNull(ip); + assertEquals(ip, "10.10.10.10"); + + //no heartbeat client ip + SentinelConfig.setConfig(TransportConfig.HEARTBEAT_CLIENT_IP, ""); + ip = TransportConfig.getHeartbeatClientIp(); + assertNotNull(ip); + + } +} \ No newline at end of file diff --git a/sentinel-transport/sentinel-transport-netty-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HttpHeartbeatSender.java b/sentinel-transport/sentinel-transport-netty-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HttpHeartbeatSender.java index f92e4744..090cd09b 100755 --- a/sentinel-transport/sentinel-transport-netty-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HttpHeartbeatSender.java +++ b/sentinel-transport/sentinel-transport-netty-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HttpHeartbeatSender.java @@ -85,7 +85,7 @@ public class HttpHeartbeatSender implements HeartbeatSender { .setParameter("v", Constants.SENTINEL_VERSION) .setParameter("version", String.valueOf(System.currentTimeMillis())) .setParameter("hostname", HostNameUtil.getHostName()) - .setParameter("ip", HostNameUtil.getIp()) + .setParameter("ip", TransportConfig.getHeartbeatClientIp()) .setParameter("port", TransportConfig.getPort()) .setParameter("pid", String.valueOf(PidUtil.getPid())); diff --git a/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/command/SimpleHttpCommandCenter.java b/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/command/SimpleHttpCommandCenter.java index 193d844b..76a361aa 100755 --- a/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/command/SimpleHttpCommandCenter.java +++ b/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/command/SimpleHttpCommandCenter.java @@ -19,11 +19,11 @@ import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; -import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -53,7 +53,7 @@ public class SimpleHttpCommandCenter implements CommandCenter { private static final int DEFAULT_PORT = 8719; @SuppressWarnings("rawtypes") - private static final Map handlerMap = new HashMap(); + private static final Map handlerMap = new ConcurrentHashMap(); private ExecutorService executor = Executors.newSingleThreadExecutor( new NamedThreadFactory("sentinel-command-center-executor")); @@ -105,12 +105,14 @@ public class SimpleHttpCommandCenter implements CommandCenter { executor.submit(new ServerThread(serverSocket)); success = true; port = serverSocket.getLocalPort(); + } else { + CommandCenterLog.info("[CommandCenter] chooses port fail, http command center will not work"); } if (!success) { port = PORT_UNINITIALIZED; } - + TransportConfig.setRuntimePort(port); executor.shutdown(); } @@ -119,11 +121,11 @@ public class SimpleHttpCommandCenter implements CommandCenter { new Thread(serverInitTask).start(); } - + /** * Get a server socket from an available port from a base port.
* Increasing on port number will occur when the port has already been used. - * + * * @param basePort base port to start * @return new socket with available port */ @@ -135,7 +137,7 @@ public class SimpleHttpCommandCenter implements CommandCenter { server.setReuseAddress(true); return server; } catch (IOException e) { - tryCount ++; + tryCount++; try { TimeUnit.MILLISECONDS.sleep(30); } catch (InterruptedException e1) { diff --git a/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HeartbeatMessage.java b/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HeartbeatMessage.java index 8292c7a3..5695632c 100755 --- a/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HeartbeatMessage.java +++ b/sentinel-transport/sentinel-transport-simple-http/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/HeartbeatMessage.java @@ -36,7 +36,7 @@ public class HeartbeatMessage { public HeartbeatMessage() { message.put("hostname", HostNameUtil.getHostName()); - message.put("ip", HostNameUtil.getIp()); + message.put("ip", TransportConfig.getHeartbeatClientIp()); message.put("app", AppNameUtil.getAppName()); message.put("port", String.valueOf(TransportConfig.getPort())); }