簡體   English   中英

我可以擴展nodejs應用程序的最佳方法是什么?

[英]What is the best way I can scale my nodejs app?

基礎

現在我的一些朋友和我正在嘗試開發一個在nodejs中制作的瀏覽器游戲。 這是一個多人自上而下的射擊游戲,客戶端和服務器端代碼中的大多數都是javascript。 我們有一個很好的總體方向,我們想進去,我們在開發游戲方面有很多樂趣。 制作這款游戲​​時我們的目標之一就是讓它盡可能地作弊。 做到這一點,我們所有的游戲邏輯都在服務器端處理。 客戶端僅通過Web套接字將其輸入發送到服務器,並且服務器使用游戲中發生的事情更新客戶端(也是Web套接字)。 這是我們問題的開始。

所有的服務器端數學都變得非常沉重,我們發現我們需要以某種方式擴展以處理超過10個玩家(我們希望能夠容納更多)。 起初我們認為我們可以根據需要垂直擴展,但由於nodejs是單線程的,因此只能利用一個核心。 這意味着獲得更強大的服務器無助於解決這個問題。 我們唯一的解決方案是橫向擴展。

我們為什么要問這里

我們還沒有找到任何關於如何擴展nodejs游戲的好例子。 我們的用例非常特別,雖然我們已盡力做到這一點,但我們真的可以從外部意見和建議中受益

細節

我們已經對如何解決這個問題投入了大量的思考。 我們已經研究了一個多星期了。 這是我們到目前為止所做的事情:

四種類型的服務器

我們將任務分成4種不同的“類型”服務器。 每個人都將完成一項特定的任務。

代理服務器

代理服務器將位於整個堆棧的前端,並且是可從Internet直接訪問的唯一服務器(可能有更多這些服務器)。 它會有haproxy,它會將所有連接路由到Web服務器。 我們之所以選擇haproxy,是因為它具有豐富的功能集,可靠性和幾乎無與倫比的速度。

Web服務器

Web服務器將接收Web請求,並為所有Web頁面提供服務。 他們還將處理游說創建/管理和游戲創建/管理。 要做到這一點,他們會告訴游戲服務器它有什么游說,用戶在那個大廳,以及他們將要玩的游戲的信息。 然后,Web服務器將更新游戲服務器關於用戶輸入,並且游戲服務器將更新游戲中發生的事件的Web服務器(誰將更新客戶端)。 Web服務器將使用TCP套接字與游戲服務器就任何類型的管理進行通信,並且在與游戲更新進行通信時將使用UDP套接字。 這將全部用nodejs完成。

游戲服務器

游戲服務器將處理有關游戲的所有游戲數學和變量更新。 游戲服務器還與數據庫服務器通信,以記錄游戲中玩家的酷炫統計數據。 這將通過nodejs完成。

數據庫服務器

db服務器將托管數據庫。 事實證明這部分是最簡單的,因為我們找到了rethinkdb ,這是有史以來最酷的數據庫。 這很容易擴展,奇怪的是,它是擴展我們的應用程序最簡單的部分。

其他一些細節

如果你無法解決整個問題,那么看看這個 ,這是我們認為我們將如何擴展的半准確圖表。

如果你只是好奇,或者認為看看我們的游戲可能會有所幫助,那么它目前在這里處於未規模狀態。

我們不想要的一些事情

  • 我們不想使用nodejs的集群模塊。 它不穩定( 這里說),它不能擴展到其他服務器,只能擴展到其他處理器。 我們想要實現橫向擴展。

我們的問題,總結一下

我們希望我們朝着正確的方向前進,我們已完成了我們的功課,但我們不確定。 我們當然可以采取一些技巧,以正確的方式做到這一點。

謝謝

我意識到這是一個很長的問題,做出深思熟慮的答案並不容易,但我真的很感激。

謝謝!!

跟隨我對你的案子的自發想法:

多核用法

node.js也可以使用多個核心進行擴展。 如何,你可以在這里閱讀( 或者只是想一想:你有一個線程/進程在一個核心上運行,你需要使用多個核心?多個線程或多個進程。將工作從主線程推送到其他線程或過程,你就完成了 )。

我個人會說開發一個不使用多核的應用程序是幼稚的。 如果您使用了一些后台進程,那么,但是如果您現在只在node.js主事件循環中工作,那么您應該投入一些時間來使應用程序可以在核心上進行擴展。

順便說一句,實現類似IPC的東西並不容易。 你可以這樣做,但是如果你的情況很復雜,那么你可以選擇集群模塊。 這顯然不是你最喜歡的,但僅僅因為某些東西被稱為“實驗性”,它並不意味着它是無用的。 試一試,也許你甚至可以修復模塊中的一些錯誤。 最有可能更好地使用一些廣泛使用的軟件來解決復雜問題,而不是發明一個新的輪子。

您還應該(如果您還沒有)考慮(明智地)使用nextTick功能。 這允許主事件循環暫停一些CPU密集型任務並同時執行其他工作。 你可以在這里閱讀它。

關於計算的一般想法

你一定要仔細看看你的游戲引擎算法。 您已經注意到這是您現在的瓶頸,實際上計算是大多數游戲中最重要的部分。 縮放確實以一種方式解決了這個問題,但縮放引入了其他問題。 此外,你不能把“縮放”作為問題解決者扔在一切上,並期望每個問題都消失。

您最好的選擇是讓您的游戲代碼優雅而快速。 想想如何有效地解決問題。 如果你無法有效地解決Javascript中的問題,但問題很容易被提取,為什么不寫一點C組件呢? 這也算作一個單獨的進程,這減少了主node.js事件循環的負載。

代理?

就個人而言,我現在還沒有看到代理級別的優勢。 你似乎沒有期望大量的用戶,因此你不需要解決像CDN解決的問題或其他任何問題......可以考慮它,但我現在不會在那里投入太多時間。

從技術上講,您的網絡服務器軟件很有可能提供代理功能。 因此可以將它放在紙上,但我現在不打算使用專用硬件。

結語

其余對我來說似乎或多或少。

游戲稍晚,但請看一下: http//goldfirestudios.com/blog/136/Horizo​​ntally-Scaling-Node.js-and-WebSockets-with-Redis

你沒有提到任何與內存管理有關的事情。 如您所知, nodejs不與其他進程共享其內存,因此如果要進行擴展,則必須使用內存數據庫。 RedisMemcache等)。 您需要在每個節點上設置發布者和訂閱者事件以接受來自redis傳入請求。 這樣,您可以擴展x nilo數量的服務器(在您的HAProxy前面)並利用從redis傳輸的數據。

還有這個node插件: http//blog.varunajayasiri.com/shared-memory-with-nodejs這可以讓你在進程之間共享內存,但只能在Linux下運行。 如果您不想一直在本地進程中發送數據或者不想處理nodes ipc api,這將有所幫助。

您還可以在node內為新的v8隔離分叉子進程,以幫助執行昂貴的cpu綁定任務。 例如,玩家可以殺死怪物並在我的動作RPG游戲中獲得相當多的戰利品。 我有一個名為LootGenerater的子進程,基本上每當玩家殺死怪物時,它會通過默認的IPC api .send將游戲idmob_iduser_id發送到進程。 一旦子進程收到它,它就會遍歷大型戰利品表並管理這些項目(存儲到redis或其他任何東西)並將其管道回來。

這有助於大大釋放事件循環,只有一個我能想到的想法可以幫助您擴展。 但最重要的是,您將需要使用內存數據庫系統,並確保您的游戲代碼體系結構是圍繞您使用的任何數據庫系統設計的。 不要犯錯我現在不得不重寫一切:)

希望這可以幫助!

注意:如果您決定使用Memcache,則需要使用另一個發布/訂閱系統。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM