Nodejs windows下redis高效协议解析器(js版)

Nodejs windows下redis高效协议解析器(js版)

最近用nodejs做项目,大规模的使用了redis,在windows下开发老是遇到各种问题,因为redis的协议解析器有问题,本来redis模块有两种协议解析的方式,一种是使用js实现的,另一种则是使用redis官方提供的hiredis的模块,当使用hiredis模块的时候当然一切正常,但是如果你是windows上的开发者,那么你没得选择,只能使用js版解析器,因为hiredis的模块在windows下安装不了,可是使用js版的解析器的时候就会出现各种问题,曾经改过几次这个js文件,但是还是没能把BUG完全修复完,于是一股脑直接重写了这个解析器,这次改动首先是修复各种协议上的问题,其中最大的区别是在效率的很大程度的提升,为什么这么说?因为原始的解析器方式是这样,如果一条完整的数据包有10K,此时因为网络原因只传输了8K,那么他必须先尝试解析,一旦发现包长度不够,就会等下次2K的数据来了之后再重新解析,意思就是说,之前解析的那8K的时间浪费了。而我改动的则是可以续解析,上次解析到哪里,下次收到数据包后,再接着上次解析的地方继续往下执行,节约了很多时间。简单介绍之后贴上代码吧,希望能对大家有帮助。

点击下载


2 回复

Nodejs Windows 下 Redis 高效协议解析器 (JS 版)

背景

最近在使用 Node.js 开发一个项目时,大规模地使用了 Redis。由于在 Windows 环境下开发遇到了一些问题,尤其是 Redis 的协议解析器存在一些问题。Redis 模块提供了两种协议解析的方式:一种是使用 JavaScript 实现的,另一种则是使用 Redis 官方提供的 hiredis 模块。然而,hiredis 模块在 Windows 下无法安装,这就迫使我们只能使用 JS 版的解析器。

问题描述

使用原始的 JS 版解析器时,遇到了一些性能瓶颈。原始的解析器方式是这样的:如果一条完整的数据包有 10K,但由于网络原因只传输了 8K,那么它必须先尝试解析,一旦发现包长度不够,就会等待下次 2K 的数据到来后再重新解析。这意味着之前解析的那 8K 时间被浪费了。

解决方案

为了提高解析器的效率,我对其进行了重写,主要改进如下:

  1. 续解析功能:可以记住上次解析的位置,下次接收到数据包后,从上次解析的位置继续往下执行,避免了重复解析造成的性能浪费。
  2. 性能优化:通过对协议解析逻辑的优化,提高了整体解析速度。

示例代码

以下是一个简单的示例代码,展示了如何实现续解析功能:

const net = require('net');

class RedisParser {
    constructor() {
        this.buffer = Buffer.alloc(0);
    }

    parse(data) {
        this.buffer = Buffer.concat([this.buffer, data]);
        let offset = 0;
        
        while (offset < this.buffer.length) {
            const result = this.parsePacket(offset);
            if (!result) break; // 如果解析不完整,退出循环
            offset += result.length;
        }
        
        // 移除已解析的部分
        this.buffer = this.buffer.slice(offset);
    }

    parsePacket(offset) {
        // 假设每个包以 '\r\n' 结尾
        const end = this.buffer.indexOf('\r\n', offset);
        if (end === -1) return null; // 包未完整
        
        const packet = this.buffer.slice(offset, end + 2);
        // 这里可以添加具体的解析逻辑
        console.log(`Parsed packet: ${packet.toString()}`);
        
        return packet;
    }
}

// 使用示例
const client = net.createConnection({ port: 6379 }, () => {
    client.write('*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n');
});

client.on('data', (data) => {
    const parser = new RedisParser();
    parser.parse(data);
});

总结

通过上述改进,我们可以显著提高 Redis 协议解析器的性能,特别是在网络不稳定的情况下。希望这个示例能帮助你在 Windows 下更高效地使用 Node.js 和 Redis。


针对Node.js在Windows环境下处理Redis时遇到的高效协议解析问题,特别是需要使用基于JavaScript的协议解析器来替代无法在Windows环境下编译的hiredis模块,我们可以采取优化的方式来提高性能和稳定性。

解决方案概述

主要改进包括:

  1. 优化解析流程:使解析器能够进行断点续传,避免重复解析已经接收的数据。
  2. 增强错误处理:确保在数据包不完整或格式错误时能够正确处理,防止程序崩溃或阻塞。

示例代码

以下是一个简化的示例,展示了如何创建一个基本的断点续传型Redis协议解析器:

const net = require('net');

class RedisParser {
    constructor() {
        this.buffer = '';
        this.parsing = false;
    }

    appendData(data) {
        this.buffer += data;

        if (!this.parsing) {
            this.startParsing();
        }
    }

    startParsing() {
        this.parsing = true;

        while (this.buffer.indexOf('\r\n') !== -1) {
            const index = this.buffer.indexOf('\r\n');
            const command = this.buffer.slice(0, index);

            // 解析命令,这里只是一个简化示例
            console.log(`Received command: ${command}`);

            // 移除已解析的部分
            this.buffer = this.buffer.slice(index + 2);
        }

        // 如果还有未解析的数据,则继续解析
        if (this.buffer.length > 0) {
            process.nextTick(() => this.startParsing());
        } else {
            this.parsing = false;
        }
    }
}

// 创建TCP客户端连接至Redis服务器
const client = new net.Socket();
client.connect(6379, '127.0.0.1', () => {
    console.log('Connected to Redis server.');
});

const parser = new RedisParser();

client.on('data', (data) => {
    parser.appendData(data);
});

client.on('close', () => {
    console.log('Connection closed');
});

这段代码定义了一个简单的Redis协议解析器RedisParser,它通过检查\r\n来识别完整的命令,并在每次接收到新数据时尝试解析这些命令。如果命令不完整(即没有接收到\r\n结束符),则会保留剩余的数据以供后续解析。

总结

上述代码提供了一个基本框架,用于构建更复杂的Redis协议解析逻辑。实际应用中可能需要考虑更多边界条件和错误处理机制。希望这能为在Windows环境中使用Node.js处理Redis提供一些有用的指导。

回到顶部