提交qiming-mcp-proxy
This commit is contained in:
1068
qiming-mcp-proxy/document-parser/src/performance/cache_manager.rs
Normal file
1068
qiming-mcp-proxy/document-parser/src/performance/cache_manager.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,704 @@
|
||||
//! 并发优化器
|
||||
//!
|
||||
//! 提供任务队列管理、工作线程池和负载均衡功能
|
||||
#![allow(dead_code)]
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::{Mutex, RwLock, Semaphore, mpsc, oneshot};
|
||||
use tokio::task::JoinHandle;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{ConcurrencyConfig, PerformanceOptimizable};
|
||||
use crate::config::AppConfig;
|
||||
use crate::error::AppError;
|
||||
|
||||
/// 并发优化器
|
||||
pub struct ConcurrencyOptimizer {
|
||||
config: ConcurrencyConfig,
|
||||
task_queue: Arc<TaskQueue>,
|
||||
worker_pool: Arc<WorkerPool>,
|
||||
load_balancer: Arc<LoadBalancer>,
|
||||
semaphore: Arc<Semaphore>,
|
||||
stats: Arc<ConcurrencyStats>,
|
||||
}
|
||||
|
||||
impl ConcurrencyOptimizer {
|
||||
/// 创建新的并发优化器
|
||||
pub async fn new(_config: &AppConfig) -> Result<Self, AppError> {
|
||||
let concurrency_config = ConcurrencyConfig::default(); // 从配置中获取
|
||||
|
||||
let task_queue = Arc::new(TaskQueue::new(concurrency_config.task_queue_size));
|
||||
let worker_pool = Arc::new(WorkerPool::new(concurrency_config.worker_threads).await?);
|
||||
let load_balancer = Arc::new(LoadBalancer::new());
|
||||
let semaphore = Arc::new(Semaphore::new(concurrency_config.max_concurrent_tasks));
|
||||
let stats = Arc::new(ConcurrencyStats::new());
|
||||
|
||||
Ok(Self {
|
||||
config: concurrency_config,
|
||||
task_queue,
|
||||
worker_pool,
|
||||
load_balancer,
|
||||
semaphore,
|
||||
stats,
|
||||
})
|
||||
}
|
||||
|
||||
/// 提交任务
|
||||
pub async fn submit_task<F, T>(&self, task: F) -> Result<TaskHandle<T>, AppError>
|
||||
where
|
||||
F: FnOnce() -> BoxFuture<'static, Result<T, AppError>> + Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
// 获取信号量许可
|
||||
let permit = self
|
||||
.semaphore
|
||||
.clone()
|
||||
.acquire_owned()
|
||||
.await
|
||||
.map_err(|_| AppError::Config("Concurrency limit exceeded".to_string()))?;
|
||||
|
||||
// 创建任务
|
||||
let task_id = Uuid::new_v4().to_string();
|
||||
let (result_tx, result_rx) = oneshot::channel();
|
||||
|
||||
let concurrent_task = ConcurrentTask {
|
||||
id: task_id.clone(),
|
||||
task: Box::new(move || {
|
||||
Box::pin(async move {
|
||||
let result = task().await;
|
||||
let _ = result_tx.send(result);
|
||||
})
|
||||
}),
|
||||
priority: TaskPriority::Normal,
|
||||
submitted_at: Instant::now(),
|
||||
timeout: self.config.task_timeout,
|
||||
};
|
||||
|
||||
// 提交到队列
|
||||
self.task_queue.enqueue(concurrent_task).await?;
|
||||
|
||||
// 更新统计
|
||||
self.stats.record_task_submitted().await;
|
||||
|
||||
// 通知工作池有新任务
|
||||
self.worker_pool.notify_new_task().await;
|
||||
|
||||
Ok(TaskHandle {
|
||||
id: task_id,
|
||||
result_rx,
|
||||
_permit: permit,
|
||||
})
|
||||
}
|
||||
|
||||
/// 提交高优先级任务
|
||||
pub async fn submit_priority_task<F, T>(&self, task: F) -> Result<TaskHandle<T>, AppError>
|
||||
where
|
||||
F: FnOnce() -> BoxFuture<'static, Result<T, AppError>> + Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
let permit = self
|
||||
.semaphore
|
||||
.clone()
|
||||
.acquire_owned()
|
||||
.await
|
||||
.map_err(|_| AppError::Config("Concurrency limit exceeded".to_string()))?;
|
||||
|
||||
let task_id = Uuid::new_v4().to_string();
|
||||
let (result_tx, result_rx) = oneshot::channel();
|
||||
|
||||
let concurrent_task = ConcurrentTask {
|
||||
id: task_id.clone(),
|
||||
task: Box::new(move || {
|
||||
Box::pin(async move {
|
||||
let result = task().await;
|
||||
let _ = result_tx.send(result);
|
||||
})
|
||||
}),
|
||||
priority: TaskPriority::High,
|
||||
submitted_at: Instant::now(),
|
||||
timeout: self.config.task_timeout,
|
||||
};
|
||||
|
||||
self.task_queue.enqueue_priority(concurrent_task).await?;
|
||||
self.stats.record_priority_task_submitted().await;
|
||||
self.worker_pool.notify_new_task().await;
|
||||
|
||||
Ok(TaskHandle {
|
||||
id: task_id,
|
||||
result_rx,
|
||||
_permit: permit,
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取队列状态
|
||||
pub async fn get_queue_status(&self) -> QueueStatus {
|
||||
QueueStatus {
|
||||
pending_tasks: self.task_queue.pending_count().await,
|
||||
active_tasks: self.worker_pool.active_count().await,
|
||||
available_workers: self.worker_pool.available_count().await,
|
||||
queue_capacity: self.config.task_queue_size,
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取并发统计
|
||||
pub async fn get_concurrency_stats(&self) -> Result<ConcurrencyStats, AppError> {
|
||||
Ok(self.stats.clone_stats().await)
|
||||
}
|
||||
|
||||
/// 调整并发参数
|
||||
pub async fn adjust_concurrency(&self, new_max_concurrent: usize) -> Result<(), AppError> {
|
||||
// 动态调整信号量
|
||||
let current_permits = self.semaphore.available_permits();
|
||||
|
||||
if new_max_concurrent > current_permits {
|
||||
self.semaphore
|
||||
.add_permits(new_max_concurrent - current_permits);
|
||||
}
|
||||
|
||||
self.stats
|
||||
.record_concurrency_adjustment(new_max_concurrent)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl PerformanceOptimizable for ConcurrencyOptimizer {
|
||||
async fn optimize(&self) -> Result<(), AppError> {
|
||||
// 优化任务队列
|
||||
self.task_queue.optimize().await?;
|
||||
|
||||
// 优化工作池
|
||||
self.worker_pool.optimize().await?;
|
||||
|
||||
// 执行负载均衡
|
||||
self.load_balancer.balance(&self.worker_pool).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_stats(&self) -> Result<serde_json::Value, AppError> {
|
||||
let stats = self.get_concurrency_stats().await?;
|
||||
let queue_status = self.get_queue_status().await;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"stats": stats,
|
||||
"queue_status": queue_status
|
||||
}))
|
||||
}
|
||||
|
||||
async fn reset_stats(&self) -> Result<(), AppError> {
|
||||
self.stats.reset().await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 任务队列
|
||||
pub struct TaskQueue {
|
||||
normal_queue: Arc<Mutex<VecDeque<ConcurrentTask>>>,
|
||||
priority_queue: Arc<Mutex<VecDeque<ConcurrentTask>>>,
|
||||
max_size: usize,
|
||||
stats: Arc<QueueStats>,
|
||||
}
|
||||
|
||||
impl TaskQueue {
|
||||
pub fn new(max_size: usize) -> Self {
|
||||
Self {
|
||||
normal_queue: Arc::new(Mutex::new(VecDeque::new())),
|
||||
priority_queue: Arc::new(Mutex::new(VecDeque::new())),
|
||||
max_size,
|
||||
stats: Arc::new(QueueStats::new()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn enqueue(&self, task: ConcurrentTask) -> Result<(), AppError> {
|
||||
let mut queue = self.normal_queue.lock().await;
|
||||
|
||||
if queue.len() >= self.max_size {
|
||||
return Err(AppError::Config("Queue is full".to_string()));
|
||||
}
|
||||
|
||||
queue.push_back(task);
|
||||
self.stats.record_enqueue().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn enqueue_priority(&self, task: ConcurrentTask) -> Result<(), AppError> {
|
||||
let mut queue = self.priority_queue.lock().await;
|
||||
|
||||
if queue.len() >= self.max_size / 2 {
|
||||
// 优先级队列占用一半容量
|
||||
return Err(AppError::Config("Priority queue is full".to_string()));
|
||||
}
|
||||
|
||||
queue.push_back(task);
|
||||
self.stats.record_priority_enqueue().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn dequeue(&self) -> Option<ConcurrentTask> {
|
||||
// 优先处理高优先级任务
|
||||
{
|
||||
let mut priority_queue = self.priority_queue.lock().await;
|
||||
if let Some(task) = priority_queue.pop_front() {
|
||||
self.stats.record_priority_dequeue().await;
|
||||
return Some(task);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理普通任务
|
||||
let mut normal_queue = self.normal_queue.lock().await;
|
||||
if let Some(task) = normal_queue.pop_front() {
|
||||
self.stats.record_dequeue().await;
|
||||
return Some(task);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn pending_count(&self) -> usize {
|
||||
let normal_count = self.normal_queue.lock().await.len();
|
||||
let priority_count = self.priority_queue.lock().await.len();
|
||||
normal_count + priority_count
|
||||
}
|
||||
|
||||
pub async fn optimize(&self) -> Result<(), AppError> {
|
||||
// 清理超时任务
|
||||
let now = Instant::now();
|
||||
|
||||
{
|
||||
let mut normal_queue = self.normal_queue.lock().await;
|
||||
normal_queue.retain(|task| now.duration_since(task.submitted_at) < task.timeout);
|
||||
}
|
||||
|
||||
{
|
||||
let mut priority_queue = self.priority_queue.lock().await;
|
||||
priority_queue.retain(|task| now.duration_since(task.submitted_at) < task.timeout);
|
||||
}
|
||||
|
||||
self.stats.record_cleanup().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 工作线程池
|
||||
pub struct WorkerPool {
|
||||
workers: Vec<Worker>,
|
||||
task_sender: mpsc::UnboundedSender<WorkerMessage>,
|
||||
stats: Arc<WorkerStats>,
|
||||
}
|
||||
|
||||
impl WorkerPool {
|
||||
pub async fn new(worker_count: usize) -> Result<Self, AppError> {
|
||||
let (task_sender, task_receiver) = mpsc::unbounded_channel();
|
||||
let task_receiver = Arc::new(Mutex::new(task_receiver));
|
||||
let stats = Arc::new(WorkerStats::new());
|
||||
|
||||
let mut workers = Vec::new();
|
||||
|
||||
for i in 0..worker_count {
|
||||
let worker = Worker::new(i, task_receiver.clone(), stats.clone()).await?;
|
||||
workers.push(worker);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
workers,
|
||||
task_sender,
|
||||
stats,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn notify_new_task(&self) {
|
||||
let _ = self.task_sender.send(WorkerMessage::NewTask);
|
||||
}
|
||||
|
||||
pub async fn active_count(&self) -> usize {
|
||||
self.stats.active_workers().await
|
||||
}
|
||||
|
||||
pub async fn available_count(&self) -> usize {
|
||||
self.workers.len() - self.active_count().await
|
||||
}
|
||||
|
||||
pub async fn optimize(&self) -> Result<(), AppError> {
|
||||
// 检查工作线程健康状态
|
||||
for worker in &self.workers {
|
||||
if !worker.is_healthy().await {
|
||||
worker.restart().await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 工作线程
|
||||
pub struct Worker {
|
||||
id: usize,
|
||||
handle: JoinHandle<()>,
|
||||
is_active: Arc<AtomicUsize>,
|
||||
last_activity: Arc<RwLock<Instant>>,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
async fn new(
|
||||
id: usize,
|
||||
task_receiver: Arc<Mutex<mpsc::UnboundedReceiver<WorkerMessage>>>,
|
||||
stats: Arc<WorkerStats>,
|
||||
) -> Result<Self, AppError> {
|
||||
let is_active = Arc::new(AtomicUsize::new(0));
|
||||
let last_activity = Arc::new(RwLock::new(Instant::now()));
|
||||
|
||||
let worker_is_active = is_active.clone();
|
||||
let worker_last_activity = last_activity.clone();
|
||||
let worker_stats = stats.clone();
|
||||
|
||||
let handle = tokio::spawn(async move {
|
||||
loop {
|
||||
// 等待任务消息
|
||||
let message = {
|
||||
let mut receiver = task_receiver.lock().await;
|
||||
receiver.recv().await
|
||||
};
|
||||
|
||||
match message {
|
||||
Some(WorkerMessage::NewTask) => {
|
||||
worker_is_active.store(1, Ordering::Relaxed);
|
||||
*worker_last_activity.write().await = Instant::now();
|
||||
|
||||
// 处理任务的逻辑在这里
|
||||
// 实际实现中会从队列中获取任务并执行
|
||||
|
||||
worker_stats.record_task_completed().await;
|
||||
worker_is_active.store(0, Ordering::Relaxed);
|
||||
}
|
||||
Some(WorkerMessage::Shutdown) => break,
|
||||
None => break, // 通道关闭
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
handle,
|
||||
is_active,
|
||||
last_activity,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn is_healthy(&self) -> bool {
|
||||
let last_activity = *self.last_activity.read().await;
|
||||
let inactive_duration = last_activity.elapsed();
|
||||
|
||||
// 如果工作线程超过5分钟没有活动,认为不健康
|
||||
inactive_duration < Duration::from_secs(300)
|
||||
}
|
||||
|
||||
pub async fn restart(&self) -> Result<(), AppError> {
|
||||
// 重启工作线程的逻辑
|
||||
// 在实际实现中,这里会重新创建工作线程
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 负载均衡器
|
||||
pub struct LoadBalancer {
|
||||
strategy: LoadBalancingStrategy,
|
||||
stats: Arc<LoadBalancerStats>,
|
||||
}
|
||||
|
||||
impl Default for LoadBalancer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadBalancer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
strategy: LoadBalancingStrategy::RoundRobin,
|
||||
stats: Arc::new(LoadBalancerStats::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn balance(&self, _worker_pool: &WorkerPool) -> Result<(), AppError> {
|
||||
match self.strategy {
|
||||
LoadBalancingStrategy::RoundRobin => {
|
||||
// 轮询负载均衡逻辑
|
||||
}
|
||||
LoadBalancingStrategy::LeastConnections => {
|
||||
// 最少连接负载均衡逻辑
|
||||
}
|
||||
LoadBalancingStrategy::WeightedRoundRobin => {
|
||||
// 加权轮询负载均衡逻辑
|
||||
}
|
||||
}
|
||||
|
||||
self.stats.record_balance_operation().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 任务句柄
|
||||
pub struct TaskHandle<T> {
|
||||
pub id: String,
|
||||
result_rx: oneshot::Receiver<Result<T, AppError>>,
|
||||
_permit: tokio::sync::OwnedSemaphorePermit,
|
||||
}
|
||||
|
||||
impl<T> TaskHandle<T> {
|
||||
/// 等待任务完成
|
||||
pub async fn await_result(self) -> Result<T, AppError> {
|
||||
match self.result_rx.await {
|
||||
Ok(result) => result,
|
||||
Err(_) => Err(AppError::Config("Task was cancelled".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
/// 等待任务完成(带超时)
|
||||
pub async fn await_result_timeout(self, timeout: Duration) -> Result<T, AppError> {
|
||||
match tokio::time::timeout(timeout, self.result_rx).await {
|
||||
Ok(Ok(result)) => result,
|
||||
Ok(Err(_)) => Err(AppError::Config("Task was cancelled".to_string())),
|
||||
Err(_) => Err(AppError::Config("Task timed out".to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 并发任务
|
||||
struct ConcurrentTask {
|
||||
id: String,
|
||||
task: Box<dyn FnOnce() -> BoxFuture<'static, ()> + Send>,
|
||||
priority: TaskPriority,
|
||||
submitted_at: Instant,
|
||||
timeout: Duration,
|
||||
}
|
||||
|
||||
/// 任务优先级
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum TaskPriority {
|
||||
Low = 0,
|
||||
Normal = 1,
|
||||
High = 2,
|
||||
Critical = 3,
|
||||
}
|
||||
|
||||
/// 工作线程消息
|
||||
enum WorkerMessage {
|
||||
NewTask,
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
/// 负载均衡策略
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum LoadBalancingStrategy {
|
||||
RoundRobin,
|
||||
LeastConnections,
|
||||
WeightedRoundRobin,
|
||||
}
|
||||
|
||||
/// 并发统计
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ConcurrencyStats {
|
||||
pub total_tasks_submitted: u64,
|
||||
pub total_tasks_completed: u64,
|
||||
pub total_tasks_failed: u64,
|
||||
pub priority_tasks_submitted: u64,
|
||||
pub average_task_duration: Duration,
|
||||
pub peak_concurrent_tasks: usize,
|
||||
pub queue_stats: QueueStatsData,
|
||||
pub worker_stats: WorkerStatsData,
|
||||
}
|
||||
|
||||
impl Default for ConcurrencyStats {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ConcurrencyStats {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_tasks_submitted: 0,
|
||||
total_tasks_completed: 0,
|
||||
total_tasks_failed: 0,
|
||||
priority_tasks_submitted: 0,
|
||||
average_task_duration: Duration::from_secs(0),
|
||||
peak_concurrent_tasks: 0,
|
||||
queue_stats: QueueStatsData::new(),
|
||||
worker_stats: WorkerStatsData::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn record_task_submitted(&self) {
|
||||
// 原子操作记录
|
||||
}
|
||||
|
||||
pub async fn record_priority_task_submitted(&self) {
|
||||
// 原子操作记录
|
||||
}
|
||||
|
||||
pub async fn record_concurrency_adjustment(&self, _new_max: usize) {
|
||||
// 记录并发调整
|
||||
}
|
||||
|
||||
pub async fn clone_stats(&self) -> ConcurrencyStats {
|
||||
self.clone()
|
||||
}
|
||||
|
||||
pub async fn reset(&self) {
|
||||
// 重置统计数据
|
||||
}
|
||||
}
|
||||
|
||||
/// 队列状态
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct QueueStatus {
|
||||
pub pending_tasks: usize,
|
||||
pub active_tasks: usize,
|
||||
pub available_workers: usize,
|
||||
pub queue_capacity: usize,
|
||||
}
|
||||
|
||||
/// 其他统计结构
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct QueueStatsData {
|
||||
pub enqueues: u64,
|
||||
pub dequeues: u64,
|
||||
pub priority_enqueues: u64,
|
||||
pub priority_dequeues: u64,
|
||||
pub cleanups: u64,
|
||||
}
|
||||
|
||||
impl Default for QueueStatsData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl QueueStatsData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enqueues: 0,
|
||||
dequeues: 0,
|
||||
priority_enqueues: 0,
|
||||
priority_dequeues: 0,
|
||||
cleanups: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WorkerStatsData {
|
||||
pub tasks_completed: u64,
|
||||
pub tasks_failed: u64,
|
||||
pub total_processing_time: Duration,
|
||||
pub restarts: u64,
|
||||
}
|
||||
|
||||
impl Default for WorkerStatsData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl WorkerStatsData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tasks_completed: 0,
|
||||
tasks_failed: 0,
|
||||
total_processing_time: Duration::from_secs(0),
|
||||
restarts: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助统计结构
|
||||
struct QueueStats {
|
||||
enqueues: AtomicU64,
|
||||
dequeues: AtomicU64,
|
||||
priority_enqueues: AtomicU64,
|
||||
priority_dequeues: AtomicU64,
|
||||
cleanups: AtomicU64,
|
||||
}
|
||||
|
||||
impl QueueStats {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
enqueues: AtomicU64::new(0),
|
||||
dequeues: AtomicU64::new(0),
|
||||
priority_enqueues: AtomicU64::new(0),
|
||||
priority_dequeues: AtomicU64::new(0),
|
||||
cleanups: AtomicU64::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
async fn record_enqueue(&self) {
|
||||
self.enqueues.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn record_dequeue(&self) {
|
||||
self.dequeues.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn record_priority_enqueue(&self) {
|
||||
self.priority_enqueues.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn record_priority_dequeue(&self) {
|
||||
self.priority_dequeues.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn record_cleanup(&self) {
|
||||
self.cleanups.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
struct WorkerStats {
|
||||
active_workers: AtomicUsize,
|
||||
tasks_completed: AtomicU64,
|
||||
tasks_failed: AtomicU64,
|
||||
}
|
||||
|
||||
impl WorkerStats {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
active_workers: AtomicUsize::new(0),
|
||||
tasks_completed: AtomicU64::new(0),
|
||||
tasks_failed: AtomicU64::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
async fn active_workers(&self) -> usize {
|
||||
self.active_workers.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
async fn record_task_completed(&self) {
|
||||
self.tasks_completed.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
struct LoadBalancerStats {
|
||||
balance_operations: AtomicU64,
|
||||
}
|
||||
|
||||
impl LoadBalancerStats {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
balance_operations: AtomicU64::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
async fn record_balance_operation(&self) {
|
||||
self.balance_operations.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,707 @@
|
||||
//! 内存优化器
|
||||
//!
|
||||
//! 提供内存使用监控、内存池管理和内存压缩功能
|
||||
|
||||
use dashmap::DashMap;
|
||||
use flate2::Compression;
|
||||
use flate2::read::GzDecoder;
|
||||
use flate2::write::GzEncoder;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tokio_util::bytes::BytesMut;
|
||||
|
||||
use super::{MemoryConfig, PerformanceOptimizable};
|
||||
use crate::config::AppConfig;
|
||||
use crate::error::AppError;
|
||||
|
||||
/// 内存优化器
|
||||
pub struct MemoryOptimizer {
|
||||
config: MemoryConfig,
|
||||
memory_pool: Arc<MemoryPool>,
|
||||
compression_manager: Arc<CompressionManager>,
|
||||
memory_monitor: Arc<MemoryMonitor>,
|
||||
stats: Arc<MemoryStats>,
|
||||
}
|
||||
|
||||
impl MemoryOptimizer {
|
||||
/// 创建新的内存优化器
|
||||
pub async fn new(_config: &AppConfig) -> Result<Self, AppError> {
|
||||
let memory_config = MemoryConfig::default(); // 从配置中获取
|
||||
|
||||
let memory_pool = Arc::new(MemoryPool::new(memory_config.pool_size));
|
||||
let compression_manager =
|
||||
Arc::new(CompressionManager::new(memory_config.enable_compression));
|
||||
let memory_monitor = Arc::new(MemoryMonitor::new(memory_config.max_memory_usage));
|
||||
let stats = Arc::new(MemoryStats::new());
|
||||
|
||||
Ok(Self {
|
||||
config: memory_config,
|
||||
memory_pool,
|
||||
compression_manager,
|
||||
memory_monitor,
|
||||
stats,
|
||||
})
|
||||
}
|
||||
|
||||
/// 分配内存
|
||||
pub async fn allocate(&self, size: usize) -> Result<MemoryBlock, AppError> {
|
||||
// 检查内存限制
|
||||
if !self.memory_monitor.can_allocate(size).await {
|
||||
// 尝试清理内存
|
||||
self.cleanup_memory().await?;
|
||||
|
||||
// 再次检查
|
||||
if !self.memory_monitor.can_allocate(size).await {
|
||||
return Err(AppError::Config(format!(
|
||||
"Memory limit exceeded: requested {} bytes, available {} bytes",
|
||||
size,
|
||||
self.memory_monitor.available_memory().await
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// 从内存池分配
|
||||
let block = self.memory_pool.allocate(size).await?;
|
||||
|
||||
// 更新统计
|
||||
self.stats.record_allocation(size);
|
||||
self.memory_monitor.record_allocation(size).await;
|
||||
|
||||
Ok(block)
|
||||
}
|
||||
|
||||
/// 释放内存
|
||||
pub async fn deallocate(&self, block: MemoryBlock) -> Result<(), AppError> {
|
||||
let size = block.size();
|
||||
|
||||
// 返回到内存池
|
||||
self.memory_pool.deallocate(block).await?;
|
||||
|
||||
// 更新统计
|
||||
self.stats.record_deallocation(size);
|
||||
self.memory_monitor.record_deallocation(size).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 压缩数据
|
||||
pub async fn compress(&self, data: &[u8]) -> Result<Vec<u8>, AppError> {
|
||||
if !self.config.enable_compression {
|
||||
return Ok(data.to_vec());
|
||||
}
|
||||
|
||||
self.compression_manager.compress(data).await
|
||||
}
|
||||
|
||||
/// 解压数据
|
||||
pub async fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, AppError> {
|
||||
if !self.config.enable_compression {
|
||||
return Ok(data.to_vec());
|
||||
}
|
||||
|
||||
self.compression_manager.decompress(data).await
|
||||
}
|
||||
|
||||
/// 清理内存
|
||||
pub async fn cleanup_memory(&self) -> Result<(), AppError> {
|
||||
// 清理内存池
|
||||
self.memory_pool.cleanup().await?;
|
||||
|
||||
// 强制垃圾回收(如果可能)
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// 在 Linux 上尝试将空闲内存归还给系统
|
||||
unsafe {
|
||||
libc::malloc_trim(0);
|
||||
}
|
||||
}
|
||||
|
||||
self.stats.record_cleanup();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 获取内存统计
|
||||
pub async fn get_memory_stats(&self) -> Result<MemoryStats, AppError> {
|
||||
Ok(self.stats.clone_stats().await)
|
||||
}
|
||||
|
||||
/// 获取内存使用情况
|
||||
pub async fn get_memory_usage(&self) -> Result<MemoryUsage, AppError> {
|
||||
Ok(MemoryUsage {
|
||||
total_allocated: self.memory_monitor.total_allocated().await,
|
||||
total_available: self.memory_monitor.available_memory().await,
|
||||
pool_usage: self.memory_pool.usage().await,
|
||||
compression_ratio: self.compression_manager.compression_ratio().await,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl PerformanceOptimizable for MemoryOptimizer {
|
||||
async fn optimize(&self) -> Result<(), AppError> {
|
||||
// 检查内存使用情况
|
||||
let usage = self.get_memory_usage().await?;
|
||||
let usage_ratio = usage.total_allocated as f64 / usage.total_available as f64;
|
||||
|
||||
// 如果内存使用超过阈值,执行清理
|
||||
if usage_ratio > self.config.cleanup_threshold {
|
||||
self.cleanup_memory().await?;
|
||||
}
|
||||
|
||||
// 优化内存池
|
||||
self.memory_pool.optimize().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_stats(&self) -> Result<serde_json::Value, AppError> {
|
||||
let stats = self.get_memory_stats().await?;
|
||||
let usage = self.get_memory_usage().await?;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"stats": stats,
|
||||
"usage": usage
|
||||
}))
|
||||
}
|
||||
|
||||
async fn reset_stats(&self) -> Result<(), AppError> {
|
||||
self.stats.reset().await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 内存池
|
||||
pub struct MemoryPool {
|
||||
pools: DashMap<usize, Arc<Mutex<VecDeque<MemoryBlock>>>>,
|
||||
max_pool_size: usize,
|
||||
stats: Arc<PoolStats>,
|
||||
}
|
||||
|
||||
impl MemoryPool {
|
||||
pub fn new(max_pool_size: usize) -> Self {
|
||||
Self {
|
||||
pools: DashMap::new(),
|
||||
max_pool_size,
|
||||
stats: Arc::new(PoolStats::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn allocate(&self, size: usize) -> Result<MemoryBlock, AppError> {
|
||||
// 计算合适的块大小(2的幂次)
|
||||
let block_size = self.calculate_block_size(size);
|
||||
|
||||
// 尝试从池中获取
|
||||
if let Some(pool) = self.pools.get(&block_size) {
|
||||
let mut pool_guard = pool.lock().await;
|
||||
if let Some(block) = pool_guard.pop_front() {
|
||||
self.stats.record_pool_hit();
|
||||
return Ok(block);
|
||||
}
|
||||
}
|
||||
|
||||
// 池中没有可用块,创建新块
|
||||
let block = MemoryBlock::new(block_size)?;
|
||||
self.stats.record_pool_miss();
|
||||
|
||||
Ok(block)
|
||||
}
|
||||
|
||||
pub async fn deallocate(&self, block: MemoryBlock) -> Result<(), AppError> {
|
||||
let block_size = block.size();
|
||||
|
||||
// 获取或创建对应大小的池
|
||||
let pool = self
|
||||
.pools
|
||||
.entry(block_size)
|
||||
.or_insert_with(|| Arc::new(Mutex::new(VecDeque::new())))
|
||||
.clone();
|
||||
|
||||
let mut pool_guard = pool.lock().await;
|
||||
|
||||
// 如果池未满,将块返回到池中
|
||||
if pool_guard.len() < self.max_pool_size {
|
||||
pool_guard.push_back(block);
|
||||
self.stats.record_pool_return();
|
||||
} else {
|
||||
// 池已满,直接丢弃块
|
||||
drop(block);
|
||||
self.stats.record_pool_discard();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn cleanup(&self) -> Result<(), AppError> {
|
||||
// 清理所有池中的一半块
|
||||
for entry in self.pools.iter() {
|
||||
let pool = entry.value().clone();
|
||||
let mut pool_guard = pool.lock().await;
|
||||
let current_size = pool_guard.len();
|
||||
let target_size = current_size / 2;
|
||||
|
||||
while pool_guard.len() > target_size {
|
||||
pool_guard.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
self.stats.record_cleanup();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn optimize(&self) -> Result<(), AppError> {
|
||||
// 移除空的池
|
||||
self.pools.retain(|_, pool| {
|
||||
if let Ok(guard) = pool.try_lock() {
|
||||
!guard.is_empty()
|
||||
} else {
|
||||
true // 如果无法获取锁,保留池
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn usage(&self) -> PoolUsage {
|
||||
let mut total_blocks = 0;
|
||||
let mut total_memory = 0;
|
||||
|
||||
for entry in self.pools.iter() {
|
||||
let block_size = *entry.key();
|
||||
if let Ok(pool_guard) = entry.value().try_lock() {
|
||||
let count = pool_guard.len();
|
||||
total_blocks += count;
|
||||
total_memory += count * block_size;
|
||||
}
|
||||
}
|
||||
|
||||
PoolUsage {
|
||||
total_pools: self.pools.len(),
|
||||
total_blocks,
|
||||
total_memory,
|
||||
stats: self.stats.get_stats().await,
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_block_size(&self, size: usize) -> usize {
|
||||
// 向上舍入到最近的2的幂次
|
||||
let mut block_size = 1;
|
||||
while block_size < size {
|
||||
block_size <<= 1;
|
||||
}
|
||||
block_size.max(64) // 最小64字节
|
||||
}
|
||||
}
|
||||
|
||||
/// 内存块
|
||||
pub struct MemoryBlock {
|
||||
data: BytesMut,
|
||||
size: usize,
|
||||
allocated_at: Instant,
|
||||
}
|
||||
|
||||
impl MemoryBlock {
|
||||
pub fn new(size: usize) -> Result<Self, AppError> {
|
||||
let data = BytesMut::with_capacity(size);
|
||||
|
||||
Ok(Self {
|
||||
data,
|
||||
size,
|
||||
allocated_at: Instant::now(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn data_mut(&mut self) -> &mut BytesMut {
|
||||
&mut self.data
|
||||
}
|
||||
|
||||
pub fn age(&self) -> Duration {
|
||||
self.allocated_at.elapsed()
|
||||
}
|
||||
}
|
||||
|
||||
/// 压缩管理器
|
||||
pub struct CompressionManager {
|
||||
enabled: bool,
|
||||
compression_level: Compression,
|
||||
stats: Arc<CompressionStats>,
|
||||
}
|
||||
|
||||
impl CompressionManager {
|
||||
pub fn new(enabled: bool) -> Self {
|
||||
Self {
|
||||
enabled,
|
||||
compression_level: Compression::default(),
|
||||
stats: Arc::new(CompressionStats::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn compress(&self, data: &[u8]) -> Result<Vec<u8>, AppError> {
|
||||
if !self.enabled {
|
||||
return Ok(data.to_vec());
|
||||
}
|
||||
|
||||
let start = Instant::now();
|
||||
let original_size = data.len();
|
||||
|
||||
let mut encoder = GzEncoder::new(Vec::new(), self.compression_level);
|
||||
encoder.write_all(data)?;
|
||||
|
||||
let compressed = encoder
|
||||
.finish()
|
||||
.map_err(|e| AppError::Config(format!("Compression error: {e}")))?;
|
||||
|
||||
let compressed_size = compressed.len();
|
||||
let duration = start.elapsed();
|
||||
|
||||
self.stats
|
||||
.record_compression(original_size, compressed_size, duration)
|
||||
.await;
|
||||
|
||||
Ok(compressed)
|
||||
}
|
||||
|
||||
pub async fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, AppError> {
|
||||
if !self.enabled {
|
||||
return Ok(data.to_vec());
|
||||
}
|
||||
|
||||
let start = Instant::now();
|
||||
let compressed_size = data.len();
|
||||
|
||||
let mut decoder = GzDecoder::new(data);
|
||||
let mut decompressed = Vec::new();
|
||||
|
||||
decoder.read_to_end(&mut decompressed)?;
|
||||
|
||||
let decompressed_size = decompressed.len();
|
||||
let duration = start.elapsed();
|
||||
|
||||
self.stats
|
||||
.record_decompression(compressed_size, decompressed_size, duration)
|
||||
.await;
|
||||
|
||||
Ok(decompressed)
|
||||
}
|
||||
|
||||
pub async fn compression_ratio(&self) -> f64 {
|
||||
self.stats.average_compression_ratio().await
|
||||
}
|
||||
}
|
||||
|
||||
/// 内存监控器
|
||||
pub struct MemoryMonitor {
|
||||
max_memory: u64,
|
||||
current_allocated: AtomicU64,
|
||||
peak_allocated: AtomicU64,
|
||||
allocation_count: AtomicUsize,
|
||||
deallocation_count: AtomicUsize,
|
||||
}
|
||||
|
||||
impl MemoryMonitor {
|
||||
pub fn new(max_memory: u64) -> Self {
|
||||
Self {
|
||||
max_memory,
|
||||
current_allocated: AtomicU64::new(0),
|
||||
peak_allocated: AtomicU64::new(0),
|
||||
allocation_count: AtomicUsize::new(0),
|
||||
deallocation_count: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn can_allocate(&self, size: usize) -> bool {
|
||||
let current = self.current_allocated.load(Ordering::Relaxed);
|
||||
current + size as u64 <= self.max_memory
|
||||
}
|
||||
|
||||
pub async fn record_allocation(&self, size: usize) {
|
||||
let new_allocated = self
|
||||
.current_allocated
|
||||
.fetch_add(size as u64, Ordering::Relaxed)
|
||||
+ size as u64;
|
||||
|
||||
// 更新峰值
|
||||
let mut peak = self.peak_allocated.load(Ordering::Relaxed);
|
||||
while new_allocated > peak {
|
||||
match self.peak_allocated.compare_exchange_weak(
|
||||
peak,
|
||||
new_allocated,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
Err(current_peak) => peak = current_peak,
|
||||
}
|
||||
}
|
||||
|
||||
self.allocation_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub async fn record_deallocation(&self, size: usize) {
|
||||
self.current_allocated
|
||||
.fetch_sub(size as u64, Ordering::Relaxed);
|
||||
self.deallocation_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub async fn total_allocated(&self) -> u64 {
|
||||
self.current_allocated.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub async fn available_memory(&self) -> u64 {
|
||||
let current = self.current_allocated.load(Ordering::Relaxed);
|
||||
self.max_memory.saturating_sub(current)
|
||||
}
|
||||
|
||||
pub async fn peak_memory(&self) -> u64 {
|
||||
self.peak_allocated.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
/// 内存统计
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MemoryStats {
|
||||
pub total_allocations: u64,
|
||||
pub total_deallocations: u64,
|
||||
pub current_allocated: u64,
|
||||
pub peak_allocated: u64,
|
||||
pub cleanup_count: u64,
|
||||
pub compression_stats: CompressionStatsData,
|
||||
pub pool_stats: PoolStatsData,
|
||||
}
|
||||
|
||||
impl Default for MemoryStats {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryStats {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_allocations: 0,
|
||||
total_deallocations: 0,
|
||||
current_allocated: 0,
|
||||
peak_allocated: 0,
|
||||
cleanup_count: 0,
|
||||
compression_stats: CompressionStatsData::new(),
|
||||
pool_stats: PoolStatsData::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_allocation(&self, _size: usize) {
|
||||
// 在实际实现中,这些应该是原子操作
|
||||
}
|
||||
|
||||
pub fn record_deallocation(&self, _size: usize) {
|
||||
// 在实际实现中,这些应该是原子操作
|
||||
}
|
||||
|
||||
pub fn record_cleanup(&self) {
|
||||
// 在实际实现中,这些应该是原子操作
|
||||
}
|
||||
|
||||
pub async fn clone_stats(&self) -> MemoryStats {
|
||||
self.clone()
|
||||
}
|
||||
|
||||
pub async fn reset(&self) {
|
||||
// 重置统计数据
|
||||
}
|
||||
}
|
||||
|
||||
/// 其他统计结构
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MemoryUsage {
|
||||
pub total_allocated: u64,
|
||||
pub total_available: u64,
|
||||
pub pool_usage: PoolUsage,
|
||||
pub compression_ratio: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PoolUsage {
|
||||
pub total_pools: usize,
|
||||
pub total_blocks: usize,
|
||||
pub total_memory: usize,
|
||||
pub stats: PoolStatsData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PoolStatsData {
|
||||
pub hits: u64,
|
||||
pub misses: u64,
|
||||
pub returns: u64,
|
||||
pub discards: u64,
|
||||
pub cleanups: u64,
|
||||
}
|
||||
|
||||
impl Default for PoolStatsData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PoolStatsData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
hits: 0,
|
||||
misses: 0,
|
||||
returns: 0,
|
||||
discards: 0,
|
||||
cleanups: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct CompressionStatsData {
|
||||
pub compressions: u64,
|
||||
pub decompressions: u64,
|
||||
pub total_original_size: u64,
|
||||
pub total_compressed_size: u64,
|
||||
pub average_compression_time: Duration,
|
||||
pub average_decompression_time: Duration,
|
||||
}
|
||||
|
||||
impl Default for CompressionStatsData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl CompressionStatsData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
compressions: 0,
|
||||
decompressions: 0,
|
||||
total_original_size: 0,
|
||||
total_compressed_size: 0,
|
||||
average_compression_time: Duration::from_secs(0),
|
||||
average_decompression_time: Duration::from_secs(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助结构的实现
|
||||
struct PoolStats {
|
||||
hits: AtomicU64,
|
||||
misses: AtomicU64,
|
||||
returns: AtomicU64,
|
||||
discards: AtomicU64,
|
||||
cleanups: AtomicU64,
|
||||
}
|
||||
|
||||
impl PoolStats {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
hits: AtomicU64::new(0),
|
||||
misses: AtomicU64::new(0),
|
||||
returns: AtomicU64::new(0),
|
||||
discards: AtomicU64::new(0),
|
||||
cleanups: AtomicU64::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn record_pool_hit(&self) {
|
||||
self.hits.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn record_pool_miss(&self) {
|
||||
self.misses.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn record_pool_return(&self) {
|
||||
self.returns.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn record_pool_discard(&self) {
|
||||
self.discards.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn record_cleanup(&self) {
|
||||
self.cleanups.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn get_stats(&self) -> PoolStatsData {
|
||||
PoolStatsData {
|
||||
hits: self.hits.load(Ordering::Relaxed),
|
||||
misses: self.misses.load(Ordering::Relaxed),
|
||||
returns: self.returns.load(Ordering::Relaxed),
|
||||
discards: self.discards.load(Ordering::Relaxed),
|
||||
cleanups: self.cleanups.load(Ordering::Relaxed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CompressionStats {
|
||||
compressions: AtomicU64,
|
||||
decompressions: AtomicU64,
|
||||
total_original_size: AtomicU64,
|
||||
total_compressed_size: AtomicU64,
|
||||
total_compression_time: RwLock<Duration>,
|
||||
total_decompression_time: RwLock<Duration>,
|
||||
}
|
||||
|
||||
impl CompressionStats {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
compressions: AtomicU64::new(0),
|
||||
decompressions: AtomicU64::new(0),
|
||||
total_original_size: AtomicU64::new(0),
|
||||
total_compressed_size: AtomicU64::new(0),
|
||||
total_compression_time: RwLock::new(Duration::from_secs(0)),
|
||||
total_decompression_time: RwLock::new(Duration::from_secs(0)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn record_compression(
|
||||
&self,
|
||||
original_size: usize,
|
||||
compressed_size: usize,
|
||||
duration: Duration,
|
||||
) {
|
||||
self.compressions.fetch_add(1, Ordering::Relaxed);
|
||||
self.total_original_size
|
||||
.fetch_add(original_size as u64, Ordering::Relaxed);
|
||||
self.total_compressed_size
|
||||
.fetch_add(compressed_size as u64, Ordering::Relaxed);
|
||||
|
||||
let mut total_time = self.total_compression_time.write().await;
|
||||
*total_time += duration;
|
||||
}
|
||||
|
||||
async fn record_decompression(
|
||||
&self,
|
||||
_compressed_size: usize,
|
||||
_decompressed_size: usize,
|
||||
duration: Duration,
|
||||
) {
|
||||
self.decompressions.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let mut total_time = self.total_decompression_time.write().await;
|
||||
*total_time += duration;
|
||||
}
|
||||
|
||||
async fn average_compression_ratio(&self) -> f64 {
|
||||
let original = self.total_original_size.load(Ordering::Relaxed);
|
||||
let compressed = self.total_compressed_size.load(Ordering::Relaxed);
|
||||
|
||||
if original > 0 {
|
||||
compressed as f64 / original as f64
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
439
qiming-mcp-proxy/document-parser/src/performance/mod.rs
Normal file
439
qiming-mcp-proxy/document-parser/src/performance/mod.rs
Normal file
@@ -0,0 +1,439 @@
|
||||
//! 性能优化模块
|
||||
//!
|
||||
//! 包含内存使用优化、并发处理优化和缓存策略
|
||||
|
||||
pub mod cache_manager;
|
||||
pub mod concurrency_optimizer;
|
||||
pub mod memory_optimizer;
|
||||
pub mod metrics_collector;
|
||||
// pub mod resource_monitor; // 模块不存在,暂时注释
|
||||
|
||||
use crate::config::AppConfig;
|
||||
use crate::error::AppError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
/// 性能优化器主结构
|
||||
#[derive(Clone)]
|
||||
pub struct PerformanceOptimizer {
|
||||
memory_optimizer: Arc<memory_optimizer::MemoryOptimizer>,
|
||||
concurrency_optimizer: Arc<concurrency_optimizer::ConcurrencyOptimizer>,
|
||||
cache_manager: Arc<cache_manager::CacheManager>,
|
||||
metrics_collector: Arc<metrics_collector::MetricsCollector>,
|
||||
// resource_monitor: Arc<resource_monitor::ResourceMonitor>, // 模块不存在,暂时注释
|
||||
_config: PerformanceConfig,
|
||||
}
|
||||
|
||||
impl PerformanceOptimizer {
|
||||
/// 创建新的性能优化器
|
||||
pub async fn new(config: &AppConfig) -> Result<Self, AppError> {
|
||||
let performance_config = PerformanceConfig::default();
|
||||
let memory_optimizer = Arc::new(memory_optimizer::MemoryOptimizer::new(config).await?);
|
||||
let concurrency_optimizer =
|
||||
Arc::new(concurrency_optimizer::ConcurrencyOptimizer::new(config).await?);
|
||||
let cache_manager = Arc::new(cache_manager::CacheManager::new(config).await?);
|
||||
let metrics_collector = Arc::new(metrics_collector::MetricsCollector::new(config).await?);
|
||||
// let resource_monitor = Arc::new(resource_monitor::ResourceMonitor::new(config).await?); // 模块不存在,暂时注释
|
||||
|
||||
Ok(Self {
|
||||
memory_optimizer,
|
||||
concurrency_optimizer,
|
||||
cache_manager,
|
||||
metrics_collector,
|
||||
// resource_monitor, // 模块不存在,暂时注释
|
||||
_config: performance_config,
|
||||
})
|
||||
}
|
||||
|
||||
/// 启动性能监控
|
||||
pub async fn start_monitoring(&self) -> Result<(), AppError> {
|
||||
// self.resource_monitor.start_monitoring().await?; // 模块不存在,暂时注释
|
||||
// self.metrics_collector.start_monitoring().await?; // 方法不存在,暂时注释
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 停止性能监控
|
||||
pub async fn stop_monitoring(&self) -> Result<(), AppError> {
|
||||
// self.resource_monitor.stop_monitoring().await?; // 模块不存在,暂时注释
|
||||
// self.metrics_collector.stop_monitoring().await?; // 方法不存在,暂时注释
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 获取内存优化器
|
||||
pub fn memory_optimizer(&self) -> &Arc<memory_optimizer::MemoryOptimizer> {
|
||||
&self.memory_optimizer
|
||||
}
|
||||
|
||||
/// 获取并发优化器
|
||||
pub fn concurrency_optimizer(&self) -> &Arc<concurrency_optimizer::ConcurrencyOptimizer> {
|
||||
&self.concurrency_optimizer
|
||||
}
|
||||
|
||||
/// 获取缓存管理器
|
||||
pub fn cache_manager(&self) -> &Arc<cache_manager::CacheManager> {
|
||||
&self.cache_manager
|
||||
}
|
||||
|
||||
/// 获取指标收集器
|
||||
pub fn metrics_collector(&self) -> &Arc<metrics_collector::MetricsCollector> {
|
||||
&self.metrics_collector
|
||||
}
|
||||
|
||||
// /// 获取资源监控器
|
||||
// pub fn resource_monitor(&self) -> &Arc<resource_monitor::ResourceMonitor> {
|
||||
// &self.resource_monitor
|
||||
// } // 模块不存在,暂时注释
|
||||
|
||||
// /// 启动资源监控
|
||||
// pub async fn start_resource_monitoring(&self) -> Result<(), DocumentParserError> {
|
||||
// self.resource_monitor.start_monitoring().await
|
||||
// } // 模块不存在,暂时注释
|
||||
|
||||
// /// 停止资源监控
|
||||
// pub async fn stop_resource_monitoring(&self) -> Result<(), DocumentParserError> {
|
||||
// self.resource_monitor.stop_monitoring().await
|
||||
// } // 模块不存在,暂时注释
|
||||
|
||||
// /// 获取资源统计
|
||||
// pub async fn get_resource_stats(&self) -> Result<resource_monitor::ResourceStats, DocumentParserError> {
|
||||
// self.resource_monitor.get_stats().await
|
||||
// } // 模块不存在,暂时注释
|
||||
|
||||
/// 优化资源使用
|
||||
pub async fn optimize_resources(&self) -> Result<(), AppError> {
|
||||
// self.resource_monitor.optimize().await // 模块不存在,暂时注释
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 执行性能优化
|
||||
pub async fn optimize(&self) -> Result<(), AppError> {
|
||||
// 执行内存优化
|
||||
self.memory_optimizer.optimize().await?;
|
||||
|
||||
// 执行并发优化
|
||||
self.concurrency_optimizer.optimize().await?;
|
||||
|
||||
// 执行缓存优化
|
||||
self.cache_manager.optimize().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 获取性能报告
|
||||
pub async fn get_performance_report(&self) -> Result<PerformanceReport, AppError> {
|
||||
// let system_resources = self.resource_monitor.get_system_resources().await?; // 模块不存在,暂时注释
|
||||
// let app_resources = self.resource_monitor.get_application_resources().await?; // 模块不存在,暂时注释
|
||||
let metrics = self.metrics_collector.get_stats().await?;
|
||||
let cache_stats = self.cache_manager.get_stats().await?;
|
||||
|
||||
Ok(PerformanceReport {
|
||||
system_resources: Default::default(),
|
||||
application_resources: Default::default(),
|
||||
metrics,
|
||||
cache_stats,
|
||||
generated_at: SystemTime::now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 性能报告
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PerformanceReport {
|
||||
pub system_resources: serde_json::Value, // resource_monitor::SystemResourceStatus, // 模块不存在,暂时使用通用类型
|
||||
pub application_resources: serde_json::Value, // resource_monitor::ApplicationResourceStatus, // 模块不存在,暂时使用通用类型
|
||||
pub metrics: serde_json::Value,
|
||||
pub cache_stats: serde_json::Value,
|
||||
pub generated_at: SystemTime,
|
||||
}
|
||||
|
||||
/// 详细性能报告
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct DetailedPerformanceReport {
|
||||
pub memory_stats: memory_optimizer::MemoryStats,
|
||||
pub concurrency_stats: concurrency_optimizer::ConcurrencyStats,
|
||||
pub cache_stats: cache_manager::CacheStats,
|
||||
pub metrics: metrics_collector::MetricsSnapshot,
|
||||
// pub resource_stats: resource_monitor::ResourceStats, // 模块不存在,暂时注释
|
||||
pub timestamp: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
/// 性能配置
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PerformanceConfig {
|
||||
/// 内存优化配置
|
||||
pub memory: MemoryConfig,
|
||||
/// 并发优化配置
|
||||
pub concurrency: ConcurrencyConfig,
|
||||
/// 缓存配置
|
||||
pub cache: CacheConfig,
|
||||
/// 资源配置
|
||||
pub resource: ResourceConfig,
|
||||
/// 监控配置
|
||||
pub monitoring: MonitoringConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ResourceConfig {
|
||||
pub max_cpu_usage: f64,
|
||||
pub max_memory_usage: u64,
|
||||
pub max_disk_usage: u64,
|
||||
pub max_network_bandwidth: u64,
|
||||
pub max_connections: usize,
|
||||
pub max_file_descriptors: usize,
|
||||
pub min_instances: usize,
|
||||
pub max_instances: usize,
|
||||
pub monitoring_interval: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MemoryConfig {
|
||||
/// 最大内存使用量(字节)
|
||||
pub max_memory_usage: u64,
|
||||
/// 内存清理阈值(百分比)
|
||||
pub cleanup_threshold: f64,
|
||||
/// 内存池大小
|
||||
pub pool_size: usize,
|
||||
/// 启用内存压缩
|
||||
pub enable_compression: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ConcurrencyConfig {
|
||||
/// 最大并发任务数
|
||||
pub max_concurrent_tasks: usize,
|
||||
/// 任务队列大小
|
||||
pub task_queue_size: usize,
|
||||
/// 工作线程数
|
||||
pub worker_threads: usize,
|
||||
/// 任务超时时间
|
||||
pub task_timeout: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct CacheConfig {
|
||||
/// 缓存大小(字节)
|
||||
pub cache_size: u64,
|
||||
/// 文档缓存大小
|
||||
pub document_cache_size: usize,
|
||||
/// 结果缓存大小
|
||||
pub result_cache_size: usize,
|
||||
/// 元数据缓存大小
|
||||
pub metadata_cache_size: usize,
|
||||
/// 缓存TTL
|
||||
pub ttl: Duration,
|
||||
/// 文档缓存TTL
|
||||
pub document_ttl: Duration,
|
||||
/// 结果缓存TTL
|
||||
pub result_ttl: Duration,
|
||||
/// 元数据缓存TTL
|
||||
pub metadata_ttl: Duration,
|
||||
/// 清理间隔
|
||||
pub cleanup_interval: Duration,
|
||||
/// 启用LRU淘汰
|
||||
pub enable_lru: bool,
|
||||
/// 缓存压缩
|
||||
pub enable_compression: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MonitoringConfig {
|
||||
/// 监控间隔
|
||||
pub interval: Duration,
|
||||
/// 启用详细监控
|
||||
pub enable_detailed: bool,
|
||||
/// 保留历史数据时间
|
||||
pub retention_period: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MetricsConfig {
|
||||
/// 指标收集间隔
|
||||
pub collection_interval: Duration,
|
||||
/// 启用系统指标收集
|
||||
pub enable_system_metrics: bool,
|
||||
/// 启用应用指标收集
|
||||
pub enable_application_metrics: bool,
|
||||
/// 启用自定义指标
|
||||
pub enable_custom_metrics: bool,
|
||||
/// 指标保留时间
|
||||
pub retention_period: Duration,
|
||||
/// 聚合窗口大小
|
||||
pub aggregation_window: Duration,
|
||||
/// 聚合间隔
|
||||
pub aggregation_interval: Duration,
|
||||
/// 启用指标导出
|
||||
pub enable_export: bool,
|
||||
/// 导出格式
|
||||
pub export_format: String,
|
||||
/// 报告生成间隔
|
||||
pub report_interval: Duration,
|
||||
/// 报告间隔
|
||||
pub reporting_interval: Duration,
|
||||
}
|
||||
|
||||
impl Default for PerformanceConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
memory: MemoryConfig {
|
||||
max_memory_usage: 2 * 1024 * 1024 * 1024, // 2GB
|
||||
cleanup_threshold: 0.8, // 80%
|
||||
pool_size: 100,
|
||||
enable_compression: true,
|
||||
},
|
||||
concurrency: ConcurrencyConfig {
|
||||
max_concurrent_tasks: 10,
|
||||
task_queue_size: 100,
|
||||
worker_threads: num_cpus::get(),
|
||||
task_timeout: Duration::from_secs(1800), // 30分钟
|
||||
},
|
||||
cache: CacheConfig {
|
||||
cache_size: 512 * 1024 * 1024, // 512MB
|
||||
document_cache_size: 1000,
|
||||
result_cache_size: 500,
|
||||
metadata_cache_size: 200,
|
||||
ttl: Duration::from_secs(3600), // 1小时
|
||||
document_ttl: Duration::from_secs(3600), // 1小时
|
||||
result_ttl: Duration::from_secs(1800), // 30分钟
|
||||
metadata_ttl: Duration::from_secs(7200), // 2小时
|
||||
cleanup_interval: Duration::from_secs(300), // 5分钟
|
||||
enable_lru: true,
|
||||
enable_compression: true,
|
||||
},
|
||||
resource: ResourceConfig {
|
||||
max_cpu_usage: 80.0,
|
||||
max_memory_usage: 8 * 1024 * 1024 * 1024, // 8GB
|
||||
max_disk_usage: 100 * 1024 * 1024 * 1024, // 100GB
|
||||
max_network_bandwidth: 1024 * 1024 * 1024, // 1GB/s
|
||||
max_connections: 1000,
|
||||
max_file_descriptors: 10000,
|
||||
min_instances: 1,
|
||||
max_instances: 10,
|
||||
monitoring_interval: Duration::from_secs(30),
|
||||
},
|
||||
monitoring: MonitoringConfig {
|
||||
interval: Duration::from_secs(30),
|
||||
enable_detailed: false,
|
||||
retention_period: Duration::from_secs(24 * 3600), // 24小时
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MemoryConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_memory_usage: 1024 * 1024 * 1024, // 1GB
|
||||
cleanup_threshold: 0.8,
|
||||
pool_size: 100,
|
||||
enable_compression: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ConcurrencyConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_concurrent_tasks: 10,
|
||||
task_queue_size: 1000,
|
||||
worker_threads: 4,
|
||||
task_timeout: Duration::from_secs(300),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CacheConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cache_size: 100 * 1024 * 1024, // 100MB
|
||||
document_cache_size: 1000,
|
||||
result_cache_size: 500,
|
||||
metadata_cache_size: 2000,
|
||||
ttl: Duration::from_secs(3600), // 1 hour
|
||||
document_ttl: Duration::from_secs(3600), // 1 hour
|
||||
result_ttl: Duration::from_secs(1800), // 30 minutes
|
||||
metadata_ttl: Duration::from_secs(7200), // 2 hours
|
||||
cleanup_interval: Duration::from_secs(300), // 5 minutes
|
||||
enable_lru: true,
|
||||
enable_compression: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MonitoringConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
interval: Duration::from_secs(30),
|
||||
enable_detailed: false,
|
||||
retention_period: Duration::from_secs(86400), // 24 hours
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ResourceConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_cpu_usage: 80.0,
|
||||
max_memory_usage: 1024 * 1024 * 1024, // 1GB
|
||||
max_disk_usage: 10 * 1024 * 1024 * 1024, // 10GB
|
||||
max_network_bandwidth: 100 * 1024 * 1024, // 100MB/s
|
||||
max_connections: 1000,
|
||||
max_file_descriptors: 1024,
|
||||
min_instances: 1,
|
||||
max_instances: 10,
|
||||
monitoring_interval: Duration::from_secs(60),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MetricsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
collection_interval: Duration::from_secs(30),
|
||||
enable_system_metrics: true,
|
||||
enable_application_metrics: true,
|
||||
enable_custom_metrics: false,
|
||||
retention_period: Duration::from_secs(3600 * 24), // 24小时
|
||||
aggregation_window: Duration::from_secs(300), // 5分钟
|
||||
aggregation_interval: Duration::from_secs(60), // 1分钟
|
||||
enable_export: false,
|
||||
export_format: "json".to_string(),
|
||||
report_interval: Duration::from_secs(300), // 5分钟
|
||||
reporting_interval: Duration::from_secs(300), // 5分钟
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 性能优化特征
|
||||
#[async_trait::async_trait]
|
||||
pub trait PerformanceOptimizable {
|
||||
/// 执行性能优化
|
||||
async fn optimize(&self) -> Result<(), AppError>;
|
||||
|
||||
/// 获取性能统计
|
||||
async fn get_stats(&self) -> Result<serde_json::Value, AppError>;
|
||||
|
||||
/// 重置性能统计
|
||||
async fn reset_stats(&self) -> Result<(), AppError>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_performance_optimizer_creation() {
|
||||
// 使用默认配置进行测试
|
||||
let config = crate::config::AppConfig::load_base_config().unwrap();
|
||||
let optimizer = PerformanceOptimizer::new(&config).await;
|
||||
assert!(optimizer.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_performance_config_default() {
|
||||
let config = PerformanceConfig::default();
|
||||
assert!(config.memory.max_memory_usage > 0);
|
||||
assert!(config.concurrency.max_concurrent_tasks > 0);
|
||||
assert!(config.cache.cache_size > 0);
|
||||
}
|
||||
}
|
||||
1373
qiming-mcp-proxy/document-parser/src/performance/resource_monitor.rs
Normal file
1373
qiming-mcp-proxy/document-parser/src/performance/resource_monitor.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user