jmeter interface test
jmeter.bat startup file
jmeter.properties configuration file
Modify the configuration file to Chinese
Interface test
Modify the maximum number of threads in tomcat
server: port: 8091 tomcat: max-threads: 10
Start test
Sentinel service
Dependency injection
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
Monitoring platform jar Download
Start command
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar
Access link http://localhost:8080/
The account password is sentinel by default
Modify configuration
spring: cloud: sentinel: transport: port: 9999 #The port for communicating with the console can be arbitrarily specified as an unused port dashboard: localhost:8080 #Specify the address of the console service
Because sentinel console is soft loaded, data display can only be performed after accessing the interface
The console implements interface flow control
sentinel rule
Flow control rules
Direct flow control mode
- Direct flow control mode is the simplest mode. When the specified interface reaches the current limiting conditions, the current limiting is turned on
Associated flow control mode
- Associated flow control mode means that when the interface associated with the specified interface reaches the current limiting condition, the current limiting is enabled for the specified interface.
- The association in the flow control mode can make other requested services reach the threshold, and this service can flow control.
link
The first way
<spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version>
@Override //Define the resource, and value specifies the resource name @SentinelResource("message") public String message() { return "message"; }
@GetMapping("/message1") public String message1() { return orderService.message(); } @GetMapping("/message2") public String message2() { return orderService.message(); }
Modify the configuration and add filter enabled=false
spring: cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: port: 9999 #The port for communicating with the console can be arbitrarily specified as an unused port dashboard: localhost:8080 #Specify the address of the console service filter: enabled: false
Add profile
@Configuration public class FilterContextConfig { @Bean public FilterRegistrationBean sentinelFilterRegistration(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new CommonFilter()); registrationBean.addUrlPatterns("/*"); //Portal resource close aggregation registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false"); registrationBean.setName("sentinelFilter"); registrationBean.setOrder(1); return registrationBean; } }
The second way
<spring-cloud-alibaba.version>2.1.3.RELEASE</spring-cloud-alibaba.version>
Modify configuration
server: port: 8091 spring: application: name: service-order cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: port: 9999 #The port for communicating with the console can be arbitrarily specified as an unused port dashboard: localhost:8080 #Specify the address of the console service web-context-unify: false
Flow control effect
Degradation rule
Hotspot rule
Hotspot parameter flow control rule is a more fine-grained flow control rule, which allows rules to be specific to parameters
@GetMapping("/message3") //This annotation must be used, otherwise the hotspot rule will not work @SentinelResource("message3") public String message3(String name, Integer age) { return "message3" + name + age; }
The second parameter age is limited. When age is 15, the lifting threshold is 1000
Authorization rules
@Component public class RequestOriginParserDefinition implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest httpServletRequest) { String serviceName = httpServletRequest.getParameter("serviceName"); return serviceName; } }
System rules
Custom exception return
@Component public class ExceptionHandlerPage implements UrlBlockHandler { @Override public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException { httpServletResponse.setContentType("application/json;charset=utf-8"); ResponseData responseData = null; if (e instanceof FlowException) { responseData = new ResponseData(-1, "The interface is current limited"); } else if (e instanceof DegradeException) { responseData = new ResponseData(-2, "The interface has been degraded"); } else if (e instanceof ParamFlowException) { responseData = new ResponseData(-3, "Interface current limited by parameters"); } else if (e instanceof AuthorityException) { responseData = new ResponseData(-4, "Interface authorization exception"); } else if (e instanceof SystemBlockException) { responseData = new ResponseData(-5, "Abnormal system load"); } else { responseData = new ResponseData(-6, e.toString()); } httpServletResponse.getWriter().write(JSON.toJSONString(responseData)); } } @Data @AllArgsConstructor @NoArgsConstructor @ToString class ResponseData { private int code; private String message; }
@SentinelResource
usage method
/** * value Define a resource * blockHandler Defines the method that should be entered when BlockException occurs inside the resource * fallback Define the method that should be entered when Throwable occurs inside the resource */ @SentinelResource( value = "message2", blockHandler = "blockHandler", fallback = "fallback" ) public String message2(String message) { return message; } /** * The return value and parameters of the current method should be consistent with the original method * It is allowed to add a BlockException parameter at the end of the parameter list to receive exceptions in the original method */ public String blockHandler(String message, BlockException e){ return "blockException"; } public String fallback(String message, Throwable e){ return "throwable"; }
Use class
@SentinelResource( value = "message2", blockHandlerClass = OrderServiceImplBlockHandler.class, blockHandler = "blockHandler", fallbackClass = OrderServiceImplFallback.class, fallback = "fallback" ) public String message2(String message) { return message; }
public class OrderServiceImplBlockHandler { public static String blockHandler(String message, BlockException e){ return "blockException"; } }
public class OrderServiceImplFallback { public static String fallback(String message, Throwable e){ return "throwable"; } }
Rule persistence
Common implementations of DataSource extension include:
- Pull mode: the client actively polls a rule management center regularly for pull rules, which can be RDBMS, files, or even VCS. The way to do this is simple, but the disadvantage is that changes cannot be obtained in time.
- Push mode: the rule center pushes uniformly, and the client monitors changes at any time by registering a listener, such as using Nacos and Zookeeper
And other configuration centers. This method has better real-time and consistency guarantee.
Sentinel currently supports the following data source extensions:
- Pull based: file, Consul
- Push-based: ZooKeeper, Redis, Nacos, Apollo, etcd
Pull mode
Principle:
- Extended writeable data source: the client actively polls and pulls rules from a rule management center, which can be RDBMS and files
Wait. - The data sources of pull mode (such as local files, RDBMS, etc.) are generally writable. When using, you need to register the data source at the client: register the corresponding read data source with the corresponding
RuleManager to register the write data source in the writabledatasourcerregistry of transport.
Import dependency
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-extension</artifactId> </dependency>
Add file
import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler; import com.alibaba.csp.sentinel.datasource.*; import com.alibaba.csp.sentinel.init.InitFunc; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager; 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.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager; import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.slots.system.SystemRuleManager; import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import java.io.File; import java.io.IOException; import java.util.List; /** * FileDataSourceInit for : Custom Sentinel storage file data source load class */ public class FileDataSourceInit implements InitFunc { @Override public void init() throws Exception { // TIPS: if you don't like this path, you can change it to the path you like String ruleDir = System.getProperty("user.home") + "/sentinel/rules"; String flowRulePath = ruleDir + "/flow-rule.json"; String degradeRulePath = ruleDir + "/degrade-rule.json"; String systemRulePath = ruleDir + "/system-rule.json"; String authorityRulePath = ruleDir + "/authority-rule.json"; String hotParamFlowRulePath = ruleDir + "/param-flow-rule.json"; this.mkdirIfNotExits(ruleDir); this.createFileIfNotExits(flowRulePath); this.createFileIfNotExits(degradeRulePath); this.createFileIfNotExits(systemRulePath); this.createFileIfNotExits(authorityRulePath); this.createFileIfNotExits(hotParamFlowRulePath); // Flow control rules ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>( flowRulePath, flowRuleListParser ); // Register a readable data source with FlowRuleManager // In this way, when the rule file changes, the rules will be updated to memory FlowRuleManager.register2Property(flowRuleRDS.getProperty()); WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>( flowRulePath, this::encodeJson ); // Register the writable data source in the writabledatasourcerregistry of the transport module // In this way, when the rules pushed by the console are received, Sentinel will first update them to memory, and then write the rules to the file WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); // Degradation rule ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>( degradeRulePath, degradeRuleListParser ); DegradeRuleManager.register2Property(degradeRuleRDS.getProperty()); WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>( degradeRulePath, this::encodeJson ); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); // System rules ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>( systemRulePath, systemRuleListParser ); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>( systemRulePath, this::encodeJson ); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); // Authorization rules ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>( flowRulePath, authorityRuleListParser ); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>( authorityRulePath, this::encodeJson ); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); // Hotspot parameter rule ReadableDataSource<String, List<ParamFlowRule>> hotParamFlowRuleRDS = new FileRefreshableDataSource<>( hotParamFlowRulePath, hotParamFlowRuleListParser ); ParamFlowRuleManager.register2Property(hotParamFlowRuleRDS.getProperty()); WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>( hotParamFlowRulePath, this::encodeJson ); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); } /** * Flow control rule object conversion */ private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<FlowRule>>() { } ); /** * Degradation rule object conversion */ private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<DegradeRule>>() { } ); /** * System rule object conversion */ private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<SystemRule>>() { } ); /** * Authorization rule object conversion */ private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<AuthorityRule>>() { } ); /** * Hotspot rule object conversion */ private Converter<String, List<ParamFlowRule>> hotParamFlowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<ParamFlowRule>>() { } ); /** * Create directory * * @param filePath */ private void mkdirIfNotExits(String filePath) { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } /** * create a file * * @param filePath * @throws IOException */ private void createFileIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } } private <T> String encodeJson(T t) { return JSON.toJSONString(t); } }
Create the resources/META-INF/services directory under the resources directory and create the file com alibaba. csp. sentinel. init. Initfunc, which reads:
pre.cg.config.FileDataSourceInit
Advantages and disadvantages of Pull
- advantage
- Simple without any dependency
- No additional dependencies
- shortcoming
- Consistency is not guaranteed (the rule is to use FileRefreshableDataSource to update regularly, which will be delayed)
- Real time performance is not guaranteed (the rule is to use FileRefreshableDataSource to update regularly)
- Pulling too often may also have performance problems
- Because the file is stored locally, it is easy to lose
Feign integrates Sentinel
Modify profile
#Enable feign support for sentinel feign: sentinel: enabled: true
Establish fault tolerance class
The fault-tolerant class needs to implement the interface where Fegin is located and all methods of the interface. Once there is a problem with the remote call of Fegin, it will enter the method with the same name in the current class and execute the fault-tolerant logic
@Service public class ProductServiceFallback implements ProductFeignClient { @Override public Product findByPid(Long pid) { Product product = new Product(); product.setId(250L) .setName("fallback"); return product; } }
Modify @ FeignClient annotation and add fault tolerance class
@FeignClient(value = "service-product",qualifier = "service-product",fallback = ProductServiceFallback.class) public interface ProductFeignClient { @GetMapping("/product/{pid}") @LoadBalanced Product findByPid(@PathVariable("pid") Long pid); }
Fault tolerance class and obtain error information (only one of the two methods can be used)
@FeignClient(value = "service-product",qualifier = "service-product" ,fallbackFactory = ProductServiceFallbackFactory.class) public interface ProductFeignClient { @GetMapping("/product/{pid}") @LoadBalanced Product findByPid(@PathVariable("pid") Long pid); }
@Component public class ProductServiceFallbackFactory implements FallbackFactory<ProductFeignClient> { @Override public ProductFeignClient create(Throwable throwable) { return new ProductFeignClient() { @Override public Product findByPid(Long pid) { Product product = new Product(); product.setId(250L) .setName("fallback"+throwable.toString()); return product; } }; } }