Jump to content

Why is my page Running Sloooow?


Ansego
Go to solution Solved by Psycho,

Recommended Posts

Hi guys,

 

I've tested this code on the dev and live server and is very slow to run, is there something I am missing or looped? Or just plain wrong? I do however get the results after a little time, I have 6 records in the test database for testing but this is meant to be built for 100+ servers, will just take for ever to load...

 

PS: Welcome any constructive suggestions

 

My thoughts: I do however have a feeling it maybe: stream_socket_client ( If so, anyway to speed it up? ) with the wait time for a response from the server. Live server I pushed this on should not have to much trouble of that though, since it is in the same rack farm as the servers that it was tested on.

 

So far I've increased and no change:

  • memory_limit = 256M in the php.ini file.
  • query_cache_size=256M in the my.ini for MySQL

CODE: ( WARNING BIT MESSY )

 

Index.php:

<?php
error_reporting(-1);
ini_set('display_errors', 'On');

spl_autoload_register(function ($class) {
    include 'lib/' . $class . '.inc';
});

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>index</title>
</head>

<body>
<?php

$servers = new servers;

?>

</body>
</html>

lib/dbcon.inc:

<?php

	include_once 'settings.inc';
	
class dbcon {
 
	protected $db_Hostname	= HOSTNAME;
	protected $db_Username	= USERNAME;
	protected $db_Password	= PASSWORD;
	protected $db_Database	= DATABASE;
	
	protected $dbConnection;

	public function __construct(){

		$this->set_connection();

		}

	public function set_connection(){
		
			$this->dbConnection=mysqli_connect($this->db_Hostname,$this->db_Username,$this->db_Password,$this->db_Database);
	
			if (mysqli_connect_errno()) {
				echo "Failed to connect to MySQL: " . mysqli_connect_error();
			}		
		}
		
	public function get_connection(){
			echo "Got connection";
			return $this->dbConnection;
		}
		
	public function close_connection(){
			echo "Connection Closed...";
			mysqli_close($this->dbConnection);
			return true;
		}

}
	
?>

lib/servers.inc:

<?php

	include_once 'settings.inc';

class servers {

	protected $dbConnection;
 
    function __construct() {
		
		spl_autoload_register(function ($class) {
			include '' . $class . '.inc';
		});
		
		$dbcon = new dbcon;
		$this->dbConnection = $dbcon->get_connection();
		$this->get_servers();
		
	} // End Construct
	
		public function get_servers(){
			
			$message = '';
			$message = '<h3>Current Servers</h3>';
					
		$con = $this->dbConnection;
		$result = mysqli_query($con,"SELECT * FROM server_status.tbl_servers;")or die("Error: ".mysqli_error($con));;
		
		while($row = mysqli_fetch_array($result)) {
			  $message .= "" . $row['ssGameType'] . " : ";
			  $message .= "" . $row['ssIP'] . ":" . $row['ssPort'] . " : ";
			  $message .= " Status:" . $this->get_status($row['ssIP'],$row['ssPort']) . " : ";
			  $message .= "Timestamp:" . $row['Timestamp'] . " : ";
			  $message .= "Orderby:" . $row['ssOrder'] . "<br />";
		}
		
			$message .= "<br />End of the \"Server List\" ";
			$message .= "<br />";
			echo $message;
					
				//$this->dbConnection->close_connection(); // FAILED
				return $message;
		}
		
		public function get_status($ServerIP,&$ServerPort){
				
				if(@stream_socket_client("tcp://$ServerIP:$ServerPort", $errno, $errstr, 5) !== false) {
					return "<strong style='color:#33CC00'>Online</strong>";
				} else {
					return "<strong style='color:#CC0000'>Offline</strong>";
				}

			}
	
} // End class

?>

Results:

Current Servers

Minecraft : xxx.xxx.xxx.xxx:25575 : Status:Online : Timestamp:2014-06-17 22:19:46 : Orderby:1
Minecraft : xxx.xxx.xxx.xxx:25576 : Status:Offline : Timestamp:2014-06-17 22:19:54 : Orderby:2
Minecraft : xxx.xxx.xxx.xxx:25577 : Status:Offline : Timestamp:2014-06-17 22:20:00 : Orderby:3
Minecraft : xxx.xxx.xxx.xxx:25578 : Status:Offline : Timestamp:2014-06-17 22:20:06 : Orderby:4
Minecraft : xxx.xxx.xxx.xxx:25579 : Status:Offline : Timestamp:2014-06-17 22:20:13 : Orderby:5
Minecraft : xxx.xxx.xxx.xxx:25580 : Status:Offline : Timestamp:2014-06-17 22:20:20 : Orderby:6

End of the "Server List" 

Advance thanks for any help guys.  :pirate:

 

 

Link to comment
Share on other sites

Have you tried a simple test script to check the connection to the servers by simply just using:

$address = "tcp://www.example.com:80";
$timeout = 30;
if(!$fp = stream_socket_client($address, $errno, $errstr, $timeout))
{
echo $errstr . "(" . $errno . ")";
exit();
}
echo "ok";
Edited by neil.johnson
Link to comment
Share on other sites

As Neil suggests, I think the problem is almost assuredly with the get_status() method. That code is making a request of an external server and is being called in a loop for multiple servers. You have zero control over how long an external server will take to respond (or not respond if it is offline). You can implement a timeout on the request. But, then you have to decide how long that timeout should be. Too short and it may timeout before the server gets a chance to respond and too long, well the user will be sitting there waiting. I had the same problem with an internal tool for a status page I built to query multiple application servers we use.

 

For something like this, there are solutions. What solution you implement depends on your needs.

 

Option 1: Caching

Can you live with the results displayed being a little old (e.g. some period of time such as 5 minutes) or do they absolutely need to be right this second current. If they can be a little old, then you could implement a process as follows. 1) Create a page that queries all the servers, gets their current status, and then updates the database with that status. 2) Create a scheduled task to run that script every 5 minutes (or whatever length of time is acceptable). 3) For the page that users will access, just query the servers and their stored statuses and display them.

 

Option 2: AJAX

If you really want the data to be as current as possible when the user opens the page, I would suggest using AJAX. When the page loads, get the servers from the database and output them to the page. But. do not get their status. Instead, put a placeholder message such as "Retrieving status".  After the page loads, kick off requests via JavaScript to get the status of each server (each server should be a separate asynchronous request). As each response is returned back to the JavaScript, update the status value.

 

I have a critique on the get_status() method:

public function get_status($ServerIP,&$ServerPort)
{
    if(@stream_socket_client("tcp://$ServerIP:$ServerPort", $errno, $errstr, 5) !== false)
    {
        return "<strong style='color:#33CC00'>Online</strong>";
    }
    else
    {
        return "<strong style='color:#CC0000'>Offline</strong>";
    }
}
 
Ideally, you do not want to put the 'structure' of the output in the if/else conditions. For one, you may have a bug with one condition and not the other that becomes hard to find. Also, if you ever want to make a change on "how" the status is displayed you have to change both conditions. You should only define the differences and have one piece of code that creates the output. Well, to be really strict, the function to get the status should be completely decoupled from the process of creating the output entirely. I.e. it should only True/False and a separate process creates the output. But, I understand that sometimes doing that can seem counter-productive. But, I would at least do something like this:
 
public function get_status($ServerIP,&$ServerPort)
{
    $online = @stream_socket_client("tcp://$ServerIP:$ServerPort", $errno, $errstr, 5) ;
    //If you decouple the process of checking the status and creating the output
    //This function would just need to return the variable $online
    if($online!==false)
    {
        $statusText = 'Online';
        $statusColor = '#33CC00';
    }
    else
    {

        $statusText = 'Offline';
        $statusColor = '#CC0000';

    }
    return "<strong style='color:{$statusColor}'>{$statusText}</strong>";
}
Edited by Psycho
Link to comment
Share on other sites

Hi guys,

 

Thanks for replying.

 

@neil.johnson

 

I have tried a simple connection script, works fine. But again when multiple servers using that script run into the same trouble of waiting. The function works, just a slow process.

 

@Psycho

 

Option 1 sounds like the only option to do, though is there  a process function for php or does it require a session? Any suggestions on a process kept alive without a user present, that would be great ( Keeping in mind I am on a Windows box... I can hear you guys spewing up! ). I understand what you mean about the get_status() function, I will implement yours. Also agree that it seems long winded to process the output in another function.

 

Looking forward to hear what you guys suggest for live process without the human element.

 

Thank you for the great information and feed back.

 

 

 

Link to comment
Share on other sites

Wouldn't the best option be to combine both of Psycho's suggestions?

 

Store a list of servers in a database, along with the time they were last pinged and the status it returned (option 1).

 

Load the page without the server statuses, then use AJAX to run a SQL query, you can then check the ping time of each result and ping it again if needed. That way the page will load pretty fast and do all the heavy lifting in the background.

Link to comment
Share on other sites

Something else to consider
 

             $result = mysqli_query($con,"SELECT * FROM server_status.tbl_servers;")or die("Error: ".mysqli_error($con));;
             $message .= "" . $row['ssGameType'] . " : ";
             $message .= "" . $row['ssIP'] . ":" . $row['ssPort'] . " : ";
             $message .= " Status:" . $this->get_status($row['ssIP'],$row['ssPort']) . " : ";
             $message .= "Timestamp:" . $row['Timestamp'] . " : ";
             $message .= "Orderby:" . $row['ssOrder'] . "<br />";

You're selecting all fields and only using 5 of them.  Unless you only have five fields in your table, you should make the database do less work.

Link to comment
Share on other sites

  • Solution

Wouldn't the best option be to combine both of Psycho's suggestions?

 

Store a list of servers in a database, along with the time they were last pinged and the status it returned (option 1).

 

Load the page without the server statuses, then use AJAX to run a SQL query, you can then check the ping time of each result and ping it again if needed. That way the page will load pretty fast and do all the heavy lifting in the background.

 

I wouldn't do that. It makes no send to show the previous result if you are going to immediately refresh it. That assumes the user knows that the data that is initially loaded is old(er) data and will be update after X seconds. I think it all depends on how fresh the data needs to be. The OP stated he is fine with cached data so I'd go that route for now. No need to over-complicate with multiple thing at once anyway.

 

 

Option 1 sounds like the only option to do, though is there  a process function for php or does it require a session? Any suggestions on a process kept alive without a user present, that would be great ( Keeping in mind I am on a Windows box... I can hear you guys spewing up! ). I understand what you mean about the get_status() function, I will implement yours. Also agree that it seems long winded to process the output in another function.

 

Looking forward to hear what you guys suggest for live process without the human element.

 

Thank you for the great information and feed back.

 

Not sure what you are getting at with the question about sessions. On a Linux box you would use a CRON job. If you are on Windows and you have full rights on that box, then just set up a windows scheduled task. Set that task to 'execute' the PHP file. The command would look something like this

 

C:\Path\to\php.exe -f "C:\Path\to\file.php"

 

Here are the basic steps needed to implement this:

 

1. Add a new column to your table for status. I would also add another field called 'last_updated'. Make that one a timestamp with the optional configuration to auto-update with the current timestamp whenever the record is modified.

 

2. In the script to display the server to the user, be sure to include the new status field (list out only the fields you need in the SELECT query as Zane advised)

 

3. Create a new script called something like 'updateStatuses.php'. Have that script do the following: 1) Query the servers to be updated, 2) While looping through the results get the current status for each server and save the status to an array, 3) After processing all of the servers, run a single UPDATE query to update all the records with the current status

 

4. Create a scheduled tasks to run the above script at a specified interval

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.