首页 > 其他 > 详细

之服务雪崩

时间:2019-07-19 17:21:28      阅读:77      评论:0      收藏:0      [点我收藏+]

什么是服务雪崩?

参考: <<重新定义spring cloud>>

代码:https://gitee.com/08081/hello-springcloud/tree/springcloud-fallback/

在微服务中,我们是服务于服务之间调用,当在微服务突然有大量的请求过来,一个服务瘫痪之后,后面的服务的请求积压,这就造成了服务雪崩!

 

技术分享图片

 

一个服务瘫痪,另外调用这个服务的服务就会超时,导致整个服务群瘫痪.

造成雪崩的原因可以归结为以下三点:

1. 服务提供者不可用 (硬件故障,程序bug 缓存击穿,用户大量请求)

2. 重试加大流量(用户重试,代码逻辑重试)

3. 服务调用者不可用(同步等待造成的资源耗尽)

最终的结果就是一个服务不可用,导致一系列的服务不可用,这种后果无法预料

如何解决在灾难性雪崩效应?

1.降级: 超时降级资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据,实现一个fallback方法,当请求出现异常之后,调用这个方法

2.隔离(线程池隔离和信号量隔离): 限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用

3.熔断: 当失败率(如因网络故障/超时造成的失败率高)达到阈值自动触发降级.熔断器触发的快速失败会进行快速恢复

4.缓存:提供请求缓存

5.提供请求合并

 解决方案之一服务降级

 先说遇到的坑吧

1. 坑1 mapping 报错.feign调用服务端的时候说实例已经实例过了

当时报错的时候错误信息没有记录.具体参考的是这篇文章 感谢作者.https://my.oschina.net/u/2000675/blog/2244769

//@FeignClient(name = "book-service",fallback = BookServiceFallback.class,path = "/")

2.坑2 在写好fallback方法之后,一直调用fallback方法,不调用原来的方法.不知为什么hystrix的默认时间一直1秒钟

尝试配置了很多次.最终结合官网解决:

feign:
  hystrix:
    enabled: true
    #局部配置 这个必须加
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000

3.坑3: 使用fallbackFactory报错

要是因为我返回空的list还去添加

代码

如何下载代码运行案例?

1.到码云下下载项目

2.运行ch3-eureka-ribbon 下的eureka-server

3.运行ch4-fegin下的ch4-book-service

4.运行ch6-hystrix下的book-consumer-hystrix

我创建了一个子项目book-consumer-hystrix

pom文件如下:

技术分享图片
spring:
  application:
    name: book-hystrix
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8888/eureka/
  instance:
    prefer-ip-address: true
server:
  port: 8002
feign:
  hystrix:
    enabled: true
    #局部配置
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000
View Code

启动类:

技术分享图片
/**
 * Created by xiaodao
 * date: 2019/7/18
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class BookConsumerHystrixApplication {

    public static void main(String[] args) {
        SpringApplication.run(BookConsumerHystrixApplication.class,args);
    }
}
View Code

 feignClient调用类:

注意坑2.的解决方案:必须加path

/**
 * Created by xiaodao
 * date: 2019/7/17
 */
@Component
//@FeignClient(name = "book-service",fallback = BookServiceFallback.class,path = "/")
@FeignClient(name = "book-service",fallbackFactory = WebFeignFallbackFactory.class,path = "/")
public interface BookService extends BookApi {
}

controller 调用类:

/**
 * Created by xiaodao
 * date: 2019/7/17
 */
@RestController
@RequestMapping("/book")
@AllArgsConstructor
public class BookController {


    private BookService bookService;

    @GetMapping("/findList")
    public List<Book> findList(){
      return   bookService.findList();
    }


}

fallback的俩个类

一个是正常的fallback

另一个是打印错误日志的fallbackFactory

/**
 * Created by xiaodao
 * date: 2019/7/18
 */
@Component
public class BookServiceFallback implements BookService {
    public List<Book> findList() {
        return Collections.emptyList();
    }
}
/**
 * Created by xiaodao
 * date: 2019/7/18
 * 这个fallback工厂类为了查看回退的原因的异常信息
 */
@Component
public class WebFeignFallbackFactory implements FallbackFactory<BookService> {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebFeignFallbackFactory.class);

    @Override
    public BookService create(Throwable throwable) {

        return new BookService(){
            // 日志最好放在各个fallback方法中,而不要直接放在create方法中
            @Override
            public List<Book> findList() {
                WebFeignFallbackFactory.LOGGER.info("fallback; reason was:", throwable);

                Book book = Book.builder().id(1000).name("异常回退!").build();
                List<Book> list = new ArrayList<>();
                list.add(book);
                return list;

            };
        };

    }
}

以下4种情况触发fallback调用

1.方法抛出非HystrixBadRequestException异常

2.方法调用超时

3.熔断器开启拦截调用

4.线程池/信号量/队列是否跑满

 解决方案之一服务请求缓存

hystrix 有俩个缺点:

1.不支持集群

2.不支持第三方缓存

所以我们做集成第三方缓存,并且可以支持集群.所以我们选用redis, 在书上,和网上的案例很多都是基于hystrixCommand 来实现的,我们来来模仿真实案例来实现.

ch6下创建俩个项目

1.book-consumer-hystrix-cache

2.book-service-cache

启动eurekaserver服务

代码

book-consumer-hystrix-cache服务

controller 添加了俩个方法

技术分享图片
@RestController
@RequestMapping("/book-consumer")
@AllArgsConstructor
public class BookController {


    private BookService bookService;

    @GetMapping("/findList")
    public List<Book> findList(){
      return   bookService.findList();
    }

    @GetMapping("get/{id}")
    public Book get(@PathVariable(value = "id")  Integer id ){
        return bookService.get(id);
    }

    @GetMapping("del/{id}")
    public Book del(@PathVariable(value = "id") Integer id ){
        return bookService.del(id);
    }


}
View Code

service:

@FeignClient(name = "book-service-cache",path = "/")
public interface BookService extends BookApi {
}

book-service-cache 服务

pom文件 依赖

      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

bootstrap.yml配置了redis的连接池

技术分享图片
spring:
  application:
    name: book-service-cache
  #redis的索引默认是0
  redis:
    database: 1
    host: localhost
    port: 6379
    password:
    lettuce:
      #负数表示没有限制
      pool:
        max-active: 100
        #最大空闲连接
        max-idle: 10
        #连接池最大阻塞等待时间(使用负数表示没有限制)
        max-wait: -1ms
        #连接池最小空闲连接
        min-idle: 0

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8888/eureka/
  instance:
    prefer-ip-address: true
server:
  port: 8000
View Code

bookServiceImpl

技术分享图片
/**
 * Created by xiaodao
 * date: 2019/7/17
 */

@RestController
@RequestMapping
@CacheConfig(cacheNames = {"xiaodao.book"})
public class BookServiceImpl implements BookApi {
//    @GetMapping(value = "list")
    @Override
    public List<Book> findList() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Book book =Book.builder().id(1).name("第一本书").build();
        System.out.println(book);
       List<Book> list =  new  CopyOnWriteArrayList<>();
       list.add(book);
       return list;
    }


    @Cacheable(key = "‘get-‘ + #id")
    @Override
    public Book get(Integer id) {
        System.out.println("-----查询------"+id+"-------");
        return Book.builder().id(id).name("使用缓存").build();
    }

    @CacheEvict(key = "‘get-‘+ #id")
    @Override
    public Book del(Integer id) {
        System.out.println("------删除-----"+id+"-------");
        return Book.builder().id(id).name("使用缓存").build();
    }


}
View Code

还有book-api也需要改造一下.

就是加了俩个接口.

技术分享图片
public interface BookApi {

    @GetMapping(value = "/book/list")
    List<Book> findList();
    @GetMapping(value = "/book/get/{id}")
    Book get(@PathVariable(value = "id")  Integer id );

    @GetMapping(value = "/book/del/{id}")
    Book del(@PathVariable(value = "id") Integer id );



}
View Code

上面基本就是缓存方案的所有代码的所有代码

贴一张注册中心的图:

技术分享图片

 

http://localhost:8002/book-consumer/get/100

{"id":100,"name":"使用缓存"}

在后台看到无论请求多少遍.只有第一遍,会加载后去就会到缓存中查找

------删除-----100-------
------删除-----100-------
------删除-----100-------
-----查询------100-------

删除的时候回调用多次

 

 

之服务雪崩

原文:https://www.cnblogs.com/bj-xiaodao/p/11203573.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!