并发请求限制器的设计与实现

129 阅读2分钟

简介

在现代Web应用中,处理并发请求是一个常见的需求。为了防止服务器过载或提高系统性能,我们通常需要限制并发请求的数量。本文介绍了一个简单的并发请求限制器的设计与实现,支持两种模式:队列模式(Queue Mode)和竞争模式(Race Mode)。通过这个限制器,您可以轻松控制并发请求的数量,确保系统在高负载下依然稳定运行。

代码实现

RequestLimit 类
export class RequestLimit {
    constructor(maxConcurrentRequests, mode = "queue") {
        this.maxConcurrentRequests = maxConcurrentRequests; // 最大并发请求数
        this.requestQueue = []; // 请求队列
        this.activeRequests = 0; // 当前活跃请求数
        this.mode = mode; // 模式(队列或竞争)
    }

    // 创建 Queue 模式的实例
    static createWithQueueMode(maxConcurrentRequests) {
        return new RequestLimit(maxConcurrentRequests, "queue");
    }

    // 创建 Race 模式的实例
    static createWithRaceMode(maxConcurrentRequests) {
        return new RequestLimit(maxConcurrentRequests, "race");
    }

    async requestWrapper(request, response) {
        return new Promise(resolve => {
            const requestFunc = async () => {
                this.activeRequests++;
                try {
                    const result = await request();
                    response(result);
                    resolve(result);
                } finally {
                    this.activeRequests--;
                    this.runNext(); // 尝试运行下一个请求
                }
            };

            // 将请求添加到队列
            this.requestQueue.push(requestFunc);
            this.runRace(); // 尝试运行请求
        });
    }

    // 运行下一个请求
    runNext() {
        while (this.activeRequests < this.maxConcurrentRequests && this.requestQueue.length > 0) {
            const nextRequest = this.requestQueue.shift(); // 从队列中取出下一个请求
            nextRequest(); // 执行下一个请求
        }
    }

    // Race模式:控制并发请求数
    runRace() {
        while (this.activeRequests < this.maxConcurrentRequests && this.requestQueue.length > 0) {
            const nextRequest = this.requestQueue.shift(); // 从队列中取出下一个请求
            nextRequest(); // 执行下一个请求
        }
    }
}
测试代码
// 随机生成 1 到 5 秒的请求持续时间
const getRandomDuration = () => Math.floor(Math.random() * 5000) + 1000;

// 模拟异步请求函数,带有随机持续时间和时间戳
const createRequest = (id) => () => new Promise(resolve => {
    const duration = getRandomDuration();
    const startTime = new Date().toLocaleTimeString();
    console.log(`Request ${id} started at ${startTime} (duration: ${duration} ms)`);

    setTimeout(() => {
        const endTime = new Date().toLocaleTimeString();
        console.log(`Request ${id} finished at ${endTime}`);
        resolve(`Result of request ${id}`);
    }, duration);
});

// 测试函数
const testRequestLimit = async (mode, maxConcurrentRequests, totalRequests) => {
    console.log(`\nTesting ${mode} mode with max ${maxConcurrentRequests} concurrent requests:`);

    const limiter = mode === 'queue'
        ? RequestLimit.createWithQueueMode(maxConcurrentRequests)
        : RequestLimit.createWithRaceMode(maxConcurrentRequests);

    const responses = [];
    const responseCollector = response => {
        console.log("-------------->", response);
    };

    // 创建并发请求
    for (let i = 1; i <= totalRequests; i++) {
        limiter.requestWrapper(createRequest(i), responseCollector);
    }
};

// 测试参数
const maxConcurrentRequests = 3; // 最大并发请求数
const totalRequests = 10;        // 总请求数

// 运行测试
(async () => {
    await testRequestLimit('race', maxConcurrentRequests, totalRequests);
})();

关键点

  1. RequestLimit 类:

    • constructor: 初始化最大并发请求数、请求队列、当前活跃请求数和模式。
    • createWithQueueMode 和 createWithRaceMode: 静态方法,用于创建不同模式的实例。
    • requestWrapper: 包装请求,将请求添加到队列并尝试运行请求。
    • runNext: 运行下一个请求,确保并发数不超过限制。
    • runRace: 在 race 模式下控制并发请求数。
  2. 测试代码:

    • getRandomDuration: 生成 1 到 5 秒的随机请求持续时间。
    • createRequest: 模拟异步请求,带有随机持续时间和时间戳。
    • testRequestLimit: 测试函数,创建并发请求并收集结果。
    • 运行测试时,选择 race 模式并设置最大并发请求数和总请求数。

总结

通过这个简单的并发请求限制器,您可以轻松控制并发请求的数量,确保系统在高负载下依然稳定运行。无论是队列模式还是竞争模式,都能满足不同的需求。希望这个实现对您有所帮助!