[英]What is the best technology for a chat/shoutbox system? Plain JS, JQuery, Websockets, or other?
我有一個舊的網站正在運行,它也有一個聊天系統,該系統通常工作正常。 但是最近,我再次選擇了該項目並開始進行改進,用戶群不斷增加。 (在VPS上運行)
現在,我擁有的這個shoutbox(在http://businessgame.be/shoutbox上運行)最近遇到了問題,當同時有30多個在線用戶時,它開始確實使整個站點變慢。
這個shoutbox系統是幾年前由老我(諷刺的是年輕的我)編寫的,他對老派的Plain Old JavaScript(POJS?)太多了,並且拒絕使用JQuery之類的框架。
我要做的是,如果有新消息,我每3秒用AJAX輪詢一次,如果是,則加載所有這些消息(將它們作為XML文件處理,然后由JS代碼解析為HTML塊,添加到shoutbox中內容。
簡化的腳本是這樣的:
AJAX功能
function createRequestObject() {
var xmlhttp;
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// Create the object
return xmlhttp;
}
function getXMLObject(XMLUrl, onComplete, onFail) {
var XMLhttp = createRequestObject();
// Check to see if the latest shout time has been initialized
if(typeof getXMLObject.counter == "undefined") {
getXMLObject.counter = 0;
}
getXMLObject.counter++;
XMLhttp.onreadystatechange = function() {
if(XMLhttp.readyState == 4) {
if(XMLhttp.status == 200) {
if(onComplete) {
onComplete(XMLhttp.responseXML);
}
} else {
if(onFail) {
onFail();
}
}
}
};
XMLhttp.open("GET", XMLUrl, true);
XMLhttp.send();
setTimeout(function() {
if(typeof XMLhttp != "undefined" && XMLhttp.readyState != 4) {
XMLhttp.abort();
if(onFail) {
onFail();
}
}
}, 5000);
}
聊天功能
function initShoutBox() {
// Check for new shouts every 2 seconds
shoutBoxInterval = setInterval("shoutBoxUpdate()", 3000);
}
function shoutBoxUpdate() {
// Get the XML document
getXMLObject("/ajax/shoutbox/shoutbox.xml?time=" + shoutBoxAppend.lastShoutTime, shoutBoxAppend);
}
function shoutBoxAppend(xmlData) {
process all the XML and add it to the content, also remember the timestamp of the newest shout
}
真實的腳本更加復雜,頁面模糊時加載速度更慢,並且跟蹤AJAX調用可避免同時進行兩次調用,發出喊叫聲,加載設置等。所有這些在這里都不重要。
對於那些感興趣的人,請在此處查看完整代碼: http : //businessgame.be/javascripts/xml.js http://businessgame.be/javascripts/shout.js
包含喊話數據的XML文件示例http://businessgame.be/ajax/shoutbox/shoutbox.xml?time=0
我這樣做是為了每30秒獲取一次在線用戶列表,並每2分鍾檢查一次新的私人消息。
我的主要問題是,由於這個老式的JS減慢了我的網站的速度,將代碼更改為JQuery會提高性能並解決此問題嗎? 還是我應該選擇一起使用其他技術,例如nodeJS,websockets或其他? 還是我忽略了這個舊代碼中的一個基本錯誤?
重寫整個聊天和私人消息系統(使用相同的后端)需要大量的工作,因此我想從一開始就正確地進行此操作,而不是在JQuery中重寫整個過程,只是為了弄清楚它不能解決問題手頭的問題。
聊天框中同時有30個人在線並不是一個例外,因此它應該是一個固定的系統。
PS:后端是PHP MySQL
我有偏見,因為我喜歡Ruby,而且我更喜歡使用Plain JS而不是JQuery和其他框架。
我相信您使用AJAX會浪費大量資源,因此應該轉到用Websocket的用例中。
30個用戶並不多...使用websockets時,我假設單個服務器進程應該能夠每秒提供數千個同時更新。
這樣做的主要原因是websocket是持久性的(每個請求都不會進行身份驗證),並且廣播到多個連接將使用與單個AJAX更新相同的數據庫查詢量。
在您的情況下,不是每個人都每次都閱讀整個XML,而是一個POST事件只會廣播最新的(發布的)喊叫聲(而不是整個XML),並將其存儲在XML中以進行持久存儲(供新訪客使用)。
另外,您不需要所有身份驗證和最終以“否,沒有任何待處理的更新”回答的請求。
從AJAX遷移到Websocket時,最小化數據庫請求(XML讀取)應該被證明是巨大的好處。
另一個好處是,有足夠多的同時用戶使AJAX輪詢的行為與DoS攻擊相同。
現在,每秒30個用戶== 10個請求。 這雖然不多,但是如果每個請求要花費100毫秒以上的時間,則可能會很沉重-這意味着服務器響應的請求少於接收的請求。
Plezi Ruby Websocket Framework的主頁上有一個簡短的喊話框示例(我是Plezi的作者,我對此有偏見):
# finish with `exit` if running within `irb`
require 'plezi'
class ChatServer
def index
render :client
end
def on_open
return close unless params[:id] # authentication demo
broadcast :print,
"#{params[:id]} joind the chat."
print "Welcome, #{params[:id]}!"
end
def on_close
broadcast :print,
"#{params[:id]} left the chat."
end
def on_message data
self.class.broadcast :print,
"#{params[:id]}: #{data}"
end
protected
def print data
write ::ERB::Util.html_escape(data)
end
end
path_to_client = File.expand_path( File.dirname(__FILE__) )
host templates: path_to_client
route '/', ChatServer
POJS客戶端看起來像這樣(DOM update
和從數據訪問( $('#text')[0].value
)使用JQuery):
ws = NaN
handle = ''
function onsubmit(e) {
e.preventDefault();
if($('#text')[0].value == '') {return false}
if(ws && ws.readyState == 1) {
ws.send($('#text')[0].value);
$('#text')[0].value = '';
} else {
handle = $('#text')[0].value
var url = (window.location.protocol.match(/https/) ? 'wss' : 'ws') +
'://' + window.document.location.host +
'/' + $('#text')[0].value
ws = new WebSocket(url)
ws.onopen = function(e) {
output("<b>Connected :-)</b>");
$('#text')[0].value = '';
$('#text')[0].placeholder = 'your message';
}
ws.onclose = function(e) {
output("<b>Disonnected :-/</b>")
$('#text')[0].value = '';
$('#text')[0].placeholder = 'nickname';
$('#text')[0].value = handle
}
ws.onmessage = function(e) {
output(e.data);
}
}
return false;
}
function output(data) {
$('#output').append("<li>" + data + "</li>")
$('#output').animate({ scrollTop:
$('#output')[0].scrollHeight }, "slow");
}
如果要添加更多事件或數據,可以考慮使用Plezi的自動分派功能 ,該功能還為您提供了易於使用的輕量級 Javascript客戶端,具有AJAJ(AJAX + JSON)后備功能。
...
但是,根據服務器的體系結構以及是否介意使用更重的框架,可以使用更常見的socket.io(盡管它以AJAX開頭,並且在預熱期后才移至websockets)。
編輯
從XML更改為JSON仍需要解析。 問題實際上是XML與JSON的解析速度。
根據以下SO問答, JSON在客戶端javascript上將更快 : 解析JSON比解析XML更快
JSON在PHP的服務器端似乎也受到青睞(可能是基於意見的,而不是經過測試的): PHP:JSON或XML解析器的速度更快嗎?
但是...我真的認為您的瓶頸不是JSON或XML。 我相信瓶頸與使用AJAX時服務器訪問,分析(和解析)數據以及查看數據的次數有關 。
EDIT2 (由於對PHP與node.js進行評論)
您可以使用Ratchet添加PHP websocket層...盡管PHP不是為長時間運行的進程而設計的,所以我會考慮添加websocket專用堆棧(使用本地代理將websocket連接路由到其他應用程序)。
我喜歡Ruby,因為它使您可以快速輕松地編寫解決方案。 Node.js也通常用作專用的websocket堆棧。
我個人會避免使用socket.io,因為它抽象了連接方法(AJAX與Websockets),並且始終以AJAX開頭,然后才“預熱”到“升級”(websockets)...此外,socket.io在以下情況下使用長輪詢沒有使用websockets,我這很糟糕。 我寧願顯示一條消息,告訴客戶端升級他們的瀏覽器。
Jonny Whatshisface指出,使用node.js解決方案,他達到了約5萬個並發用戶的限制(這可能與本地代理的連接限制有關)。 他說,使用C解決方案時,並發用戶數不超過200K不會有問題。
顯然,這還取決於每秒的更新次數,以及是否要廣播數據還是將其發送到特定的客戶端...如果您要為200K用戶每用戶每秒發送2個更新,則為40萬個更新。 但是,每2秒僅更新一次所有用戶,即每秒10萬次更新。 因此,試圖找出最大負載可能會令人頭疼。
就個人而言,我無法在應用程序上達到這些數字,因此我從未親手發現Plezi的極限……盡管在測試期間,我每秒發送數十萬個更新沒有問題(但我確實做到了)由於可用端口和我的本地計算機上的打開文件句柄限制而受到連接限制)。
這絕對表明使用websocket可以帶來多大的改進(尤其是因為您聲明要注意30個並發用戶的速度下降)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.