微服务存在的问题及解决方案
1. 存在问题
1.1 接口拖慢
因为一个接口在并发时,正好执行时长又比较长,那么当前这个接口占用过多的 Tomcat 连接,导致其他接口无法即时获取到 Tomcat 连接来完成请求,导致接口拖慢,甚至失败。
假如商品服务业务并发较高,占用过多 Tomcat 连接。可能会导致商品服务的所有接口响应时间增加,延迟变高,甚至是长时间阻塞直至查询失败。
1.2 服务器雪崩问题
什么是服务器雪崩?
举例:假如此时有一个 "商品服务",其它几乎所有的服务基本都会直接或间接的使用它,但是如果此时 "商品服务" 崩溃了,就会导致整个服务全盘崩溃(红色表示出现问题),这个现象就是所谓的服务器雪崩。
2. 服务器保护方案
由于服务器雪崩现象的出现,因此,就需要对引入可能出现问题服务的服务进行保护,即服务器保护:
-
降级:断路器会统计访问某个服务的请求数量,统计服务提供方的异常比例,当比例过高表明该接口会影响到其它服务,应该拒绝调用该接口,而是直接走降级逻辑。
-
熔断:熔断机制用于在服务出现问题时快速失败,避免调用链路中的服务相互等待,导致整体系统响应变慢甚至不可用。
-
超时:设置合理的超时时间可以避免长时间等待响应导致的问题。当请求超时时,可以选择快速失败并返回错误信息,或者重试等策略。
-
线程隔离:线程隔离是指为每个服务分配独立的线程池,这样即使某个服务出现问题也不会影响到其他服务。
-
限流:限流是最常见的服务保护措施之一,其目的是为了防止服务因为过大的流量而崩溃。
对于某些关键资源或者参数的访问,可以采取特殊的限流措施来防止这些热点成为瓶颈
2.1 熔断降级
2.1.1 说明
熔断降级是解决雪崩问题的重要手段,包括熔断和降级两个方案。
熔断 是由断路器 统计服务调用的异常比例、慢请求比例,如果超出阈值 则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。熔断发生在服务调用方即客户端。
降级是当遇到访问失败可以快速返回一些默认数据或者友好提示,用户体验会更好。熔断降级结合后是当线路断开后直接走降级线路避免再次去请求失败线路。降级方法需要在服务调用方即客户端实现。
2.1.2 Sentinel 安装与集成
一、安装
实现服务保护的工具有很多,Spring Cloud Alibaba 技术栈中 Sentinel 是实现服务保护的中间件。
Sentinel 是阿里巴巴开源的一款服务保护框架,目前已经加入 Spring Cloud Alibaba 中。
使用:
-
下载 jar 包:Releases · alibaba/Sentinel · GitHub
本地资源:sentinel 本地服务
-
运行
将 jar 包拷贝到 虚拟机/data/soft/sentinel 目录下重命名为
sentinel-dashboard.jar
:创建 Dockerfile 文件
powershellFROM openjdk:11-jdk ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezo ARG SENTINEL_VERSION=1.8.6 # copy sentinel jar ADD ./sentinel-dashboard.jar /home/sentinel-dashboard.jar RUN chmod -R +x /home/sentinel-dashboard.jar ENTRYPOINT ["sh","-c","java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar $JAVA_OPTS /home/sentinel-dashboard.jar"]
-
执行命令创建镜像
powershelldocker build -t sentinel-dashboard .
-
创建并启动容器
powershelldocker run --name sentinel-dashboard -d -p 9090:8090 sentinel-dashboard:latest
启动 sentinel
powershelldocker start sentinel-dashboard
-
登录 sentinel 容器并设置时区
powershelldocker exec -it sentinel-dashboard /bin/bash ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezon
-
访问
http://微服务IP:9090
-
账户、密码:admin
二、集成
举例:现在有两个服务 A、B,其中 A 服务需要使用到 B 服务,而此时,就需要对 A 服务进行保护,防止 B 服务崩溃导致 A 服务无法运行。
在需要保护的架构中导入依赖:
xml
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
修改配置文件
yaml
spring:
cloud:
sentinel:
transport:
# 服务器配置
dashboard: 192.168.101.68:9090
client-ip: 192.168.101.1
# 本地配置
# dashboard: localhost:8090
http-method-specify: true # 开启请求方式前缀可根据http请求方法区分簇点链路
2.1.3 降级
调用了目标服务接口,发现有问题,走降级逻辑(要自己写)
修改配置项
yaml
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
在 OpenFeign 处配置降级逻辑
java
@Slf4j
@Component
public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {
@Override
public ItemClient create(Throwable cause) {
return new ItemClient() {
@Override
public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
log.warn("远程调用ItemClient queryItemByIds方法出现降级,参数:{}", ids);
return List.of();
}
@Override
public void deductStock(List<OrderDetailDTO> items) {
log.warn("远程调用ItemClient deductStock方法出现降级,参数:{}", items);
}
};
}
}
在接口处进行配置,指定要使用的降级逻辑
java
@FeignClient(name = "item-service", path = "/items", fallbackFactory = ItemClientFallbackFactory.class)
public interface ItemClient { ... }
api/item/
│
├── ItemClient.java
│
└── ItemClientFallbackFactory.java
在需要保护的服务启动类上配置要扫描的包
java
// 扫描
@SpringBootApplication(scanBasePackages = {"com.hmall.cart", "com.hmall.api"})
@MapperScan("com.hmall.cart.mapper")
@EnableFeignClients(basePackages = "com.hmall.api")
public class CartServiceApplication { ... }
2.1.4 熔断
降级逻辑达到了阈值,则直接熔断,不调用目标服务接口。
工作原理:
- 默认情况下,熔断器是关闭的。那么所有请求都正常执行的;
- 如果有服务出现了问题,并且失败比例达到了设置的阈值,那么熔断器会打开,所有的请求直接走降级逻辑,返回托底数据;
- 到达熔断时间后,熔断器会处于半开状态,会允许一个请求过来,如果这个请求成功,则关闭熔断器,如果这个请求失败,继续打开熔断器。周而复始。

配置熔断策略:
通过 Sentinel 面板进行配置
-
异常数配置
说明:2 秒内最小请求数为 2,异常数达到 1 发生熔断,熔断时长为 20 秒。
-
慢调用比例配置
说明:
- RT(接口响应时间)超过 200 毫秒的请求调用就是慢调用
- 统计最近 3000ms 内的最少 2 次请求,如果慢调用比例大于等于 50%,则触发熔断
- 熔断持续时长 20s
-
异常比例配置
说明:
- 统计最近 3000ms 内的最少 2 次请求,如果异常比例不低于 0.5,则触发熔断
- 熔断持续时长 20s
2.2 请求限流

什么是 QPS?
QPS 是 "Queries Per Second" 的缩写,中文通常称为 "每秒查询率 " 或 "每秒请求数"。它是一个衡量系统性能的重要指标,特别是在评估 Web 服务器、数据库系统、API 接口等的负载能力时经常使用。
QPS 表示系统在一秒钟内能够处理的查询或请求的数量。这个指标可以帮助开发者和运维人员了解系统的处理能力和性能瓶颈。例如,如果一个 Web 服务的 QPS 为 100,则意味着该服务在一秒钟内最多可以处理 100 个请求。
2.3 线程隔离
为指定接口分配固定数量的线程,即使当前接口出现不可用的情况。也只会消耗给你分配的线程数。不影响其他线程。
线程隔离有两种方式实现:
- 线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果
- 信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求

Sentinel 的线程隔离就是基于信号量隔离实现的,而 Hystix 两种都支持,但默认是基于线程池隔离。