精华 node开发游戏服务器遇到的性能问题
发布于 9 年前 作者 wf744 39247 次浏览 最后一次编辑是 8 年前 来自 问答

问题描述: 使用node开发了一个游戏服务器,为了尽可能提高服务器的性能,服务器采用多进程的架构,前面处理玩家socket连接的是多个node进程,使用 child_process 模块,服务器启动时fork出来,而处理玩家游戏逻辑的是单独一个node进程(因为玩家之间需要交互,而且玩家都是有状态的,所以无法分成多个进程)这个作为主进程;主进程与子进程之间使用使用child_process模块内建的通讯方式进行通讯;

现在服务器性能出现瓶颈,服务器同时在线去到1500人左右,CPU占用率在40+左右,目标是3000人同时在线;通过CPU Profile分析,唯一无状态的可分离出来而且比较占用CPU的,就是玩家数据读数据库和保存数据库的时候,数据库使用的是mongodb,所以现在想把读写数据库的逻辑独立到一个新的进程中;但是问题来了,由于玩家的数据是一个大的Json结构,最大的大小能达到600+K,而node的child_process模块的内建进程间通讯是通过JSON.stringify和JSON.parse来转换成字符串来进行通讯的,所

以独立出来以后,性能的问题,又指向了child_process模块中的进程之间的通讯的函数,通过实验: JSON.strinify 一个600K+玩家的数据平均需要35ms,JSON.parse 一个600K+玩家的数据平均需要20ms,而且这两个函数都是同步的,会造成阻塞;这也就是说主进程无法把一些包含大数据处理的任务分派到其他进程去做,这也直接限制了主进程的承载量和在线玩家人数;

尝试找过一写解决的方案: 1.异步版的 JSON.stringify 和 JSON.parse ,可惜没有结果,正如这里的讨论:https://github.com/joyent/node/issues/7543 2.为node加入多线程?node有几个多线程的库,但是貌似都不支持共享进程内存,无法操作主进程的内存,只能通过字符串进行交换数据,也就是说轮回到以上进程间的通讯问题;

这个问题一直比较困扰,还没有找到好的解决方法,希望大牛来赐教

95 回复

总感觉是用其他语言的思维来写node

读写数据库消耗大,可以缓存一下 自豪地采用 CNodeJS ionic

总感觉是用其他语言的思维来写 node。

没考虑横向扩展到多服务器模式?

把服务分一分。例如,存储丢给专门的服务处理。逻辑服务器只处理游戏逻辑

每次都需要朝数据库读写这么大的数据么?我觉得你首先要做的是拆分数据,每次读写这么大的数据消耗当然大。 你数据库更新的频率是多少?每个人600k,1500个人要900M,3000人要1.8G,还要再乘以8换算成bits,感觉好大。 能贴下你们机器的参数么?感觉这个机器好牛逼的。

参考下传奇源代码吧,传奇也是独立进程读写数据库的,进程间使用socket通信,自定义通信协议,不要使用文本格式,数据更新频率和更新范围优化下,如果还不行的话,那就是计算瓶颈,你得换语言,换机器。

NODE优势是处理IO,你用他来每次处理180k+的JSON数据转换,JSON转化是非常消耗CPU的,所以应该适当的拆分,重构,NODE尽量少处理逻辑

@captainblue2013 其实你用什么语言都好,到最后为了提高这个承载,思想都是趋于一致的

@Acceptedlc 缓存? 1.如果缓存在主进程,那么就会占用本进程内存,而且玩家数据比较大,这样会加大GC的压力,同时直接拉低了同时在线人数(node的heap最大去到1.7G,容不了多少个玩家的数据) 2.如果计划缓存在其他进程,那么就又会回到我上面的的问题(进程间的通讯瓶颈)

@leapon 横向扩展我们也是做了的,不过是针对没有状态的服务器,比如处理玩家长连接的连接服务器,我们就可以任意扩展他的数量 游戏逻辑服务器中的玩家,是有交互性的,(比如一个玩家要挑战另外一个玩家,却发现这个玩家不在这个进程里,这又会涉及到进程间通讯,也会回到我上面的那个问题中去,而且这样实时性低,对玩家体验不好),而且是有状态的,不像web服务器那么简单,可以很轻松就进行横向扩展;

@joesonw 现在就这么做啊,但是由于现在需要传输很大的数据, node进程之间的通讯,是使用了json parse 和 stringify来进行序列化成字符串来传输的,但是这两个函数是同步的,所以就出现了瓶颈嘛

@wf744 丢redis,或者rabbitmq之类的。另外试试用bson。

总感觉是用其他语言的思维来写 node。 爲啥要JSON.stringify 和 JSON.parse

@jiangzhuo 这个是node的 child_process 模块底层使用了 JSON.stringify 和 JSON.parse来进行序列化之后再通过管道进行传输数据, 我们也没办法

@joesonw 关键是在丢给redis或者其他任何第三方进程前,都要先进行序列化操作吧(序列化成字符串,或者是 buffer, 网络上只能传输二进制数据), 所以现在就是瓶颈出现在这个序列化的操作上

@wf744 子進程間爲什麼要傳遞這麼多的數據

玩家存檔怎麼這麼大

就算真有這麼大不能增量修改嘛,爲啥要全存

@coordcn 拆分数据比较难,因为本来玩家就是一个整体的对象,你把他的数据进行了拆分,那么肯定不便于后续的开发; 数据库更新的频率是:玩家上线就会读取mongodb 加载玩家的数据;玩家下线或者是意外断线就把玩家的数据写到mongodb中去; 600K是最极端的情况,就是当一个玩家拥有游戏中的所有宠物和装备的情况,但是我们来计算上限肯定就是按照最差的情况去计算; 机器配置不高啊,就是8核 8G内存 非SSD

nodejs + mongodb, 那么最自然的就是用json来进行数据存储了,所以这个改变的可能性不高

“参考下传奇源代码吧,传奇也是独立进程读写数据库的” 现在我们也是想把读写数据库独立出来啊,问题就出现在玩家数据很大,序列化操作是同步的(childprocess模块底层代码决定的),瓶颈变成了进程间的通讯

@wf744

那我是不是可以理解成最极端的情况下,你们的玩家600K数据会在进程间传来传去?

玩家数据肯定可以拆分的,你们数据库设计有问题,这个必须做拆分,装备,宠物全部都整到一起,还要在进程之间传来传去,这想想也醉了。难道我增加了一件装备,就要将整个人物数据都传一遍?这个也太奢侈了。

在数据设计上下点功夫吧,拆分是唯一的办法,不然就换语言,3000个人内存都不够。

@coordcn

“那我是不是可以理解成最极端的情况下,你们的玩家600K数据会在进程间传来传去?” 可以这么理解,整个流程是: 玩家上线就会读取mongodb 加载玩家的数据;玩家下线或者是意外断线就把玩家的数据写到mongodb中去;所以在这个过程中,玩家做的任何操作都是操作内存,如果进行拆分,那么玩家登陆要加载多次数据库,同时玩家下线,保存也要保存多次数据库,这样的话,当游戏逻辑服务器把玩家数据丢给数据库代理进程的时候,虽然每次传输的数据是小了,但是频率高了(因为被拆分了,需要传输多次),而且总的传输数据量是没有变的

@wf744

非要一起传的话,用socket都没有用,这么大的数据,即便用自己的协议,解码也消耗蛮多的。

我个人建议,可以试着拆分下,看效果,然后取得平衡。玩家肯定有相同的数据,能压缩的压缩,能合并的合并,目标3000,搞到2000,尽力了就可以了。每种数据更新频率不同,这个要好好利用,原来那种一股脑儿更新的做法会把一些死数据也更新了,如果能根据实际更新数据来做更新,肯定比原理的方法节省。

v8已经很快,但必须要承认,这是跟其他脚本语言相比的快,当然还有更快的luajit。再快的脚本跟原生的比都要差一个数量级。node的优势在IO吞吐,计算密集型的,如果设计不好,很容易出瓶颈的。

不适用childprocess,使用pm2自带cluster模式,进程间使用rpc通讯

进程间通信直接传obj- -。。为什么还要json一下。。

@MiguelValentine

请参考《深入浅出Node》或者node源码,你传输的是obj,但是底层仍然会自动json来进行传输的

@o6875461

rpc通讯 原理还是管道或者是socket吧,还是逃不过这个问题

@coordcn

兄弟,你说的是有道理,只能尽量试试拆分,确实想不到更好的办法了; 确实是有很多是死数据,每次玩家进行游戏,都是更新那么一部分的数据,大部分数据其实都是不更新的

你们开始架构设计有问题,架构师的修行还是不够啊

@wf744 rpc socket应该就不用json.parse和json.stringify操作了,不满足你的要求?

@o6875461 是不是用json.parse和json.stringify ,这个还真需要确认一下

@28509993

你有什么更好架构的想法,不妨说来听听哦

说点自己的经验吧,我们也是TCP服务器,交互内存管理使用了redis(纯缓存),例如排行榜这种东西,落地使用的是mysql(连接池),网络包使用protobufjs正/反序列化(比json好不少,对于大数字压缩,量和效率都有优化,毕竟字节流),游戏是通服大区的,没有使用cluster,服务器间交互这块做了一个中央TCP服务器,自己封的RPC,用于各服务器间的数据交换以及全服的一些定时器刷新,例如:竞技场一周重置一次啊,以及做下通服数据redis到mysql的定时落地。 游戏服务器玩家内存这块,自己写的缓存管理器,使用引用计数方式管理。跑不了,上线全加载,在线期间定时刷,断线立即存储。之前实测的吞吐还是比楼主的要高些,主要测试的是1500玩家在线,定时刷回DB,我之前定得是5秒一次,内存没爆,CPU基本80+,但是相应其他操作倒是不卡的说,正式上线根据以往的经验,我们一般都是3分钟刷一次,所以我这样测试算是变相压力型测试,增大了他的IO压力。P.S. 我们玩家数据不如楼主这么多的了,但是也有几百K吧,具体没有算过。 关于楼主的问题,感觉以下几个方面可以进行优化,纯个人观点,有不对的地方,麻烦大家指出啊… 第一:楼主一次性进行较大IO操作从db加载到内存,可以考虑一次上线操作分多次数据查询拼接玩家数据对象,毕竟这样能够更好利用node本身tick的机制,你多次小IO,从响应层面,我认为应该优于前者,至少不会造成这么久的阻塞。这就是所谓的数据分离。(有问题请指出)。 第二:感觉使用cluster对于web服务器而言这种无状态的会很好,然游戏服务器这块我认为不是特别合适啊。有大量的内存操作,无法共享对于后续的开发会带来不少问题呢。除此之外就是楼主诟病的Json问题,实质上这步操作是多余的,理论上来看,我加载好了直接使用当然是最好,然后楼主还多了一步传输,虽然从架构上分离了这个负载,实质上由于数据IO这块的影响依然没有解决,这种不必要的数据交换,如果能够优化掉当然会好很多。我是不太建议使用cluster,特别是对于游戏服务器,他本身已经耗费了资源去传输他的socket对象,实质上效率有多高,我认为跟你自己写的网络通信来比,肯定是比不过。如果要使用,共享内存这块可以多参考redis,如此你的开发也会省事很多。 以上仅是个人观点,如果有不太好的地方楼主也自行参考。

@sunwenteng

兄弟,你们的游戏是什么类型的?感觉你们的服务器架构跟我们的很不一样啊。我们的是卡牌游戏,有很多个区的,你们的是全服大区,那么你们面临的挑战性感觉大好多啊。 “3分钟刷一次”是定时保存玩家数据的意思吗?如果是保存玩家数据,这时间会不会太短了些?这样服务器压力会很大,80+的CPU占用率是很恐怖的 “第一”点,其实我们是踩过坑的,如果登陆的时候涉及到多个异步操作的话,最好是压缩成一个异步操作,否则登陆的等待时间会更长,会一直出现卡在进入游戏的进度条哪里的,要等很久才能进去,这是我们的切身体会和经验。 “第二”点,我们只有对那些没有状态的服务器才使用cluster模式的,其他有状态的都无法使用,不然就会出现跨服跨进程通讯的情况,成本非常的高,所以现在的想法就是把有状态的服务器中的一些无状态的业务尽量地分离出去,比如处理玩家的socket连接已经被分离出去,还有现在这个读取和保存数据库的业务也想要分离出去一样。这样才能把有状态的服务器的计算能力不断提高,才能容纳更多的玩家。 “传输他的socket对象”只会在第一次发生,这个性能的损耗基本可以忽略不计; redis 可以实现共享内存,但是代价也很大,他的get set都是要先转成字符串先的,所以这个方法遇到的问题,跟我上面遇到的问题是一样的,都要先通过JSON.parse 和 JSON.stringify 来进行对象与字符串之间的转换。

让你们架构师先看看网易的pomelo. 觉得自己设计的分分钟完爆就全自己来,我觉得怎么也有可以参考借鉴的地方。

游戏类型是城建+RPG,仿照的一款国外游戏,因此采用了大区的设计方法,然实质上也是通过内部“分区分服”的做法制作,只是交互这块达到全服交互,因为由于运营这块有风险,所以服务器之后也要支持分区分服,所以架构进行了如此设计。 恩 我们单服架构实质上主要参考的还是TrinityCore的写法来做,这个以前做过端游的童鞋不少应该都看过,楼主可以自行看下。 “3分钟刷一次”这个是以往的开发经验定得时间,80+是我们5秒存一次的结果,只是为了测试压力才设置的时间,实质上这个时间可以根据自己之后的压力进行调整。另外CPU即使达到80+,但是对于内存操作的响应还是没有多少延迟的。例如,我的一个移动操作,仅仅需要改变玩家内存的坐标,那么这个操作响应实质上也是非常快的。 另外跨进程通信确实有不少损伤,但是我们的跨进程通信都是交互业务,但凡交互业务在设计上都有限制,例如竞技场战斗,我们是全服打得,然而对于用户,都会有战斗次数限制,所以,即使这个有不少损伤,但是凡是可以量化的,都不会有问题。 “第一点”,这个问题主要讨论的是上线操作,理论上上线操作属于游戏业务中复杂度以及IO最高的操作,我这里提得数据分离一方面是查询做多次,另一方面如果你们这块数据量实在是非常大,就把这个操作往lazy模式制作,我不知道你们业务结构的复杂度,是否导致你们业务关联度比较高,如果能够拆分,就做懒加载,用到的时候再加载,这样写起来确实蛋疼,但是能够分摊掉你们上线的卡得问题。 “第二点”,这个我比较疑惑不知道你们现在这块为什么要做如此多的分离,首先,玩家在线期间,所有数据CRUD基本都是操作内存,这一块,nodejs的响应和原生c++的响应相差并不多,具体你可以看深入浅出这书上的一些对比。唯一能够大幅度影响nodejs本身性能的就是你有大量的阻塞操作、或者代码块中有较高次数的IO循环,除此之外我暂时没有想到其他。另外,你们如果做了这样的分离,势必对之后编码的复杂度以及设计有提升,写起来我感觉会比较麻烦,无法无脑的编写,不过这个也考验你们主程的设计能力,node本身作为游戏服务器这块是起步阶段,如果设计的过于复杂,日后招人维护都是个问题,所以架构可以设计的复杂,但是在业务的书写这块,最好是无脑方式。 “socket传输”,这块我确实没有过深入研究,句柄共享应该只会有一次,但是不知道之后的数据流通信是否有损失,这个我不知道。 “redis”,他的使用在乎的不是效率代价,使用他是去解决node本身内存瓶颈,1.4G,另外引用redis官网的那句话,当你发现缓存出现效率问题的时候,永远不要质疑redis,因为我们的应用级别是无法让他出现handle不了的时候的。

@sunwenteng

1.TrinityCore才发现还有这样的游戏服务器框架,可惜C++忘却得差不多了… 2.“3分钟刷一次”,为什么要保存得那么频繁,我们之前定的是20分钟就保存所有在线玩家一次,但是发现其实没什么用,因为node服务器没有试过挂掉,因为我们在最后捕获了所有的异常,估计唯一出现无法保存的就是断电之类的小概率事件了,由于这个定时保存玩家数据,会给服务器带来一定的压力,所以之后我们索性直接取消了这个定时任务; 3.跨进程通信,我们准备做的跨服战也是用到这个的,还是设计到跨进程传输玩家数据就会遇到我上面那个问题,真是头痛;按你说的,虽然是每个玩家的次数可以限制,但是在线玩家数量你总没有限制吧?所以这个随着在线人数的增加,这终究会是一个问题; 4.“这个我比较疑惑不知道你们现在这块为什么要做如此多的分离”一个服务器的处理能力是有限的对吧?如何扩展这个服务器的承载能力?那么只能是把这个服务器的一些无状态的计算分离到别的进程去,比如如果这个服务器其中一个业务逻辑是计算 “斐波那契数列”,因为它是没有状态的,那么我们就可以很容易可以把这个业务逻辑分离到另外的进程去了,我们现在做的就是这样的工作,比如数据库读取和存储,都是没有状态的,你塞一个玩家的对象给他,那么他就去存储就是了;你给一个玩家ID给他,那么他就直接去数据库读取这个玩家的数据,读取完毕,然后把这个玩家的数据返回来就是了,这些都是没有状态的,这部分的工作,完全是可以分离出去,那么分离出去后,原来的服务器的工作量就轻了,那么承载就肯定是上去了;

“socket传输”,socket这个只会在connect的时候才会出现多个进程争夺同一个socket的情况,当被某一个进程拿到了这个socket之后,数据传输是完全没有损耗的。 “redis”关于这个,我们暂时没有出现1.4G瓶颈的问题,因为我们玩家下线后,就马上清掉他的缓存了,所以只要内存没有泄露,这个完全没有问题。但是关键是,如果我们使用redis,那么我们现在是在存储到redis前,进行 redisClient.set(xxxxx, playerData)操作钱,转换这个playerData为字符串时有性能问题(playerData这个对象太大了);

Node有“不支持共享进程内存”的特点,进行复杂逻辑处理的上限就很快显现出来了。

所以选择Node做复杂的网络游戏服务器这种应用,感觉考虑多少有些欠妥,难道整个团队都没有会写C的服务器人员。

终于发现有跟我一样用node写后端的人了

用Node做重逻辑服务器确实是个巨大的技术挑战!针对以上瓶颈,建议如下: 1、重构网络协议; 2、弃用json自行组织数据; 3、最终将游戏逻辑实现多进程分布负载。

@wencan 厉害!赶快给楼主支个招呀

@Antoni1883

我使用node写后端,是因为我的程序是处理数据,需要从网络异步读数据,需要异步写数据到mongodb,需要写mongodb的pipeline和mapreduce,还需要函数式特性做数据处理——其中耗时计算很少

如果说我有什么好建议给LZ,那就是建议LZ放弃node;或者说拆分程序,node程序只负责其中一块

@wf744 能不能解释下,为什么要选用node ??难道就因为数据库是mongo???

@wencan 刚才仔细看了下楼主600K个人数据应该不会频繁在服务器流动,整个游戏过程期间应该少于2次。 否则就有暴力操作数据的嫌疑~

另外,JSON单对一个客户数据的转换处理就需要消耗55ms,如果加上网络传输一个玩家操作的响应时间至少需要70ms以上,这个游戏类型则一定不会是动作网络游戏敢跑的服务器架构。

@Antoni1883

确实如此,没有用之前,主要是看中了异步IO的便捷性 使用node来做重逻辑,务必不能有效率低的代码,不然就很快死翘翘了,对人员的算法,数据结构有一定需求 之前写C的,不过相对C中的多线程,死锁等问题,nodejs还是来得简单多了

@wencan

看中的是以下几点: 1.异步IO 2.介绍中号称的高性能 3.生态环境很成熟 4.解析性语言,不需要编译多好啊

@Antoni1883

恩,600K 是最极端的情况,是当玩家拥有游戏中的所有的资源的情况下的极端情况,现在我们重构了一部分系统,这个体积有所下降了

对,上线,下线, 整个游戏过程期间应该少于2次,这个数据太大了,就是由于太大了,现在遇到的问题就是把这个”大块头“扔出去给其他进程处理的代价太大了,出现了瓶颈

确实如此,如果是动作类的,基本是必死无疑,我们的是卡牌游戏,还能接受吧…

可否用 protobufjs 去定义通信规则? -.-

@idreamshen 目前我们的协议都是直接json,然后转换成字符串,然后buf.writeString的,不知道使用 protobufjs 是否需要大规模的重构

@wf744 棋牌应用应该没有什么大规模重构的问题。最多是增加些协议相关部分工作量而已。

建议楼主程序拆分

node擅长拉客,你却让他去挖矿!!!楼主加油!!!

cluster不错,国外大一些的项目都是用这个 自豪地采用 CNodeJS ionic

确实是一个很棘手的问题,我们也在解决。。。

@hainee 神回复,精华中的精华!!!

你这数据太大了吧,,,我们这加上战斗战报,以及玩家信息也才不到70k。 600k。太恐怖了,把数据拆分了吧。。

这贴讨论的内容相当充分啊

偶尔上来逛一下,忽然发现这贴还有人回复,感觉不错,可以结贴了。 上面这个问题是在游戏上线前的一个性能顾虑(但他确实是node多进程通讯间的一个比较麻烦的问题,数据一大就会出现性能上的瓶颈) 我们项目(手游)已经上线了,单服最高同时在线4.5K+,相信可以更高,由于运营策略,同时在线也不需要去到更高就开新服了,4.5K+在线的时候,CPU占用在30%~45%左右,而且这不是node而导致的CPU占用率高,而是游戏逻辑代码写得不够好而导致的(当然没有经过profile分析,我们写的代码确实很多地方都不高效),所以其实node来应对中小型游戏感觉还是卓卓有余的,大家就不用担忧了,而且配合pm2来进行进程管理,真是非常的方便,上百个服,维护一次就5分钟左右的事情,安全,高效,开发效率也挺高的,而且node还可以比较方便地实现代码热更新,这个还是非常的不错的,如果是中小型游戏,建议大家采用

@wf744 大神我想走node服务端开发路线,不知道这条路好走么?pomelo好似停止更新了

@wf744 所以最后你们是怎么解决这些问题的?

楼主各种分离的思路很赞,mark一下

一看帖子时间,我猜@sunwenteng 做的应该是clash of kings?

虽然lz说可以结贴了,用node写游戏服务器的话这个问题相当普遍,我也说说我的思路吧。 用redis应该能解决楼主的问题 redis> hmset user:id field1 value1 field2 value2 … 虽然user这个对象可能有几千个属性,但是每次更新的时候其实只需要改变其中很少的几个,根据我的经验,对于卡牌游戏一般不超过10个。

如果实在需要序列化/反序列化很大的对象,可以使用stream,比如JSONStream。

楼主高性能服务器: 1.考虑数据传输,JSON传输实在不可取,建议对数据制定自己的规则 ,就如上面所说的protobuf 或者bytestream 或者fast压缩算法 2.Nodejs确实不是做复杂逻辑运算的料,这块可以使用C++模块扩展功能 3.网易的node游戏框架还是不错的pomelo

可以将大的 JSON 分而治之,看业务情况是否可以划分。

用户数据可以用ES6的Proxy,来避免一次传输整个JSON。

可能是我没做过游戏,我一直没明白为什么是进程间传数,而不是进程间共享数据? 自豪地采用 CNodeJS ionic

@wf744

有问题还是要解决问题的, 我读下来问题在于 JSON.stringify & JSON.parse 是 v8 提供的功能, 这两个函数是在 v8 线程中执行的, 相当于常说的的 while(true) 一段时间去阻塞js执行, event-loop 中其他的事件得不到执行, 就阻塞了~

所以是要一个 JSON.parseAsyncJSON.stringifyAsync 在 libuv 提供的线程池中去做这个解析操作是吧~如果有 C/C++ 同事, 拿 C/C++ 的json库封装一个?

https://github.com/nodejs/node/issues/2031#issuecomment-114285544

It is impossible to serialize a V8 object, or convert a string back to a V8 object, off the main thread. This is a limitation of the VM and not something io.js can implement on its own.

😂

@magicdawn 问题的根本在于nodejs 的进程通信用的是 V8 的 JSON.stringify & JSON.parse 。。。并不是简单提供JSON.parseAsync 和 JSON.stringifyAsync 就能解决的。

我认为上面说的 “不要整体传输,只更新变化部分” 的思路是可行的。如果非要整体传,应该绕开 nodejs 的进程通信,自己用 C++ Addon 实现进程间通信,这样数据格式就可以自由定制了,比如用更紧凑的二进制等。

@myy

问题的根本在于nodejs 的进程通信用的是 V8 的 JSON.stringify & JSON.parse 。。。并不是简单提供JSON.parseAsync 和 JSON.stringifyAsync 就能解决的。

child_process 里 调用的是, sync 版, 可以再定制一个 child_process2 😂😂😂 前面有人提到 Google 的 protobuf, 可以考虑下

@wf744 提供一个思路,仅供探讨:自定义二进制的数据格式,然后通过直接读写 stdin, stdout 原始流的方式直接传输,避免JSON.stringify & JSON.parse

@magicdawn 就算是 Async,对于600k+ 的数据量来说,系列化/反序列化 纯计算用的时间还是一样的,只是时间更分散些。。。我感觉这不能从根本上提高多少。。。 根本性的改善,要么是用局部更新方式,再就是用更小更快的格式(二进制)。

用户数据可以用ES6的Proxy,来避免一次传输整个JSON。

就算拆分也不见得有用,可能会回到之前的分离出数据库读写前cpu占用高的情况

@wf744 问下楼主,你们用的node版本是多少?

cluster模式 参考下eggjs的进程通信 自豪地采用 CNodeJS ionic

在多进程使用过程中有时候需要在进程间共享缓存一些数据,比如:

session数据 数据库查询缓存 有一定时效的信息,比如oauth使用的access_token 常规的缓存机制需要引入第三方模块,如memcached/redis等。node-shared-cache(链接)就是专门解决此类问题的轻量级方案。相比第三方模块,node-shared-cache的优势有:

无需跨进程通讯,使用共享内存的方式,因而可以同步使用 API简单,和操作普通js对象一样的使用方式 超高性能,接近普通js对象操作的速度,每秒300w次查询 支持持久化,进程退出后内容不会清空

https://cnodejs.org/topic/55755426c4e7fbea6e9a30c8 这个模块共享内存,如果是多台服务器就不行了

好贴要马克

感觉数据结构设计有问题,缓存有问题,建议重构

@wf744 建议还是使用mysql的分表去把数据拆分开,否则数据整个对象存储,存取都是一个负担

@miss61008596 整个大对象存储 肯定不合适的

高负载的计算可以考虑异构,采用rust或者go来做

@Vizwind redis写起来稍微麻烦点 比如你同时需要操作2个玩家数据 给A玩家+ 100金币 给B玩家 -100金币 此时你是不是需要些redis lua 脚本了呢,如果这样的逻辑过多 实际上应该也是很多的吧,写起来会很麻烦把。

@dou4cc 经过我测试 es6 proxy 代理 用户数据操作 来达到标记修改了哪些部分 实测性能太差了。。一秒钟的读写操作 只有30W

@ipengyo proxy 不止是做 observable,还可以 lazy(如果你接受 await everywhere 的话)。

@dou4cc 我最终放弃了 感觉有点得不偿失 与普通对象比 性能损耗有点大。

@ipengyo 性能不会差啊?你 lazy 了吗?

@dou4cc 没有哦 请问大哥有demo 可以参考一下你的写法吗

马克,这个帖子的讨论真的是精华

回到顶部