解决MySql “Host is blocked because of many connection error” 的问题

解决MySql “Host is blocked because of many connection error” 的问题

      这些天,连接MySql出现了

     Host is blocked because of many connection error” In MySQL的问题,从网上搜索了一些解决方式,现记录如下:

Today, I got following MySQL error in a PHP application: Host ‘host_name’ is blocked because of many connection errors; unblock with ‘mysqladmin flush-hosts’. It means that mysqld has received many connection requests from the given host. Default max_connect_errors value is 10, that is remote host will be blocked if there is more than 10 connection errors.

To fix, type the following command

# mysqladmin flush-hosts

To avoid this happening again, edit my.cnf

# vi /etc/my.cnf

Add the following line

max_connect_errors=10000

The value of the max_connect_errors system variable determines how many successive interrupted connection requests are permitted. Restart MySQL to reload configuration file

# service mysqld restart

Or, the value ‘max_connect_errors’ can also be set at runtime, type the following commands

# mysql -uroot -p
# mysql> SET GLOBAL max_connect_errors=10000;

activeMQ+stomp+php实现消息队列

一、ActiveMQ的安装与配置

1、安装JDK

2、安装ActiveMQ

wget http://mirror.esocc.com/apache/activemq/apache-activemq/5.8.0/apache-activemq-5.8.0-bin.tar.gz

3、配置ActiveMQ,使其支持stomp

在配置文件/usr/local/activemq/conf/activemq.xml,添加

<transportConnectors>
<!– DOS protection, limit concurrent connections to 1000 and frame size to 100MB –>
<transportConnector name=”openwire” uri=”tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600″/>
<transportConnector name=”amqp” uri=”amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600″/>
<transportConnector name=”stomp” uri=”stomp://localhost:61613″/>
</transportConnectors>

4、启动ActiveMQ

/usr/local/activemq/bin/activemq start

二、安装php的stomp扩展

查看最新的stomp

http://pecl.php.net/package/stomp

wget http://pecl.php.net/get/stomp-1.0.5.tgz

tar -zxf  stomp-1.0.5.tgz

/usr/bin/phpize5

./configure –enable-stomp –with-php-config=/usr/bin/php-config5

make & make install

在php.ini中添加

extension = stomp.so

三、php—实现定时从消息队列里取出数据

从队列里取出数据(此程序以守护进行的方式运行),代码如下:

<?php
/**
* ActiveMQ Client
*
* @author yiluxiangbei<2498038528@qq.com>
*/

class MessageQueueApp extends BaseAppEx
{

/**
* Default prefetch size
*
* @var int
*/
public $prefetchSize = 1000;
/**
* sleep of time (unit sencond)
*
* @var int
*/
private $_sleepIntval = 60;

private $_stomp    = null;

private $_mysqli   = null;

public function run()
{
while(true){
try{
//connecting database
try {
} catch (Exception $ex) {
die(‘MySQL connection failed: ‘.$ex->getMessage());
}
//connecting activemq
try {
$this->_stomp = new Stomp($this->conf[‘MessageQueue’][‘stompUri’]);
} catch (StompException $e) {
die(‘Connection failed: ‘.$e->getMessage());
}

$this->_stomp->subscribe($this->conf[‘MessageQueue’][‘queueUri’], array(‘activemq.prefetchSize’ => $this->prefetchSize));

$frame = null;
$data = array();
while (TRUE == $this->_stomp->hasFrame())
{
$temp = array();
$frame = $this->_stomp->readFrame();
if (FALSE !== $frame)
{
//file_put_contents(ROOT_PATH.’/cache/MQ’, $frame->body.”\n”, FILE_APPEND);
//operate dataBase
$temp = json_decode($frame->body, true);

$data = array_merge($data, $temp);

$this->_stomp->ack($frame);

} else {
continue;
}
}

$result = $this->_handleData1($data);

}catch (Exception $e){
echo “Exception is: “.$e->getMessage().”\n\n”;
}
echo “Statistic Over, {$this->_sleepIntval} seconds to next statistics..\n\n”;
$this->_stomp->unsubscribe($this->conf[‘MessageQueue’][‘queueUri’]);
unset($this->_stomp);
$this->_mysqli->close();
sleep($this->_sleepIntval);
}
}

/*
* data to store(The three table is not related)
*
* @param data array
* @return result bool
*/
private function _handleData1($data)
{
$insert_1 = “INSERT INTO `msg1`(`info`, `time`) VALUES”;
$insert_2 = “INSERT INTO `msg2`(`relateId`, `info`, `time`) VALUES”;
$insert_3 = “INSERT INTO `msg3`(`relateId`, `info`, `time`) VALUES”;
$count = count($data);

if (!empty($data)) {
$i = 0;
foreach ($data as $randId => $val) {
if ($i == 0) {
$insert_1 = $insert_1.”(‘{$val[0][0]}’, ‘{$val[0][1]}’)”;
$insert_2 = $insert_2.”(2, ‘{$val[1][0]}’, ‘{$val[1][1]}’)”;
$insert_3 = $insert_3.”(3, ‘{$val[2][0]}’, ‘{$val[2][1]}’)”;
} else {
$insert_1 = $insert_1.”,(‘{$val[0][0]}’, ‘{$val[0][1]}’)”;
$insert_2 = $insert_2.”,(2, ‘{$val[1][0]}’, ‘{$val[1][1]}’)”;
$insert_3 = $insert_3.”,(3, ‘{$val[2][0]}’, ‘{$val[2][1]}’)”;
}

$i++;
}
}
//echo $insert_1,PHP_EOL;
//echo $insert_2,PHP_EOL;
//echo $insert_3,PHP_EOL;
$success = TRUE;
$this->_mysqli->autocommit(0);

$this->_mysqli->query($insert_1);
echo $this->_mysqli->affected_rows,PHP_EOL;
if ($count != $this->_mysqli->affected_rows) {
$success = FALSE;
}

$this->_mysqli->query($insert_2);
echo $this->_mysqli->affected_rows,PHP_EOL;
if ($count != $this->_mysqli->affected_rows) {
$success = FALSE;
}

$this->_mysqli->query($insert_3);
echo $this->_mysqli->affected_rows,PHP_EOL;
if ($count != $this->_mysqli->affected_rows) {
$success = FALSE;
}

if ($success) {
$this->_mysqli->commit();
} else {
$this->_mysqli->rollback();
}

$this->_mysqli->autocommit(1);

}

/*
* data to store(The three table is related)
*
* @param data array
* @return result bool
*/
private function _handleData($data)
{
$this->_mysqli->commit();
} else {
$this->_mysqli->rollback();
}

$this->_mysqli->autocommit(1);

}

/*
* data to store(The three table is related)
*
* @param data array
* @return result bool
*/
private function _handleData($data)
{
$success = TRUE;

$this->_mysqli->autocommit(0);

$insert_1 = “INSERT INTO `msg1`(`info`, `time`) VALUES(‘{$data[0][0]}’, ‘{$data[0][1]}’)”;
$result1 = $this->_mysqli->query($insert_1);
if (!$result1 || $this->_mysqli->affected_rows!=1) {
$success = FALSE;
}

$relateId = $this->_mysqli->insert_id;

$insert_2 = “INSERT INTO `msg2`(`relateId`, `info`, `time`) VALUES({$relateId},'{$data[1][0]}’,'{$data[1][1]}’)”;
$result2  = $this->_mysqli->query($insert_2);
if (!$result2 || $this->_mysqli->affected_rows!=1) {
$success = FALSE;
}

$insert_3 = “INSERT INTO `msg3`(`relateId`, `info`, `time`) VALUES({$relateId},'{$data[2][0]}’,'{$data[2][1]}’)”;
$result3  = $this->_mysqli->query($insert_3);
if (!$result3 || $this->_mysqli->affected_rows!=1) {
$success = FALSE;
}

if ($success) {
$this->_mysqli->commit();
} else {
$this->_mysqli->rollback();
}

$this->_mysqli->autocommit(1);

return $success;
}
}
?>

将数据插入队列中

<?php
class DebugApp extends BaseAppEx
{
/**
* test
*/

public function index()
{

$randId = uniqid();
$time = date(‘Y-m-d H:i:s’, time());

$data = array();

$data[$randId][0] = array(‘msg1’, $time);
$data[$randId][1] = array(‘msg2’, $time);
$data[$randId][2] = array(‘msg3’, $time);

$data = json_encode($data);

$this->_sendMQ($data);
}
private function _sendMQ($data)
{
try {
$stomp = new Stomp($this->conf[‘MessageQueue’][‘stompUri’]);
} catch (StompException $e) {
//die(‘Connection failed: ‘.$e->getMessage());
throw new Exception($e->getMessage());
}

if (empty($data)) {
throw new Exception(‘Parameter must not be empty!’);
}

$isSucc = $stomp->send($this->conf[‘MessageQueue’][‘queueUri’], $data, array(‘persistent’ => ‘true’));
if (false == $isSucc)
{
throw new Exception(“$data send failed!”);
}

unset($stomp);
}
}
?>

四、参考资料

http://activemq.apache.org/

http://activemq.apache.org/version-5-getting-started.html

http://activemq.apache.org/examples.html

http://activemq.apache.org/contributing.html

ActiveMQ+In+Action.pdf

Linux 下 strace 命令用法总结

Linux 下 strace 命令用法总结

1 功能说明
strace 命令是一种强大的工具, 能够显示任何由用户空间程式发出的系统调用. strace 显示这些调用的参数并返回符号形式的值. strace 从内核接收信息, 而且无需以任何特别的方式来构建内核. strace 的每一行输出包括系统调用名称, 然后是参数和返回值.

下面记录几个常用option:

-f -F选项告诉strace同时跟踪fork和vfork出来的进程

-o xxx.txt 输出到某个文档.

-e execve 只记录 execve 这类系统调用.

2 详细用法
usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] … [-o file]

[-p pid] … [-s strsize] [-u username] [-E var=val] …

[command [arg …]]

or: strace -c [-e expr] … [-O overhead] [-S sortby] [-E var=val] …

[command [arg …]]

-c — count time, calls, and errors for each syscall and report summary

-f — follow forks, -ff — with output into separate files

-F — attempt to follow vforks, -h — print help message

-i — print instruction pointer at time of syscall

-q — suppress messages about attaching, detaching, etc.

-r — print relative timestamp, -t — absolute timestamp, -tt — with usecs

-T — print time spent in each syscall, -V — print version

-v — verbose mode: print unabbreviated argv, stat, termio[s], etc. args

-x — print non-ascii strings in hex, -xx — print all strings in hex

-a column — alignment COLUMN for printing syscall results (default 40)

-e expr — a qualifying expression: option=[!]all or option=[!]val1[,val2]…

options: trace, abbrev, verbose, raw, signal, read, or write

-o file — send trace output to FILE instead of stderr

-O overhead — set overhead for tracing syscalls to OVERHEAD usecs

-p pid — trace process with process id PID, may be repeated

-s strsize — limit length of print strings to STRSIZE chars (default 32)

-S sortby — sort syscall counts by: time, calls, name, nothing (default time)

-u username — run command as username handling setuid and/or setgid

-E var=val — put var=val in the environment for command

-E var — remove var from the environment for command

3 参数说明
-c 统计每一系统调用的所执行的时间,次数和出错的次数等.

-d 输出strace关于标准错误的调试信息.

-f 跟踪由fork调用所产生的子进程.

-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.

-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.

-h 输出简要的帮助信息.

-i 输出系统调用的入口指针.

-q 禁止输出关于脱离的消息.

-r 打印出相对时间关于每一个系统调用.

-t 在输出中的每一行前加上时间信息.

-tt 在输出中的每一行前加上时间信息,微秒级.

-ttt 微秒级输出,以秒了表示时间.

-T 显示每一调用所耗的时间.

-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.

-V 输出strace的版本信息.

-x 以十六进制形式输出非标准字符串.

-xx 所有字符串以十六进制形式输出.

-a column 设置返回值的输出位置.默认 为40.

-e expr 指定一个表达式,用来控制如何跟踪.格式如下:

[qualifier=][!]value1[,value2]…

qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其它调用.有两个特殊的符号 all 和 none. 注意有些shell使用!来执行历史记录里的命令,所以要使用\\.

-e trace=set 只跟踪指定的系统调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.

-e trace=file 只跟踪有关文件操作的系统调用.

-e trace=process 只跟踪有关进程控制的系统调用.

-e trace=network 跟踪与网络有关的所有系统调用.

-e strace=signal 跟踪所有与系统信号有关的系统调用.

-e trace=ipc 跟踪所有与进程通讯有关的系统调用.

-e abbrev=set 设定strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.

-e raw=set 将指定的系统调用的参数以十六进制显示.

-e signal=set 指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.

-e read=set 输出从指定文件中读出的数据.例如-e read=3,5

-e write=set 输出写入到指定文件中的数据.

-o filename 将strace的输出写入文件filename

-p pid 跟踪指定的进程pid.

-s strsize 指定输出的字符串的最大长度.默认为32.文件名一直全部输出.

-u username 以username 的UID和GID执行被跟踪的命令.
3 用strace调试程序

在理想世界里, 每当一个程序不能正常执行一个功能 时, 它就会给出一个有用的错误提示, 告诉在足够的改正错误的线索. 但遗憾的是, 我们不是生活在理想世界里, 起码不总是生活在理想世界里. 有时 候一个程序出现了问题, 无法找到原因. 这就是调试程序出现的原因. strace是一个必不可少的调试工具, strace用来监视系统调用. 不仅 可以调试一个新开始的程序, 也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上 面).

首先让我们看一个真实的例子:

启动KDE时出现问题, 前一段时间, 我在启动KDE的时候出了问题, KDE 的错误信息无法给我任何有帮助的线索.
_KDE_IceTransSocketCreateListener: failed to bind listener
_KDE_IceTransSocketUNIXCreateListener: …SocketCreateListener() failed
_KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local

Cannot establish any listening sockets DCOPServer self-test failed.

对我来说这个错误信息没有太多意义, 只是一个对KDE 来说至关重要的负责进程间通信的程序无法启动. 我还可以知道这个错误和ICE协议(Inter Client Exchange)有关, 除此之 外, 我不知道什么是KDE启动出错的原因. 我决定采用strace看一下在启动 dcopserver时到底程序做了什么:
strace -f -F -o ~/dcop-strace.txt dcopserver

这里 -f -F选项告诉strace同时跟踪fork 和vfork出来的进程, -o选项把所有strace输出写到~/dcop-strace.txt里 面, dcopserver是要启动和调试的程 序. 再次出现错误之后, 我检查了错误输出文件dcop-strace.txt, 文件里有很多系统调用的记录. 在程序运行出错前的有关记录如下:

其中第一行显示程序试图创建/tmp/.ICE- unix目录, 权限为0777, 这个操作因为目录已经存在而失败了. 第二个系统调用(lstat64)检查了目录状态, 并显示这个目录的权限是 0755, 这里出现了第一个程序运行错误的线索: 程序试图创建属性为0777的目录, 但是已经存在了一个属性为 0755的目录. 第三个系统调用 (unlink)试图删除一个文件, 但是这个文件并不存在. 这并不奇怪, 因为这个操作只是试图删掉可能存在的老文件.

但是, 第四行确认了错误所在. 它试图绑定到/tmp /.ICE-unix/dcop27207-1066844596, 但是出现了拒绝访问错误. ICE_unix目录的用户和组都是root, 并且只 有所有者具有写权限. 一个非root用户无法在这个目录下面建立文件, 如果把目录属性改成0777,  则前面的操作有可能可以执行, 而这正是第一 步错误出现时进行过的操作.

所以我运行了chmod 0777 /tmp /.ICE-unix之后KDE就可以正常启动了, 问题解决了, 用strace进行跟踪调试只需要花很短的几分钟时间跟踪程序运行, 然后检查并分析 输出文件.

说明: 运行chmod 0777只是一个测试, 一般 不要把一个目录设置成所有用户可读写, 同时不设置粘滞位(sticky bit). 给目录设置粘滞位可以阻止一个用户随意删除可写目录下面其它人的文 件. 一般会发现/tmp目录因为这个原因设置了粘滞位. KDE可以正常启动之后, 运行chmod +t /tmp/.ICE-unix 给.ICE_unix设置粘滞位.

2 用strace解决库依赖问题
starce 的另一个用处是解决和动态库相关的问题. 当对一个可执行文件运行ldd 时, 它会告诉程序使用的动态库和找到动态库的位置. 但是如果正在使用一个比较老的glibc版本(2.2或更早), 可能会有一个有bug的ldd程 序, 它可能会报告在一个目录下发现一个动态库, 但是真正运行程序时动态连接程序 (/lib/ld-linux.so.2)却可能到另外一个目录去找 动态连接库. 这通常因为/etc/ld.so.conf和 /etc/ld.so.cache文件不一致, 或者/etc/ld.so.cache被破 坏. 在glibc 2.3.2版本上这个错误不会出现, 可能ld-linux的这个bug已经被解决了.

尽管这样, ldd并不能把所有程序依赖的动态库列出 来, 系统调用dlopen可以在需要的时候自动调入需要的动态库, 而这些库可能不会被ldd列出来. 作为glibc的一部分的 NSS(Name Server Switch)库就是一个典型的例子, NSS的一个作用就是告诉应用程序到哪里去寻找系统帐号数据库. 应用程序不会 直接连接到NSS库, glibc则会通 过dlopen自动调入NSS库. 如果这样的库偶然丢失, 不会被告知存在库依赖问题, 但这样的程序就无法 通过用户名解析得到用户ID了.

让我 们看一个例子:

whoami程序会给出自己的用户名, 这个程序在一些 需要知道运行程序的真正用户的脚本程序里面非常有用, whoami的一个示 例输出如下:
27207 mkdir(“/tmp/.ICE-unix”, 0777) = -1 EEXIST (File exists)
27207 lstat64(“/tmp/.ICE-unix”, {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096, …}) = 0
27207 unlink(“/tmp/.ICE-unix/dcop27207-1066844596″) = -1 ENOENT (No such file or directory)
27207 bind(3, {sin_family=AF_UNIX, path=”/tmp/.ICE-unix/dcop27207-1066844596”}, 38) = -1 EACCES (Permission denied)
27207 write(2, “_KDE_IceTrans”, 13) = 13
27207 write(2, “SocketCreateListener: failed to “…, 46) = 46
27207 close(3) = 0 27207 write(2, “_KDE_IceTrans”, 13) = 13
27207 write(2, “SocketUNIXCreateListener: …Soc”…, 59) = 59
27207 umask(0) = 0 27207 write(2, “_KDE_IceTrans”, 13) = 13
27207 write(2, “MakeAllCOTSServerListeners: fail”…, 64) = 64
27207 write(2, “Cannot establish any listening s”…, 39) = 39

假设因为某种原因在升级 glibc的过程中负责用户名 和用户ID转换的库NSS丢失, 我们可以通过把nss库改名来模拟这个环境:
# whoami
root

这里可以看到, 运行whoami时出现了错 误, ldd程序的输出不会提供有用的帮助:

只会看到whoami依赖Libc.so.6和ld-linux.so.2, 它没有给出运行 whoami所必须的其它库. 这里时用strace跟踪 whoami时的输出:
# mv /lib/libnss_files.so.2 /lib/libnss_files.so.2.backup
# whoami
whoami: cannot find username for UID 0

可以发现在不同目录下面查找libnss.so.2的尝 试, 但是都失败了. 如果没有strace这样的工具, 很难发现这个错误是由于缺少动态库造成的. 现在只需要找到libnss.so.2并把它放回 到正确的位置就可以了.

3 限制strace只跟踪特定的系统调用
如果 已经知道要找什么, 可以让strace只跟踪一些类型的系统调用. 例如, 需要看看在configure脚本里面执行的程序, 需要监视的系统调用就 是execve. 让strace只记录execve的调用用这个命令:
# ldd /usr/bin/whoami
libc.so.6 => /lib/libc.so.6 (0x4001f000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

部分输出结果为:

已经看到了, strace不仅可以被程序员使用, 普 通系统管理员和用户也可以使用strace来调试系统错误. 必须承认, strace的输出不总是容易理解, 但是很多输出对大多数人来说是不重要 的. 会慢慢学会从大量输出中找到可能需要的信息, 像权限错误, 文件未找到之类的, 那时strace就会成为一个有力的工具了.

gearman + php

向一个机器添加Gearman需要两步:

1.构建并启动这个守护进程

2.构建与php(或Python等)版本相匹配的PHP扩展。

我安装版本是Gearman 1.1.5:

1. 安装依赖包:

sudo apt-get update

sudo apt-get upgrade
sudo apt-get install gcc autoconf bison flex libtool make libboost-all-dev libcurl4-openssl-dev curl libevent-dev memcached uuid-dev libsqlite3-dev libmysqlclient-dev

2.下载Gearman版本

wget https://launchpad.net/gearmand/1.2/1.1.5/+download/gearmand-1.1.5.tar.gz

3.解压、编译、安装源码包

tar xvzf gearmand-1.1.5.tar.gz
cd gearmand-1.1.5
./configure
make
make install

注:这个过程中可能无法编译成功,这时候要根据个人实际情况,看它报的是什么错,然后根据报错,更新或者安装共享库。

sudo apt-get install ***等。

4.为大多数最新的共享库创建必须的链接和缓存。其中可能报:

error: gearman: error while loading shared libraries: libgearman.so.6: cannot open shared object file: No such file or directory

解决办法:sudo ldconfig

5.通过pecl安装gearman

sudo apt-get install php-pear
sudo pecl install gearman
sudo gedit /etc/php5/cgi/php.ini

注:有些版本的php.ini可能不在/etc/php5/cgi/这个路径下,我的是在/etc/php5/cli/这个路径下。

另外,可能你的机器上没安装php5这个工具,如果没安装的话,可以直接通过在先安装:sudo apt-get install php5

如果上面的方法无法安装gearman的php扩展,可以尝试下下面方法:

$ wget http://pecl.php.net/get/gearman-1.1.1.tgz
$ tar zxvf gearman-1.0.2.tgz
$ cd gearman-1.0.2/
$ phpize
$ make
$ make install
$ sudo echo “extension = gearman.so” > /etc/php5/conf.d/gearman.ini

6. 在php.ini文件末尾添加”extension=gearman.so”

7. 检测扩展是否安装成功

$ php –info | grep “gearman support”
gearman support => enabled

显示出:gearman support => enabled,就表示安装成功啦。

8 测试

1)sudo ldconfig

2)启动gearmand: gearmand -d &

这一步可能会遇到:

启动这个 agent,即 Gearman 守护程序:
/usr/local/sbin/gearmand –daemon
报错:Could not open log file “/usr/local/var/log/gearmand.log”, from “/usr/sbin”, switching to stderr. (No such file or directory)
解决:
mkdir -p /usr/local/var/log/
cd /usr/local/var/log/
touch gearmand.log
再次尝试启动:
/usr/local/sbin/gearmand –daemon
成功运行.查看进程:ps -ef | grep gearmand
root     19390     1  0 17:50 ?        00:00:00 gearmand –daemon
root     19403     1  0 17:54 ?        00:00:00 /usr/local/sbin/gearmand –daemon
root     19406  1556  0 17:54 pts/3    00:00:00 grep gearmand

3)查看gearmand是否在运行:ps auxw | grep [g]earmand

4)检查germand的任务检测端口4730:sudo lsof -i tcp:4730

9.例子:从PHP使用Gearman

=====================================================

从 PHP 使用 Gearman 类似于之前的示例,惟一的区别在于这里是在 PHP 内创建 producer 和 consumer。
每个 consumer 的工作均封装在一个或多个 PHP 函数内。
先用 PHP 编写的一个 Gearman worker。将这些代码保存在一个名为 worker.php 的文件中。
<?php
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction(“title”, “title_function”);
while ($worker->work());

function title_function($job)
{
return ucwords(strtolower($job->workload()));
}
?>

再用 PHP 编写的一个 producer,或 client。将此代码保存在一个名为 client.php 的文件内。
<?php
$client= new GearmanClient();
$client->addServer();
print $client->do(“title”, “All The World’s a stage!”);
print “\n”;
?>

现在,可以用如下的命令行连接客户机与 worker 了:
php worker.php &
php client.php
结果:
All The World’s a stage!

10. 对上面的例子中代码的一些分析:

首先, PHP Gearman Extension 提供了一个名为 GearmanClient 的类别,它可以让程式安排工作给 Job Server 。而 addServer 方法表示要通知的是哪些 Job Server ,也就是说如果有多台 Job Server 的话,就可以透过 addServer 新增。然后我们将要呼叫哪个 Worker 以及该 Worker 所需要的资料,利用 GearmanClient 的 doBackground 方法传送过去。 doBackground 方法顾名思义就是在背景执行, Client 在丢出需求后就可以继续处理其他的程式,也就是我们常说的「射后不理」。
doBackground 方法的第一个参数是告诉 Job Server 要执行哪个功能,而这个功能则是由 Worker 提供的;要注意是,这个参数只是识别用的,并不是真正的函式名称。而第二个参数是要传给 Worker 的资料,它必须是个字串;因此如果要传送的是阵列的话,我们就要用 PHP 的 serialize 函式来对这些资料做序列化。
PHP 的 Gearman Extension 也提供了一个 GearmanWorker 类别,让我们可以实作 Worker 。而 GearmanWorker 类别也提供了addServer 方法,让所生成的 Worker 物件可以注册到 Job Server 中。
另外 GearmanWorker 类别也提供了 addFuncton 方法,告诉 Job Server 自己可以处理哪些工作。 addFunction 的第一个参数就是对应到 GearmanClient::doBackground 方法的第一个参数,也就是功能名称;这使得 Client 和 Worker 能透过这个名称来互相沟通。而第二个参数则是一个callback函式,它会指向真正应该要处理该工作的函式或类别方法等。
最后因为 Worker 因为要随时准备服务,是不能被中断的,因此我们透过一个无限迴圈来让它常驻在 Job Server 中。

 

 

 

已守护进程运行worker.php

# nohup php -c /usr/local/php/etc/php.ini worker.php >/dev/null 2>&1 &


这里,有几点需要说明一下:
1、这里直接用php cli方式运行,添加-c参数是为了加载php.ini配置文件,以加载gearman扩展
2、worker应该做成守护进程(CLI模式),可以开启多个,这样client发起的任务就会分发到各个worker分别来执行(自动负载均衡 )
这个例子由于太过简单,即使开启多个worker也无法看出效果,不过可以通过终止其中一个,可以看出系统自动切换到其他worker继续正常执行
3、同理,client也是可以开启多个的(模型请参考之前的那边日志)

4、同时,job也可以开启多个,以避免单点故障

php-fpm常用操作命令

查看php运行目录命令:
which php
/usr/bin/php

查看php-fpm进程数:
ps aux | grep -c php-fpm

查看运行内存
/usr/bin/php  -i|grep mem

重启php-fpm
/etc/init.d/php-fpm restart

在phpinfo()输出内容可以看到php相关配置。
Loaded Configuration File /etc/php.ini

==============================

首先要找到php-fpm.conf配置文件,查看pid的配置路径(不是安装路径),然后把下面对应的地方改掉才能正常执行。

[root@DO-SG-H1 ~]# ps aux | grep php-fpm
root     11799  0.0  0.0 103248   880 pts/0    S+   13:51   0:00 grep –color php-fpm
root     11973  0.0  0.0 417748   964 ?        Ss   Jun01   0:20 php-fpm: master process (/etc/php-fpm.conf)

cat /etc/php-fpm.conf
看到
pid = /var/run/php-fpm/php-fpm.pid

php-fpm 启动:
/usr/local/php/sbin/php-fpm
php-fpm 关闭:
kill -INT `cat /var/run/php-fpm/php-fpm.pid`
php-fpm 重启:
kill -USR2 `cat /var/run/php-fpm/php-fpm.pid`

查看php-fpm进程数:
ps aux | grep -c php-fpm

=============================

[root@DO-SG-H1 ~]# find / -name ‘php-fpm’ -type d
/var/log/php-fpm
/var/run/php-fpm

用这个find命令查找出来的路径是不对的

which php
/usr/bin/php

 

 

 

杀死所有PHP进程

ps -ef | grep pure-ftpd | grep -v grep | awk ‘{print $2″ “$3}’ | xargs kill -9 = pkill php

docker 入门

1、安装(centos)

yum -y istall docker.io

2、启动

service docker start

3、加入开机启动

chkconfig docker on

4、下载镜像

docker pull centos

5、查看已下载镜像

docker images

6、启动一个容器

docker run -i -t –name=’your name’ centos /bin/bash

7、删除镜像

docker rm image_id

8、查看所有镜像

docker ps -a

9、开启一个容器

docer start contarner

 

 

Centos搭建PHP5.3.28+Nginx1.0.9+Mysql5.5.17

安装依赖库和开发环境

 

#依赖库和开发工具
yum -y install gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers

#Nginx
yum -y install pcre-devel  zlib-devel

#Php
yum -y install gd-devel libjpeg-devel libpng-devel freetype-devel libxml2-devel curl-devel freetype-devel
 
#Mysql
yum -y install bison gcc gcc-c++ autoconf automake zlib* libxml* ncurses-devel libtool-ltdl-devel* mysql-devel

 

下载软件包

 

#创建目录
mkdir /web 
cd /web 
 
#PHP5.3.7 
wget http://cn.php.net/distributions/php-5.3.8.tar.bz2 
#PHP库文件
wget http://ncu.dl.sourceforge.net/project/mcrypt/MCrypt/2.6.8/mcrypt-2.6.8.tar.gz
wget http://ncu.dl.sourceforge.net/project/mhash/mhash/0.9.9.9/mhash-0.9.9.9.tar.gz
wget http://ncu.dl.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.gz
wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz

#Nginx1.0.9
wget http://www.nginx.org/download/nginx-1.0.9.tar.gz

#Nginx(pcre)
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.13.tar.gz

#Mysql5.5.17
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.17.tar.gz/from/http://mysql.ntu.edu.tw/

#Mysql(cmake)
wget http://www.cmake.org/files/v2.8/cmake-2.8.6.tar.gz

安装Mysql

#安装cmake
tar -zxvf cmake-2.8.6.tar.gz
cd cmake-2.8.6/
./configure
gmake && gmake install  && cd ../

#添加mysql用户
/usr/sbin/groupadd mysql
/usr/sbin/useradd -g mysql mysql
mkdir -p /data/mysql
chown -R mysql:mysql /data/mysql

#安装Mysql
tar -zxvf mysql-5.5.17.tar.gz
cd mysql-5.5.17
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/mysql -DSYSCONFDIR=/etc/
make && make install

#设置Mysql
#在support-files目录中有五个配置信息文件:
#my-small.cnf (内存<=64M)
#my-medium.cnf (内存 128M)
#my-large.cnf (内存 512M)
#my-huge.cnf (内存 1G-2G)
#my-innodb-heavy-4G.cnf (内存 4GB)
cd /usr/local/mysql
cp ./support-files/my-medium.cnf /etc/my.cnf 
vi /etc/my.cnf
#在 [mysqld] 段增加
datadir = /data/mysql
wait-timeout = 30
max_connections = 512
default-storage-engine = MyISAM
#在 [mysqld] 段修改
max_allowed_packet = 16M 

#生成授权表
cd /usr/local/mysql
./scripts/mysql_install_db --user=mysql

#更改密码
/usr/local/mysql/bin/mysqladmin -u root password 123456

#开启mysql
/usr/local/mysql/bin/mysqld_safe &

#测试连接mysql
/usr/local/mysql/bin/mysql -u root -p 123456
show databases;
exit;

#设置开机启动
vi /etc/rc.d/rc.local

#加入
/usr/local/mysql/bin/mysqld_safe &

 

安装PHP

 

#1
tar -zxvf libiconv-1.14.tar.gz && cd libiconv-1.14/
./configure --prefix=/usr/local
make && make install && cd ../

#2
tar -zxvf libmcrypt-2.5.8.tar.gz && cd libmcrypt-2.5.8/
./configure &&  make && make install
/sbin/ldconfig && cd libltdl/ && ./configure --enable-ltdl-install
make && make install && cd ../

#3
tar -zxvf mhash-0.9.9.9.tar.gz && cd mhash-0.9.9.9/ && ./configure
make && make install && cd ../

#4
ln -s /usr/local/lib/libmcrypt.la /usr/lib/libmcrypt.la
ln -s /usr/local/lib/libmcrypt.so /usr/lib/libmcrypt.so
ln -s /usr/local/lib/libmcrypt.so.4 /usr/lib/libmcrypt.so.4
ln -s /usr/local/lib/libmcrypt.so.4.4.8 /usr/lib/libmcrypt.so.4.4.8
ln -s /usr/local/lib/libmhash.a /usr/lib/libmhash.a
ln -s /usr/local/lib/libmhash.la /usr/lib/libmhash.la
ln -s /usr/local/lib/libmhash.so /usr/lib/libmhash.so
ln -s /usr/local/lib/libmhash.so.2 /usr/lib/libmhash.so.2
ln -s /usr/local/lib/libmhash.so.2.0.1 /usr/lib/libmhash.so.2.0.1
ln -s /usr/local/bin/libmcrypt-config /usr/bin/libmcrypt-config

#5
tar -zxvf mcrypt-2.6.8.tar.gz &&cd mcrypt-2.6.8/
/sbin/ldconfig
./configure
make && make install && cd ../

#6
tar -xjvf php-5.3.8.tar.bz2 
cd php-5.3.8

./configure --prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--with-iconv-dir=/usr/local/ --with-freetype-dir \
--with-mysql=/usr/local/mysql \
--with-mysqli=/usr/local/mysql/bin/mysql_config \
--with-jpeg-dir --with-png-dir --with-zlib \
--with-mhash --enable-sockets --enable-ftp \
--with-libxml-dir --enable-xml --disable-rpath \
--enable-safe-mode --enable-bcmath \
--enable-shmop --enable-sysvsem \
--enable-inline-optimization --with-curl \
--with-curlwrappers \
--enable-mbregex \
--enable-mbstring --with-mcrypt --with-gd \
--enable-gd-native-ttf --with-openssl --with-mhash \
--enable-pcntl --enable-sockets --with-ldap --with-ldap-sasl \
--enable-fpm \
--with-xmlrpc --enable-zip --enable-soap \
--without-pear \


make ZEND_EXTRA_LIBS='-liconv'

#注意这里容易出现 make: *** [ext/phar/phar.php] 错误 127

#出现mysql client解决方法 
#ln -s /usr/local/mysql/lib/libmysqlclient.so /usr/lib/
#ln -s /usr/local/mysql/lib/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.18

#或者chmod: 无法访问 “ext/phar/phar.phar”: 没有那个文件或目录
#make: [ext/phar/phar.phar] 错误 1 (忽略)
#解决方法在编译的时候加--without-pear参数
#如果还不行,make的时候不添加 ZEND_EXTRA_LIBS='-liconv' 参数

make install

#选择PHP.ini配置文件
cp php.ini-production /usr/local/php/etc/php.ini

 

更改PHP-FPM

 

#添加WWW用户
/usr/sbin/groupadd www && /usr/sbin/useradd -g www www
mkdir -p /var/log/nginx && chmod +w /var/log/nginx &&chown -R www:www /var/log/nginx
mkdir -p /data/www && chmod +w /data/www && chown -R www:www /data/www

cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
vi /usr/local/php/etc/php-fpm.conf
  
#去掉/更改 配置文件中的;
pm.max_children = 64 
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 1024
user = www
group = www 

#检查语法是否正确
/usr/local/php/sbin/php-fpm -t
#出现NOTICE: configuration file /usr/local/php/etc/php-fpm.conf test is successful 测试成功
/usr/local/php/sbin/php-fpm &
#设置开机启动
vi /etc/rc.d/rc.local
#在行末加入
/usr/local/php/sbin/php-fpm &

#返回安装包目录 
cd /web

安装Nginx

 

#安装pcre库
tar -zxvf pcre-8.13.tar.gz && cd pcre-8.13/ && ./configure
make && make install && cd ../

#安装Nginx
tar -zxvf nginx-1.0.9.tar.gz && cd nginx-1.0.9 &&
./configure --user=www --group=www \
--prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre \
--lock-path=/var/run/nginx.lock \
--pid-path=/var/run/nginx.pid

make && make install && cd ../

#更改配置
vi /usr/local/nginx/conf/nginx.conf

#修改一些参数,别直接替换文件,这只是一部分
user www

events {
    use epoll;
    worker_connections  1024;
}

location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

#注意这里
#$document_root$fastcgi_script_name;
#检测配置文件
/usr/local/nginx/sbin/nginx -t

#提示表示成功
#nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
#nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

#开启Nginx
/usr/local/nginx/sbin/nginx &
#平滑重启Nginx
/usr/local/nginx/sbin/nginx -s reload

#添加开机启动
vi /etc/rc.d/rc.local
#最后移行加入
/usr/local/nginx/sbin/nginx

#测试
cd /usr/local/nginx/html/
touch index.php
vi /usr/local/nginx/html/index.php
<?php
phpinfo();
?>

非常全面的PHP header函数设置HTTP头的示例

//定义编码
header( 'Content-Type:text/html;charset=utf-8 ');
//Atom
header('Content-type: application/atom+xml');
//CSS
header('Content-type: text/css');
//Javascript
header('Content-type: text/javascript');
//JPEG Image
header('Content-type: image/jpeg');
//JSON
header('Content-type: application/json');
//PDF
header('Content-type: application/pdf');
//RSS
header('Content-Type: application/rss+xml; charset=ISO-8859-1');
//Text (Plain)
header('Content-type: text/plain');
//XML
header('Content-type: text/xml');
// ok
header('HTTP/1.1 200 OK');
//设置一个404头:
header('HTTP/1.1 404 Not Found');
//设置地址被永久的重定向
header('HTTP/1.1 301 Moved Permanently');
//转到一个新地址
header('Location: http://www.example.org/');
//文件延迟转向:
header('Refresh: 10; url=http://www.example.org/');
print 'You will be redirected in 10 seconds';
//当然,也可以使用html语法实现
// <meta http-equiv="refresh" content="10;http://www.example.org/ />
// override X-Powered-By: PHP:
header('X-Powered-By: PHP/4.4.0');
header('X-Powered-By: Brain/0.6b');
//文档语言
header('Content-language: en');
//告诉浏览器最后一次修改时间
$time = time() - 60; // or filemtime($fn), etc
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $time).' GMT');
//告诉浏览器文档内容没有发生改变
header('HTTP/1.1 304 Not Modified');
//设置内容长度
header('Content-Length: 1234');
//设置为一个下载类型
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="example.zip"');
header('Content-Transfer-Encoding: binary');
// load the file to send:
readfile('example.zip');
// 对当前文档禁用缓存
header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Pragma: no-cache');
//设置内容类型:
header('Content-Type: text/html; charset=iso-8859-1');
header('Content-Type: text/html; charset=utf-8');
header('Content-Type: text/plain'); //纯文本格式
header('Content-Type: image/jpeg'); //JPG***
header('Content-Type: application/zip'); // ZIP文件
header('Content-Type: application/pdf'); // PDF文件
header('Content-Type: audio/mpeg'); // 音频文件
header('Content-Type: application/x-shockw**e-flash'); //Flash动画
//显示登陆对话框
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Basic realm="Top Secret"');
print 'Text that will be displayed if the user hits cancel or ';
print 'enters wrong login data';

Http协议三次握手过程

TCP(Transmission Control Protocol) 传输控制协议

TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:

位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)

Sequence number(顺序号码) Acknowledge number(确认号码)

TCP/IP基础--TCP三次握手

第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包

第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

完成三次握手,主机A与主机B开始传送数据。

 
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据.

 

实例:

IP 192.168.1.116.3337 > 192.168.1.123.7788: S 3626544836:3626544836
IP 192.168.1.123.7788 > 192.168.1.116.3337: S 1739326486:1739326486 ack 3626544837
IP 192.168.1.116.3337 > 192.168.1.123.7788: ack 1739326487,ack 1

第一次握手:192.168.1.116发送位码syn=1,随机产生seq number=3626544836的数据包到192.168.1.123,192.168.1.123由SYN=1知道192.168.1.116要求建立联机;

第二次握手:192.168.1.123收到请求后要确认联机信息,向192.168.1.116发送ack number=3626544837,syn=1,ack=1,随机产生seq=1739326486的包;

第三次握手:192.168.1.116收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,192.168.1.116会再发送ack number=1739326487,ack=1,192.168.1.123收到后确认seq=seq+1,ack=1则连接建立成功。