Jump to content

PHP Websocket Usage / Memory


Monkuar

Recommended Posts

For example, take a look at this: https://code.google.com/p/phpwebsocket/

 

When I run the server, it works fine and I am using the server for my Inventory system on my game. When users drag and drop items in their inventory to change position, it sends the data to the html 5 websocket server, and updates the positions accordingly/etc. And I will use it for a bunch of other stuff later.

 

My question is: What kind of VPS would I be looking for in terms of ram/cpu power to keep a websocket server like this up 24/7? Is it more memory intensive than socket/io/nodejs? Or what? How can I test these things? Looking at cmd.exe or php.exe in my task manager when having it run on my local windows machine isn't really a good way to test performance, or to estimate how much ram or VPS/CPU power of a server I'll need before launch.  I can get a idea, but I don't think it's going to be close to reality. That's why I'm asking you guys here if you would know.  Thanks :)

Edited by Monkuar
Link to comment
Share on other sites

The only real test would be a live server and some real traffic running your specific scripts.

 

It all matters, all it takes is one bottleneck.

You want a decent network when using websockets.

You have to pay attention to your polling and how much header data sending, which will increase the sizes and reduce latency.

As long as you aren't doing live/real time data could look into caching responses to lighten a lot of the loads.

Not having enough memory is always a concern, get as much as you can afford, plan to have extra for higher traffic instances.

The cpu is not as much of a concern as I've seen servers at 100% all the time and keep working. At the same time you want a decent one that can do the work.

 

ovh.com is a pretty good host with fair prices and reliable.

They have the classic vps and also the cloud ones, if went cloud could easily bump up your plan but cost a bit more.

I would never bother running a server less than a quad core and 4 gig of memory, preferably a dedicated.

I see they have a vps under classic that's 4 cores,8gig memory and 100 gig storage for 22 a month.

 

Just tossing a suggestion out there, if went with one of their awesome dedicated servers can sell off a few virtual dedicated or private servers to others and still have plenty for yourself for free or even a profit for yourself.

https://www.ovh.com/us/dedicated-servers/range-2013/2013-EG-128.xml

 

Is software to become your own host or management of virtual servers.

virtkick

archipel

feathur

solusvm

virtpanel

hypervm

Link to comment
Share on other sites

The only real test would be a live server and some real traffic running your specific scripts.

 

It all matters, all it takes is one bottleneck.

You want a decent network when using websockets.

You have to pay attention to your polling and how much header data sending, which will increase the sizes and reduce latency.

As long as you aren't doing live/real time data could look into caching responses to lighten a lot of the loads.

Not having enough memory is always a concern, get as much as you can afford, plan to have extra for higher traffic instances.

The cpu is not as much of a concern as I've seen servers at 100% all the time and keep working. At the same time you want a decent one that can do the work.

 

ovh.com is a pretty good host with fair prices and reliable.

They have the classic vps and also the cloud ones, if went cloud could easily bump up your plan but cost a bit more.

I would never bother running a server less than a quad core and 4 gig of memory, preferably a dedicated.

I see they have a vps under classic that's 4 cores,8gig memory and 100 gig storage for 22 a month.

 

Just tossing a suggestion out there, if went with one of their awesome dedicated servers can sell off a few virtual dedicated or private servers to others and still have plenty for yourself for free or even a profit for yourself.

https://www.ovh.com/us/dedicated-servers/range-2013/2013-EG-128.xml

 

Is software to become your own host or management of virtual servers.

virtkick

archipel

feathur

solusvm

virtpanel

hypervm

 

 

Thanks, but I usually just install debian, and run a full web stack via putty/console.   I usually do these on cheap VPS's. But, are you saying a dedicated is needed to run a websocket server for sure? If that is the case, I might need to raise my budget :P I will check out ovh, and others, thanks.  Yeah, 4 gigs of ram+ is probably what I would want just to be safe. I could always upgrade. Ram is dirtcheap nowadays as well.

 

There is no way I can afford those XEON servers though. I don't even think if my game went viral, I would make enough money off microtransactions to even pay that off per month.. lol

Edited by Monkuar
Link to comment
Share on other sites

But, are you saying a dedicated is needed to run a websocket server for sure?

No, not necessarily. It depends on your traffic of course. If you only have a few dozen concurrent connections, you'll probably be fine with a smallish VPS. If you have hundreds or thousands of concurrent connections, then it's not going to be very cost effective to stay with VPS's.

 

If you'd like to get a dedicated, check out http://www.soyoustart.com/us/essential-servers/

 

They have servers starting at like $42. The only caveat is that you basically have 0 support. You need to be able to completely manage the box for yourself. The support will help out if there is something completely out of your hands, like a disk fried or something. But they will not help with software issues.

Link to comment
Share on other sites

No, not necessarily. It depends on your traffic of course. If you only have a few dozen concurrent connections, you'll probably be fine with a smallish VPS. If you have hundreds or thousands of concurrent connections, then it's not going to be very cost effective to stay with VPS's.

 

If you'd like to get a dedicated, check out http://www.soyoustart.com/us/essential-servers/

 

They have servers starting at like $42. The only caveat is that you basically have 0 support. You need to be able to completely manage the box for yourself. The support will help out if there is something completely out of your hands, like a disk fried or something. But they will not help with software issues.

Yeah, I've been around linux VPS's and an active member of LowEndTalk. I have a small bash script I made that installs the basic php/mysql stack on debian 64's. I use basic iptables and nginx rate limiting as well and citadel to mitigate script kiddy flooders. (Although, a real DDOS is still dangerous).

 

I've been doing some testing with my php websocket server though. With my game server, let me show you an example:

 

c1bedb77df99e4de69af0c6bdd375fb7.gif

 

How does php.exe (the web socket game server) only use around 4kilobytes of cpu power? That doesn't make sense. Is it only because there is 2 concurrent users?

 

I'm only assuming the cpu power wont be the issue, but the bandwidth will be, fair assumption?

Edited by Monkuar
Link to comment
Share on other sites

Not sure what you mean by "4kilobytes of cpu power". kilobytes is a size of data, not a measurement of cpu power. 4% of cpu power makes sense. Meaning it took 4% of your total cpu to execute the php script. It doesn't take much cpu to execute a script, unless it's really complex and a lot of code.

Link to comment
Share on other sites

Not sure what you mean by "4kilobytes of cpu power". kilobytes is a size of data, not a measurement of cpu power. 4% of cpu power makes sense. Meaning it took 4% of your total cpu to execute the php script. It doesn't take much cpu to execute a script, unless it's really complex and a lot of code.

Oh. Wow. I am dumb. I meant memory usage. For cpu usage, I will check the other tab in the task manager. I'm just trying to figure out what kind of server I will need.

 

The websocket server is essentially being run in a while loop 24/7 right? Why isn't it taking it's toll on the cpu yet? If you do a while loop iteration function on the web browser, the script will halt and eventually crash. Why doesn't this happen for the php websocket server?

Link to comment
Share on other sites

It won't necessarily halt and crash when running in a browser. It depends on what your max_execution_time is set for in your php.ini. PHP being executed via the CLI can run forever by default (can also be overridden) as it has a (default) value of 0 for max_execution_time which means it can run forever and not time out.

 

And just because something is running forever doesn't mean it takes more memory or cpu power to process what's going on. It depends on "what IS going on".

for(x = 0; x < 10000000000; $x++)
{
  echo "$x<br>";
  sleep(100);
}

The above will run for a very long time, and sleep for 100 seconds in between cycles. Just because it's running for a long time doesn't mean it will take a lot of CPU. Now if you had a TON of code within the for() loop, and it was doing a lot of complex things, then it would require a lot more cpu power and RAM as it's doing a lot more.

  • Like 1
Link to comment
Share on other sites

Good explanation. Thank you.

 

Now help me stress test this bad boy on my main server at home to see what kind of server I'll need. Ram/CPU/Bandwidth... Is it possible? Or should I just buy a cheap VPS for a couple bucks and do it there?

 

Problem is even if I were to buy a server, how the hell do I stress test concurrent users when I'm only a 1 man show?

 

These are very important factors that need to be considered before launch. I'm very skeptical.

Edited by Monkuar
Link to comment
Share on other sites

The websocket server is essentially being run in a while loop 24/7 right? Why isn't it taking it's toll on the cpu yet?

Just because something is running 24/7 doesn't mean it is actually doing something 24/7. A properly written server would use stream_select in it's main loop so that it only does something when it needs to do something. What that function does is basically tell the operating system "Hey, let me know if anything interesting happens with these sockets. Until then, you can ignore me and do whatever." So the operating put your script into what is essentially suspended state and watch those those sockets. During this time your script is not actually running, thus consumes no CPU time. Once the operating system sees some activity on the sockets it will resume your script and let it do what it needs to do.

 

As for computing what kind of memory you might need, the best way obviously is to do some profiling and stress testing to see what kinds of memory the script actually uses. You can however estimate it. There are a few different types of memory consumption that you'll want to look at:

  • How much memory PHP consumes just to run a script. Last time I checked this was about 30MB, but this will vary greatly depending on how PHP was compiled, so check for yourself.
  • How much memory your script consumes in general. For things like the global configuration, the server information, etc. Memory that is used regardless of any clients being connected
  • How much memory each connection will required, both when activly doing something and when just passivly listening.
The first two values you can get just by running your server script then checking how much memory is being used before anything connects to it.

 

The last value you can estimate by just looking at what kind of information you store for each connected user. For example, every user will have at least their socket connection, and possibly some additional details like an identifier, socket buffer, etc. Lets assume each client connection contains the following for the entire duration of the script:

  • The socket resource
  • A 60-character identifier token
  • Character stats (hp, str, armor, etc)
  • A 1KiB recieving buffer
  • A 1KiB sending buffer
Estimate the memory usage for each of those items. To make things easy, use a precision of 0.5KiB so anything that would be less than 0.5KiB is counted as 0.5KiB instead. By over-estimating you can balance out PHP's overhead. That would give estimates of:
  • 0.5KiB
  • 0.5KiB
  • 0.5KiB
  • 1.0KiB
  • 1.0KiB
Total: 3.5KiB constant usage per connection.

 

Figuring the usage when the client is activly doing something would depend on what is being done. What you'll want to do is just look at each possible operation and try and come up with a memory usage profile for each one. Then you could either average them out, use the maximum, or just whichever would be the most common. How you choose to do that is pretty much up to you. I'm just going to 1MB typical usage for activity for example purposes.

 

 

So if you had for example 128MB of memory to work with, you could in theory support:

  • 131072KiB / 3.5KiB = 37,449 connections that are doing nothing but sitting there.
  • 131072KiB / 1027.5 = 127 connections all doing something at the same time
So how much you could realistically support would fall somewhere in that range.

 

That said, just because you theoretically have enough memory to support 37 thousand clients doesn't mean you actually can. You also need to factor in various OS limitions (ie # of allowed file descriptors), processing power (need to be able to process the requests fast enough), other running programs (web server, database, etc). All these additional factors are why it's generally best to just profile and stress test. With some work you can estimate a ball-park of what you might need resource wise though.

Link to comment
Share on other sites

Just because something is running 24/7 doesn't mean it is actually doing something 24/7. A properly written server would use stream_select in it's main loop so that it only does something when it needs to do something. What that function does is basically tell the operating system "Hey, let me know if anything interesting happens with these sockets. Until then, you can ignore me and do whatever." So the operating put your script into what is essentially suspended state and watch those those sockets. During this time your script is not actually running, thus consumes no CPU time. Once the operating system sees some activity on the sockets it will resume your script and let it do what it needs to do.

 

As for computing what kind of memory you might need, the best way obviously is to do some profiling and stress testing to see what kinds of memory the script actually uses. You can however estimate it. There are a few different types of memory consumption that you'll want to look at:

  • How much memory PHP consumes just to run a script. Last time I checked this was about 30MB, but this will vary greatly depending on how PHP was compiled, so check for yourself.
  • How much memory your script consumes in general. For things like the global configuration, the server information, etc. Memory that is used regardless of any clients being connected
  • How much memory each connection will required, both when activly doing something and when just passivly listening.
The first two values you can get just by running your server script then checking how much memory is being used before anything connects to it.

 

The last value you can estimate by just looking at what kind of information you store for each connected user. For example, every user will have at least their socket connection, and possibly some additional details like an identifier, socket buffer, etc. Lets assume each client connection contains the following for the entire duration of the script:

  • The socket resource
  • A 60-character identifier token
  • Character stats (hp, str, armor, etc)
  • A 1KiB recieving buffer
  • A 1KiB sending buffer
Estimate the memory usage for each of those items. To make things easy, use a precision of 0.5KiB so anything that would be less than 0.5KiB is counted as 0.5KiB instead. By over-estimating you can balance out PHP's overhead. That would give estimates of:
  • 0.5KiB
  • 0.5KiB
  • 0.5KiB
  • 1.0KiB
  • 1.0KiB
Total: 3.5KiB constant usage per connection.

 

Figuring the usage when the client is activly doing something would depend on what is being done. What you'll want to do is just look at each possible operation and try and come up with a memory usage profile for each one. Then you could either average them out, use the maximum, or just whichever would be the most common. How you choose to do that is pretty much up to you. I'm just going to 1MB typical usage for activity for example purposes.

 

 

So if you had for example 128MB of memory to work with, you could in theory support:

  • 131072KiB / 3.5KiB = 37,449 connections that are doing nothing but sitting there.
  • 131072KiB / 1027.5 = 127 connections all doing something at the same time
So how much you could realistically support would fall somewhere in that range.

 

That said, just because you theoretically have enough memory to support 37 thousand clients doesn't mean you actually can. You also need to factor in various OS limitions (ie # of allowed file descriptors), processing power (need to be able to process the requests fast enough), other running programs (web server, database, etc). All these additional factors are why it's generally best to just profile and stress test. With some work you can estimate a ball-park of what you might need resource wise though.

 

Well, that was a thought out and nice reply.

 

Currently, I'm not using stream_select, or I cannot find it inside my server file. What the server is actually running (literally) is:

1600ee2b1fea2961a802582269a31792.png

 

And this is what is being buffered or as u said (memory usage for each concurrent user):

$wsClients[ integer ClientID ] = array(
		0 => resource  Socket,                            // client socket
		1 => string    MessageBuffer,                     // a blank string when there's no incoming frames
		2 => integer   ReadyState,                        // between 0 and 3
		3 => integer   LastRecvTime,                      // set to time() when the client is added
		4 => int/false PingSentTime,                      // false when the server is not waiting for a pong
		5 => int/false CloseStatus,                       // close status that wsOnClose() will be called with
		6 => integer   IPv4,                              // client's IP stored as a signed long, retrieved from ip2long()
		7 => int/false FramePayloadDataLength,            // length of a frame's payload data, reset to false when all frame data has been read (cannot reset to 0, to allow reading of mask key)
		8 => integer   FrameBytesRead,                    // amount of bytes read for a frame, reset to 0 when all frame data has been read
		9 => string    FrameBuffer,                       // joined onto end as a frame's data comes in, reset to blank string when all frame data has been read
		10 => integer  MessageOpcode,                     // stored by the first frame for fragmented messages, default value is 0
		11 => integer  MessageBufferLength                // the payload data length of MessageBuffer
		)
And the maximum amount in bytes per payload are:

 

	// the maximum length, in bytes, of a frame's payload data (a message consists of 1 or more frames), this is also internally limited to 2,147,479,538
	define('WS_MAX_FRAME_PAYLOAD_RECV', 500);
	
	// the maximum length, in bytes, of a message's payload data, this is also internally limited to 2,147,483,647
	define('WS_MAX_MESSAGE_PAYLOAD_RECV', 500);
Not that much, 500 bytes? That's nothing. But then again, I am using this gameserver for only inventory item slot updates and a chat server. For example: Check this out, no HTTP requests, items are updated via websockets.

a27c9c5ff2f291ab0ea65e65d50d36b0.gif

 

 

And this takes care of that ^:

cb.socket.send('SLOTUPDATE 412 2');
2 being the slot position. This then runs this inside my websocket gameserver:

elseif ($command == 'SLOTUPDATE') {
			
			
			
			
			$item_id = intval($message[0]); if ($item_id < 1){return;}
			$slot_id = intval($message[1]); if ($slot_id < 1){echo "No.."; return;}
			if ($slot_id > 20) { wsSend($clientID, 'GERROR You have exceeded the maximum <b>slot</b> limit. '); return; }
			//Check if the user even owns this item:
			$checkquery = $db->query('SELECT rpg_items_id,slot_position from rpg_user_items where user_id = '.$users[$clientID]['user_id'].'  LIMIT 20 ');
			if (!$db->num_rows($checkquery)){
				echo "Invalid Item ID, or item does not exist."; return;
			}
			//If they're moving it into the same slot? Cannot do it that..
			while ($checkdata = $db->fetch_assoc($checkquery)){
				
				$slotarray[] = $checkdata['slot_position'];
			}
			//var_dump($slotarray);
			if (in_array($slot_id, $slotarray)) {
				wsSend($clientID, 'GERROR You already have an item in that specific slot, please move it.');return;
			}
			//If the system got passed all the checks and exits'... move the damn item!
			$db->query('UPDATE rpg_user_items SET slot_position = '.$slot_id.' where itemid = '.$item_id.' AND user_id = '.$users[$clientID]['user_id'].' LIMIT 1 ');
			wsSend($clientID, 'GSUCCESS Item successfully moved.');
			echo var_dump($message);
			
			
			
			}
Also, this thing is a MYSQL saver if you think about it. The websocket stores ALL user's data (essentially sessions), in a variable, and you can update a user without even authenticating them per each update. Yes, I authenticate them upon connection to the websocket server then once authenticated, I store their server values to the array in the websocket. And you can use them like a wild billy goat freely and securely. It's actually pretty awesome. It's pretty much like php $_SESSION's, but inside a websocket connection, and there is no fwrite, or fopen crap too. It's actually a performance INCREASE in my opinion when dealing with mysql updates; especially when updating the user, or in this case, item slots.

 

For example in that gif I posted above. That's around 5 HTTP requests and 5kb of transfer data saved because of websockets. That mind sound very small now, but if there is let's say 2,000 users updating their item slots, that's over 10000 kilobytes saved just in that short period of time ALONE. (Whether it be a day, 2 days, a month, whatever).

 

 

But I do need to figure out the length of the data being store inside the websocket connection (the session essentially).

Pretty much this:

de648cc4d88af944cea53bcfeac35b9e.png

 

Cannot be that much.

 

Wait, let me get the size of the session array information per user:

 

function addUser($clientID, $username, $userID, $rowdata) {
		global $users;
		
		// let all clients know about this user joining (not including the user joining)
		foreach ($users as $clientID2 => $username2) {
			wsSend($clientID2, 'ONJOIN '.$username.' '.$rowdata[0]['selected_characterid'].'');
		}
		
		// send list of usernames to the user joining
		$usernames = getUsernames();
		
		echo ' Add User Function Dump:'; echo " \n ";
		var_dump($usernames);
		
		
		wsSend($clientID, 'USERS '.implode(' ', $usernames));
		
		//Flood Control Data
		$users[$clientID]['last_session_request'] = microtime_float();
		
		
		// store the user's client ID and username
		$users[$clientID]['username'] = $username;
		$users[$clientID]['user_id'] = $userID;
		$users[$clientID]['timezone'] = $rowdata[0]['timezone'];
		$users[$clientID]['selected_characterid'] = $rowdata[0]['selected_characterid'];
		
		//RPG Values
		$users[$clientID]['min_dmg'] = $rowdata[0]['min_dmg'];
		$users[$clientID]['max_dmg'] = $rowdata[0]['max_dmg'];
		
		$serialized = serialize($users);
if (function_exists('mb_strlen')) {
    $size = mb_strlen($serialized, '8bit');
} else {
    $size = strlen($serialized);
}

		echo $size;
		var_dump($users);
	}
So the $size is outputting roughly, 231 bytes for the user's session in socket. That's pretty much the "Character stats (hp, str, armor, etc)", part you were talking about.

 

After adding these up, you're actually pretty damn close with your numbers...

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.