弹性需求:
微服务本质上是分布式的。它具有更多的组件和运动部件。在分布式体系结构中,应对任何意外故障是要解决的最大挑战之一。可能是硬件故障,网络故障等。系统从故障中恢复并保持正常运行的能力使系统更具弹性。它还避免了任何级联故障。
为什么是隔板?
使用“舱壁”将一艘船分成多个小隔间。隔板用于密封船舶的各个部分,以防止洪水时整艘船沉没。同样,在设计软件时应该预期会出现故障。应将应用程序拆分为多个组件,并以一种组件的故障不会影响另一组件的方式隔离资源。
例如:假设有两个服务A和B。A的某些API依赖于B。由于某种原因,B的运行速度很慢。因此,当我们收到依赖于B的多个并发请求给A时,A的性能也会受到影响。它可能会阻塞A的线程。由于A可能无法处理不依赖于B的其他请求。因此,这里的想法是隔离资源/在A中为B分配一些线程。这样我们就不会消耗A的所有线程并防止从所有请求挂起!
样品申请
我们将使用与先前文章相同的应用程序。
源代码在这里。
要了解隔板模式的使用,让我们在应用程序中考虑一下。我们的产品服务有2个端点。
- / product / {id} –一个端点,提供有关特定产品的更多详细信息以及等级和内容。这取决于评级服务的结果。用户更新其评分,留下评论,回复评论,一切都通过此端点进行。
- / products –和终结点,该终结点根据一些搜索条件提供了我们在目录中拥有的产品列表。它不依赖于任何其他服务。用户可以从列表中直接订购产品(添加到购物车)。
产品服务是具有多个线程的典型Web应用程序。我们将应用程序的线程数限制为15。这意味着产品服务最多可以处理15个并发用户。如果所有用户都忙于更多地了解该产品,留下评论,查看评论等,则正在搜索产品并尝试订购产品的用户可能会遇到应用程序运行缓慢的情况。这是个问题。
产品控制器
(“ v1”)
公共 类 ProductController {
私有 ProductService productService ;
(“ / product / {id}”)
public ProductDTO getProduct( int id){
返回 这个。productService。getProduct(id);
}
(“ /产品”)
公开 列表< ProductDTO > getProducts(){
返回 这个。productService。getProducts();
}
}
ProductService在内部调用RatingService,其实现如下所示。
公共 类 RatingServiceImpl 实现 RatingService {
(“ $ {rating.service.url}”)
私有 String ratingServiceUrl ;
私有 RestTemplate restTemplate ;
public ProductRatingDTO getRatings(int productId){
字符串 url = this。ratingServiceUrl + “ /” + productId ;
ProductRatingDTO productRatingDTO = 新的 ProductRatingDTO();
尝试{
productRatingDTO = this。restTemplate。getForObject(URL,ProductRatingDTO。类);
} catch(Exception e){
e。printStackTrace();
}
返回 productRatingDTO ;
}
}
ProductService的application.yaml如下更新。
服务器
tomcat的
最大线程数15
如果我使用JMeter进行性能测试,以模拟更多试图访问特定产品详细信息的用户,而有些用户则试图访问产品列表,那么我得到的结果如下所示。我们仅能提出26个产品要求。即使没有任何依赖性,平均响应时间也为3.6秒。福州小程序开发
让我们看看隔板实现如何在这里拯救我们!
隔板实施:
- 我正在使用Resilience4j库。
- application.yaml更改
- 即使我们有15个线程,我们也允许最多10个并发请求请求评级服务。
- 最大等待时间是当现有10个线程繁忙时我们收到任何其他评级服务请求时,我们仅等待10毫秒并立即使请求失败。
服务器
tomcat的
最大线程数15
港口8082
等级
服务内容
网址 http // // localhost 8081 / v1 / ratings
resilience4j.bulkhead
实例
ratingService
maxConcurrentCalls 10
maxWaitDuration 10ms
RatingServiceImpl更改
- @Bulkhead使用我们在application.yaml中定义的实例。
- fallBackMethod是可选的。当我们有10个以上的并发请求时,将使用它
公共 类 RatingServiceImpl 实现 RatingService {
(“ $ {rating.service.url}”)
私有 String ratingServiceUrl ;
私有 RestTemplate restTemplate ;
(名称 = “ratingService” ,fallbackMethod = “getFallbackRatings” ,类型 = 隔板。键入。SEMAPHORE)
public ProductRatingDTO getRatings(int productId){
字符串 url = this。ratingServiceUrl + “ /” + productId ;
ProductRatingDTO productRatingDTO = 新的 ProductRatingDTO();
尝试{
productRatingDTO = this。restTemplate。getForObject(URL,ProductRatingDTO。类);
} catch(Exception e){
e。printStackTrace();
}
返回 productRatingDTO ;
}
public ProductRatingDTO getFallbackRatings(int productId,Exception e){
系统。出来。println(“回退:” + productId);
返回 新的 ProductRatingDTO();
}
}
现在,在启动我们的服务之后,运行相同的测试会产生以下结果,这非常非常有趣。
- 产品要求的平均响应时间为106毫秒,而没有安装隔板的情况下为3.6秒。这是因为我们没有耗尽产品服务的资源。
- 通过使用后备方法,对product / 1的任何其他请求都将使用默认响应进行响应。
概要:
使用隔板模式,我们为特定的组件分配资源,这样我们就不会不必要地消耗应用程序的所有资源。即使在意外负载下,我们的应用程序仍然可以正常运行。