本文目录导读:

- 项目结构
- Maven配置 (pom.xml)
- 主应用类
- 配置类
- 实体类
- 服务客户端 (Feign)
- 服务实现
- 控制器
- 应用配置 (application.yml)
- Istio 配置
- Docker 部署配置
- Kubernetes 部署文件
- Prometheus 配置
- 使用说明
- 监控和追踪
我来为您提供一个完整的服务网格Java实现案例,使用Spring Cloud和Istio的集成方案。
项目结构
service-mesh-demo/
├── pom.xml
├── src/main/java/com/example/
│ ├── ServiceMeshApplication.java
│ ├── config/
│ │ ├── SleuthConfig.java
│ │ └── ResilienceConfig.java
│ ├── controller/
│ │ ├── OrderController.java
│ │ ├── UserController.java
│ │ └── PaymentController.java
│ ├── service/
│ │ ├── OrderService.java
│ │ ├── UserService.java
│ │ └── PaymentService.java
│ └── interceptor/
│ └── TraceInterceptor.java
└── resources/
├── application.yml
└── istio/
├── virtual-service.yaml
└── destination-rule.yaml
Maven配置 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>service-mesh-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.8</spring-cloud.version>
</properties>
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Spring Cloud Sleuth -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- Resilience4j -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>2.0.2</version>
</dependency>
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Prometheus -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
主应用类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.sleuth.zipkin2.EnableZipkinServer;
@SpringBootApplication
@EnableFeignClients
public class ServiceMeshApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceMeshApplication.class, args);
}
}
配置类
1 追踪配置 (SleuthConfig.java)
package com.example.config;
import brave.sampler.Sampler;
import org.springframework.cloud.sleuth.zipkin2.ZipkinProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class SleuthConfig {
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public ZipkinProperties zipkinProperties() {
ZipkinProperties properties = new ZipkinProperties();
properties.setBaseUrl("http://zipkin:9411");
properties.setEnabled(true);
return properties;
}
}
2 弹性配置 (ResilienceConfig.java)
package com.example.config;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.timelimiter.TimeLimiter;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
@Configuration
public class ResilienceConfig {
@Bean
public CircuitBreaker circuitBreaker() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.permittedNumberOfCallsInHalfOpenState(3)
.slidingWindowSize(10)
.minimumNumberOfCalls(5)
.build();
return CircuitBreaker.of("orderService", config);
}
@Bean
public Retry retry() {
RetryConfig config = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(100))
.build();
return Retry.of("orderService", config);
}
@Bean
public TimeLimiter timeLimiter() {
TimeLimiterConfig config = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(3))
.build();
return TimeLimiter.of("orderService", config);
}
}
实体类
package com.example.model;
import lombok.Data;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private Long id;
private Long userId;
private String orderNumber;
private BigDecimal amount;
private String status;
private LocalDateTime createTime;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String username;
private String email;
private String phone;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Payment {
private Long id;
private Long orderId;
private BigDecimal amount;
private String paymentMethod;
private String status;
private LocalDateTime paymentTime;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.code(200)
.message("success")
.data(data)
.build();
}
public static <T> ApiResponse<T> error(int code, String message) {
return ApiResponse.<T>builder()
.code(code)
.message(message)
.build();
}
}
服务客户端 (Feign)
package com.example.client;
import com.example.model.ApiResponse;
import com.example.model.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/api/users/{id}")
ApiResponse<User> getUserById(@PathVariable("id") Long id);
}
@Component
class UserClientFallback implements UserClient {
@Override
public ApiResponse<User> getUserById(Long id) {
return ApiResponse.error(503, "用户服务不可用");
}
}
package com.example.client;
import com.example.model.ApiResponse;
import com.example.model.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = "payment-service", fallback = PaymentClientFallback.class)
public interface PaymentClient {
@PostMapping("/api/payments")
ApiResponse<Payment> createPayment(@RequestBody Payment payment);
@GetMapping("/api/payments/order/{orderId}")
ApiResponse<Payment> getPaymentByOrderId(@PathVariable("orderId") Long orderId);
}
@Component
class PaymentClientFallback implements PaymentClient {
@Override
public ApiResponse<Payment> createPayment(Payment payment) {
return ApiResponse.error(503, "支付服务不可用");
}
@Override
public ApiResponse<Payment> getPaymentByOrderId(Long orderId) {
return ApiResponse.error(503, "支付服务不可用");
}
}
服务实现
1 订单服务 (OrderService.java)
package com.example.service;
import com.example.client.PaymentClient;
import com.example.client.UserClient;
import com.example.model.*;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.UUID;
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderService {
private final UserClient userClient;
private final PaymentClient paymentClient;
// 使用ConcurrentHashMap存储订单(模拟数据库)
private final ConcurrentHashMap<Long, Order> orderStore = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, List<Order>> userOrdersStore = new ConcurrentHashMap<>();
@CircuitBreaker(name = "orderService", fallbackMethod = "createOrderFallback")
@Retry(name = "orderService")
public ApiResponse<Order> createOrder(Long userId, BigDecimal amount) {
log.info("开始创建订单,用户ID: {}, 金额: {}", userId, amount);
// 调用用户服务获取用户信息
ApiResponse<User> userResponse = userClient.getUserById(userId);
if (userResponse.getCode() != 200) {
return ApiResponse.error(userResponse.getCode(), "获取用户信息失败");
}
User user = userResponse.getData();
log.info("成功获取用户信息: {}", user.getUsername());
// 创建订单
Long orderId = System.currentTimeMillis();
Order order = Order.builder()
.id(orderId)
.userId(userId)
.orderNumber(generateOrderNumber(userId))
.amount(amount)
.status("CREATED")
.createTime(LocalDateTime.now())
.build();
orderStore.put(orderId, order);
userOrdersStore.computeIfAbsent(userId, k -> new ArrayList<>()).add(order);
// 调用支付服务
Payment payment = Payment.builder()
.orderId(orderId)
.amount(amount)
.paymentMethod("BALANCE")
.status("PENDING")
.build();
ApiResponse<Payment> paymentResponse = paymentClient.createPayment(payment);
if (paymentResponse.getCode() != 200) {
order.setStatus("PAYMENT_FAILED");
return ApiResponse.error(500, "支付创建失败");
}
order.setStatus("PAID");
log.info("订单创建成功,订单号: {}", order.getOrderNumber());
return ApiResponse.success(order);
}
@CircuitBreaker(name = "orderService", fallbackMethod = "getOrderFallback")
public ApiResponse<Order> getOrder(Long orderId) {
log.info("查询订单,订单ID: {}", orderId);
Order order = orderStore.get(orderId);
if (order == null) {
return ApiResponse.error(404, "订单不存在");
}
// 异步获取支付信息
CompletableFuture<ApiResponse<Payment>> paymentFuture =
CompletableFuture.supplyAsync(() -> paymentClient.getPaymentByOrderId(orderId));
try {
ApiResponse<Payment> paymentResponse = paymentFuture.get();
if (paymentResponse.getCode() == 200) {
order.setStatus("PAID");
}
} catch (Exception e) {
log.warn("获取支付信息失败", e);
}
return ApiResponse.success(order);
}
@CircuitBreaker(name = "orderService", fallbackMethod = "getUserOrdersFallback")
public ApiResponse<List<Order>> getUserOrders(Long userId) {
log.info("查询用户订单,用户ID: {}", userId);
List<Order> orders = userOrdersStore.getOrDefault(userId, new ArrayList<>());
return ApiResponse.success(orders);
}
private String generateOrderNumber(Long userId) {
return "ORD-" + userId + "-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
}
// 降级方法
private ApiResponse<Order> createOrderFallback(Long userId, BigDecimal amount, Throwable t) {
log.error("创建订单降级,用户ID: {}", userId, t);
return ApiResponse.error(503, "订单服务暂时不可用,请稍后重试");
}
private ApiResponse<Order> getOrderFallback(Long orderId, Throwable t) {
log.error("查询订单降级,订单ID: {}", orderId, t);
return ApiResponse.error(503, "订单服务暂时不可用,请稍后重试");
}
private ApiResponse<List<Order>> getUserOrdersFallback(Long userId, Throwable t) {
log.error("查询用户订单降级,用户ID: {}", userId, t);
return ApiResponse.error(503, "订单服务暂时不可用,请稍后重试");
}
}
2 用户服务 (UserService.java)
package com.example.service;
import com.example.model.ApiResponse;
import com.example.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Service
public class UserService {
private final ConcurrentHashMap<Long, User> userStore = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
// 初始化一些测试数据
userStore.put(1L, User.builder()
.id(1L)
.username("zhangsan")
.email("zhangsan@example.com")
.phone("13800138000")
.build());
userStore.put(2L, User.builder()
.id(2L)
.username("lisi")
.email("lisi@example.com")
.phone("13900139000")
.build());
}
public ApiResponse<User> getUserById(Long id) {
log.info("查询用户信息,用户ID: {}", id);
// 模拟延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
User user = userStore.get(id);
if (user == null) {
return ApiResponse.error(404, "用户不存在");
}
return ApiResponse.success(user);
}
}
3 支付服务 (PaymentService.java)
package com.example.service;
import com.example.model.ApiResponse;
import com.example.model.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Service
public class PaymentService {
private final ConcurrentHashMap<Long, Payment> paymentStore = new ConcurrentHashMap<>();
public ApiResponse<Payment> createPayment(Payment payment) {
log.info("创建支付记录,订单ID: {}", payment.getOrderId());
// 模拟支付处理
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Long paymentId = System.currentTimeMillis();
payment.setId(paymentId);
payment.setPaymentTime(LocalDateTime.now());
payment.setStatus("SUCCESS");
// 生成支付流水号
payment.setPaymentMethod("WeChat Pay");
paymentStore.put(paymentId, payment);
log.info("支付成功,支付ID: {}", paymentId);
return ApiResponse.success(payment);
}
public ApiResponse<Payment> getPaymentByOrderId(Long orderId) {
log.info("查询支付记录,订单ID: {}", orderId);
Payment payment = paymentStore.values().stream()
.filter(p -> p.getOrderId().equals(orderId))
.findFirst()
.orElse(null);
if (payment == null) {
return ApiResponse.error(404, "支付记录不存在");
}
return ApiResponse.success(payment);
}
}
控制器
1 订单控制器 (OrderController.java)
package com.example.controller;
import com.example.model.ApiResponse;
import com.example.model.Order;
import com.example.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import java.math.BigDecimal;
import java.util.List;
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@PostMapping
public ResponseEntity<ApiResponse<Order>> createOrder(
@RequestParam("userId") Long userId,
@RequestParam("amount") BigDecimal amount) {
return ResponseEntity.ok(orderService.createOrder(userId, amount));
}
@GetMapping("/{orderId}")
public ResponseEntity<ApiResponse<Order>> getOrder(@PathVariable Long orderId) {
return ResponseEntity.ok(orderService.getOrder(orderId));
}
@GetMapping("/user/{userId}")
public ResponseEntity<ApiResponse<List<Order>>> getUserOrders(@PathVariable Long userId) {
return ResponseEntity.ok(orderService.getUserOrders(userId));
}
}
2 用户控制器 (UserController.java)
package com.example.controller;
import com.example.model.ApiResponse;
import com.example.model.User;
import com.example.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<User>> getUserById(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}
}
3 支付控制器 (PaymentController.java)
package com.example.controller;
import com.example.model.ApiResponse;
import com.example.model.Payment;
import com.example.service.PaymentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/payments")
@RequiredArgsConstructor
public class PaymentController {
private final PaymentService paymentService;
@PostMapping
public ResponseEntity<ApiResponse<Payment>> createPayment(@RequestBody Payment payment) {
return ResponseEntity.ok(paymentService.createPayment(payment));
}
@GetMapping("/order/{orderId}")
public ResponseEntity<ApiResponse<Payment>> getPaymentByOrderId(@PathVariable Long orderId) {
return ResponseEntity.ok(paymentService.getPaymentByOrderId(orderId));
}
}
应用配置 (application.yml)
server:
port: 8080
spring:
application:
name: order-service
sleuth:
sampler:
probability: 1.0
zipkin:
base-url: http://zipkin:9411
enabled: true
management:
endpoints:
web:
exposure:
include: health,info,prometheus,metrics
metrics:
export:
prometheus:
enabled: true
endpoint:
health:
show-details: always
resilience4j:
circuitbreaker:
instances:
orderService:
register-health-indicator: true
sliding-window-size: 10
sliding-window-type: COUNT_BASED
minimum-number-of-calls: 5
permitted-number-of-calls-in-half-open-state: 3
automatic-transition-from-open-to-half-open-enabled: true
wait-duration-in-open-state: 5s
failure-rate-threshold: 50
event-consumer-buffer-size: 10
retry:
instances:
orderService:
max-attempts: 3
wait-duration: 100ms
retry-exceptions:
- java.io.IOException
timelimiter:
instances:
orderService:
timeout-duration: 3s
cancel-running-future: true
logging:
level:
com.example: DEBUG
org.springframework.cloud.sleuth: DEBUG
Istio 配置
1 虚拟服务 (virtual-service.yaml)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: order-service-virtual-service
namespace: default
spec:
hosts:
- order-service
http:
- match:
- headers:
version:
exact: v1
route:
- destination:
host: order-service
subset: v1
weight: 100
- route:
- destination:
host: order-service
subset: v2
weight: 0
2 目标规则 (destination-rule.yaml)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: order-service-destination-rule
namespace: default
spec:
host: order-service
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
connectionPool:
tcp:
maxConnections: 100
connectTimeout: 100ms
http:
http1MaxPendingRequests: 100
http2MaxRequests: 1000
maxRequestsPerConnection: 100
outlierDetection:
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 60s
maxEjectionPercent: 50
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
3 网关配置 (gateway.yaml)
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: ingress-gateway
namespace: default
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*.example.com"
4 服务入口 (service-entry.yaml)
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-services
namespace: default
spec:
hosts:
- "*.google.com"
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
Docker 部署配置
1 Dockerfile
FROM openjdk:11-jre-slim LABEL maintainer="your-email@example.com" WORKDIR /app COPY target/service-mesh-demo-1.0.0.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
2 docker-compose.yml
version: '3.8'
services:
order-service:
build: .
container_name: order-service
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_CLIENT_ENABLED=true
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
networks:
- mesh-network
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
zipkin:
image: openzipkin/zipkin:2.23
container_name: zipkin
ports:
- "9411:9411"
networks:
- mesh-network
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
networks:
- mesh-network
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
networks:
- mesh-network
networks:
mesh-network:
driver: bridge
Kubernetes 部署文件
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: default
labels:
app: order-service
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: order-service
version: v1
template:
metadata:
labels:
app: order-service
version: v1
spec:
containers:
- name: order-service
image: your-registry/order-service:1.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: ZIPKIN_BASE_URL
value: "http://zipkin:9411"
restartPolicy: Always
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: default
labels:
app: order-service
spec:
selector:
app: order-service
ports:
- port: 8080
targetPort: 8080
name: http
type: ClusterIP
---
# service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: order-service-monitor
namespace: monitoring
labels:
app: order-service
spec:
selector:
matchLabels:
app: order-service
endpoints:
- port: http
path: /actuator/prometheus
interval: 15s
Prometheus 配置
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'spring-boot-apps'
metrics_path: '/actuator/prometheus'
static_configs:
- targets:
- 'order-service:8080'
labels:
application: 'order-service'
group: 'service-mesh'
- job_name: 'istio-mesh'
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- default
- istio-system
relabel_configs:
- source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
regex: istio-proxy;(https|http)
action: keep
使用说明
1 本地运行
# 构建项目 mvn clean package # 运行服务 java -jar target/service-mesh-demo-1.0.0.jar # 测试API curl -X POST "http://localhost:8080/api/orders?userId=1&amount=100.00" curl -X GET "http://localhost:8080/api/orders/1234567890" curl -X GET "http://localhost:8080/api/orders/user/1"
2 部署到Kubernetes
# 构建Docker镜像 docker build -t order-service:1.0.0 . # 推送到仓库 docker push your-registry/order-service:1.0.0 # 部署服务 kubectl apply -f deployment.yaml kubectl apply -f service.yaml # 部署Istio配置 istioctl install --set profile=demo kubectl apply -f gateway.yaml kubectl apply -f virtual-service.yaml kubectl apply -f destination-rule.yaml
监控和追踪
1 访问监控面板
- Zipkin UI: http://localhost:9411
- Prometheus UI: http://localhost:9090
- Grafana UI: http://localhost:3000
2 查看追踪信息
# 查看Pod状态 kubectl get pods # 查看服务日志 kubectl logs -f deployment/order-service # 查看Zipkin追踪 curl "http://localhost:9411/api/v2/traces?serviceName=order-service"
这个服务网格案例展示了如何使用Java和Spring Cloud实现服务网格的核心功能,包括服务发现、负载均衡、熔断、重试、追踪等,并结合Istio实现了完整的服务网格解决方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播