我是一名自学成才的AS3/Flex/AIR开发人员,我已经构建了一个运行在AIR上的触摸屏kiosk系统,可以从在线Flex应用程序远程管理内容。
这是我第一次做服务器端的东西,所以如果需要的话,请随时纠正我的问题。
AIR应用和Flex应用都连接到mysql数据库,使用php脚本和Zend框架进行简单的CRUD操作。信息亭每隔30秒调用服务器进行更新。
所有这些简单的服务器端php脚本是由Flash Builder的数据向导自动生成的。我做了简单的调整(gateway.php, amf_config.ini, mysqli连接参数),并将所有内容部署到客户端的服务器上。这是一个共享服务器类型。
现在,系统工作了。但效果缓慢。每个创建/读取/更新/删除操作都工作,但我认为它应该快得多。此外,这些操作给服务器的cpu带来了很大的负载。根据托管人员的说法,这个系统打开的php-cgi进程占用了服务器40%的cpu功率,这样做会减慢服务器上托管的其他站点的速度。
我的问题是:
首先,是否一开始就有问题,或者Zend框架是否期望这种性能?自动生成的脚本写的Flash Builder写得很差,可以优化吗?这种类型的系统可以保留在共享托管服务器上吗?我们是否应该转移到VPS服务器以获得更好的性能?是否有可能,如果我在mysql数据库上使用phpmyadmin创建的表没有优化构建,它会对性能产生这种影响?
我不知道php或mysql。如能提供任何帮助,我将不胜感激。
萨尔河
这是Flash Builder编写的脚本:我没有添加任何东西-只是改变了连接参数。
<?php
class KiosksService {
var $username = "--------";
var $password = "--------";
var $server = "--------";
var $port = "3306";
var $databasename = "--------";
var $tablename = "kiosks";
var $connection;
/**
* The constructor initializes the connection to database. Everytime a request is
* received by Zend AMF, an instance of the service class is created and then the
* requested method is invoked.
*/
public function __construct() {
$this->connection = mysqli_connect(
$this->server,
$this->username,
$this->password,
$this->databasename,
$this->port
);
$this->throwExceptionOnError($this->connection);
}
/**
* Returns all the rows from the table.
*
* Add authroization or any logical checks for secure access to your data
*
* @return array
*/
public function getAllKiosks() {
$stmt = mysqli_prepare($this->connection, "SELECT * FROM $this->tablename");
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
$rows = array();
mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
while (mysqli_stmt_fetch($stmt)) {
$row->Pingdate = new DateTime($row->Pingdate);
$rows[] = $row;
$row = new stdClass();
mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
}
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
return $rows;
}
/**
* Returns the item corresponding to the value specified for the primary key.
*
* Add authorization or any logical checks for secure access to your data
*
*
* @return stdClass
*/
public function getKiosksByID($itemID) {
$stmt = mysqli_prepare($this->connection, "SELECT * FROM $this->tablename where KioskID=?");
$this->throwExceptionOnError();
mysqli_stmt_bind_param($stmt, 'i', $itemID);
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
if(mysqli_stmt_fetch($stmt)) {
$row->Pingdate = new DateTime($row->Pingdate);
return $row;
} else {
return null;
}
}
/**
* Returns the item corresponding to the value specified for the primary key.
*
* Add authorization or any logical checks for secure access to your data
*
*
* @return stdClass
*/
public function createKiosks($item) {
$stmt = mysqli_prepare($this->connection, "INSERT INTO $this->tablename (Station, Branch, Chain, Pingdate, Layout, Online, Clips, Extra) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$this->throwExceptionOnError();
mysqli_stmt_bind_param($stmt, 'sssssisi', $item->Station, $item->Branch, $item->Chain, $item->Pingdate->toString('YYYY-MM-dd HH:mm:ss'), $item->Layout, $item->Online, $item->Clips, $item->Extra);
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
$autoid = mysqli_stmt_insert_id($stmt);
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
return $autoid;
}
/**
* Updates the passed item in the table.
*
* Add authorization or any logical checks for secure access to your data
*
* @param stdClass $item
* @return void
*/
public function updateKiosks($item) {
$stmt = mysqli_prepare($this->connection, "UPDATE $this->tablename SET Station=?, Branch=?, Chain=?, Pingdate=?, Layout=?, Online=?, Clips=?, Extra=? WHERE KioskID=?");
$this->throwExceptionOnError();
mysqli_stmt_bind_param($stmt, 'sssssisii', $item->Station, $item->Branch, $item->Chain, $item->Pingdate->toString('YYYY-MM-dd HH:mm:ss'), $item->Layout, $item->Online, $item->Clips, $item->Extra, $item->KioskID);
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
}
/**
* Deletes the item corresponding to the passed primary key value from
* the table.
*
* Add authorization or any logical checks for secure access to your data
*
*
* @return void
*/
public function deleteKiosks($itemID) {
$stmt = mysqli_prepare($this->connection, "DELETE FROM $this->tablename WHERE KioskID = ?");
$this->throwExceptionOnError();
mysqli_stmt_bind_param($stmt, 'i', $itemID);
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
}
/**
* Returns the number of rows in the table.
*
* Add authorization or any logical checks for secure access to your data
*
*
*/
public function count() {
$stmt = mysqli_prepare($this->connection, "SELECT COUNT(*) AS COUNT FROM $this->tablename");
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
mysqli_stmt_bind_result($stmt, $rec_count);
$this->throwExceptionOnError();
mysqli_stmt_fetch($stmt);
$this->throwExceptionOnError();
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
return $rec_count;
}
/**
* Returns $numItems rows starting from the $startIndex row from the
* table.
*
* Add authorization or any logical checks for secure access to your data
*
*
*
* @return array
*/
public function getKiosks_paged($startIndex, $numItems) {
$stmt = mysqli_prepare($this->connection, "SELECT * FROM $this->tablename LIMIT ?, ?");
$this->throwExceptionOnError();
mysqli_stmt_bind_param($stmt, 'ii', $startIndex, $numItems);
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
$rows = array();
mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
while (mysqli_stmt_fetch($stmt)) {
$row->Pingdate = new DateTime($row->Pingdate);
$rows[] = $row;
$row = new stdClass();
mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
}
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
return $rows;
}
/**
* Utility function to throw an exception if an error occurs
* while running a mysql command.
*/
private function throwExceptionOnError($link = null) {
if($link == null) {
$link = $this->connection;
}
if(mysqli_error($link)) {
$msg = mysqli_errno($link) . ": " . mysqli_error($link);
throw new Exception('MySQL Error - '. $msg);
}
}
}
?>
虽然Zend框架的性能可能有点问题,但在您的示例中没有Zend框架代码。
这个系统打开了6个php-cgi进程
对于每个操作?这似乎不太可能。如果您提供一个访问日志的示例,显示一个典型的事务,以及他们提供的支持此断言的证据,将会很有帮助。
通过cgi运行php是一个非常糟糕的主意如果你在一点点关心性能(或者你的服务器机房有多热)。使用mod_php或php-fpm,甚至php通过fcgi与操作码缓存将减少执行时间超过75%。
查看代码,这里没有明显的错误——除了getkiosks_page——在没有显式ORDER BY的情况下进行行范围选择是非常草率的。
每个创建/读取/更新/删除操作都可以工作,但我认为它应该快得多
它有多快?请求在web服务器上的时间有多长,它执行了哪些查询?要花多长时间?数据库的结构是什么?查询的解释计划是什么样的?
我不能评论Zend框架,因为我从未使用过它。
CGI总是比快速CGI慢,更好的是,mod_php或类似的东西。当你使用CGI时,每次解释器启动和脚本完成后,所有的东西都被删除。
当你使用快速CGI或PHP模块时,web服务器模块可以维护一些状态,比如数据库连接,跨调用。