MMO xkcd WebSockets fixed by PubNub (pubnub.com)
Hello all hackers from HackerNews. We notice a new MMO was released by n01se and xkcd yesterday (September 26th, 2012) with multiple users flying around with a balloon figure. If you got stuck, you can click your balloon guy and turn into a ghost to seamlessly move through the landscape unhindered by mortal barriers like trees and hills. There was a problem however with the scaling of users on the system. The max concurrency could only be 20 users at a time leaving many wonder where the MMO part of the MMO was. We ripped out the non-scaling Node.JS code. ENJOY.
Enter the xkcd World with Friends: http://www.pubnub.com/static/pubnub-xkcd/index.html
52 comments
[ 0.20 ms ] story [ 312 ms ] threadEnter the xkcd World with Friends: http://www.pubnub.com/static/pubnub-xkcd/index.html
[0] It could theoretically be done p2p.
The clients would then (again theoretically) be able to agree on a game state, optimize messaging and the other things you would normally do on the server.
http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-...
From earlier today for about 20 hours of run time: we had 13,000 successful connections to the server, 22,000 failed attempts to connect. The server is averaging about 100k per second outbound when fully loaded with 20 clients. With the quick improvements we made after the HN flood we got the CPU down to about 1-5% on a t1.micro when 20 clients are connected and interacting. The real issue for us is the bandwidth.
The server and protocol could be MUCH more efficient (visibility pruning, binary messages, etc). But it was something chouser and I hacked up over the weekend and it's now working quite well within the cap.
What I was actually interested in was PubNub stats to see how such service can help with apps like yours and to help in figuring out how much it'll cost.
So there are servers, you just don't run any yourself and it is all abstracted away by their API.
What they did, in this case, is mock the WebSocket interface (so that they didn't need to rewrite the whole original app) and make it use the PubNub API internally. See https://github.com/pubnub/pubnub-xkcd/blob/master/websocket....
Why?
Shouldn't the emulation only occur when necessary and be a graceful degradation not forcing all clients to downgrade to a less efficient transport?
Also the dynamic poll/sample interval you implemented seems to hit 1000ms (1 second) and stay there.
Oh, and also since I'm personally paying for the bandwidth and my wife would be unhappy with a big bill at the end of the month paying for a game for other people :-)
So I only see updates from those in my area. Then change channels as you move?
And start users in different spawn points when usage is high?
I'm talking about dividing the map into multiple channels so that users only receives updates from those around them, and hopefully make it more responsive.
So for 1000x1000 areas, if I'm at "x":3033521.3,"y":-3025356.4, my client subscribes to /xkcd_x3033_y-3025
And adjoining area/channels if they're close to a border. (but only sends updates to the current area/channel.)
...IF it's easy enough for the client to dynamically change channels, and be subscribed to multiple (up to 4) channels.
Then combine this with multiple spawn locations at other interesting locations when demand is high. But they can still explore and meet others.
So it should more responsive and less data sent than everyone getting updates from everyone.
There most definitely is a server, so can anyone explain what they meant by that instead?
In the video and from my experience I see a bunch of dead users spawning from a single point making a 'pillar of death' and a few users moving that are skipping around, but none in any kind of fluid motion.
Perhaps have multiple spawns, offset by a small random amount.
Not sure how your system works but perhaps have areas in separate channels, and users only subscribe to updates from that area?
I'd rather see a few users in my area that can interact with me quickly than a flood of non-responsive ones.
However, one of the problems with a t1.micro server on AWS is that the hypervisor will detect heavy load and start throttling the VM using a heavy handed approach which basically just pauses the VM for several seconds. This would cause buffers to build up and when the VM started running again you would have a burst of traffic.
The symptom was that you would see other avatars stop moving for a few seconds and then suddenly jump around and then be back to smooth. All clients would still receive all the updates (WebSockets is reliable over TCP), but they would come in bursts whenever the VM was throttled. So a few minutes after moving to the AWS server we realized what was happening (we use AWS for development and knew to recognize the behavior) so we implemented a few easy fixes to the server (such as change deltas and doing JSON of the data once instead of per client, etc) to bring the CPU usage down to a reasonable level so that it wouldn't get throttled. Combined with the 20 connection cap that resulted in a very smooth and low latency experience for the players that were able to connect.
One thing we are considering with the original is what you suggested where players only get updates for things that are visible to them. However, this means more processing on the server because each client gets a different data set which has to be generated. So it's sort of a tradeoff between decreasing bandwidth and increasing CPU (surprisingly often the case in the real world). If the CPU increase causes throttling then we would start encountering burstiness again. So it might be worth it or it might not.
Anyways, if we have some free time we may play with some ideas. One of the first things is being able to simulate load manually. Doing a mad dash to try and implement improvements while thousands of HN users are trying to connect (we didn't know that a friend had posted it there) is certainly an adrenaline rush but not the most ideal way to do development :-)
Another solution would be to use a larger AWS instance. Right now on the t1.micro with 20 users the CPU stays around 1-5% (which is a safe zone for throttling). Larger instances don't have the throttling problem so in addition to more horse power we would be able to use a much higher percentage of it. However, it's just a spare time project for us and I'm still trying to figure out to explain to the wife why we are paying (mostly bandwidth) for other people to play an online game. :-)
And surprisingly AWS doesn't seem to have a way to accept donations or gift cards for AWS costs. Seems like a logical for encouraging free and open source development projects like this.
I'd like to hope having 1000's in the same map with fast updates, without being a huge burden to any one person is possible.
Perhaps run a master instance at 1110.n01se.net Invite others to run a slave instance that is configured to connect to your master, report health, and serve areas as directed.
The master serves the client and assigns a spawn point to the client to other interesting locations when load is high. It also manages the list of slaves and the areas covered and updates it with clients as it changes.
(But there's a potential bottleneck here. Not sure how to do this yet...
Also how do you subdivide the map so high traffic areas are smaller? I'm guessing Quadtrees so the subdivide data can be very small.
How well can clients be connected to multiple servers?
And is a master/slave relationship needed?)
Well I'll leave it there. It's an interesting problem and I think it's part of what node.js is trying to become.
Everyone is spawning at the same point. I just see a flood of dead users. Some jerk around a little and appear and disappear. But very little interaction.
Is it possible to multiple spawn points when demand is high and separate channels/servers for various areas that you switch as you move? (like Second Life)
I believe a node.js (or something else) version could be federated, and/or clients connect to various servers as they travel.
I know this is just a toy, but it would be interesting to see this work well at a large scale.
The second time I tried, my first player window saw the other player fairly quickly, but it never registered the change to a ghost or my name change and it just showed the second player as a balloon guy floating up forever (even after the second client window disconnected).
I did this testing at 7:30am CST. There were about 90 other players that I was getting updates from. However, this is the same type of behavior I've seen whenever I have connected since it went live. And friends in other locations see the same behavior so it's not just my environment.