手把手教你写 httpclient 框架(七)- 异步处理与性能优化

前言

在前面的文章中,我们已经构建了一个功能完整的 HTTP 客户端框架。但是在高并发的生产环境中,性能往往是决定框架成败的关键因素。本文将深入探讨如何通过异步处理和各种优化技术来提升框架的性能。

现代应用对性能的要求越来越高:

  • 高并发:需要同时处理大量请求
  • 低延迟:响应时间要尽可能短
  • 高吞吐:单位时间内处理更多请求
  • 资源效率:合理利用 CPU、内存和网络资源

本文将从以下几个方面来优化我们的框架:

  1. 异步编程模型设计
  2. 线程池优化
  3. 连接池管理
  4. 缓存机制
  5. 批量处理
  6. 性能监控和调优

异步编程模型深入设计

异步处理的优势

相比同步处理,异步处理有以下优势:

java 复制代码
// 同步处理 - 阻塞线程
public User getUser(Long id) {
    // 线程被阻塞,等待网络 I/O
    return httpClient.execute(request, handler);
}

// 异步处理 - 非阻塞
public CompletableFuture<User> getUserAsync(Long id) {
    // 线程立即返回,不阻塞
    return httpClient.executeAsync(request, handler);
}

增强的异步注解

我们扩展 @Async 注解,支持更多配置选项:

java 复制代码
package io.github.nemoob.httpclient.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
 * 增强的异步执行注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Async {
    
    /**
     * 执行器名称
     */
    String executor() default "";
    
    /**
     * 超时时间
     */
    long timeout() default -1;
    
    /**
     * 超时时间单位
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
    
    /**
     * 是否启用回调优化
     */
    boolean callbackOptimization() default true;
    
    /**
     * 失败重试次数
     */
    int retryCount() default 0;
    
    /**
     * 重试延迟(毫秒)
     */
    long retryDelay() default 1000;
}

高性能异步执行器管理

java 复制代码
package io.github.nemoob.httpclient.async;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 异步执行器管理器
 * 提供多种类型的线程池,针对不同场景优化
 */
public class AsyncExecutorManager {
    
    // 默认执行器 - 适用于一般 I/O 操作
    private static final ExecutorService DEFAULT_EXECUTOR = createDefaultExecutor();
    
    // 快速执行器 - 适用于轻量级操作
    private static final ExecutorService FAST_EXECUTOR = createFastExecutor();
    
    // 批量执行器 - 适用于批量操作
    private static final ExecutorService BATCH_EXECUTOR = createBatchExecutor();
    
    // 自定义执行器注册表
    private static final ConcurrentHashMap<String, ExecutorService> CUSTOM_EXECUTORS = new ConcurrentHashMap<>();
    
    /**
     * 创建默认执行器
     * 使用缓存线程池,适合 I/O 密集型任务
     */
    private static ExecutorService createDefaultExecutor() {
        return new ThreadPoolExecutor(
            10,                                    // 核心线程数
            200,                                   // 最大线程数
            60L, TimeUnit.SECONDS,                 // 空闲线程存活时间
            new LinkedBlockingQueue<>(1000),       // 工作队列
            new NamedThreadFactory("atlas-http-default"),
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );
    }
    
    /**
     * 创建快速执行器
     * 使用固定线程池,适合快速响应
     */
    private static ExecutorService createFastExecutor() {
        int processors = Runtime.getRuntime().availableProcessors();
        return new ThreadPoolExecutor(
            processors * 2,                       // 核心线程数
            processors * 2,                       // 最大线程数
            0L, TimeUnit.MILLISECONDS,            // 立即回收空闲线程
            new ArrayBlockingQueue<>(100),        // 有界队列
            new NamedThreadFactory("atlas-http-fast"),
            new ThreadPoolExecutor.AbortPolicy()  // 快速失败
        );
    }
    
    /**
     * 创建批量执行器
     * 使用工作窃取线程池,适合批量并行处理
     */
    private static ExecutorService createBatchExecutor() {
        return ForkJoinPool.commonPool();
    }
    
    /**
     * 获取执行器
     */
    public static ExecutorService getExecutor(String name) {
        if (name == null || name.isEmpty()) {
            return DEFAULT_EXECUTOR;
        }
        
        switch (name.toLowerCase()) {
            case "default":
                return DEFAULT_EXECUTOR;
            case "fast":
                return FAST_EXECUTOR;
            case "batch":
                return BATCH_EXECUTOR;
            default:
                return CUSTOM_EXECUTORS.getOrDefault(name, DEFAULT_EXECUTOR);
        }
    }
    
    /**
     * 注册自定义执行器
     */
    public static void registerExecutor(String name, ExecutorService executor) {
        CUSTOM_EXECUTORS.put(name, executor);
    }
    
    /**
     * 关闭所有执行器
     */
    public static void shutdown() {
        shutdownExecutor(DEFAULT_EXECUTOR);
        shutdownExecutor(FAST_EXECUTOR);
        CUSTOM_EXECUTORS.values().forEach(AsyncExecutorManager::shutdownExecutor);
    }
    
    private static void shutdownExecutor(ExecutorService executor) {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
    
    /**
     * 命名线程工厂
     */
    private static class NamedThreadFactory implements ThreadFactory {
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
        
        NamedThreadFactory(String namePrefix) {
            this.namePrefix = namePrefix + "-thread-";
        }
        
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r, namePrefix + threadNumber.getAndIncrement());
            thread.setDaemon(true);
            thread.setPriority(Thread.NORM_PRIORITY);
            return thread;
        }
    }
}

异步结果处理优化

java 复制代码
package io.github.nemoob.httpclient.async;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 异步结果处理工具
 * 提供各种异步操作的优化实现
 */
public class AsyncResultHandler {
    
    /**
     * 带超时的异步执行
     */
    public static <T> CompletableFuture<T> executeWithTimeout(
            Supplier<T> supplier, 
            long timeout, 
            java.util.concurrent.TimeUnit unit,
            Executor executor) {
        
        CompletableFuture<T> future = CompletableFuture.supplyAsync(supplier, executor);
        
        // 创建超时任务
        CompletableFuture<T> timeoutFuture = new CompletableFuture<>();
        AsyncExecutorManager.getExecutor("fast").execute(() -> {
            try {
                unit.sleep(timeout);
                timeoutFuture.completeExceptionally(new java.util.concurrent.TimeoutException("Operation timed out"));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        // 返回最先完成的结果
        return future.applyToEither(timeoutFuture, Function.identity());
    }
    
    /**
     * 批量异步执行
     */
    public static <T> CompletableFuture<java.util.List<T>> executeAll(
            java.util.List<Supplier<T>> suppliers,
            Executor executor) {
        
        java.util.List<CompletableFuture<T>> futures = suppliers.stream()
            .map(supplier -> CompletableFuture.supplyAsync(supplier, executor))
            .collect(java.util.stream.Collectors.toList());
        
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenApply(v -> futures.stream()
                .map(CompletableFuture::join)
                .collect(java.util.stream.Collectors.toList()));
    }
    
    /**
     * 异步重试机制
     */
    public static <T> CompletableFuture<T> executeWithRetry(
            Supplier<T> supplier,
            int maxRetries,
            long retryDelay,
            Executor executor) {
        
        return executeWithRetryInternal(supplier, maxRetries, retryDelay, executor, 0);
    }
    
    private static <T> CompletableFuture<T> executeWithRetryInternal(
            Supplier<T> supplier,
            int maxRetries,
            long retryDelay,
            Executor executor,
            int currentAttempt) {
        
        return CompletableFuture.supplyAsync(supplier, executor)
            .handle((result, throwable) -> {
                if (throwable == null) {
                    return CompletableFuture.completedFuture(result);
                }
                
                if (currentAttempt >= maxRetries) {
                    CompletableFuture<T> failedFuture = new CompletableFuture<>();
                    failedFuture.completeExceptionally(throwable);
                    return failedFuture;
                }
                
                // 延迟后重试
                return CompletableFuture
                    .delayedExecutor(retryDelay, java.util.concurrent.TimeUnit.MILLISECONDS, executor)
                    .execute(() -> executeWithRetryInternal(supplier, maxRetries, retryDelay, executor, currentAttempt + 1));
            })
            .thenCompose(Function.identity());
    }
    
    /**
     * 异步回调链优化
     */
    public static <T, R> CompletableFuture<R> chainAsync(
            CompletableFuture<T> future,
            Function<T, CompletableFuture<R>> mapper,
            Executor executor) {
        
        return future.thenComposeAsync(mapper, executor);
    }
}

连接池管理优化

高性能连接池实现

java 复制代码
package io.github.nemoob.httpclient.pool;

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * HTTP 连接池
 * 复用连接,减少连接建立开销
 */
public class HttpConnectionPool {
    
    private final int maxPoolSize;
    private final int maxIdleTime;
    private final ConcurrentHashMap<String, ConnectionQueue> pools = new ConcurrentHashMap<>();
    
    public HttpConnectionPool(int maxPoolSize, int maxIdleTime) {
        this.maxPoolSize = maxPoolSize;
        this.maxIdleTime = maxIdleTime;
        
        // 启动清理线程
        startCleanupThread();
    }
    
    /**
     * 获取连接
     */
    public PooledConnection getConnection(String host, int port) throws Exception {
        String key = host + ":" + port;
        ConnectionQueue queue = pools.computeIfAbsent(key, k -> new ConnectionQueue());
        
        PooledConnection connection = queue.poll();
        if (connection != null && connection.isValid()) {
            return connection;
        }
        
        // 创建新连接
        URL url = new URL("http", host, port, "/");
        HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
        return new PooledConnection(httpConnection, key, this);
    }
    
    /**
     * 归还连接
     */
    public void returnConnection(PooledConnection connection) {
        if (connection.isValid()) {
            ConnectionQueue queue = pools.get(connection.getPoolKey());
            if (queue != null && queue.size() < maxPoolSize) {
                connection.updateLastUsed();
                queue.offer(connection);
                return;
            }
        }
        
        // 关闭连接
        connection.close();
    }
    
    /**
     * 启动清理线程
     */
    private void startCleanupThread() {
        Thread cleanupThread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(30000); // 30秒清理一次
                    cleanup();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }, "connection-pool-cleanup");
        
        cleanupThread.setDaemon(true);
        cleanupThread.start();
    }
    
    /**
     * 清理过期连接
     */
    private void cleanup() {
        long now = System.currentTimeMillis();
        
        pools.values().forEach(queue -> {
            queue.removeIf(connection -> {
                if (now - connection.getLastUsed() > maxIdleTime) {
                    connection.close();
                    return true;
                }
                return false;
            });
        });
    }
    
    /**
     * 连接队列
     */
    private static class ConnectionQueue extends LinkedBlockingQueue<PooledConnection> {
        private final AtomicInteger size = new AtomicInteger(0);
        
        @Override
        public boolean offer(PooledConnection connection) {
            if (super.offer(connection)) {
                size.incrementAndGet();
                return true;
            }
            return false;
        }
        
        @Override
        public PooledConnection poll() {
            PooledConnection connection = super.poll();
            if (connection != null) {
                size.decrementAndGet();
            }
            return connection;
        }
        
        public int size() {
            return size.get();
        }
    }
    
    /**
     * 池化连接
     */
    public static class PooledConnection {
        private final HttpURLConnection connection;
        private final String poolKey;
        private final HttpConnectionPool pool;
        private long lastUsed;
        private boolean closed = false;
        
        public PooledConnection(HttpURLConnection connection, String poolKey, HttpConnectionPool pool) {
            this.connection = connection;
            this.poolKey = poolKey;
            this.pool = pool;
            this.lastUsed = System.currentTimeMillis();
        }
        
        public HttpURLConnection getConnection() {
            return connection;
        }
        
        public String getPoolKey() {
            return poolKey;
        }
        
        public long getLastUsed() {
            return lastUsed;
        }
        
        public void updateLastUsed() {
            this.lastUsed = System.currentTimeMillis();
        }
        
        public boolean isValid() {
            return !closed && connection != null;
        }
        
        public void close() {
            closed = true;
            if (connection != null) {
                connection.disconnect();
            }
        }
        
        public void returnToPool() {
            pool.returnConnection(this);
        }
    }
}

缓存机制实现

多级缓存系统

java 复制代码
package io.github.nemoob.httpclient.cache;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 多级缓存系统
 * L1: 内存缓存(快速访问)
 * L2: 本地文件缓存(持久化)
 */
public class MultiLevelCache {
    
    // L1 缓存 - 内存
    private final ConcurrentHashMap<String, CacheEntry> memoryCache = new ConcurrentHashMap<>();
    
    // L2 缓存 - 文件(简化实现)
    private final ConcurrentHashMap<String, CacheEntry> fileCache = new ConcurrentHashMap<>();
    
    private final int maxMemoryCacheSize;
    private final long defaultTtl;
    private final ScheduledExecutorService cleanupExecutor;
    
    public MultiLevelCache(int maxMemoryCacheSize, long defaultTtl) {
        this.maxMemoryCacheSize = maxMemoryCacheSize;
        this.defaultTtl = defaultTtl;
        this.cleanupExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread thread = new Thread(r, "cache-cleanup");
            thread.setDaemon(true);
            return thread;
        });
        
        // 定期清理过期缓存
        cleanupExecutor.scheduleAtFixedRate(this::cleanup, 1, 1, TimeUnit.MINUTES);
    }
    
    /**
     * 获取缓存
     */
    public <T> T get(String key, Class<T> type) {
        // 先查 L1 缓存
        CacheEntry entry = memoryCache.get(key);
        if (entry != null && !entry.isExpired()) {
            return type.cast(entry.getValue());
        }
        
        // 再查 L2 缓存
        entry = fileCache.get(key);
        if (entry != null && !entry.isExpired()) {
            // 提升到 L1 缓存
            putToMemoryCache(key, entry);
            return type.cast(entry.getValue());
        }
        
        return null;
    }
    
    /**
     * 设置缓存
     */
    public void put(String key, Object value) {
        put(key, value, defaultTtl);
    }
    
    public void put(String key, Object value, long ttl) {
        CacheEntry entry = new CacheEntry(value, System.currentTimeMillis() + ttl);
        
        // 存入 L1 缓存
        putToMemoryCache(key, entry);
        
        // 存入 L2 缓存
        fileCache.put(key, entry);
    }
    
    /**
     * 存入内存缓存
     */
    private void putToMemoryCache(String key, CacheEntry entry) {
        // 检查缓存大小限制
        if (memoryCache.size() >= maxMemoryCacheSize) {
            evictLRU();
        }
        
        memoryCache.put(key, entry);
    }
    
    /**
     * LRU 淘汰策略
     */
    private void evictLRU() {
        String oldestKey = null;
        long oldestTime = Long.MAX_VALUE;
        
        for (java.util.Map.Entry<String, CacheEntry> entry : memoryCache.entrySet()) {
            if (entry.getValue().getCreateTime() < oldestTime) {
                oldestTime = entry.getValue().getCreateTime();
                oldestKey = entry.getKey();
            }
        }
        
        if (oldestKey != null) {
            memoryCache.remove(oldestKey);
        }
    }
    
    /**
     * 清理过期缓存
     */
    private void cleanup() {
        long now = System.currentTimeMillis();
        
        // 清理内存缓存
        memoryCache.entrySet().removeIf(entry -> entry.getValue().isExpired(now));
        
        // 清理文件缓存
        fileCache.entrySet().removeIf(entry -> entry.getValue().isExpired(now));
    }
    
    /**
     * 缓存条目
     */
    private static class CacheEntry {
        private final Object value;
        private final long expireTime;
        private final long createTime;
        
        public CacheEntry(Object value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
            this.createTime = System.currentTimeMillis();
        }
        
        public Object getValue() {
            return value;
        }
        
        public long getCreateTime() {
            return createTime;
        }
        
        public boolean isExpired() {
            return isExpired(System.currentTimeMillis());
        }
        
        public boolean isExpired(long now) {
            return now > expireTime;
        }
    }
}

智能缓存拦截器

java 复制代码
package io.github.nemoob.httpclient.cache;

import io.github.nemoob.httpclient.*;

/**
 * 智能缓存拦截器
 * 根据请求特征自动决定缓存策略
 */
public class SmartCacheInterceptor extends AbstractRequestInterceptor {
    
    private final MultiLevelCache cache;
    private final CacheStrategy strategy;
    
    public SmartCacheInterceptor(MultiLevelCache cache, CacheStrategy strategy) {
        this.cache = cache;
        this.strategy = strategy;
    }
    
    @Override
    public void preHandle(RequestContext context) throws Exception {
        Request request = context.getRequest();
        
        // 只缓存 GET 请求
        if (request.getMethod() != HttpMethod.GET) {
            return;
        }
        
        String cacheKey = generateCacheKey(request);
        CachePolicy policy = strategy.getCachePolicy(request);
        
        if (policy.isReadFromCache()) {
            Object cachedResponse = cache.get(cacheKey, Object.class);
            if (cachedResponse != null) {
                // 设置缓存响应
                context.setResponse(createCachedResponse(cachedResponse));
                context.setAttribute("cacheHit", true);
            }
        }
        
        context.setAttribute("cacheKey", cacheKey);
        context.setAttribute("cachePolicy", policy);
    }
    
    @Override
    public void postHandle(RequestContext context) throws Exception {
        Boolean cacheHit = (Boolean) context.getAttribute("cacheHit");
        if (cacheHit != null && cacheHit) {
            return; // 缓存命中,无需处理
        }
        
        String cacheKey = (String) context.getAttribute("cacheKey");
        CachePolicy policy = (CachePolicy) context.getAttribute("cachePolicy");
        Response response = context.getResponse();
        
        if (cacheKey != null && policy != null && policy.isWriteToCache() && 
            response != null && isSuccessResponse(response)) {
            
            // 缓存响应
            cache.put(cacheKey, response, policy.getTtl());
        }
    }
    
    /**
     * 生成缓存键
     */
    private String generateCacheKey(Request request) {
        StringBuilder keyBuilder = new StringBuilder();
        keyBuilder.append(request.getMethod().name())
                  .append(":");
                  .append(request.getUrl());
        
        // 包含重要的请求头
        if (request.getHeaders() != null) {
            request.getHeaders().entrySet().stream()
                .filter(entry -> isCacheableHeader(entry.getKey()))
                .sorted(java.util.Map.Entry.comparingByKey())
                .forEach(entry -> keyBuilder.append("|").append(entry.getKey()).append("=").append(entry.getValue()));
        }
        
        return java.security.MessageDigest.getInstance("MD5")
            .digest(keyBuilder.toString().getBytes())
            .toString();
    }
    
    /**
     * 判断是否是可缓存的请求头
     */
    private boolean isCacheableHeader(String headerName) {
        return !headerName.equalsIgnoreCase("Authorization") &&
               !headerName.equalsIgnoreCase("Cookie") &&
               !headerName.equalsIgnoreCase("Date");
    }
    
    /**
     * 判断是否是成功响应
     */
    private boolean isSuccessResponse(Response response) {
        int statusCode = response.getStatusCode();
        return statusCode >= 200 && statusCode < 300;
    }
    
    /**
     * 创建缓存响应
     */
    private Response createCachedResponse(Object cachedData) {
        // 简化实现,实际应该完整恢复响应对象
        return (Response) cachedData;
    }
    
    /**
     * 缓存策略接口
     */
    public interface CacheStrategy {
        CachePolicy getCachePolicy(Request request);
    }
    
    /**
     * 缓存策略
     */
    public static class CachePolicy {
        private final boolean readFromCache;
        private final boolean writeToCache;
        private final long ttl;
        
        public CachePolicy(boolean readFromCache, boolean writeToCache, long ttl) {
            this.readFromCache = readFromCache;
            this.writeToCache = writeToCache;
            this.ttl = ttl;
        }
        
        public boolean isReadFromCache() {
            return readFromCache;
        }
        
        public boolean isWriteToCache() {
            return writeToCache;
        }
        
        public long getTtl() {
            return ttl;
        }
    }
}

批量处理优化

批量请求处理器

java 复制代码
package io.github.nemoob.httpclient.batch;

import io.github.nemoob.httpclient.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.ArrayList;

/**
 * 批量请求处理器
 * 将多个请求合并处理,提高吞吐量
 */
public class BatchRequestProcessor {
    
    private final HttpClient httpClient;
    private final int batchSize;
    private final long batchTimeout;
    private final ConcurrentLinkedQueue<BatchItem> pendingRequests = new ConcurrentLinkedQueue<>();
    private final ScheduledExecutorService scheduler;
    
    public BatchRequestProcessor(HttpClient httpClient, int batchSize, long batchTimeout) {
        this.httpClient = httpClient;
        this.batchSize = batchSize;
        this.batchTimeout = batchTimeout;
        this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread thread = new Thread(r, "batch-processor");
            thread.setDaemon(true);
            return thread;
        });
        
        // 定期处理批量请求
        scheduler.scheduleAtFixedRate(this::processBatch, batchTimeout, batchTimeout, TimeUnit.MILLISECONDS);
    }
    
    /**
     * 添加请求到批量处理队列
     */
    public <T> CompletableFuture<T> addRequest(Request request, ResponseHandler<T> handler) {
        CompletableFuture<T> future = new CompletableFuture<>();
        BatchItem item = new BatchItem(request, handler, future);
        
        pendingRequests.offer(item);
        
        // 如果达到批量大小,立即处理
        if (pendingRequests.size() >= batchSize) {
            scheduler.execute(this::processBatch);
        }
        
        return future;
    }
    
    /**
     * 处理批量请求
     */
    private void processBatch() {
        List<BatchItem> batch = new ArrayList<>();
        
        // 收集批量请求
        BatchItem item;
        while ((item = pendingRequests.poll()) != null && batch.size() < batchSize) {
            batch.add(item);
        }
        
        if (batch.isEmpty()) {
            return;
        }
        
        // 并行执行批量请求
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        
        for (BatchItem batchItem : batch) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    Object result = httpClient.execute(batchItem.request, batchItem.handler);
                    batchItem.future.complete(result);
                } catch (Exception e) {
                    batchItem.future.completeExceptionally(e);
                }
            }, AsyncExecutorManager.getExecutor("batch"));
            
            futures.add(future);
        }
        
        // 等待所有请求完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .whenComplete((result, throwable) -> {
                if (throwable != null) {
                    // 处理批量执行异常
                    System.err.println("Batch execution failed: " + throwable.getMessage());
                }
            });
    }
    
    /**
     * 批量项
     */
    private static class BatchItem {
        final Request request;
        final ResponseHandler<?> handler;
        final CompletableFuture<Object> future;
        
        @SuppressWarnings("unchecked")
        BatchItem(Request request, ResponseHandler<?> handler, CompletableFuture<?> future) {
            this.request = request;
            this.handler = handler;
            this.future = (CompletableFuture<Object>) future;
        }
    }
}

性能监控和调优

性能指标收集器

java 复制代码
package io.github.nemoob.httpclient.metrics;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 性能指标收集器
 * 收集详细的性能数据用于监控和调优
 */
public class PerformanceMetrics {
    
    // 请求计数
    private final LongAdder totalRequests = new LongAdder();
    private final LongAdder successfulRequests = new LongAdder();
    private final LongAdder failedRequests = new LongAdder();
    
    // 响应时间统计
    private final AtomicLong totalResponseTime = new AtomicLong();
    private final AtomicLong minResponseTime = new AtomicLong(Long.MAX_VALUE);
    private final AtomicLong maxResponseTime = new AtomicLong();
    
    // 分位数统计(简化实现)
    private final ConcurrentHashMap<String, LongAdder> responseTimeDistribution = new ConcurrentHashMap<>();
    
    // 连接池统计
    private final AtomicLong activeConnections = new AtomicLong();
    private final AtomicLong poolHits = new AtomicLong();
    private final AtomicLong poolMisses = new AtomicLong();
    
    // 缓存统计
    private final AtomicLong cacheHits = new AtomicLong();
    private final AtomicLong cacheMisses = new AtomicLong();
    
    /**
     * 记录请求开始
     */
    public void recordRequestStart() {
        totalRequests.increment();
    }
    
    /**
     * 记录请求完成
     */
    public void recordRequestComplete(long responseTime, boolean success) {
        if (success) {
            successfulRequests.increment();
        } else {
            failedRequests.increment();
        }
        
        // 更新响应时间统计
        totalResponseTime.addAndGet(responseTime);
        updateMinResponseTime(responseTime);
        updateMaxResponseTime(responseTime);
        updateResponseTimeDistribution(responseTime);
    }
    
    /**
     * 记录连接池命中
     */
    public void recordPoolHit() {
        poolHits.incrementAndGet();
    }
    
    /**
     * 记录连接池未命中
     */
    public void recordPoolMiss() {
        poolMisses.incrementAndGet();
    }
    
    /**
     * 记录缓存命中
     */
    public void recordCacheHit() {
        cacheHits.incrementAndGet();
    }
    
    /**
     * 记录缓存未命中
     */
    public void recordCacheMiss() {
        cacheMisses.incrementAndGet();
    }
    
    /**
     * 更新最小响应时间
     */
    private void updateMinResponseTime(long responseTime) {
        long current;
        do {
            current = minResponseTime.get();
            if (responseTime >= current) {
                break;
            }
        } while (!minResponseTime.compareAndSet(current, responseTime));
    }
    
    /**
     * 更新最大响应时间
     */
    private void updateMaxResponseTime(long responseTime) {
        long current;
        do {
            current = maxResponseTime.get();
            if (responseTime <= current) {
                break;
            }
        } while (!maxResponseTime.compareAndSet(current, responseTime));
    }
    
    /**
     * 更新响应时间分布
     */
    private void updateResponseTimeDistribution(long responseTime) {
        String bucket = getResponseTimeBucket(responseTime);
        responseTimeDistribution.computeIfAbsent(bucket, k -> new LongAdder()).increment();
    }
    
    /**
     * 获取响应时间桶
     */
    private String getResponseTimeBucket(long responseTime) {
        if (responseTime < 100) return "<100ms";
        if (responseTime < 500) return "100-500ms";
        if (responseTime < 1000) return "500ms-1s";
        if (responseTime < 5000) return "1-5s";
        return ">5s";
    }
    
    /**
     * 获取性能报告
     */
    public PerformanceReport getReport() {
        long total = totalRequests.sum();
        long successful = successfulRequests.sum();
        long failed = failedRequests.sum();
        
        double successRate = total > 0 ? (double) successful / total : 0;
        double avgResponseTime = successful > 0 ? (double) totalResponseTime.get() / successful : 0;
        
        long poolTotal = poolHits.get() + poolMisses.get();
        double poolHitRate = poolTotal > 0 ? (double) poolHits.get() / poolTotal : 0;
        
        long cacheTotal = cacheHits.get() + cacheMisses.get();
        double cacheHitRate = cacheTotal > 0 ? (double) cacheHits.get() / cacheTotal : 0;
        
        return new PerformanceReport(
            total, successful, failed, successRate,
            avgResponseTime, minResponseTime.get(), maxResponseTime.get(),
            poolHitRate, cacheHitRate,
            new ConcurrentHashMap<>(responseTimeDistribution)
        );
    }
    
    /**
     * 性能报告
     */
    public static class PerformanceReport {
        public final long totalRequests;
        public final long successfulRequests;
        public final long failedRequests;
        public final double successRate;
        public final double avgResponseTime;
        public final long minResponseTime;
        public final long maxResponseTime;
        public final double poolHitRate;
        public final double cacheHitRate;
        public final ConcurrentHashMap<String, LongAdder> responseTimeDistribution;
        
        public PerformanceReport(long totalRequests, long successfulRequests, long failedRequests,
                               double successRate, double avgResponseTime, long minResponseTime,
                               long maxResponseTime, double poolHitRate, double cacheHitRate,
                               ConcurrentHashMap<String, LongAdder> responseTimeDistribution) {
            this.totalRequests = totalRequests;
            this.successfulRequests = successfulRequests;
            this.failedRequests = failedRequests;
            this.successRate = successRate;
            this.avgResponseTime = avgResponseTime;
            this.minResponseTime = minResponseTime;
            this.maxResponseTime = maxResponseTime;
            this.poolHitRate = poolHitRate;
            this.cacheHitRate = cacheHitRate;
            this.responseTimeDistribution = responseTimeDistribution;
        }
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("Performance Report:\n");
            sb.append(String.format("Total Requests: %d\n", totalRequests));
            sb.append(String.format("Success Rate: %.2f%%\n", successRate * 100));
            sb.append(String.format("Avg Response Time: %.2fms\n", avgResponseTime));
            sb.append(String.format("Min Response Time: %dms\n", minResponseTime));
            sb.append(String.format("Max Response Time: %dms\n", maxResponseTime));
            sb.append(String.format("Pool Hit Rate: %.2f%%\n", poolHitRate * 100));
            sb.append(String.format("Cache Hit Rate: %.2f%%\n", cacheHitRate * 100));
            
            sb.append("Response Time Distribution:\n");
            responseTimeDistribution.forEach((bucket, count) -> 
                sb.append(String.format("  %s: %d\n", bucket, count.sum()))
            );
            
            return sb.toString();
        }
    }
}

使用示例和最佳实践

高性能配置示例

java 复制代码
// 配置高性能 HTTP 客户端
@Configuration
public class HighPerformanceHttpClientConfig {
    
    @Bean
    public HttpConnectionPool connectionPool() {
        return new HttpConnectionPool(100, 300000); // 100个连接,5分钟空闲时间
    }
    
    @Bean
    public MultiLevelCache httpCache() {
        return new MultiLevelCache(1000, 600000); // 1000个条目,10分钟TTL
    }
    
    @Bean
    public BatchRequestProcessor batchProcessor(HttpClient httpClient) {
        return new BatchRequestProcessor(httpClient, 10, 100); // 批量大小10,100ms超时
    }
    
    @Bean
    public PerformanceMetrics performanceMetrics() {
        return new PerformanceMetrics();
    }
}

异步客户端使用

java 复制代码
@HttpClient("https://api.example.com")
public interface HighPerformanceUserService {
    
    // 快速异步请求
    @GET("/users/{id}")
    @Async(executor = "fast", timeout = 1000)
    CompletableFuture<User> getUserFast(@Path("id") Long id);
    
    // 批量异步请求
    @GET("/users")
    @Async(executor = "batch")
    CompletableFuture<List<User>> getUsersBatch(@Query("ids") List<Long> ids);
    
    // 带重试的异步请求
    @POST("/users")
    @Async(retryCount = 3, retryDelay = 1000)
    CompletableFuture<User> createUserWithRetry(@Body User user);
}

性能监控

java 复制代码
@Service
public class PerformanceMonitoringService {
    
    @Autowired
    private PerformanceMetrics metrics;
    
    @Scheduled(fixedRate = 60000) // 每分钟输出一次报告
    public void printPerformanceReport() {
        PerformanceMetrics.PerformanceReport report = metrics.getReport();
        System.out.println(report.toString());
        
        // 性能告警
        if (report.successRate < 0.95) {
            System.err.println("WARNING: Success rate below 95%");
        }
        
        if (report.avgResponseTime > 5000) {
            System.err.println("WARNING: Average response time above 5s");
        }
    }
}

性能调优建议

1. 线程池调优

java 复制代码
// 根据应用特点调整线程池参数
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,    // 核心线程数 = CPU核心数 * 2
    maxPoolSize,     // 最大线程数 = CPU核心数 * 4
    keepAliveTime,   // 空闲线程存活时间
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(queueSize), // 队列大小
    new ThreadFactory() { /* 自定义线程工厂 */ },
    new RejectedExecutionHandler() { /* 拒绝策略 */ }
);

2. JVM 调优

bash 复制代码
# 推荐的 JVM 参数
-Xms2g -Xmx2g                    # 堆内存大小
-XX:+UseG1GC                     # 使用 G1 垃圾收集器
-XX:MaxGCPauseMillis=200         # 最大 GC 暂停时间
-XX:+UseStringDeduplication      # 字符串去重
-XX:+OptimizeStringConcat        # 优化字符串连接

3. 网络调优

java 复制代码
// 系统属性调优
System.setProperty("http.keepAlive", "true");
System.setProperty("http.maxConnections", "20");
System.setProperty("http.maxRedirects", "3");
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

总结

本文详细介绍了 Atlas HTTP Client 框架的异步处理和性能优化技术。关键要点包括:

  1. 异步编程模型:基于 CompletableFuture 的现代异步编程
  2. 线程池优化:针对不同场景的专用线程池
  3. 连接池管理:高效的连接复用机制
  4. 多级缓存:内存+文件的多级缓存系统
  5. 批量处理:提高吞吐量的批量请求处理
  6. 性能监控:全面的性能指标收集和分析

通过这些优化技术,我们的框架可以在高并发环境下提供优秀的性能表现。

至此,《手把手教你写 httpclient 框架》系列文章全部完成。我们从零开始,逐步构建了一个功能完整、性能优秀的 HTTP 客户端框架,涵盖了:

  • 架构设计思路
  • 注解系统实现
  • 动态代理机制
  • HTTP 网络通信
  • 拦截器扩展机制
  • Spring Boot 集成
  • 异步处理和性能优化

希望这个系列能够帮助你深入理解框架设计的思路和实现技巧,在实际工作中设计出更好的技术方案。

相关推荐
绝无仅有3 小时前
redis面试史上最全的笔记整理总结
后端·面试·github
ajassi20003 小时前
开源 java android app 开发(十四)自定义绘图控件--波形图
android·java·开源
摆个烂3 小时前
Apache HTTP基于端口的多站点部署完整教程
网络协议·http·apache
一叶飘零_sweeeet3 小时前
从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技术全解析
java·skywalking
七夜zippoe3 小时前
Java 生态监控体系实战:Prometheus+Grafana+SkyWalking 整合全指南(三)
java·grafana·prometheus
陈遇巧4 小时前
Spring Framework
java·笔记·spring
我是华为OD~HR~栗栗呀4 小时前
20届-高级开发(华为oD)-Java面经
java·c++·后端·python·华为od·华为
绝无仅有4 小时前
面试数据库MySQL 99% 必问的十道题及详细解答
后端·面试·github
摇滚侠5 小时前
java.lang.RuntimeException: java.lang.OutOfMemoryError
java·开发语言·intellij-idea