目录
微服务高可用技术
在大型复杂的分布式系统中,高可用相关的技术架构至关重要。构建高可用的分布式系统,需要确保系统在面对各种故障和挑战时仍能保持稳定运行,为用户提供持续的服务。以下是实现微服务高可用性的关键技术和策略:
服务的高可用性
将分布式系统中的各个服务打造成高可用的服务,是应对分布式系统中各种问题的关键。这包括但不限于:
服务调用超时:处理服务间调用超时的问题,确保系统的响应性。
服务调用失败:管理服务间调用失败的情况,保证系统的鲁棒性。
关键技术与策略
为了解决上述问题,高可用分布式系统中采用了多种重要技术:
资源隔离
通过资源隔离技术,防止某个服务或组件占用过多资源,影响其他服务的正常运行。这可以是进程级、线程级或容器级的隔离。
限流与过载保护
实施限流机制,限制服务的请求速率,防止系统过载。过载保护确保在系统负载过高时,能够自动调整以防止系统崩溃。
熔断
熔断机制是在故障发生时,快速切断故障点,防止故障蔓延。当检测到服务调用失败率超过一定阈值时,熔断器会打开,暂时停止对故障服务的调用,转而提供降级处理。
优雅降级
在系统出现故障或负载过高时,通过降级非核心功能,保证核心功能的可用性。降级可以是减少功能的复杂度,或者提供简化的服务。
容错
容错机制允许系统在部分组件失效的情况下仍然能够正常运作。这包括数据备份、冗余设计和故障转移等。
超时控制
设置合理的超时时间,避免长时间等待无效的请求,从而释放资源并提高系统的响应速度。
监控与运维
建立全面的监控体系,实时监测系统的健康状况和性能指标。通过日志分析、指标收集和告警机制,及时发现并解决潜在问题。
服务降级、熔断、限流概念
服务雪崩效应
服务雪崩效应通常发生在高并发情况下,当所有请求堆积在同一个线程池中进行处理时,如果大量的请求访问同一个接口,可能会导致其他服务没有线程来处理请求,从而导致整个系统的崩溃。这是服务雪崩效应的一种典型表现。
服务降级
在高并发情况下,为了防止用户长时间等待,可以使用服务降级的方式。具体做法是直接返回一个友好的提示给客户端,通过调用 `fallBack` 方法来处理。服务降级可以确保在系统压力过大时,仍然能够提供最基本的用户体验。
服务熔断
服务熔断机制的目的是保护服务。在高并发情况下,如果请求达到一定阈值(可以自定义设置),超过阈值的请求将被直接拒绝,以保护当前服务。服务熔断通常与服务降级一起使用,即在熔断时返回友好的提示信息。
服务隔离
由于默认情况下,所有的服务接口共用一个线程池,如果大量的请求访问同一个接口,可能会达到 Tomcat 线程池的默认极限,从而导致其他服务无法访问。解决服务雪崩效应的方法之一是使用服务隔离机制,主要有两种方式:
线程池隔离
原理:每个接口(服务)都有自己的独立线程池,因为每个线程池互不影响,所以可以有效防止服务雪崩效应。
实现:每个服务接口都有自己独立的线程池,每个线程池互不影响。
信号量隔离
原理:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行。当请求进来时,先判断计数器的数值,如果超过设置的最大线程个数则拒绝该请求,如果不超过则通行,此时计数器+1;请求返回成功后,计数器-1。
服务限流
服务限流是指对接口访问进行限制,以防止系统过载。常用的服务限流算法包括令牌桶、漏桶和计数器等。
令牌桶算法:允许以固定的速率产生令牌,请求只有在有令牌的情况下才能通过。适用于处理突发流量。
漏桶算法:以固定的速率处理请求,将多余的请求缓存起来,适用于平滑流量。
计数器算法:在一定时间窗口内统计请求次数,超过限制则拒绝请求。适用于简单的限流场景。
Hystrix 介绍
Hystrix 概述
Hystrix 是一个由国外知名视频网站 Netflix 开源的高可用架构框架,广泛应用于分布式系统中。Hystrix 的全称是 "Hystrix is a latency and fault tolerance library",意为“豪猪”,象征其具有强大的自我保护能力。Hystrix 能够有效解决分布式系统架构中打造高可用服务面临的一系列技术难题,帮助系统在高并发、高复杂度的环境中保持稳定运行。
Hystrix 的核心机制
在微服务架构中,系统的每个业务功能都被拆分为独立的模块,服务之间通过互相调用来完成业务需求。然而,由于网络不稳定或其他外部因素,可能会出现服务不可用的情况。如果某个服务出现问题,其他服务继续调用该服务可能会导致线程阻塞。当大量请求同时访问时,线程资源会被耗尽,进而可能导致服务瘫痪。由于服务间存在相互调用的依赖关系,这种问题很容易引发“蝴蝶效应”,导致整个系统崩溃。
为了解决这一问题,Hystrix 提供了多种机制来应对服务雪崩效应,确保系统的稳定性和可靠性。
资源隔离
资源隔离是 Hystrix 的核心机制之一,它包括两种主要方式:
线程池隔离
每个服务调用都有独立的线程池,限制调用分布式服务的资源使用。某个服务的调用出现问题时,不会影响其他服务的调用。这种方式通过为每个服务分配独立的线程池,避免了资源竞争和雪崩效应。
信号量隔离
使用信号量来限制并发请求的数量,确保服务调用的并发量不会超过预设的阈值。这种方式通过限制请求数量,防止资源被过度占用。
降级机制
Hystrix 提供了降级机制,以应对服务调用失败的情况:
超时降级
当服务调用超时时,Hystrix 会自动触发降级逻辑,避免线程长时间阻塞。
资源不足时降级
当线程池或信号量的资源不足时,Hystrix 会触发降级逻辑,向客户端返回托底数据(fallback),确保系统不会因为资源耗尽而崩溃。
熔断机制
熔断机制是 Hystrix 的另一个重要特性,主要用于防止服务调用的失败率过高导致系统崩溃:
熔断触发
当某个服务的失败率达到一定阈值时(如因网络故障或超时导致的失败率过高),Hystrix 会自动触发熔断机制,停止对该服务的调用,防止故障扩散。
快速失败与恢复
熔断器触发后,Hystrix 会快速返回失败响应,避免线程阻塞。同时,熔断器会在一定时间后尝试恢复,重新允许对该服务的调用。
缓存机制
Hystrix 提供了请求缓存和请求合并的功能,帮助提升系统性能:
请求缓存
基于请求的缓存机制,避免重复执行相同的请求,减少资源消耗。
请求合并
将多个相同的请求合并为一个,减少服务调用的次数,提升系统响应速度。
EurekaTest
在前面使用的EurekaTest工程,添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
主类添加@EnableCircuitBreaker注解
在调用远程的服务的方法上添加@HystrixCommand(fallbackMethod="error"),error是自定义的方法名,本地服务回调方法
@RestController
@RequiredArgsConstructor
@RequestMapping("/test")
public class TestController {
private final RestTemplate restTemplate;
@RequestMapping("/hello")
@HystrixCommand(fallbackMethod="error",
commandProperties={@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
value = "3500")})//Hystrix默认超时为1000ms,如果响应超过1000ms,就会触发熔断,fallbackMethod如果发生熔断,调用error()方法
public Object hello() {
return restTemplate.getForEntity("http://EurekaClient/client/hello", String.class);
}
public String error(Throwable throwable) {
System.out.println("异常信息:" + throwable.getMessage()); //访问远程服务失败,该如何处理,这些处理逻辑就可以写在该方法中
return "ERROR";
}
}
有了服务的熔断,随之就会有服务的降级,所谓服务降级,就是当某个服务熔断之后,服务端提供的服务将不再被调用,此时由客户端自己准备一个本地的fallback回调,返回一个默认值来代表服务端的返回,这种做法,虽然不能得到正确的返回结果,但至少保证了服务的可用,比直接抛出错误或服务不可用要好很多,当然这需要根据具体的业务场景来选择。
我们在调用服务提供者时,我们自己也有可能会抛异常,默认情况下方法拋了异常会自动进行服务降级,交给服务降级中的方法去处理。
如果远程服务有一个异常抛出后我们不希望进入到服务降级方法中去处理,而是直接将异常抛给用户,那么我们可以在@HystrixCommand注解中忽略异常
@HystrixCommand(fallbackMethod="error",ignoreExceptions = Exception.class)
我们也可以自定义类继承HystriXCommand实现自定义的Hystrix请求, 来重写getFallback,在getFallback方法中调用getEXecutionException方法来获取服务抛出的异常
@Override
public String getFallback() { //调用getExecutionException()方法来获取服务抛出的异常
System.out.println("异常信息为:" + getExecutionException().getMessage()); //实现服务熔断/降级逻辑
return "error";
}
请求缓存是在同一请求多次访问中保证只调用一次服务提供者的接口。在这同一次请求中,第一次调用的结果会被缓存,确保多次访问返回相同的结果。请求缓存可以通过以下两种方式实现:
通过自定义类继承 HystriXCommand
自定义类继承 HystriXCommand 类,并覆盖 getCacheKey 方法来开启缓存。
public class MyCommand extends HystrixCommand<String> {
private final String key;
public MyCommand(String key) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.key = key;
}
@Override
protected String run() {
// 实际的业务逻辑
return "Hello " + key;
}
@Override
protected String getCacheKey() {
return key;
}
}
使用注解的形式:
相关注解:@CacheResult、@CacheKey 和 @CacheRemove。
在微服务架构中,一个项目被拆分成多个独立的模块,这些模块通过远程调用来互相配合工作。在高并发情况下,通信次数的增加会导致总的通信时间增加,同时线程池的资源是有限的,高并发环境会导致大量线程处于等待状态,进而导致响应延迟。为了解决这些问题,需要了解 Hystrix 的请求合并机制。
请求合并的原理
HystrixCollapser:Hystrix 提供了一个抽象类 HystrixCollapser,它在 HystrixCommand 之前放置一个合并处理器,将处于一个很短的时间窗(默认10毫秒)内对同一依赖服务的多个请求进行整合,并以批量方式发起请求。通过请求合并,可以减少通信消耗和线程数的占用,提高系统的性能和响应速度。
public class MyCollapser extends HystrixCollapser<List<String>, String, String> {
private final String key;
public MyCollapser(String key) {
this.key = key;
}
@Override
protected String getRequestArgument() {
return key;
}
@Override
protected HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, String>> requests) {
return new BatchCommand(requests);
}
@Override
protected String mapResponseToRequest(List<String> batchResponse, CollapsedRequest<String, String> request) {
// 根据请求和批量响应映射结果
return batchResponse.stream()
.filter(response -> response.contains(request.getArgument()))
.findFirst()
.orElse(null);
}
private static class BatchCommand extends HystrixCommand<List<String>> {
private final Collection<CollapsedRequest<String, String>> requests;
public BatchCommand(Collection<CollapsedRequest<String, String>> requests) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.requests = requests;
}
@Override
protected List<String> run() {
// 实际的批量请求逻辑
List<String> responses = new ArrayList<>();
for (CollapsedRequest<String, String> request : requests) {
responses.add("Hello " + request.getArgument());
}
return responses;
}
}
}

1万+

被折叠的 条评论
为什么被折叠?



