2014-09-30 17 views
6

Có ai biết giải pháp tốt để mở rộng ứng dụng dựa trên node.js - socket.io lên trên nhiều lõi không? Tôi hiện đang thử nghiệm giải pháp được trình bày trong tài liệu socket.io, để sử dụng socket.io qua nhiều nút, nhưng không thành công cụ thể.Quy mô node.js [email protected]*.* với cụm và socket.io-redis trên Heroku

Tôi đã tạo một sân chơi cho điều này trên github: https://github.com/liviuignat/socket.io-clusters là bản sao sửa đổi của ứng dụng trò chuyện từ trang web socket.io. Nó sử dụng express, cluster, [email protected]socket.io-redis.

Hiện cũng có một triển khai sử dụng sticky-session trong chi nhánh feature/sticky có vẻ hoạt động tốt hơn.

Cuối cùng, ứng dụng cần được xuất bản lên Heroku, được chia tỷ lệ trên nhiều dynos.

Ban đầu tôi tryied làm một cái gì đó như thế này - để khởi động server chỉ dành cho các nút cluster, nhưng tôi luôn luôn nhận được lỗi: thất bại: Kết nối bị đóng trước khi nhận một phản ứng bắt tay

if (cluster.isMaster) {  
    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 

    cluster.on('exit', function(worker, code, signal) { 
    console.log('worker ' + worker.process.pid + ' died'); 
    }); 
} else { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
    }) 
    .setupApp() 
    .setupRoutes() 
    .start(); 
} 

Sau đó, tôi đã cố gắng khởi động máy chủ cũng cho các nút điều khiển:

if (cluster.isMaster) { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
    }) 
    .setupApp() 
    .setupRoutes() 
    .start(); 

    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 

    cluster.on('exit', function(worker, code, signal) { 
    console.log('worker ' + worker.process.pid + ' died'); 
    }); 
} else { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
    }) 
    .setupApp() 
    .setupRoutes() 
    .start(); 
} 

tôi cũng đã thử nó sử dụng cả hai sticky-sessionsocket.io-redis tại các chi nhánh feature/sticky, mà dường như thực hiện thành công, nhưng vẫn không có vẻ là một giải pháp tốt:

if (cluster.isMaster) { 
    sticky(function() { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
     }) 
     .setupApp() 
     .setupRoutes(); 
    return server.http; 
    }).listen(3000, function() { 
    console.log('server started on 3000 port'); 
    }); 

    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 

    cluster.on('exit', function(worker, code, signal) { 
    console.log('worker ' + worker.process.pid + ' died'); 
    }); 
} else { 
    sticky(function() { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
     }) 
     .setupApp() 
     .setupRoutes(); 
    return server.http; 
    }).listen(3000, function() { 
    console.log('server started on 3000 port'); 
    }); 
} 

Tôi sẽ làm nhiều thử nghiệm hơn trong những ngày tiếp theo, nhưng sẽ giúp ích nhiều nếu có ai đưa ra một số ý tưởng.

Cảm ơn,

Trả lời

2

Có thể bạn đang tìm kiếm socket.io-redis. http://socket.io/blog/introducing-socket-io-1-0/ (cuộn đến phần 'Khả năng mở rộng')

Dưới đây là một ví dụ ngắn về cách tạo các giàn giáo với socket.io + nhanh:

var cluster = require('cluster'); 

var express = require('express') 
    , app = express() 
    , server = require('http').createServer(app); 

var 
    io = require('socket.io').listen(server) 
    var redis = require('socket.io-redis'); 
    io.adapter(redis({ host: 'localhost', port: 6379 })); 



var workers = process.env.WORKERS || require('os').cpus().length; 

/** 
* Start cluster. 
*/ 

if (cluster.isMaster) { 

    /** 
    * Fork process. 
    */ 

    console.log('start cluster with %s workers', workers-1); 
    workers--; 
    for (var i = 0; i < workers; ++i) { 
    var worker = cluster.fork(); 
    console.log('worker %s started.', worker.process.pid); 
    } 

    /** 
    * Restart process. 
    */ 

    cluster.on('death', function(worker) { 
    console.log('worker %s died. restart...', worker.process.pid); 
    cluster.fork(); 
    }); 


} else { 
    server.listen(process.env.PORT || 9010); 
} 

Redis đã pub/sub và tất cả các nút socket.io cần đăng ký redis để nhận tất cả tin nhắn từ một kênh. Bằng cách này, một quy trình có thể truyền phát thông điệp tới một kênh (xuất bản) và tất cả các quy trình khác nhận được các thông báo với độ trễ tối thiểu để phát chúng tới các khách hàng được kết nối của họ (đăng ký). Bạn thậm chí có thể mở rộng điều này với các phiên dựa trên redis.

Mô-đun cụm mà bạn đang đề cập đến là một chút gây hiểu nhầm theo ý kiến ​​của tôi. Nó giúp tạo ra các quy trình con phụ như xa như tôi hiểu khái niệm, nhưng không 'đồng bộ hóa' các kênh trên nhiều nút. Nếu khách hàng của bạn không cần phải giao tiếp với người khác thì điều đó là tốt. Nếu bạn muốn phát tin nhắn tới tất cả các máy khách được kết nối trên tất cả các nút, bạn cần mô-đun redis.

+0

Hi Steffen, tôi đang sử dụng socket.io-redis mà không thành công. –

+0

Tôi đã thêm một ví dụ được lấy từ một dự án mà tôi đã làm việc trong một thời gian trở lại. Vào thời điểm đó mọi thứ hơi khác một chút, nhưng tôi đã cập nhật nó để sử dụng socket.io-redis cho socket.io> = 1.0 – Steffen

+0

Cảm ơn, có vẻ như tôi đã quản lý nó để làm việc với một máy chủ đơn giản (xem: https://github.com/liviuignat/chat-example-cluster/blob/master/index.js).Tôi sẽ chơi với nó nhiều hơn một chút, bởi vì trong dự án chính của tôi nó vẫn có vấn đề. –

Các vấn đề liên quan