Files
sol-trade-sdk/src/perf/ultra_low_latency.rs
T
2025-10-06 23:40:27 +08:00

600 lines
20 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 🚀 超低延迟优化模块 - 目标实现<1ms端到端延迟
//!
//! 这个模块包含针对亚毫秒级延迟的极致优化:
//! - 无锁并发事件处理
//! - CPU亲和性绑定
//! - 零分配内存管理
//! - 预测性预取优化
//! - 硬件加速序列化
use std::sync::{Arc, atomic::{AtomicU64, AtomicUsize, AtomicBool, Ordering}};
use std::time::{Duration, Instant};
// use std::collections::VecDeque;
use crossbeam_queue::ArrayQueue;
use crossbeam_utils::CachePadded;
use fzstream_common::EventMessage;
use tokio::sync::Notify;
use anyhow::Result;
use log::{info, warn, debug};
/// 🚀 无锁事件分发器 - 使用环形缓冲区实现极速事件分发
pub struct LockFreeEventDispatcher {
/// 无锁环形缓冲区,支持多生产者单消费者
event_queues: Vec<Arc<ArrayQueue<EventMessage>>>,
/// 客户端映射到队列的索引
client_queue_mapping: Arc<dashmap::DashMap<String, usize>>,
/// 队列选择策略(轮询计数器)
queue_selector: CachePadded<AtomicUsize>,
/// 性能统计
stats: Arc<UltraLowLatencyStats>,
/// 预取优化器
prefetch_optimizer: Arc<PrefetchOptimizer>,
/// CPU绑定配置
cpu_affinity: Option<CpuAffinityConfig>,
}
/// CPU亲和性配置
#[derive(Clone, Debug)]
pub struct CpuAffinityConfig {
/// 绑定到特定CPU核心
pub core_ids: Vec<usize>,
/// 启用NUMA优化
pub numa_optimization: bool,
/// 优先级设置
pub priority: ThreadPriority,
}
#[derive(Clone, Debug)]
pub enum ThreadPriority {
Normal,
High,
RealTime,
}
/// 🚀 预取优化器 - 预测性数据预加载
pub struct PrefetchOptimizer {
/// 预测缓存:基于历史模式预取可能需要的数据
prediction_cache: Arc<ArrayQueue<EventMessage>>,
/// 预取命中统计
hit_count: AtomicU64,
/// 预取失效统计
miss_count: AtomicU64,
/// 学习模式开关
learning_enabled: AtomicBool,
}
impl PrefetchOptimizer {
pub fn new(cache_size: usize) -> Self {
Self {
prediction_cache: Arc::new(ArrayQueue::new(cache_size)),
hit_count: AtomicU64::new(0),
miss_count: AtomicU64::new(0),
learning_enabled: AtomicBool::new(true),
}
}
/// 预测性预取事件数据
#[inline(always)]
pub fn prefetch_event_data(&self, event: &EventMessage) {
if !self.learning_enabled.load(Ordering::Relaxed) {
return;
}
// 基于事件类型的简单预测逻辑
// 在实际应用中,这里可以实现更复杂的机器学习预测算法
if let Ok(_) = self.prediction_cache.push(event.clone()) {
// 预取成功
}
}
/// 尝试从预取缓存获取事件
#[inline(always)]
pub fn try_get_prefetched(&self) -> Option<EventMessage> {
if let Some(event) = self.prediction_cache.pop() {
self.hit_count.fetch_add(1, Ordering::Relaxed);
Some(event)
} else {
self.miss_count.fetch_add(1, Ordering::Relaxed);
None
}
}
/// 获取预取统计信息
pub fn get_stats(&self) -> (u64, u64, f64) {
let hits = self.hit_count.load(Ordering::Relaxed);
let misses = self.miss_count.load(Ordering::Relaxed);
let hit_rate = if hits + misses > 0 {
hits as f64 / (hits + misses) as f64
} else {
0.0
};
(hits, misses, hit_rate)
}
}
/// 🚀 超低延迟统计收集器
pub struct UltraLowLatencyStats {
/// 事件处理计数
pub events_processed: CachePadded<AtomicU64>,
/// 纳秒级延迟统计
pub total_latency_ns: CachePadded<AtomicU64>,
/// 最小延迟(纳秒)
pub min_latency_ns: CachePadded<AtomicU64>,
/// 最大延迟(纳秒)
pub max_latency_ns: CachePadded<AtomicU64>,
/// 亚毫秒事件计数(<1ms
pub sub_millisecond_events: CachePadded<AtomicU64>,
/// 超快事件计数(<100μs
pub ultra_fast_events: CachePadded<AtomicU64>,
/// 极速事件计数(<10μs
pub lightning_fast_events: CachePadded<AtomicU64>,
/// 队列溢出计数
pub queue_overflows: CachePadded<AtomicU64>,
/// 预取命中计数
pub prefetch_hits: CachePadded<AtomicU64>,
}
impl UltraLowLatencyStats {
pub fn new() -> Self {
Self {
events_processed: CachePadded::new(AtomicU64::new(0)),
total_latency_ns: CachePadded::new(AtomicU64::new(0)),
min_latency_ns: CachePadded::new(AtomicU64::new(u64::MAX)),
max_latency_ns: CachePadded::new(AtomicU64::new(0)),
sub_millisecond_events: CachePadded::new(AtomicU64::new(0)),
ultra_fast_events: CachePadded::new(AtomicU64::new(0)),
lightning_fast_events: CachePadded::new(AtomicU64::new(0)),
queue_overflows: CachePadded::new(AtomicU64::new(0)),
prefetch_hits: CachePadded::new(AtomicU64::new(0)),
}
}
/// 记录事件处理延迟(纳秒级精度)
#[inline(always)]
pub fn record_event_latency(&self, latency_ns: u64) {
self.events_processed.fetch_add(1, Ordering::Relaxed);
self.total_latency_ns.fetch_add(latency_ns, Ordering::Relaxed);
// 更新最小值
let mut current_min = self.min_latency_ns.load(Ordering::Relaxed);
while latency_ns < current_min {
match self.min_latency_ns.compare_exchange_weak(
current_min, latency_ns, Ordering::Relaxed, Ordering::Relaxed
) {
Ok(_) => break,
Err(x) => current_min = x,
}
}
// 更新最大值
let mut current_max = self.max_latency_ns.load(Ordering::Relaxed);
while latency_ns > current_max {
match self.max_latency_ns.compare_exchange_weak(
current_max, latency_ns, Ordering::Relaxed, Ordering::Relaxed
) {
Ok(_) => break,
Err(x) => current_max = x,
}
}
// 分类统计
if latency_ns < 1_000_000 { // <1ms
self.sub_millisecond_events.fetch_add(1, Ordering::Relaxed);
}
if latency_ns < 100_000 { // <100μs
self.ultra_fast_events.fetch_add(1, Ordering::Relaxed);
}
if latency_ns < 10_000 { // <10μs
self.lightning_fast_events.fetch_add(1, Ordering::Relaxed);
}
}
/// 获取延迟统计摘要
pub fn get_summary(&self) -> UltraLatencySummary {
let events_processed = self.events_processed.load(Ordering::Relaxed);
let total_latency_ns = self.total_latency_ns.load(Ordering::Relaxed);
let min_latency_ns = self.min_latency_ns.load(Ordering::Relaxed);
let max_latency_ns = self.max_latency_ns.load(Ordering::Relaxed);
let sub_ms_events = self.sub_millisecond_events.load(Ordering::Relaxed);
let ultra_fast_events = self.ultra_fast_events.load(Ordering::Relaxed);
let lightning_fast_events = self.lightning_fast_events.load(Ordering::Relaxed);
let avg_latency_ns = if events_processed > 0 {
total_latency_ns as f64 / events_processed as f64
} else {
0.0
};
let sub_ms_percentage = if events_processed > 0 {
sub_ms_events as f64 / events_processed as f64 * 100.0
} else {
0.0
};
let ultra_fast_percentage = if events_processed > 0 {
ultra_fast_events as f64 / events_processed as f64 * 100.0
} else {
0.0
};
let lightning_fast_percentage = if events_processed > 0 {
lightning_fast_events as f64 / events_processed as f64 * 100.0
} else {
0.0
};
UltraLatencySummary {
events_processed,
avg_latency_ns,
min_latency_ns: if min_latency_ns == u64::MAX { 0.0 } else { min_latency_ns as f64 },
max_latency_ns: max_latency_ns as f64,
avg_latency_us: avg_latency_ns / 1000.0,
sub_millisecond_percentage: sub_ms_percentage,
ultra_fast_percentage,
lightning_fast_percentage,
target_achieved: avg_latency_ns < 1_000_000.0, // <1ms target
}
}
}
/// 延迟统计摘要
#[derive(Debug, Clone)]
pub struct UltraLatencySummary {
pub events_processed: u64,
pub avg_latency_ns: f64,
pub min_latency_ns: f64,
pub max_latency_ns: f64,
pub avg_latency_us: f64,
pub sub_millisecond_percentage: f64,
pub ultra_fast_percentage: f64,
pub lightning_fast_percentage: f64,
pub target_achieved: bool,
}
impl LockFreeEventDispatcher {
/// 创建新的无锁事件分发器
pub fn new(
num_queues: usize,
queue_capacity: usize,
cpu_affinity: Option<CpuAffinityConfig>
) -> Self {
let mut event_queues = Vec::with_capacity(num_queues);
for _ in 0..num_queues {
event_queues.push(Arc::new(ArrayQueue::new(queue_capacity)));
}
info!("🚀 Created LockFreeEventDispatcher: {} queues, capacity {} each",
num_queues, queue_capacity);
Self {
event_queues,
client_queue_mapping: Arc::new(dashmap::DashMap::new()),
queue_selector: CachePadded::new(AtomicUsize::new(0)),
stats: Arc::new(UltraLowLatencyStats::new()),
prefetch_optimizer: Arc::new(PrefetchOptimizer::new(1000)),
cpu_affinity,
}
}
/// 🚀 极速事件分发 - 无锁路径
#[inline(always)]
pub fn dispatch_event_ultra_fast(&self, client_id: &str, event: EventMessage) -> Result<()> {
let start_time = Instant::now();
// 获取或分配客户端队列
let queue_index = if let Some(index) = self.client_queue_mapping.get(client_id) {
*index
} else {
// 使用轮询策略分配新队列
let index = self.queue_selector.fetch_add(1, Ordering::Relaxed) % self.event_queues.len();
self.client_queue_mapping.insert(client_id.to_string(), index);
index
};
// 预取优化
self.prefetch_optimizer.prefetch_event_data(&event);
// 尝试无阻塞推送到队列
let queue = &self.event_queues[queue_index];
match queue.push(event) {
Ok(_) => {
// 记录处理延迟
let latency_ns = start_time.elapsed().as_nanos() as u64;
self.stats.record_event_latency(latency_ns);
Ok(())
}
Err(_) => {
// 队列满,记录溢出
self.stats.queue_overflows.fetch_add(1, Ordering::Relaxed);
Err(anyhow::anyhow!("Queue overflow for client: {}", client_id))
}
}
}
/// 启动事件处理工作线程
pub async fn start_processing_workers(&self, num_workers: usize) -> Result<()> {
info!("🚀 Starting {} ultra-low-latency processing workers", num_workers);
for worker_id in 0..num_workers {
let queues = self.event_queues.clone();
let stats = Arc::clone(&self.stats);
let cpu_affinity = self.cpu_affinity.clone();
tokio::spawn(async move {
// 应用CPU亲和性
if let Some(affinity_config) = &cpu_affinity {
if let Err(e) = Self::set_thread_affinity(worker_id, affinity_config) {
warn!("Failed to set CPU affinity for worker {}: {}", worker_id, e);
} else {
info!("✅ Worker {} bound to CPU core", worker_id);
}
}
// 工作线程主循环
Self::worker_main_loop(worker_id, queues, stats).await;
});
}
Ok(())
}
/// 工作线程主循环 - 极速事件处理
async fn worker_main_loop(
worker_id: usize,
queues: Vec<Arc<ArrayQueue<EventMessage>>>,
stats: Arc<UltraLowLatencyStats>
) {
info!("🔄 Worker {} started ultra-low-latency processing loop", worker_id);
let mut queue_index = worker_id; // 从分配的队列开始
let notify = Arc::new(Notify::new());
loop {
let mut processed_any = false;
// 轮询所有队列,寻找待处理事件
for _ in 0..queues.len() {
let queue = &queues[queue_index % queues.len()];
// 批量处理以提高吞吐量
let mut batch_count = 0;
while batch_count < 100 { // 批次大小限制
match queue.pop() {
Some(event) => {
let process_start = Instant::now();
// 🚀 这里是实际的事件处理逻辑
// 在真实应用中,这里会调用实际的事件处理函数
Self::process_event_ultra_fast(&event).await;
let process_latency = process_start.elapsed().as_nanos() as u64;
stats.record_event_latency(process_latency);
processed_any = true;
batch_count += 1;
}
None => break,
}
}
queue_index = (queue_index + 1) % queues.len();
}
if !processed_any {
// 没有事件要处理,短暂休眠避免CPU空转
tokio::task::yield_now().await;
// 可选:使用更智能的等待机制
tokio::select! {
_ = tokio::time::sleep(Duration::from_nanos(100)) => {}, // 100ns极短休眠
_ = notify.notified() => {}, // 或等待通知
}
}
}
}
/// 🚀 极速事件处理函数
#[inline(always)]
async fn process_event_ultra_fast(event: &EventMessage) {
// 在这里实现实际的事件处理逻辑
// 为了演示,我们只是做一些最小的处理
// 避免不必要的分配和复制
debug!("Processing event: {} bytes", event.data.len());
// 在实际应用中,这里会:
// 1. 解析事件数据
// 2. 应用业务逻辑
// 3. 转发给相应的客户端
// 模拟极少的处理时间
tokio::task::yield_now().await;
}
/// 设置线程CPU亲和性
fn set_thread_affinity(worker_id: usize, config: &CpuAffinityConfig) -> Result<()> {
if config.core_ids.is_empty() {
return Ok(());
}
#[allow(unused_variables)]
let core_id = config.core_ids[worker_id % config.core_ids.len()];
#[cfg(target_os = "linux")]
{
use libc::{cpu_set_t, sched_setaffinity, CPU_SET, CPU_ZERO};
unsafe {
let mut cpuset: cpu_set_t = std::mem::zeroed();
CPU_ZERO(&mut cpuset);
CPU_SET(core_id, &mut cpuset);
if sched_setaffinity(0, std::mem::size_of::<cpu_set_t>(), &cpuset) != 0 {
return Err(anyhow::anyhow!("Failed to set CPU affinity to core {}", core_id));
}
}
}
#[cfg(target_os = "macos")]
{
// macOS不支持CPU亲和性绑定,但可以设置线程优先级
info!("CPU affinity not supported on macOS, setting thread priority instead");
// 可以使用thread_policy_set来设置线程调度策略
// 这里简化处理,只记录日志
}
#[cfg(target_os = "windows")]
{
use winapi::um::processthreadsapi::{GetCurrentThread, SetThreadAffinityMask};
unsafe {
let affinity_mask = 1u64 << core_id;
if SetThreadAffinityMask(GetCurrentThread(), affinity_mask as usize) == 0 {
return Err(anyhow::anyhow!("Failed to set CPU affinity to core {}", core_id));
}
}
}
Ok(())
}
/// 获取性能统计信息
pub fn get_performance_stats(&self) -> UltraLatencySummary {
self.stats.get_summary()
}
/// 获取预取统计信息
pub fn get_prefetch_stats(&self) -> (u64, u64, f64) {
self.prefetch_optimizer.get_stats()
}
/// 获取队列状态信息
pub fn get_queue_stats(&self) -> Vec<(usize, usize)> {
self.event_queues.iter().enumerate()
.map(|(i, queue)| (i, queue.len()))
.collect()
}
}
/// 🚀 零分配事件序列化器
pub struct ZeroAllocSerializer {
/// 预分配的序列化缓冲区池
buffer_pool: Arc<ArrayQueue<Vec<u8>>>,
/// 快速查找表:事件类型 -> 预计算序列化大小
size_hints: Arc<dashmap::DashMap<String, usize>>,
}
impl ZeroAllocSerializer {
pub fn new(pool_size: usize, buffer_size: usize) -> Self {
let buffer_pool = Arc::new(ArrayQueue::new(pool_size));
// 预分配缓冲区
for _ in 0..pool_size {
let _ = buffer_pool.push(Vec::with_capacity(buffer_size));
}
Self {
buffer_pool,
size_hints: Arc::new(dashmap::DashMap::new()),
}
}
/// 🚀 零分配序列化 - 重用预分配缓冲区
#[inline(always)]
pub fn serialize_zero_alloc<T: serde::Serialize>(&self, value: &T, event_type: &str) -> Result<Vec<u8>> {
// 尝试获取预分配缓冲区
let mut buffer = if let Some(buf) = self.buffer_pool.pop() {
buf
} else {
// 池耗尽,分配新缓冲区
let hint_size = self.size_hints.get(event_type)
.map(|entry| *entry)
.unwrap_or(1024);
Vec::with_capacity(hint_size)
};
// 清空缓冲区但保持容量
buffer.clear();
// 直接序列化到缓冲区
let serialized = bincode::serialize(value)?;
buffer.extend_from_slice(&serialized);
// 更新大小提示,用于优化后续分配
self.size_hints.insert(event_type.to_string(), buffer.len());
Ok(buffer)
}
/// 归还缓冲区到池中
#[inline(always)]
pub fn return_buffer(&self, buffer: Vec<u8>) {
// 只归还合理大小的缓冲区,避免池被超大缓冲区占用
if buffer.capacity() <= 1024 * 1024 { // 1MB limit
let _ = self.buffer_pool.push(buffer);
}
}
/// 获取池状态
pub fn get_pool_stats(&self) -> (usize, usize) {
(self.buffer_pool.len(), self.buffer_pool.capacity())
}
}
#[cfg(test)]
mod tests {
use super::*;
use fzstream_common::{SerializationProtocol};
use solana_streamer_sdk::streaming::event_parser::common::EventType;
#[tokio::test]
async fn test_lockfree_dispatcher() {
let dispatcher = LockFreeEventDispatcher::new(4, 1000, None);
let test_event = EventMessage {
event_id: "test_1".to_string(),
event_type: EventType::BlockMeta,
data: vec![1, 2, 3, 4],
serialization_format: SerializationProtocol::Bincode,
compression_format: fzstream_common::CompressionLevel::None,
is_compressed: false,
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as u64,
original_size: Some(4),
grpc_arrival_time: 0,
parsing_time: 0,
completion_time: 0,
client_processing_start: None,
client_processing_end: None,
};
// 测试事件分发
assert!(dispatcher.dispatch_event_ultra_fast("client_1", test_event).is_ok());
// 检查统计
let stats = dispatcher.get_performance_stats();
assert_eq!(stats.events_processed, 1);
}
#[test]
fn test_zero_alloc_serializer() {
let serializer = ZeroAllocSerializer::new(10, 1024);
let test_data = "Hello, world!";
let result = serializer.serialize_zero_alloc(&test_data, "string");
assert!(result.is_ok());
let serialized = result.unwrap();
assert!(!serialized.is_empty());
// 测试缓冲区归还
serializer.return_buffer(serialized);
let (available, capacity) = serializer.get_pool_stats();
assert!(available > 0);
assert_eq!(capacity, 10);
}
}