网站首页 > 教程文章 正文
1. 系统可观测性概述
系统可观测性(Observability)是指通过系统外部输出(如日志、指标和追踪)来理解系统内部状态的能力。在现代分布式系统中,可观测性已成为确保系统可靠性、性能和安全性的关键要素。
1.1 可观测性的三大支柱
- 日志(Logging):记录离散事件,提供系统运行时的详细上下文信息
- 指标(Metrics):提供系统性能和状态的数值度量,通常随时间聚合
- 追踪(Tracing):记录请求在分布式系统中的完整生命周期和调用路径
1.2 可观测性与监控的区别
传统监控主要关注已知问题和预设阈值,而可观测性更注重探索未知问题,通过丰富的上下文数据帮助开发者理解系统行为。
2. 可观测性架构设计
2.1 整体架构
一个完整的可观测性系统通常包含以下组件:
- 数据采集层:在应用中埋点,收集日志、指标和追踪数据
- 数据处理层:对采集的数据进行聚合、转换和丰富
- 存储层:存储处理后的数据,支持高效查询
- 可视化与分析层:提供数据展示、告警和探索功能
2.2 设计原则
- 低侵入性:尽量减少对业务代码的影响
- 高性能:数据采集不应显著影响应用性能
- 一致性:跨服务的数据格式和语义保持一致
- 可扩展性:支持大规模分布式系统
- 安全性:保护敏感数据,确保合规性
3. Java实现可观测性
下面我们通过一个具体的Java示例来演示如何实现系统的可观测性。
3.1 项目设置与依赖
首先,我们创建一个Maven项目,并添加必要的依赖:
xml
<dependencies>
<!-- Micrometer - 指标收集 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.9.5</version>
</dependency>
<!-- OpenTelemetry - 分布式追踪 -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-jaeger</artifactId>
<version>1.22.0</version>
</dependency>
<!-- Logback with JSON layout -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.contrib</groupId>
<artifactId>logback-json-classic</artifactId>
<version>0.1.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.contrib</groupId>
<artifactId>logback-jackson</artifactId>
<version>0.1.5</version>
</dependency>
<!-- Web应用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.4</version>
</dependency>
</dependencies>3.2 日志实现
首先配置结构化的JSON日志输出:
xml
<!-- src/main/resources/logback.xml -->
<configuration>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter
class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
<prettyPrint>false</prettyPrint>
</jsonFormatter>
<timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
<appendLineSeparator>true</appendLineSeparator>
</layout>
</encoder>
</appender>
<appender name="STASH" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.json</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.json</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"service":"order-service","environment":"production"}</customFields>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON" />
<appender-ref ref="STASH" />
</root>
</configuration>创建日志工具类,确保包含必要的上下文信息:
java
// src/main/java/com/example/observability/logging/StructuredLogger.java
package com.example.observability.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import java.util.Map;
import java.util.UUID;
public class StructuredLogger {
private final Logger logger;
public StructuredLogger(Class<?> clazz) {
this.logger = LoggerFactory.getLogger(clazz);
}
public static void setTraceId(String traceId) {
MDC.put("traceId", traceId);
}
public static void setSpanId(String spanId) {
MDC.put("spanId", spanId);
}
public static void clear() {
MDC.clear();
}
public void info(String message, Map<String, Object> context) {
if (context != null) {
context.forEach((key, value) -> MDC.put(key, String.valueOf(value)));
}
logger.info(message);
if (context != null) {
context.keySet().forEach(MDC::remove);
}
}
public void error(String message, Throwable throwable, Map<String, Object> context) {
if (context != null) {
context.forEach((key, value) -> MDC.put(key, String.valueOf(value)));
}
logger.error(message, throwable);
if (context != null) {
context.keySet().forEach(MDC::remove);
}
}
// 其他日志级别方法...
}3.3 指标实现
使用Micrometer实现指标收集:
java
// src/main/java/com/example/observability/metrics/MetricsManager.java
package com.example.observability.metrics;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class MetricsManager {
private final MeterRegistry meterRegistry;
public MetricsManager(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
// 记录HTTP请求
public void recordHttpRequest(String method, String endpoint, int statusCode, long duration) {
Counter.builder("http_requests_total")
.description("Total HTTP requests")
.tag("method", method)
.tag("endpoint", endpoint)
.tag("status", String.valueOf(statusCode))
.register(meterRegistry)
.increment();
Timer.builder("http_request_duration_seconds")
.description("HTTP request duration")
.tag("method", method)
.tag("endpoint", endpoint)
.tag("status", String.valueOf(statusCode))
.register(meterRegistry)
.record(duration, TimeUnit.MILLISECONDS);
}
// 记录业务指标
public void recordBusinessEvent(String eventType, String entity, double value) {
Counter.builder("business_events_total")
.description("Business events counter")
.tag("event_type", eventType)
.tag("entity", entity)
.register(meterRegistry)
.increment();
meterRegistry.summary("business_events_value", "event_type", eventType, "entity", entity)
.record(value);
}
// 记录错误
public void recordError(String errorType, String source) {
Counter.builder("errors_total")
.description("Application errors")
.tag("error_type", errorType)
.tag("source", source)
.register(meterRegistry)
.increment();
}
}创建指标配置类:
java
// src/main/java/com/example/observability/config/MetricsConfig.java
package com.example.observability.config;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
@Configuration
public class MetricsConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config()
.commonTags("application", "order-service", "environment", "production");
}
@Bean
public PrometheusMeterRegistry prometheusMeterRegistry() {
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
// 配置直方图桶
registry.config().meterFilter(
MeterFilter.updateHistogramConfig(
Timer.builder("http_request_duration_seconds")
.publishPercentiles(0.5, 0.95, 0.99)
.publishPercentileHistogram()
.distributionStatisticExpiry(Duration.ofMinutes(10))
.distributionStatisticBufferLength(3)
.register(registry).getId(),
DistributionStatisticConfig.builder()
.percentiles(0.5, 0.95, 0.99)
.percentilePrecision(2)
.build()
)
);
return registry;
}
}3.4 分布式追踪实现
使用OpenTelemetry实现分布式追踪:
java
// src/main/java/com/example/observability/tracing/TracingConfig.java
package com.example.observability.tracing;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TracingConfig {
@Bean
public OpenTelemetry openTelemetry() {
// 配置Jaeger导出器
JaegerGrpcSpanExporter jaegerExporter = JaegerGrpcSpanExporter.builder()
.setEndpoint("http://localhost:14250")
.build();
// 配置资源属性
Resource resource = Resource.getDefault()
.merge(Resource.create(Attributes.builder()
.put(ResourceAttributes.SERVICE_NAME, "order-service")
.put(ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "production")
.build()));
// 配置跟踪提供程序
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(jaegerExporter).build())
.setResource(resource)
.build();
// 创建OpenTelemetry实例
OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
.build();
// 注册全局实例
io.opentelemetry.api.GlobalOpenTelemetry.set(openTelemetrySdk);
return openTelemetrySdk;
}
}创建追踪工具类:
java
// src/main/java/com/example/observability/tracing/TracingManager.java
package com.example.observability.tracing;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.Callable;
@Component
public class TracingManager {
private final Tracer tracer;
public TracingManager(Tracer tracer) {
this.tracer = tracer;
}
public Span startSpan(String name, SpanKind kind) {
return tracer.spanBuilder(name)
.setSpanKind(kind)
.startSpan();
}
public void endSpan(Span span) {
span.end();
}
public void recordException(Span span, Throwable throwable) {
span.recordException(throwable);
}
public void addEvent(Span span, String name, Map<String, Object> attributes) {
if (attributes != null) {
io.opentelemetry.api.common.Attributes.Builder attrsBuilder =
io.opentelemetry.api.common.Attributes.builder();
attributes.forEach((key, value) -> attrsBuilder.put(key, value.toString()));
span.addEvent(name, attrsBuilder.build());
} else {
span.addEvent(name);
}
}
public <T> T withSpan(Span span, Callable<T> callable) {
try (Scope scope = span.makeCurrent()) {
return callable.call();
} catch (Exception e) {
recordException(span, e);
throw new RuntimeException(e);
} finally {
endSpan(span);
}
}
public void withSpan(Span span, Runnable runnable) {
try (Scope scope = span.makeCurrent()) {
runnable.run();
} catch (Exception e) {
recordException(span, e);
throw new RuntimeException(e);
} finally {
endSpan(span);
}
}
}3.5 整合可观测性组件
创建拦截器整合日志、指标和追踪:
java
// src/main/java/com/example/observability/web/ObservabilityInterceptor.java
package com.example.observability.web;
import com.example.observability.logging.StructuredLogger;
import com.example.observability.metrics.MetricsManager;
import com.example.observability.tracing.TracingManager;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Component
public class ObservabilityInterceptor implements HandlerInterceptor {
private final MetricsManager metricsManager;
private final TracingManager tracingManager;
private static final StructuredLogger logger = new StructuredLogger(ObservabilityInterceptor.class);
public ObservabilityInterceptor(MetricsManager metricsManager, TracingManager tracingManager) {
this.metricsManager = metricsManager;
this.tracingManager = tracingManager;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
// 创建或获取跟踪ID
String traceId = request.getHeader("X-Trace-Id");
if (traceId == null || traceId.isEmpty()) {
traceId = UUID.randomUUID().toString();
}
// 创建span
Span span = tracingManager.startSpan(request.getRequestURI(), SpanKind.SERVER);
// 设置日志上下文
StructuredLogger.setTraceId(traceId);
StructuredLogger.setSpanId(span.getSpanContext().getSpanId());
// 记录请求开始
Map<String, Object> logContext = new HashMap<>();
logContext.put("method", request.getMethod());
logContext.put("uri", request.getRequestURI());
logContext.put("remoteAddr", request.getRemoteAddr());
logger.info("Request started", logContext);
// 存储span和traceId到请求属性中
request.setAttribute("span", span);
request.setAttribute("traceId", traceId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
Span span = (Span) request.getAttribute("span");
String traceId = (String) request.getAttribute("traceId");
// 记录指标
metricsManager.recordHttpRequest(
request.getMethod(),
request.getRequestURI(),
response.getStatus(),
duration
);
// 记录错误
if (ex != null) {
metricsManager.recordError(ex.getClass().getSimpleName(), request.getRequestURI());
tracingManager.recordException(span, ex);
}
// 添加追踪属性
span.setAttribute("http.method", request.getMethod());
span.setAttribute("http.url", request.getRequestURI());
span.setAttribute("http.status_code", response.getStatus());
span.setAttribute("http.duration_ms", duration);
// 记录请求完成
Map<String, Object> logContext = new HashMap<>();
logContext.put("method", request.getMethod());
logContext.put("uri", request.getRequestURI());
logContext.put("status", response.getStatus());
logContext.put("durationMs", duration);
logContext.put("traceId", traceId);
logger.info("Request completed", logContext);
// 结束span
tracingManager.endSpan(span);
// 清理日志上下文
StructuredLogger.clear();
}
}注册拦截器:
java
// src/main/java/com/example/observability/config/WebConfig.java
package com.example.observability.config;
import com.example.observability.web.ObservabilityInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final ObservabilityInterceptor observabilityInterceptor;
public WebConfig(ObservabilityInterceptor observabilityInterceptor) {
this.observabilityInterceptor = observabilityInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(observabilityInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/actuator/**");
}
}3.6 业务代码示例
创建一个订单服务示例,展示如何在实际业务中使用可观测性组件:
java
// src/main/java/com/example/observability/service/OrderService.java
package com.example.observability.service;
import com.example.observability.logging.StructuredLogger;
import com.example.observability.metrics.MetricsManager;
import com.example.observability.tracing.TracingManager;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@Service
public class OrderService {
private static final StructuredLogger logger = new StructuredLogger(OrderService.class);
private final MetricsManager metricsManager;
private final TracingManager tracingManager;
private final Random random = new Random();
public OrderService(MetricsManager metricsManager, TracingManager tracingManager) {
this.metricsManager = metricsManager;
this.tracingManager = tracingManager;
}
public String createOrder(String productId, int quantity, double price) {
// 创建业务span
Span span = tracingManager.startSpan("create_order", SpanKind.INTERNAL);
return tracingManager.withSpan(span, () -> {
try {
// 模拟业务逻辑
Map<String, Object> logContext = new HashMap<>();
logContext.put("productId", productId);
logContext.put("quantity", quantity);
logContext.put("price", price);
logger.info("Creating order", logContext);
// 模拟处理时间
Thread.sleep(random.nextInt(200));
// 模拟偶尔失败
if (random.nextDouble() < 0.1) {
throw new RuntimeException("Inventory check failed");
}
String orderId = "ORD" + System.currentTimeMillis();
// 记录业务指标
metricsManager.recordBusinessEvent("order_created", "order", price * quantity);
// 添加追踪事件
Map<String, Object> eventAttrs = new HashMap<>();
eventAttrs.put("orderId", orderId);
eventAttrs.put("totalValue", price * quantity);
tracingManager.addEvent(span, "order_created", eventAttrs);
logger.info("Order created successfully", Map.of("orderId", orderId));
return orderId;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
tracingManager.recordException(span, e);
metricsManager.recordError("interrupted", "order_service");
throw new RuntimeException("Order creation interrupted", e);
} catch (Exception e) {
tracingManager.recordException(span, e);
metricsManager.recordError("creation_failed", "order_service");
logger.error("Order creation failed", e, Map.of("productId", productId));
throw e;
}
});
}
public double getOrderStats() {
Span span = tracingManager.startSpan("get_order_stats", SpanKind.INTERNAL);
return tracingManager.withSpan(span, () -> {
try {
logger.info("Fetching order statistics", null);
// 模拟数据库查询
Thread.sleep(random.nextInt(100));
// 模拟返回统计数据
double stats = random.nextDouble() * 1000;
metricsManager.recordBusinessEvent("stats_fetched", "order", stats);
return stats;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
tracingManager.recordException(span, e);
throw new RuntimeException("Stats fetching interrupted", e);
}
});
}
}创建REST控制器:
java
// src/main/java/com/example/observability/web/OrderController.java
package com.example.observability.web;
import com.example.observability.service.OrderService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping("/orders")
public ResponseEntity<Map<String, Object>> createOrder(
@RequestParam String productId,
@RequestParam int quantity,
@RequestParam double price) {
try {
String orderId = orderService.createOrder(productId, quantity, price);
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("orderId", orderId);
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.internalServerError().body(response);
}
}
@GetMapping("/stats")
public ResponseEntity<Map<String, Object>> getStats() {
try {
double stats = orderService.getOrderStats();
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("stats", stats);
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.internalServerError().body(response);
}
}
}3.7 健康检查和监控端点
添加Spring Boot Actuator端点用于健康检查和指标导出:
yaml
# src/main/resources/application.yml
management:
endpoints:
web:
exposure:
include: health, metrics, prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
http.server.requests: true
percentiles:
http.server.requests: 0.5, 0.95, 0.994. 部署与可视化
4.1 使用Docker Compose部署可观测性栈
yaml
# docker-compose.yml
version: '3.8'
services:
# Jaeger - 分布式追踪
jaeger:
image: jaegertracing/all-in-one:1.40
ports:
- "16686:16686"
- "14250:14250"
# Prometheus - 指标收集
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
# Grafana - 数据可视化
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- ./grafana-dashboards:/var/lib/grafana/dashboards
# Elasticsearch + Kibana - 日志存储和可视化
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
kibana:
image: docker.elastic.co/kibana/kibana:8.5.0
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:92004.2 Prometheus配置
yaml
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'order-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']5. 测试与验证
5.1 创建测试类验证可观测性功能
java
// src/test/java/com/example/observability/ObservabilityTest.java
package com.example.observability;
import com.example.observability.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@SpringBootTest
public class ObservabilityTest {
@Autowired
private OrderService orderService;
@Test
public void testOrderCreation() {
String orderId = orderService.createOrder("PROD123", 2, 29.99);
assertNotNull(orderId);
}
@Test
public void testOrderStats() {
double stats = orderService.getOrderStats();
assertNotNull(stats);
}
}5.2 生成负载测试
java
// src/test/java/com/example/observability/LoadTest.java
package com.example.observability;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class LoadTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void generateLoad() throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(10);
// 生成100个请求
for (int i = 0; i < 100; i++) {
final int index = i;
executor.submit(() -> {
try {
ResponseEntity<String> response = restTemplate.postForEntity(
"/orders?productId=PROD{index}&quantity=1&price=10.99",
null,
String.class,
index
);
System.out.println("Request " + index + ": " + response.getStatusCode());
} catch (Exception e) {
System.out.println("Request " + index + " failed: " + e.getMessage());
}
});
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
}
}6. 总结与最佳实践
通过以上实现,我们构建了一个完整的可观测性系统,具有以下特点:
- 全面的数据收集:集成了日志、指标和追踪三大支柱
- 低侵入性设计:通过拦截器和AOP方式减少对业务代码的影响
- 上下文关联:使用Trace ID和Span ID关联不同系统的日志和追踪数据
- 性能优化:使用批量处理和异步操作减少对应用性能的影响
- 标准化输出:遵循OpenTelemetry和Micrometer标准,确保与各种监控后端兼容
6.1 最佳实践
- 合理采样:在高流量系统中实施采样策略,减少数据量
- 敏感信息处理:确保日志和追踪数据中不包含敏感信息
- 告警策略:基于指标数据设置合理的告警阈值
- 容量规划:监控可观测性系统本身的资源使用情况
- 文档和培训:为开发团队提供可观测性工具的使用指南和最佳实践
6.2 扩展方向
- 实时分析:集成流处理平台,实现实时异常检测
- AI运维:使用机器学习算法自动检测异常模式和根因分析
- 用户体验监控:集成真实用户监控(RUM)数据
- 成本优化:基于使用情况优化可观测性数据存储和查询成本
通过以上设计和实现,我们建立了一个强大且可扩展的可观测性系统,能够帮助开发者和运维团队快速发现、诊断和解决系统中的问题,提高系统的可靠性和性能。
猜你喜欢
- 2025-09-28 阿里云工程师日常面对云服务器的必备工具与命令(附实操与源码)
- 2025-09-28 Linux磁盘爆满紧急救援指南:5步清理释放50GB+小白也能轻松搞定
- 2025-09-28 可视化分布式监控系统 Prometheus + Grafana 快速搭建
- 2025-09-28 日志查询哪家强?用Loki 替换ELK没商量,是时候用这个轻量级方案
- 2025-09-28 十几年的java开发程序员了,还停留在curd吗?看看接下来能学什么
- 2025-09-28 Prometheus运维(Prometheus初始化设置,接入主机及进程监控)
- 2025-09-28 集群外部署Prometheus+Grafana监控K8S解析
- 2025-09-28 Go 项目的布局:你是怎么组织你的Go代码的?
- 2025-09-28 用开源软件,搭建类似向日葵或todesk的远程控制软件
- 2025-09-28 致这个这个看脸的世界 — 高颜值监控绘图工具Grafana
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)
