Spring Cloud Alibaba入门
spring Cloud Alibaba版本说明
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
springcloud 的版本号是用伦敦地铁站站名标记的版本、因为错综复杂、用数字标记不是太友好
依赖关系
spring boot –> spring cloud –> spring cloud alibaba
Nacos服务治理
Nacos服务注册
- 首先我们要先下载相应的Nacos服务、然后启动Nacos服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR3</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <parent> <groupId>com.dream.xiaobo</groupId> <artifactId>springcloudalibaba</artifactId> <version>0.0.1-SNAPSHOT</version> </parent>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.1.RELEASE</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11
| spring: cloud: nacos: discovery: server-addr: localhost:8848
application: name: provider
server: port: 8082
|
Nacos 服务发现
1 2 3 4 5 6 7 8 9 10 11 12 13
| <parent> <groupId>com.dream.xiaobo</groupId> <artifactId>springcloudalibaba</artifactId> <version>0.0.1-SNAPSHOT</version> </parent>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.1.RELEASE</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @RestController public class ConsumerController {
@Autowired private DiscoveryClient discoveryClient;
@GetMapping("/instances") public List<ServiceInstance> instances(){
List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");
return provider; } }
|
Nacos 服务调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| @RestController @Slf4j public class ConsumerController {
@Autowired private DiscoveryClient discoveryClient;
@Autowired private RestTemplate restTemplate;
@GetMapping("/instances") public List<ServiceInstance> instances(){
List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");
return provider; }
@GetMapping(value = "/index") public String index(){
List<ServiceInstance> list = this.discoveryClient.getInstances("provider");
int index = ThreadLocalRandom.current().nextInt(list.size());
ServiceInstance serviceInstance = list.get(index);
URI uri = serviceInstance.getUri();
log.info("调用的端口是:" + serviceInstance.getPort());
return "调用的端口是"+serviceInstance.getPort() + "uri是:" + serviceInstance.getUri(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration public class ConsumerConfiguration {
@Bean public RestTemplate restTemplate(){
return new RestTemplate(); } }
|
这里只实现了简单的调用、并没有太多的起到负载均衡、这里面的随机数相当于了负载均衡
Ribbon 负载均衡
Ribbon 不是spring Alibaba的组件、是Netfilx的、底层是RestTemplate、用的是轮询算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration public class ConsumerConfiguration {
@Bean @LoadBalanced public RestTemplate restTemplate(){
return new RestTemplate(); } }
|
1 2 3 4 5
| @GetMapping(value = "/ribbonIndex") public String ribbonIndex(){
return this.restTemplate.getForObject("http://provider/index", String.class); }
|
这是一种轮询算法
Ribbon之随机算法
1 2 3 4 5 6 7
| server: port: 8180
provider: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
|
Ribbon之权重算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Slf4j public class NacosWeightedRule extends AbstractLoadBalancerRule {
@Autowired private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override public void initWithNiwsConfig(IClientConfig iClientConfig) { }
@Override public Server choose(Object o) { ILoadBalancer loadBalancer = this.getLoadBalancer(); BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) loadBalancer; String name = baseLoadBalancer.getName(); NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); try { Instance instance = namingService.selectOneHealthyInstance(name); log.info("选择的实例是port={},instance={}",instance.getPort(),instance); return new NacosServer(instance); } catch (NacosException e) { e.printStackTrace(); return null; } } }
|
1 2 3 4
| provider: ribbon: NFLoadBalancerRuleClassName: com.southwind.configuration.NacosWeightedRule
|
Sentinel 服务限流降级
雪崩效应
这里来说以下雪崩效应的理解、举个例子、就好比现在有A、B、C、D四块服务、现在项目中D需要调用C、C需要调用B、B需要调用A、但是由于A出现了一点点的小问题、导致B无法调用它、这样就会导致B内从增加、而导致B、C、D服务都不能正常工作、这样的问题就叫做雪崩效应
雪崩效应的解决方案
设置线程
这里可以设置线程、例如、B访问A时设置一个线程访问时间、如果在规定时间内没有获取到相应的线程就释放掉、这样就不会产生阻塞线程从而使得B的内存崩溃了
设置限流
例如、给A服务设置一个访问上限、假如给A设置10个访问上限、这样B来了10个访问线程之后就不会再有线程去访问、从而防止内存崩溃
熔断器 Sentienl Hystrix
系统将某些不重要的接口功能进行降低、限制一些功能的使用、只提供部分功能、不提供全部功能
只接受系统能够承载的访问量、超出即抛出异常
例如、B访问A时、A反应很慢、这样就会导致B反应也很慢、所以直接熔断、不去访问A了、直接返回错误
熔断器效果
Sentinel的使用方法
下载相应的jar、用于启动Sentinel、然后运行下载的jar即可
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.1.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| spring: cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 filter: enabled: false application: name: provider
server: port: 8082
management: endpoints: web: exposure: include: "*"
|
效果图
流量规则
直接流控
直接将其访问的方法加入阈值
关联流控
关联阈值是关联别的方法、简单点说就是别人做事我背锅、例如关联一个list方法、那么访问list方法时我就会被收到控制
1 2 3 4 5 6 7 8 9 10 11
| public class Test {
static RestTemplate restTemplate = new RestTemplate(); public static void main(String[] args) throws Exception{
for (int i = 0; i < 1000; i++) { restTemplate.getForObject("http://localhost:8082/list",String.class); Thread.sleep(200); } } }
|
链路流控
链路流控其实就是控制service层、但是service不能直接被访问、所以要和调用的Controller进行关联
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-web-servlet</artifactId> <version>1.7.1</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration public class FilterConfiguration {
@Bean public FilterRegistrationBean registrationBean(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new CommonFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false"); registrationBean.setName("sentinelFilter"); return registrationBean; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @RestController public class ProviderController {
@Autowired private ProviderService providerService;
@Value("${server.port}") private String port;
@GetMapping("/index") public String index(){
return "端口号为:"+port; } @GetMapping(value = "list") public String list(){
return "list"; } @GetMapping(value = "/test1") public String test1(){
providerService.test();
return "test1"; } @GetMapping(value = "/test2") public String test2(){
providerService.test(); return "test2"; } }
|
1 2 3 4 5 6 7 8 9 10
| @Service public class ProviderService {
@SentinelResource public void test(){
System.out.println("test"); } }
|
流量效果
直接失败
直接抛出异常、没什么附加功能
warm up
warm up就会在系统刚开始的性能比较低、举个例子就好比一个业务员刚上班、可能状态不是很好、所以他会在刚开始的时候只接受一个人办理业务、过了一会他可能状态适应了、会一个人接受多个人同时办理业务、这里大家可以想一下抢购、抢购业务用的可能就是这个
排队等待
排队等待就是出现异常时不会直接抛出、会等待一下、等待下一个时间段请求、如果请求上了、就不会抛出异常、正常执行、否则会抛出异常
- 失败
1 2 3 4 5 6 7 8 9 10 11
| public class Test {
static RestTemplate restTemplate = new RestTemplate(); public static void main(String[] args) throws Exception{
for (int i = 0; i < 1000; i++) { restTemplate.getForObject("http://localhost:8082/index",String.class); Thread.sleep(500); } } }
|
失败原因、以为0.5s+0.3s < 1s 所以在等待之后的请求当中还在阈值1s当中、所以不会请求成功、而会抛出异常
- 成功
1 2 3 4 5 6 7 8 9 10 11
| public class Test {
static RestTemplate restTemplate = new RestTemplate(); public static void main(String[] args) throws Exception{
for (int i = 0; i < 1000; i++) { restTemplate.getForObject("http://localhost:8082/index",String.class); Thread.sleep(500); } } }
|
成功原因、因为0.5s + 0.5s = 1s、所以在等待之后阈值正好为1、所以后得到下一次的请求
降级规则
RT
单个请求的响应时间超过阈值、则进入准降级状态、接下来 1 S 内连续 5 个请求响应时间均超过阈值、就进行降级、持续时间为时间窗口的值
异常比例
每秒异常数量占通过量的比例大于阈值、就进行降级处理、持续时间为时间窗口的值
异常数
1 分钟内的异常数超过阈值就进行降级处理、时间窗口的值要大于 60S、否则刚结束熔断又进入下一次熔断了
热点规则
热点规则是流控规则的更细粒度操作、可以具体到对某个热点参数的限流、设置限流之后、如果带着限流参数的请求量超过阈值、则进行限流、时间为统计窗口时长
1 2 3 4 5 6 7 8
| @GetMapping(value = "/test") @SentinelResource("test") public String test( @RequestParam(value = "num1",required = false) Integer num1, @RequestParam(value = "num2", required = false) Integer num2 ){ return num1 + "-" + num2; }
|
授权规则
给指定的资源设置流控应用(追加参数)、可以对流控应用进行访问权限的设置、具体就是添加白名单和黑名单
1 2 3 4 5 6 7 8 9 10
| public class RequestOriginParserDefinition implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest httpServletRequest) { String name = httpServletRequest.getParameter("name"); if(StringUtils.isEmpty(name)){ throw new RuntimeException("name is null"); } return name; } }
|
1 2 3 4 5 6 7
| public class SentinelConfiguration {
@PostConstruct public void init(){ WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition()); } }
|
正确的开始、微小的长进、然后持续、嘿、我是小博、带你一起看我目之所及的世界……