Merge branch 'master' into feature/cluster-flow-control
This commit is contained in:
commit
465b44b7e7
13
README.md
13
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
|
### 3. Define Rules
|
||||||
|
|
||||||
|
|
@ -93,6 +93,8 @@ rules.add(rule);
|
||||||
FlowRuleManager.loadRules(rules);
|
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
|
### 4. Check the Result
|
||||||
|
|
||||||
After running the demo for a while, you can see the following records in `~/logs/csp/${appName}-metrics.log`.
|
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
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,13 @@ import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
*/
|
*/
|
||||||
public class CommonFilter implements Filter {
|
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
|
@Override
|
||||||
public void init(FilterConfig filterConfig) {
|
public void init(FilterConfig filterConfig) {
|
||||||
|
httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter(HTTP_METHOD_SPECIFY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -57,6 +61,8 @@ public class CommonFilter implements Filter {
|
||||||
HttpServletRequest sRequest = (HttpServletRequest) request;
|
HttpServletRequest sRequest = (HttpServletRequest) request;
|
||||||
Entry entry = null;
|
Entry entry = null;
|
||||||
|
|
||||||
|
Entry methodEntry = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String target = FilterUtil.filterTarget(sRequest);
|
String target = FilterUtil.filterTarget(sRequest);
|
||||||
// Clean and unify the URL.
|
// Clean and unify the URL.
|
||||||
|
|
@ -73,6 +79,13 @@ public class CommonFilter implements Filter {
|
||||||
ContextUtil.enter(target, origin);
|
ContextUtil.enter(target, origin);
|
||||||
entry = SphU.entry(target, EntryType.IN);
|
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);
|
chain.doFilter(request, response);
|
||||||
} catch (BlockException e) {
|
} catch (BlockException e) {
|
||||||
HttpServletResponse sResponse = (HttpServletResponse) response;
|
HttpServletResponse sResponse = (HttpServletResponse) response;
|
||||||
|
|
@ -88,6 +101,9 @@ public class CommonFilter implements Filter {
|
||||||
Tracer.trace(e4);
|
Tracer.trace(e4);
|
||||||
throw e4;
|
throw e4;
|
||||||
} finally {
|
} finally {
|
||||||
|
if (methodEntry != null) {
|
||||||
|
methodEntry.exit();
|
||||||
|
}
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entry.exit();
|
entry.exit();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,6 @@ public class CommonFilterTest {
|
||||||
@After
|
@After
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
FlowRuleManager.loadRules(null);
|
FlowRuleManager.loadRules(null);
|
||||||
ClusterBuilderSlot.getClusterNodeMap().clear();
|
ClusterBuilderSlot.resetClusterNodes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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!";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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<ClusterTokenClient> 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<ClusterTokenClient> clients = new ArrayList<ClusterTokenClient>();
|
||||||
|
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() {}
|
||||||
|
}
|
||||||
|
|
@ -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() {}
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ import com.alibaba.csp.sentinel.node.metric.MetricNode;
|
||||||
* @author qinan.qn
|
* @author qinan.qn
|
||||||
* @author leyou
|
* @author leyou
|
||||||
* @author Eric Zhao
|
* @author Eric Zhao
|
||||||
|
* @author leitao
|
||||||
*/
|
*/
|
||||||
public interface Node {
|
public interface Node {
|
||||||
|
|
||||||
|
|
@ -147,7 +148,7 @@ public interface Node {
|
||||||
void increaseThreadNum();
|
void increaseThreadNum();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase current thread count.
|
* Decrease current thread count.
|
||||||
*/
|
*/
|
||||||
void decreaseThreadNum();
|
void decreaseThreadNum();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ app.controller('MetricCtl', ['$scope', '$stateParams', 'MetricService', '$interv
|
||||||
forceFit: true,
|
forceFit: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 250,
|
height: 250,
|
||||||
padding: [10, 30, 70, 30]
|
padding: [10, 30, 70, 50]
|
||||||
});
|
});
|
||||||
var maxQps = 0;
|
var maxQps = 0;
|
||||||
for (var i in metric.data) {
|
for (var i in metric.data) {
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,14 @@ angular.module('sentinelDashboardApp')
|
||||||
|
|
||||||
// toggle side bar
|
// toggle side bar
|
||||||
$scope.click = function ($event) {
|
$scope.click = function ($event) {
|
||||||
let element = angular.element($event.target);
|
|
||||||
let entry = angular.element($event.target).scope().entry;
|
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) {
|
$scope.apps.forEach(function (item) {// collapse other app bars
|
||||||
element.parent().children('ul').hide();
|
if (item != entry) {
|
||||||
} else {
|
item.active = false;
|
||||||
element.parent().parent().children('li').children('ul').hide();
|
|
||||||
element.parent().children('ul').show();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
package com.alibaba.csp.sentinel.transport.config;
|
package com.alibaba.csp.sentinel.transport.config;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||||
|
import com.alibaba.csp.sentinel.util.HostNameUtil;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author leyou
|
* @author leyou
|
||||||
|
|
@ -25,6 +27,7 @@ public class TransportConfig {
|
||||||
public static final String CONSOLE_SERVER = "csp.sentinel.dashboard.server";
|
public static final String CONSOLE_SERVER = "csp.sentinel.dashboard.server";
|
||||||
public static final String SERVER_PORT = "csp.sentinel.api.port";
|
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_INTERVAL_MS = "csp.sentinel.heartbeat.interval.ms";
|
||||||
|
public static final String HEARTBEAT_CLIENT_IP = "csp.sentinel.heartbeat.client.ip";
|
||||||
|
|
||||||
private static int runtimePort = -1;
|
private static int runtimePort = -1;
|
||||||
|
|
||||||
|
|
@ -66,4 +69,18 @@ public class TransportConfig {
|
||||||
public static void setRuntimePort(int port) {
|
public static void setRuntimePort(int port) {
|
||||||
runtimePort = 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ public class HttpHeartbeatSender implements HeartbeatSender {
|
||||||
.setParameter("v", Constants.SENTINEL_VERSION)
|
.setParameter("v", Constants.SENTINEL_VERSION)
|
||||||
.setParameter("version", String.valueOf(System.currentTimeMillis()))
|
.setParameter("version", String.valueOf(System.currentTimeMillis()))
|
||||||
.setParameter("hostname", HostNameUtil.getHostName())
|
.setParameter("hostname", HostNameUtil.getHostName())
|
||||||
.setParameter("ip", HostNameUtil.getIp())
|
.setParameter("ip", TransportConfig.getHeartbeatClientIp())
|
||||||
.setParameter("port", TransportConfig.getPort())
|
.setParameter("port", TransportConfig.getPort())
|
||||||
.setParameter("pid", String.valueOf(PidUtil.getPid()));
|
.setParameter("pid", String.valueOf(PidUtil.getPid()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
@ -53,7 +53,7 @@ public class SimpleHttpCommandCenter implements CommandCenter {
|
||||||
private static final int DEFAULT_PORT = 8719;
|
private static final int DEFAULT_PORT = 8719;
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static final Map<String, CommandHandler> handlerMap = new HashMap<String, CommandHandler>();
|
private static final Map<String, CommandHandler> handlerMap = new ConcurrentHashMap<String, CommandHandler>();
|
||||||
|
|
||||||
private ExecutorService executor = Executors.newSingleThreadExecutor(
|
private ExecutorService executor = Executors.newSingleThreadExecutor(
|
||||||
new NamedThreadFactory("sentinel-command-center-executor"));
|
new NamedThreadFactory("sentinel-command-center-executor"));
|
||||||
|
|
@ -105,6 +105,8 @@ public class SimpleHttpCommandCenter implements CommandCenter {
|
||||||
executor.submit(new ServerThread(serverSocket));
|
executor.submit(new ServerThread(serverSocket));
|
||||||
success = true;
|
success = true;
|
||||||
port = serverSocket.getLocalPort();
|
port = serverSocket.getLocalPort();
|
||||||
|
} else {
|
||||||
|
CommandCenterLog.info("[CommandCenter] chooses port fail, http command center will not work");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ public class HeartbeatMessage {
|
||||||
|
|
||||||
public HeartbeatMessage() {
|
public HeartbeatMessage() {
|
||||||
message.put("hostname", HostNameUtil.getHostName());
|
message.put("hostname", HostNameUtil.getHostName());
|
||||||
message.put("ip", HostNameUtil.getIp());
|
message.put("ip", TransportConfig.getHeartbeatClientIp());
|
||||||
message.put("app", AppNameUtil.getAppName());
|
message.put("app", AppNameUtil.getAppName());
|
||||||
message.put("port", String.valueOf(TransportConfig.getPort()));
|
message.put("port", String.valueOf(TransportConfig.getPort()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue