1. 程式人生 > >小白的踩坑記錄——socket.io-解決多程序

小白的踩坑記錄——socket.io-解決多程序

需求:

利用socket.io實現多程序長連線,實時獲取kafka資料

問題重現:

啟動單個程序的時候,socket.io可以正常的獲取到長連線進行實時資料,但是利用多個執行緒的時候就會報長連線404,並且下圖已經清晰的顯示了socket.io握手的錯誤:

這裡寫圖片描述

有圖可見,ws連線建立之前多出了三個http的請求,而且是每三個http請求之後就會有ws請求,這就說明,socket.io沒有直接建立ws連線方式,而是先通過http請求訪問服務端的相關輪訓配置資訊以及sid,sid唯一標識連線,可理解為socketId。

為什麼會出現這種情況呢?

當我們開啟一個程序的時候,就不會出現這種404的報錯,但是當我們啟動了多個執行緒的時候就會出現這種問題。當前例項是用pm2啟動的多執行緒,利用了pm2中的某種演算法,但是這種演算法socket.io並不支援,因此在socket.io客戶端連線建立階段傳送的多個http請求,會被pm2定位到不同的worker程序中,總而言之,客戶端多次請求的服務端程序不是同一個程序才導致的ws連線無法成功建立。

那怎麼解決呢?

那麼如何才能解決呢?最簡單的方案就是確保客戶端的每次請求都可以定位到同一個服務程序即可。

官方解決方法:利用nginx反向代理+iphash
官方地址: https://socket.io/docs/using-multiple-nodes/
本例項利用官網這種方式解決的,具體如下:

第一種方法:

nginx.conf

upstream io_nodes {
  ip_hash;
  server 127.0.0.1:3131;
  server 127.0.0.1:3132;
  server 127.0.0.1:3133;
}
server {
    listen 3000;
    server_name io.yourhost.com;
    location / {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
      proxy_http_version 1.1;
      proxy_pass http://io_nodes;
    }
}

app.js

import socketList from './src/router/socket';
const app = new Koa();
// socket - socket.io
const server = require('http').createServer(app.callback());
server.setMaxListeners(30);
const port = 3131 + parseIn(process.env.NODE_APP_INSTANCE);
socketList.initialize(port);

app的詳細配置就不展示了...

export default server;
// pm2
server.listen(port, () => console.log(`Server started on port ${port}`));

vue重要程式碼

import VueSocketio from 'vue-socket.io';
Vue.use(VueSocketio, url);

第二種方法:

利用sticky-session外掛

app.js

import socketList from './src/router/socket';
import sticky from 'sticky-session';
const app = new Koa();
// socket - socket.io
const server = require('http').createServer(app.callback());
server.setMaxListeners(30);
socketList.initialize(server);

app的詳細配置就不展示了...

export default server;
// sticky
const options = {
  workers: 3
};
if (!sticky.listen(server, port, options)) {
  // Master code
  server.once('listening', () => {
    console.log('server started on 3000 port');
  });
} else {
  console.log('sticky listen');
  // Worker code
}

我是初次接觸socket.io的小白,對socket.io的理解還不到位,對於文章當中的專業說法還不到位,如果有建議,我會非常開心的接受並修改的,也希望和大家分享我自己的淺見。