在 Vue 3 中,onActivated() 是一个生命周期钩子函数,用于在组件被激活时执行特定的逻辑。它是 Vue Router 提供的一个功能,用于处理组件的激活(activation)。
具体来说,当使用 <router-view> 渲染的组件被路由导航到并加载时,如果该组件在路由中是被激活的(activated),onActivated() 钩子函数就会被调用。
你之前的代码中并没有包含 onActivated(),可能是因为你的组件没有直接涉及到路由导航,或者你没有在路由配置中配置相应的路由。如果你需要在组件被激活时执行一些逻辑,可以在你的路由配置中为相应的路由添加 onActivated 钩子函数。123
什么是服务监控
服务监控概念
在说概念前,其实可以借助一下生活中的一个例子来理解: 想象你是一位餐馆经理。你的餐馆里有很多员工在不同岗位工作:厨师在做饭,服务员在端菜,收银员在结账。如果你想让餐馆顺利运营,你需要知道每个员工的工作状态。如果某个岗位出现问题,比如厨师突然生病了,你需要及时知道并做出调整,以确保餐馆正常运作,不会影响顾客体验。 服务监控就像是餐馆经理对员工工作状态的监视。它包括以下几个方面:
系统应用状态: 就像经理需要知道每个员工在做什么,服务监控需要知道每个系统应用在做什么,是否正常运行。 内存和线程: 就像餐馆需要确保有足够的食材和员工,系统也需要足够的内存和线程来处理任务。监控这些可以确保系统不会因为资源不足而崩溃。 堆栈: 就像经理需要知道每道菜的制作流程,监控堆栈信息可以帮助了解程序的执行流程,找出哪里出了问题。 日志: 就像经理需要记录每天的销售和反馈,系统日志记录了所有的操作和错误信息,方便追踪和排查问题。
服务监控的主要目的是在问题发生或即将发生时,能准确、快速地发现问题,从而减小影响范围。就像餐馆经理能及时发现并处理员工的问题,以避免影响整个餐馆的运营。 服务监控在微服务改造过程中的重要性不言而喻,没有强大的监控能力,改造成微服务架构后,就无法掌控各个不同服务的情况,在遇到调用失败时,如果不能快速发现系统的问题,对于业务来说就是一场灾难
服务常用技术栈
1、Spring Boot Actuator
Spring Boot Actuator 提供了一系列内置的端点,用于监控和管理 Spring Boot 应用程序。它可以暴露健康检查、应用信息、环境变量、JVM 指标、HTTP 请求追踪等。 适用于使用 Spring Boot 构建的微服务应用,集成简单,功能强大。 以下是一些常见端点:
2、Micrometer
Micrometer 是一个用于 JVM 应用程序的应用指标度量库。它提供与多种监控系统的集成,如 Prometheus、Graphite、JMX、New Relic、Datadog 等。需要在 Spring Boot 之外的 JVM 应用中进行指标监控,或者需要集成到多种监控系统中。优势是其有统一的 API,便于扩展和集成。
3、Dropwizard Metrics
Dropwizard Metrics 提供了一组用于度量 JVM 应用程序性能的工具,包括计数器、计时器、仪表等。它可以与多种后端系统集成,如 Graphite、Ganglia、Prometheus 等。需要在非 Spring Boot 应用中实现详细的性能度量。优势:轻量级,易于集成,功能全面。
如何做好监控
我本次使用的是利用 Spring Boot Actuator 配合 Admin-Ui,整合 Nacos,来做的各个微服务的系统监控。以下是具体的步骤:
漏桶算法(Leaky Bucket)
漏桶算法是另一种流量整形和速率限制算法。它将流量视为水倒入一个固定容量的桶中,如果桶满了,水就会溢出(即请求被拒绝)。桶底有一个漏洞,水以一定的速度从桶中漏出,从而控制平均流量。适用于需要严格控制流量,不允许突发流量的场景。漏桶算法通常需要自己实现,但也可以使用现有的库,比如Bucket4j。
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Refill;
@Service
public class ApiService {
private final Bucket bucket = Bucket.builder()
.addLimit(Bandwidth.classic(10, Refill.greedy(10, TimeUnit.SECONDS))) // 每10秒添加10个令牌
.build();
@Autowired
private RestTemplate restTemplate;
public String callApi() {
try {
bucket.asScheduler().consume(1); // 消耗一个令牌
} catch (InterruptedException | InsufficientTokensException e) {
throw new RuntimeException("Rate limit exceeded", e);
}
return restTemplate.getForObject("http://example.com/api", String.class);
}
}
滑动窗口算法
滑动窗口算法用于跟踪在特定时间窗口内的请求数量。当窗口内的请求数达到限制时,新的请求将被拒绝或延迟。窗口可以随着时间的推移而滑动,以适应不同的时间间隔。
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
@Service
public class ApiService {
private final long windowSizeInMilliseconds;
private final int maxRequestsPerWindow;
private final Queue<Long> window = new LinkedList<>();
public ApiService(long windowSizeInMilliseconds, int maxRequestsPerWindow) {
this.windowSizeInMilliseconds = windowSizeInMilliseconds;
this.maxRequestsPerWindow = maxRequestsPerWindow;
}
public synchronized boolean tryAcquire() {
long currentTime = System.currentTimeMillis();
// 移除窗口外的时间戳
while (!window.isEmpty() && currentTime - window.peek() > windowSizeInMilliseconds) {
window.poll();
}
// 如果窗口内的请求数已达到上限,则不允许新的请求
if (window.size() >= maxRequestsPerWindow) {
return false;
}
// 在窗口内添加当前请求的时间戳
window.offer(currentTime);
return true;
}
}
分布式限流
如果应用部署在多个实例或节点上,需要实现分布式限流以确保全局的调用频率不超过限制。可以使用Redis等分布式缓存系统来共享令牌或记录请求计数
错误码定义混乱,字段结构不一致
我们常常会遇到接口文档与实际错误码定义、字段结构不一致的问题,例如文档中标明错误码400代表参数错误,但实际上可能收到的是404错误响应;又或者返回的数据结构与文档描述不相吻合,这使得我们难以精准识别并恰当处理结果。针对此类问题,应当采取以下策略: 首先,构建自定义错误处理机制,创建专门的错误处理类,对所有可能出现的错误码进行统一且明确的处理。这样,无论接口返回何种错误码,都能确保有一套标准的逻辑进行响应和记录。 其次,针对那些与文档描述不符或者含义模糊不清的错误码和字段,应及时与第三方系统的技术团队展开沟通交流,明确其真实含义和用途。这样的互动有助于确保接口对接的精确性,避免因对错误码或字段理解不准确而引发的系统内部错误。 对于接口文档与实际不符的情况,一方面要通过定制化的错误处理机制增强系统的容错性与一致性,另一方面要强化与第三方系统的沟通协作,确保对接接口的清晰性和准确性,从而有效避免潜在问题对自身系统产生的不良影响。
返回的数据格式不统一
对于同一个系统,接口返回的数据格式在不同场景下可能有所差异,例如有的时候返回JSON对象,有的时候却是字符串或其他格式,例如xml等。 针对这类问题,我们需要编写包容性较强的解析逻辑,确保在任何情况下都能准确解构并处理返回数据。创建多个数据模型类对应不同格式的数据,根据接口返回的内容决定使用哪个模型类进行反序列化。针对不同的数据格式编写适配器,确保数据能统一转换为应用程序可处理的格式。