Nodejs异构系统通信的解决方案

Nodejs异构系统通信的解决方案

是这样的:我想用Node做Web Server处理高并发http请求,然后将前端获取的一些数据传递给本地的Ruby进程做计算分析,最后Ruby将处理结果返回给Node并响应给浏览器。

可问题是以前没做过异构系统之间的通讯,不清楚有什么好一点的解决方案。

目前我有这几种想法,不知哪种方案可行(或者以下是否有可行的…):

  • 通过Node的child_process模块跑Ruby脚本,每请求一次执行一次。
  • 同时开启Node进程和Ruby进程,双方直接通过Socket通信
  • 使用Redis做共享空间

不想使用现成的库,因为毕竟之前对这方面不了解,也想借此机会学习学习。

麻烦各位,提供个具体思路,谢谢。


12 回复

Node.js 异构系统通信的解决方案

在您的需求中,您希望使用 Node.js 处理高并发 HTTP 请求,并将前端获取的数据传递给本地的 Ruby 进程进行计算分析。最终,Ruby 将处理结果返回给 Node 并响应给浏览器。以下是一些可行的解决方案,以及具体的实现思路和示例代码。

方案一:通过 child_process 模块运行 Ruby 脚本

思路

  • 使用 Node.js 的 child_process 模块来创建一个子进程,运行 Ruby 脚本。
  • 每次接收到 HTTP 请求时,Node.js 将数据传递给子进程,等待 Ruby 脚本处理完毕后返回结果。

示例代码

const http = require('http');
const { spawn } = require('child_process');

// 创建 HTTP 服务器
const server = http.createServer(async (req, res) => {
    if (req.method === 'POST' && req.url === '/analyze') {
        let body = [];
        req.on('data', chunk => {
            body.push(chunk);
        }).on('end', async () => {
            const data = Buffer.concat(body).toString();
            
            // 启动 Ruby 子进程
            const rubyProcess = spawn('ruby', ['analyze.rb']);
            
            // 将数据发送给 Ruby 子进程
            rubyProcess.stdin.write(data);
            rubyProcess.stdin.end();

            // 接收 Ruby 子进程的输出
            let result = '';
            rubyProcess.stdout.on('data', chunk => {
                result += chunk.toString();
            });

            rubyProcess.on('close', code => {
                if (code !== 0) {
                    res.writeHead(500);
                    res.end('Ruby process exited with error');
                } else {
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(result);
                }
            });
        });
    } else {
        res.writeHead(404);
        res.end('Not Found');
    }
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Ruby 脚本 analyze.rb

#!/usr/bin/env ruby

input = gets
# 进行一些计算分析
output = input.reverse # 示例操作

puts output

方案二:使用 Socket 通信

思路

  • 开启 Node.js 和 Ruby 进程,并让它们通过 Socket 通信。
  • Node.js 作为客户端,向 Ruby 进程发送请求,接收处理结果。

示例代码

Node.js 服务端

const net = require('net');
const client = new net.Socket();

client.connect(1234, 'localhost', () => {
    const data = JSON.stringify({ key: 'value' });
    client.write(data);
});

client.on('data', (data) => {
    console.log('Received from Ruby:', data.toString());
    client.destroy(); // 关闭连接
});

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

Ruby 服务端

require 'socket'

server = TCPServer.open(1234)

loop do
    client = server.accept
    request = client.gets
    puts "Received from Node.js: #{request}"

    # 进行一些计算分析
    response = request.reverse # 示例操作

    client.puts response
    client.close
end

方案三:使用 Redis 作为共享存储

思路

  • 使用 Redis 作为共享存储,Node.js 和 Ruby 进程可以读写相同的数据。
  • Node.js 将数据写入 Redis,Ruby 进程读取并处理数据,处理完成后将结果写回 Redis。

示例代码

Node.js 服务端

const redis = require('redis');
const client = redis.createClient();

client.on('error', (err) => {
    console.error('Error connecting to Redis:', err);
});

const server = http.createServer(async (req, res) => {
    if (req.method === 'POST' && req.url === '/analyze') {
        let body = [];
        req.on('data', chunk => {
            body.push(chunk);
        }).on('end', async () => {
            const data = Buffer.concat(body).toString();
            
            // 将数据写入 Redis
            client.set('analyze_data', data);

            // 设置一个监听器,等待 Redis 中的结果
            client.get('analyze_result', (err, result) => {
                if (err) throw err;
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(result);
            });
        });
    } else {
        res.writeHead(404);
        res.end('Not Found');
    }
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Ruby 客户端

require 'redis'

redis = Redis.new

# 监听 Redis 中的数据
data = redis.get('analyze_data')
puts "Received from Node.js: #{data}"

# 进行一些计算分析
result = data.reverse # 示例操作

# 将结果写回 Redis
redis.set('analyze_result', result)

以上是三种可行的解决方案及其示例代码,您可以根据实际需求选择合适的方案。


got it! 已经折腾出可行方案了~ 尽管没人回答,还是谢谢各位看官~

-closed-

怎么个可行方案呢?

Apache的 Thrift 是否满足你呢?

这个貌似不错,不过不想借助framework,已经用原生代码解决了~仍然感谢

需要测试你ipc的吞吐量

IPC吞吐量,你指的是一次进程通信中交换的数据量吧?这个不算大

第一种肯定不行。load会很高。 后面两种还可行。

Socket是很通用的办法吧,实现起来也最简单

简单的实现就是用类似dnode的远程RPC调用 Ruby给node提供服务 或者Ruby直接提供http服务,通过http通信也可以 无非就是几个服务独立,node不做计算,计算都异步请求你的Ruby或者其他语言做的服务就行了

你好,我想问一下进程间通过管道传送数据是同步还是异步的啊,我是win10的

针对你的需求,可以采用多种方法来实现 Node.js 和 Ruby 进程之间的异构系统通信。这里我们主要探讨一下你提到的三种方案,并且提供一些具体的思路和代码示例。

方案1: 使用 Node.js 的 child_process 模块

这种方法比较简单,适合于一次性调用的情况。你可以通过 child_process 模块创建一个子进程运行 Ruby 脚本,并将需要的数据通过命令行参数传递过去,再接收返回的结果。

示例代码:

Node.js 端:

const { spawn } = require('child_process');
const child = spawn('ruby', ['calc.rb', 'data']);

child.stdout.on('data', (data) => {
    console.log(`Received result from Ruby script: ${data}`);
});

child.stderr.on('data', (data) => {
    console.error(`Error in Ruby script: ${data}`);
});

Ruby 脚本 (calc.rb):

puts "Got data: #{ARGV[0]}"
# Perform your computation here
puts "Computation Result"

这种方式适合于少量数据的传输和一次性调用的场景。

方案2: 通过 Socket 通信

如果需要频繁交互或长时间连接,可以考虑使用 Socket 通信。两边都需要监听各自的端口,并通过 Socket 发送数据。

示例代码:

Node.js 服务器端:

const net = require('net');

const server = net.createServer((socket) => {
    socket.write('Welcome to the Node server\n');
    socket.on('data', (data) => {
        console.log(`Data received from Ruby: ${data.toString()}`);
        // 处理数据...
        socket.write('Data processed successfully.');
    });
});

server.listen(3000, () => {
    console.log('Node server listening on port 3000');
});

Ruby 客户端:

require 'socket'

socket = TCPSocket.open("localhost", 3000)
socket.puts "Hello Node"
response = socket.read
puts "Response from Node: #{response}"
socket.close

方案3: 使用 Redis 做共享空间

如果希望两个服务解耦,并能更加灵活地进行数据交换,可以考虑使用 Redis 作为消息队列。Node.js 和 Ruby 都可以轻松地与 Redis 交互,从而达到异步通信的效果。

示例代码:

Node.js 端:

const redis = require('redis');
const client = redis.createClient();

client.publish('channel', 'some data');

Ruby 端:

require 'redis'
redis = Redis.new
puts "Listening..."
redis.subscribe('channel') do |on|
  on.message do |channel, message|
    puts "Received data: #{message}"
  end
end

以上就是对你问题的解答,选择哪种方式取决于你的具体应用场景以及性能需求。希望这些信息对你有所帮助!

回到顶部