datai/datai-scenes/datai-scene-salesforce/docs/prompts/027-performance-optimization.md

790 lines
24 KiB
Markdown
Raw Normal View History

# Prompt - 性能优化和限流处理
## 输入引用
引用相关的 docs 文档链接:
- [REQ-010-17.md](../requirements/REQ-010-17.md) - 性能优化和限流处理需求文档
- [0026-performance-optimization.md](../decisions/adr/0026-performance-optimization.md) - 性能优化和限流处理架构决策
- [REQ-010.md](../requirements/REQ-010.md) - Salesforce元数据拉取和部署主需求文档
- [REQ-010-1.md](../requirements/REQ-010-1.md) - 数据库表结构设计和创建
- [REQ-010-2.md](../requirements/REQ-010-2.md) - 基础实体类和Mapper创建
- [REQ-010-5.md](../requirements/REQ-010-5.md) - Metadata API客户端封装
- [REQ-010-6.md](../requirements/REQ-010-6.md) - 元数据拉取核心功能
- [REQ-010-8.md](../requirements/REQ-010-8.md) - 元数据部署核心功能
- [metadata-module.md](../reference-code/com/docs/metadata-module.md) - Salesforce Metadata API 模块说明(唯一真源)
- [index.md](../reference-code/com/docs/index.md) - Salesforce SOAP API Java 客户端参考文档(唯一真源)
## Context Maps
强制列出本次 Prompt 依赖的 Canvas 文件:
- [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示
- **相关节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式
- **快照时间**: 2026-01-19 00:00:00
## 目标
实现性能优化和限流处理功能包括API限流处理、并发控制、缓存优化、数据库优化、文件处理优化、性能监控。优化系统性能避免API限流提高系统稳定性。
## 输出格式
代码示例语言Java
## 约束
- **技术栈限制**: 必须基于现有的Spring Boot 3 + Vue 3技术栈
- **架构约束**: 必须遵循Authentication.canvas中定义的架构和调用关系
- **模块约束**: 必须在datai-salesforce-metadata模块下实现
- **数据库约束**: 必须使用MyBatis Plus作为持久层框架
- **性能约束**: 系统性能必须满足要求,不能影响用户体验
- **依赖约束**: 必须依赖于所有其他子需求
## Rule Set
"请严格参考 @Authentication.canvas 中的状态机转移逻辑,不要自行发挥。"
**具体规则**
- 必须使用Canvas中定义的类名和方法名
- 必须遵循Canvas中定义的调用关系
- 必须参考Canvas中的流程图逻辑
## 验收标准
- **功能完整性**: 所有性能优化和限流处理功能能够正常工作
- **性能指标**: 系统性能满足要求API响应时间、数据库查询时间、文件处理时间都在合理范围内
- **稳定性**: 系统稳定性高,不会因为性能问题导致系统崩溃
- **代码规范性**: 代码符合项目编码规范,有清晰的注释
- **可维护性**: 代码结构清晰,易于扩展和维护
- **可测试性**: 代码易于单元测试和集成测试
## 风险
- **限流处理风险**: 限流处理不当可能导致API调用失败
- **并发控制风险**: 并发控制不当可能导致系统资源耗尽
- **缓存风险**: 缓存不一致可能导致数据错误
- **数据库优化风险**: 数据库优化不当可能导致查询性能下降
- **文件处理风险**: 文件处理优化不当可能导致内存溢出
- **性能监控风险**: 性能监控不准确可能导致误判
## 实现指南
### 1. API限流处理
#### 1.1 创建限流配置类
```java
package com.datai.salesforce.metadata.config;
import com.google.common.util.concurrent.RateLimiter;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "rate-limit")
public class RateLimitConfig {
private int permitsPerSecond = 10;
private int maxRetries = 3;
private long initialRetryInterval = 1000;
private double retryMultiplier = 2.0;
@Bean
public RateLimiter rateLimiter() {
return RateLimiter.create(permitsPerSecond);
}
}
```
#### 1.2 创建限流注解
```java
package com.datai.salesforce.metadata.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
int permitsPerSecond() default 10;
int maxRetries() default 3;
long initialRetryInterval() default 1000;
double retryMultiplier() default 2.0;
}
```
#### 1.3 创建限流切面
```java
package com.datai.salesforce.metadata.aspect;
import com.google.common.util.concurrent.RateLimiter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class RateLimitAspect {
private final RateLimiter rateLimiter;
@Around("@annotation(rateLimit)")
public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
if (!rateLimiter.tryAcquire()) {
log.warn("Rate limit exceeded, method: {}", joinPoint.getSignature().getName());
throw new RuntimeException("Rate limit exceeded");
}
return joinPoint.proceed();
}
}
```
#### 1.4 创建限流异常类
```java
package com.datai.salesforce.metadata.exception;
import lombok.Getter;
@Getter
public class RateLimitException extends RuntimeException {
private final int statusCode;
public RateLimitException(int statusCode, String message) {
super(message);
this.statusCode = statusCode;
}
public RateLimitException(int statusCode, String message, Throwable cause) {
super(message, cause);
this.statusCode = statusCode;
}
}
```
#### 1.5 创建限流服务
```java
package com.datai.salesforce.metadata.service;
import com.google.common.util.concurrent.RateLimiter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class RateLimitService {
private final RateLimiter rateLimiter;
@Retryable(
value = {RateLimitException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2.0)
)
public <T> T executeWithRateLimit(RunnableWithResult<T> runnable) {
if (!rateLimiter.tryAcquire()) {
log.warn("Rate limit exceeded");
throw new RateLimitException(429, "Rate limit exceeded");
}
return runnable.run();
}
@FunctionalInterface
public interface RunnableWithResult<T> {
T run();
}
}
```
### 2. 并发控制
#### 2.1 创建线程池配置类
```java
package com.datai.salesforce.metadata.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@Data
@Configuration
@ConfigurationProperties(prefix = "thread-pool")
public class ThreadPoolConfig {
private int corePoolSize = 5;
private int maxPoolSize = 10;
private int queueCapacity = 100;
private long keepAliveTime = 60;
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds((int) keepAliveTime);
executor.setThreadNamePrefix("task-executor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Bean(name = "priorityTaskExecutor")
public Executor priorityTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds((int) keepAliveTime);
executor.setThreadNamePrefix("priority-task-executor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setTaskDecorator(runnable -> {
if (runnable instanceof PriorityTask) {
return (PriorityTask) runnable;
}
return new PriorityTask(runnable, 5);
});
executor.initialize();
return executor;
}
}
```
#### 2.2 创建优先级任务类
```java
package com.datai.salesforce.metadata.task;
import lombok.Getter;
@Getter
public class PriorityTask implements Runnable, Comparable<PriorityTask> {
private final Runnable runnable;
private final int priority;
public PriorityTask(Runnable runnable, int priority) {
this.runnable = runnable;
this.priority = priority;
}
@Override
public void run() {
runnable.run();
}
@Override
public int compareTo(PriorityTask other) {
return Integer.compare(other.priority, this.priority);
}
}
```
#### 2.3 创建并发控制服务
```java
package com.datai.salesforce.metadata.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@Slf4j
@Service
@RequiredArgsConstructor
public class ConcurrencyControlService {
private final Executor taskExecutor;
private final Executor priorityTaskExecutor;
@Async("taskExecutor")
public CompletableFuture<Void> executeAsync(Runnable runnable) {
try {
runnable.run();
return CompletableFuture.completedFuture(null);
} catch (Exception e) {
log.error("Execute async task failed", e);
return CompletableFuture.failedFuture(e);
}
}
@Async("priorityTaskExecutor")
public CompletableFuture<Void> executeAsyncWithPriority(Runnable runnable, int priority) {
try {
runnable.run();
return CompletableFuture.completedFuture(null);
} catch (Exception e) {
log.error("Execute async task with priority failed", e);
return CompletableFuture.failedFuture(e);
}
}
}
```
### 3. 缓存优化
#### 3.1 创建缓存配置类
```java
package com.datai.salesforce.metadata.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
}
```
#### 3.2 创建缓存服务
```java
package com.datai.salesforce.metadata.service;
import com.datai.salesforce.metadata.entity.OrgConfig;
import com.datai.salesforce.metadata.entity.TaskDefinition;
import com.datai.salesforce.metadata.entity.MetadataComponent;
import com.datai.salesforce.metadata.mapper.OrgConfigMapper;
import com.datai.salesforce.metadata.mapper.TaskDefinitionMapper;
import com.datai.salesforce.metadata.mapper.MetadataComponentMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class CacheService {
private final OrgConfigMapper orgConfigMapper;
private final TaskDefinitionMapper taskDefinitionMapper;
private final MetadataComponentMapper metadataComponentMapper;
@Cacheable(value = "orgConfig", key = "#id", unless = "#result == null")
public OrgConfig getOrgConfigById(Long id) {
log.info("Cache miss for org config: {}", id);
return orgConfigMapper.selectById(id);
}
@CachePut(value = "orgConfig", key = "#orgConfig.id")
public OrgConfig updateOrgConfig(OrgConfig orgConfig) {
orgConfigMapper.updateById(orgConfig);
return orgConfig;
}
@CacheEvict(value = "orgConfig", key = "#id")
public void deleteOrgConfig(Long id) {
orgConfigMapper.deleteById(id);
}
@Cacheable(value = "taskDefinition", key = "#id", unless = "#result == null")
public TaskDefinition getTaskDefinitionById(Long id) {
log.info("Cache miss for task definition: {}", id);
return taskDefinitionMapper.selectById(id);
}
@CachePut(value = "taskDefinition", key = "#taskDefinition.id")
public TaskDefinition updateTaskDefinition(TaskDefinition taskDefinition) {
taskDefinitionMapper.updateById(taskDefinition);
return taskDefinition;
}
@CacheEvict(value = "taskDefinition", key = "#id")
public void deleteTaskDefinition(Long id) {
taskDefinitionMapper.deleteById(id);
}
@Cacheable(value = "metadataComponent", key = "#id", unless = "#result == null")
public MetadataComponent getMetadataComponentById(Long id) {
log.info("Cache miss for metadata component: {}", id);
return metadataComponentMapper.selectById(id);
}
@CachePut(value = "metadataComponent", key = "#metadataComponent.id")
public MetadataComponent updateMetadataComponent(MetadataComponent metadataComponent) {
metadataComponentMapper.updateById(metadataComponent);
return metadataComponent;
}
@CacheEvict(value = "metadataComponent", key = "#id")
public void deleteMetadataComponent(Long id) {
metadataComponentMapper.deleteById(id);
}
}
```
### 4. 数据库优化
#### 4.1 创建批量操作服务
```java
package com.datai.salesforce.metadata.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.datai.salesforce.metadata.entity.MetadataComponent;
import com.datai.salesforce.metadata.mapper.MetadataComponentMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class BatchOperationService extends ServiceImpl<MetadataComponentMapper, MetadataComponent> {
private final MetadataComponentMapper metadataComponentMapper;
public boolean saveBatch(List<MetadataComponent> list) {
return saveBatch(list, 100);
}
public boolean updateBatchById(List<MetadataComponent> list) {
return updateBatchById(list, 100);
}
public boolean removeBatchByIds(List<Long> ids) {
return removeByIds(ids);
}
}
```
#### 4.2 创建查询优化服务
```java
package com.datai.salesforce.metadata.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.datai.salesforce.metadata.entity.MetadataComponent;
import com.datai.salesforce.metadata.mapper.MetadataComponentMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class QueryOptimizationService {
private final MetadataComponentMapper metadataComponentMapper;
public Page<MetadataComponent> pageQuery(int pageNum, int pageSize, String componentType, String apiName) {
QueryWrapper<MetadataComponent> queryWrapper = new QueryWrapper<>();
if (componentType != null && !componentType.isEmpty()) {
queryWrapper.eq("component_type", componentType);
}
if (apiName != null && !apiName.isEmpty()) {
queryWrapper.like("api_name", apiName);
}
queryWrapper.orderByDesc("create_time");
return metadataComponentMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
}
public List<MetadataComponent> batchQuery(List<Long> ids) {
return metadataComponentMapper.selectBatchIds(ids);
}
}
```
### 5. 文件处理优化
#### 5.1 创建流式文件处理服务
```java
package com.datai.salesforce.metadata.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@Slf4j
@Service
@RequiredArgsConstructor
public class FileProcessingService {
public void processLargeFile(Path filePath, FileProcessor processor) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(filePath)) {
String line;
while ((line = reader.readLine()) != null) {
processor.process(line);
}
}
}
public void compressFile(Path sourcePath, Path targetPath) throws IOException {
try (InputStream in = Files.newInputStream(sourcePath);
OutputStream out = new GZIPOutputStream(Files.newOutputStream(targetPath))) {
byte[] buffer = new byte[8192];
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
}
public void decompressFile(Path sourcePath, Path targetPath) throws IOException {
try (InputStream in = new GZIPInputStream(Files.newInputStream(sourcePath));
OutputStream out = Files.newOutputStream(targetPath)) {
byte[] buffer = new byte[8192];
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
}
@FunctionalInterface
public interface FileProcessor {
void process(String line);
}
}
```
#### 5.2 创建并行文件处理服务
```java
package com.datai.salesforce.metadata.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class ParallelFileProcessingService {
@Async
public CompletableFuture<Void> processFilesInParallel(List<Path> filePaths, FileProcessingService.FileProcessor processor) {
List<CompletableFuture<Void>> futures = filePaths.stream()
.map(filePath -> CompletableFuture.runAsync(() -> {
try {
processFile(filePath, processor);
} catch (Exception e) {
log.error("Process file failed: {}", filePath, e);
}
}))
.collect(Collectors.toList());
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
}
private void processFile(Path filePath, FileProcessingService.FileProcessor processor) throws Exception {
try (BufferedReader reader = java.nio.file.Files.newBufferedReader(filePath)) {
String line;
while ((line = reader.readLine()) != null) {
processor.process(line);
}
}
}
}
```
### 6. 性能监控
#### 6.1 创建性能监控配置类
```java
package com.datai.salesforce.metadata.config;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PerformanceMonitoringConfig {
@Bean
public Timer apiCallTimer(MeterRegistry registry) {
return Timer.builder("api.call.timer")
.description("API call timer")
.register(registry);
}
@Bean
public Timer databaseQueryTimer(MeterRegistry registry) {
return Timer.builder("database.query.timer")
.description("Database query timer")
.register(registry);
}
@Bean
public Timer fileProcessingTimer(MeterRegistry registry) {
return Timer.builder("file.processing.timer")
.description("File processing timer")
.register(registry);
}
}
```
#### 6.2 创建性能监控服务
```java
package com.datai.salesforce.metadata.service;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@RequiredArgsConstructor
public class PerformanceMonitoringService {
private final MeterRegistry meterRegistry;
private final Timer apiCallTimer;
private final Timer databaseQueryTimer;
private final Timer fileProcessingTimer;
public void recordApiCall() {
Counter.builder("api.call.count")
.description("API call count")
.register(meterRegistry)
.increment();
}
public void recordApiCallTime(long duration, TimeUnit unit) {
apiCallTimer.record(duration, unit);
}
public void recordDatabaseQueryTime(long duration, TimeUnit unit) {
databaseQueryTimer.record(duration, unit);
}
public void recordFileProcessingTime(long duration, TimeUnit unit) {
fileProcessingTimer.record(duration, unit);
}
public <T> T recordApiCall(RunnableWithResult<T> runnable) {
long startTime = System.currentTimeMillis();
try {
recordApiCall();
T result = runnable.run();
long duration = System.currentTimeMillis() - startTime;
recordApiCallTime(duration, TimeUnit.MILLISECONDS);
return result;
} catch (Exception e) {
log.error("API call failed", e);
throw new RuntimeException(e);
}
}
public <T> T recordDatabaseQuery(RunnableWithResult<T> runnable) {
long startTime = System.currentTimeMillis();
try {
T result = runnable.run();
long duration = System.currentTimeMillis() - startTime;
recordDatabaseQueryTime(duration, TimeUnit.MILLISECONDS);
return result;
} catch (Exception e) {
log.error("Database query failed", e);
throw new RuntimeException(e);
}
}
public <T> T recordFileProcessing(RunnableWithResult<T> runnable) {
long startTime = System.currentTimeMillis();
try {
T result = runnable.run();
long duration = System.currentTimeMillis() - startTime;
recordFileProcessingTime(duration, TimeUnit.MILLISECONDS);
return result;
} catch (Exception e) {
log.error("File processing failed", e);
throw new RuntimeException(e);
}
}
@FunctionalInterface
public interface RunnableWithResult<T> {
T run() throws Exception;
}
}
```
## 使用记录
| 日期 | 使用场景 | 输入参数 | 输出结果 | 反馈 | 改进措施 |
|------|---------|---------|---------|------|----------|
| 2026-01-19 | 实现性能优化和限流处理功能 | REQ-010-17需求文档0026-performance-optimization ADR文档 | 代码示例和实现指南 | 无 | 无 |