Archive for 八月, 2012

作者:heiyeluren

博客:http://blog.csdn.net/heiyeshuwu

时间:2012/8/8

 

 

【 概述 】

在PHP开发中工作里非常多使用到超时处理到超时的场合,我说几个场景:

1. 异步获取数据如果某个后端数据源获取不成功则跳过,不影响整个页面展现

2. 为了保证Web服务器不会因为当个页面处理性能差而导致无法访问其他页面,则会对某些页面操作设置

3. 对于某些上传或者不确定处理时间的场合,则需要对整个流程中所有超时设置为无限,否则任何一个环节设置不当,都会导致莫名执行中断

4. 多个后端模块(MySQL、Memcached、HTTP接口),为了防止单个接口性能太差,导致整个前面获取数据太缓慢,影响页面打开速度,引起雪崩

5. 。。。很多需要超时的场合

 

这些地方都需要考虑超时的设定,但是PHP中的超时都是分门别类,各个处理方式和策略都不同,为了系统的描述,我总结了PHP中常用的超时处理的总结。

 

 

 

【Web服务器超时处理】

 

[ Apache ]

 

一般在性能很高的情况下,缺省所有超时配置都是30秒,但是在上传文件,或者网络速度很慢的情况下,那么可能触发超时操作。

 

目前 apache fastcgi php-fpm 模式 下有三个超时设置:

 

fastcgi 超时设置:

修改 httpd.conf 的fastcgi连接配置,类似如下:

 

<IfModule mod_fastcgi.c>    FastCgiExternalServer /home/forum/apache/apache_php/cgi-bin/php-cgi -socket /home/forum/php5/etc/php-fpm.sock

ScriptAlias /fcgi-bin/ “/home/forum/apache/apache_php/cgi-bin/”

AddHandler php-fastcgi .php

Action php-fastcgi /fcgi-bin/php-cgi

AddType application/x-httpd-php .php

</IfModule>

 

缺省配置是 30s,如果需要定制自己的配置,需要修改配置,比如修改为100秒:(修改后重启 apache):

<IfModule mod_fastcgi.c>

FastCgiExternalServer /home/forum/apache/apache_php/cgi-bin/php-cgi -socket /home/forum/php5/etc/php-fpm.sock  -idle-timeout 100

ScriptAlias /fcgi-bin/ “/home/forum/apache/apache_php/cgi-bin/”

AddHandler php-fastcgi .php

Action php-fastcgi /fcgi-bin/php-cgi

AddType application/x-httpd-php .php

</IfModule>

 

 

如果超时会返回500错误,断开跟后端php服务的连接,同时记录一条apache错误日志:

 

[Thu Jan 27 18:30:15 2011] [error] [client 10.81.41.110] FastCGI: comm with server “/home/forum/apache/apache_php/cgi-bin/php-cgi” aborted: idle timeout (30 sec)

[Thu Jan 27 18:30:15 2011] [error] [client 10.81.41.110] FastCGI: incomplete headers (0 bytes) received from server “/home/forum/apache/apache_php/cgi-bin/php-cgi”

 

其他 fastcgi 配置参数说明:

 

IdleTimeout 发呆时限ProcessLifeTime 一个进程的最长生命周期,过期之后无条件kill

MaxProcessCount 最大进程个数

DefaultMinClassProcessCount 每个程序启动的最小进程个数

DefaultMaxClassProcessCount 每个程序启动的最大进程个数

IPCConnectTimeout 程序响应超时时间

IPCCommTimeout 与程序通讯的最长时间,上面的错误有可能就是这个值设置过小造成的

MaxRequestsPerProcess 每个进程最多完成处理个数,达成后自杀

 

 

 

[ Lighttpd ]

配置:lighttpd.conf

 

Lighttpd配置中,关于超时的参数有如下几个(篇幅考虑,只写读超时,写超时参数同理):

 

主要涉及选项:

server.max-keep-alive-idle = 5

server.max-read-idle = 60

server.read-timeout = 0

server.max-connection-idle = 360

 

————————————————–

# 每次keep-alive 的最大请求数, 默认值是16

server.max-keep-alive-requests = 100

 

# keep-alive的最长等待时间, 单位是秒,默认值是5

server.max-keep-alive-idle = 1200

 

# lighttpd的work子进程数,默认值是0,单进程运行

server.max-worker = 2

 

# 限制用户在发送请求的过程中,最大的中间停顿时间(单位是秒),

# 如果用户在发送请求的过程中(没发完请求),中间停顿的时间太长,lighttpd会主动断开连接

# 默认值是60(秒)

server.max-read-idle = 1200

 

# 限制用户在接收应答的过程中,最大的中间停顿时间(单位是秒),

# 如果用户在接收应答的过程中(没接完),中间停顿的时间太长,lighttpd会主动断开连接

# 默认值是360(秒)

server.max-write-idle = 12000

 

# 读客户端请求的超时限制,单位是秒, 配为0表示不作限制

# 设置小于max-read-idle时,read-timeout生效

server.read-timeout = 0

 

# 写应答页面给客户端的超时限制,单位是秒,配为0表示不作限制

# 设置小于max-write-idle时,write-timeout生效

server.write-timeout = 0

 

# 请求的处理时间上限,如果用了mod_proxy_core,那就是和后端的交互时间限制, 单位是秒

server.max-connection-idle = 1200

————————————————–

说明:

对于一个keep-alive连接上的连续请求,发送第一个请求内容的最大间隔由参数max-read-idle决定,从第二个请求起,发送请求内容的最大间隔由参数max-keep-alive-idle决定。请求间的间隔超时也由max-keep-alive-idle决定。发送请求内容的总时间超时由参数read-timeout决定。Lighttpd与后端交互数据的超时由max-connection-idle决定。

 

延伸阅读:

http://www.snooda.com/read/244

 

 

[ Nginx ]

配置:nginx.conf

 

http {

#Fastcgi: (针对后端的fastcgi 生效, fastcgi 不属于proxy模式)

fastcgi_connect_timeout 5;    #连接超时

fastcgi_send_timeout 10;       #写超时

fastcgi_read_timeout 10;        #读取超时

 

#Proxy: (针对proxy/upstreams的生效)

proxy_connect_timeout 15s;    #连接超时

proxy_read_timeout 24s;          #读超时

proxy_send_timeout 10s;         #写超时

}

 

说明:

Nginx 的超时设置倒是非常清晰容易理解,上面超时针对不同工作模式,但是因为超时带来的问题是非常多的。

 

延伸阅读:

http://hi.baidu.com/pibuchou/blog/item/a1e330dd71fb8a5995ee3753.html

http://hi.baidu.com/pibuchou/blog/item/7cbccff0a3b77dc60b46e024.html

http://hi.baidu.com/pibuchou/blog/item/10a549818f7e4c9df703a626.html

http://www.apoyl.com/?p=466

 

 

【PHP本身超时处理】

 

[ PHP-fpm ] 

 

配置:php-fpm.conf

 

<?xml version=”1.0″ ?>

<configuration>

//…

Sets the limit on the number of simultaneous requests that will be served.

Equivalent to Apache MaxClients directive.

Equivalent to PHP_FCGI_CHILDREN environment in original php.fcgi

Used with any pm_style.

#php-cgi的进程数量

<value name=”max_children”>128</value>

 

 

The timeout (in seconds) for serving a single request after which the worker process will be terminated

Should be used when ‘max_execution_time’ ini option does not stop script execution for some reason

‘0s’ means ‘off’

#php-fpm 请求执行超时时间,0s为永不超时,否则设置一个 Ns 为超时的秒数

<value name=”request_terminate_timeout”>0s</value>

 

The timeout (in seconds) for serving of single request after which a php backtrace will be dumped to slow.log file

‘0s’ means ‘off’

<value name=”request_slowlog_timeout”>0s</value>

 

</configuration>

 

 

 

说明:

在 php.ini 中,有一个参数 max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时:

 

<value name=”request_terminate_timeout”>0s</value>

 

就是说如果是使用 mod_php5.so 的模式运行 max_execution_time 是会生效的,但是如果是php-fpm模式中运行时不生效的。

延伸阅读:

http://blog.s135.com/file_get_contents/

 

 

[ PHP ]

 

配置:php.ini

 

选项:

max_execution_time = 30

 

或者在代码里设置:

ini_set(“max_execution_time”, 30);

set_time_limit(30);

 

说明:

对当前会话生效,比如设置0一直不超时,但是如果php的 safe_mode 打开了,这些设置都会不生效。

效果一样,但是具体内容需要参考php-fpm部分内容,如果php-fpm中设置了 request_terminate_timeout 的话,那么 max_execution_time 就不生效。

 

 

【后端&接口访问超时】

 

【HTTP访问】

 

一般我们访问HTTP方式很多,主要是:curl, socket, file_get_contents() 等方法。

如果碰到对方服务器一直没有响应的时候,我们就悲剧了,很容易把整个服务器搞死,所以在访问http的时候也需要考虑超时的问题。

 

[ CURL 访问HTTP]

CURL 是我们常用的一种比较靠谱的访问HTTP协议接口的lib库,性能高,还有一些并发支持的功能等。

CURL:

 

curl_setopt($ch, opt) 可以设置一些超时的设置,主要包括:

 

*(重要) CURLOPT_TIMEOUT 设置cURL允许执行的最长秒数。

*(重要) CURLOPT_TIMEOUT_MS 设置cURL允许执行的最长毫秒数。 (在cURL 7.16.2中被加入。从PHP 5.2.3起可使用。 )

 

CURLOPT_CONNECTTIMEOUT 在发起连接前等待的时间,如果设置为0,则无限等待。

CURLOPT_CONNECTTIMEOUT_MS 尝试连接等待的时间,以毫秒为单位。如果设置为0,则无限等待。  在cURL 7.16.2中被加入。从PHP 5.2.3开始可用。

CURLOPT_DNS_CACHE_TIMEOUT 设置在内存中保存DNS信息的时间,默认为120秒。

 

curl普通秒级超时:

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,$url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_TIMEOUT, 60);   //只需要设置一个秒的数量就可以

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

curl_setopt($ch, CURLOPT_USERAGENT, $defined_vars[‘HTTP_USER_AGENT’]);

 

curl普通秒级超时使用:

curl_setopt($ch, CURLOPT_TIMEOUT, 60);

 

curl如果需要进行毫秒超时,需要增加:

curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

或者是:

curl_setopt ( $ch,  CURLOPT_NOSIGNAL, true); 是可以支持毫秒级别超时设置的

 

curl一个毫秒级超时的例子:

<?php

if (!isset($_GET[‘foo’])) {

// Client

$ch = curl_init(‘http://example.com/’);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_NOSIGNAL, 1);    //注意,毫秒超时一定要设置这个

curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);  //超时毫秒,cURL 7.16.2中被加入。从PHP 5.2.3起可使用

$data = curl_exec($ch);

$curl_errno = curl_errno($ch);

$curl_error = curl_error($ch);

curl_close($ch);

 

if ($curl_errno > 0) {

echo “cURL Error ($curl_errno): $curl_error\n”;

} else {

echo “Data received: $data\n”;

}

} else {

// Server

sleep(10);

echo “Done.”;

}

?>

 

其他一些技巧:

1. 按照经验总结是:cURL 版本 >= libcurl/7.21.0 版本,毫秒级超时是一定生效的,切记。

2. curl_multi的毫秒级超时也有问题。。单次访问是支持ms级超时的,curl_multi并行调多个会不准

 

 

[流处理方式访问HTTP]

除了curl,我们还经常自己使用fsockopen、或者是file操作函数来进行HTTP协议的处理,所以,我们对这块的超时处理也是必须的。

 

一般连接超时可以直接设置,但是流读取超时需要单独处理。

自己写代码处理:

$tmCurrent = gettimeofday();

$intUSGone = ($tmCurrent[‘sec’] – $tmStart[‘sec’]) * 1000000

+ ($tmCurrent[‘usec’] – $tmStart[‘usec’]);

if ($intUSGone > $this->_intReadTimeoutUS) {

return false;

}

 

或者使用内置流处理函数 stream_set_timeout() 和 stream_get_meta_data() 处理:

 

<?php// Timeout in seconds

$timeout = 5;

$fp = fsockopen(“example.com”, 80, $errno, $errstr, $timeout);

if ($fp) {

fwrite($fp, “GET / HTTP/1.0\r\n”);

fwrite($fp, “Host: example.com\r\n”);

fwrite($fp, “Connection: Close\r\n\r\n”);

stream_set_blocking($fp, true);   //重要,设置为非阻塞模式

stream_set_timeout($fp,$timeout);   //设置超时

$info = stream_get_meta_data($fp);

while ((!feof($fp)) && (!$info[‘timed_out’])) {

$data .= fgets($fp, 4096);

$info = stream_get_meta_data($fp);

ob_flush;

flush();

}

if ($info[‘timed_out’]) {

echo “Connection Timed Out!”;

} else {

echo $data;

}

}

 

 

file_get_contents 超时:

 

<?php$timeout = array(

‘http’ => array(

‘timeout’ => 5 //设置一个超时时间,单位为秒

)

);

$ctx = stream_context_create($timeout);

$text = file_get_contents(“http://example.com/”, 0, $ctx);

?>

 

 

fopen 超时:

<?php$timeout = array(

‘http’ => array(

‘timeout’ => 5 //设置一个超时时间,单位为秒

)

);

$ctx = stream_context_create($timeout);

if ($fp = fopen(“http://example.com/”, “r”, false, $ctx)) {

while( $c = fread($fp, 8192)) {

echo $c;

}

fclose($fp);

}

?>

 

 

 

 

【MySQL】
php中的mysql客户端都没有设置超时的选项,mysqli和mysql都没有,但是libmysql是提供超时选项的,只是我们在php中隐藏了而已。

 

那么如何在PHP中使用这个操作捏,就需要我们自己定义一些MySQL操作常量,主要涉及的常量有:

MYSQL_OPT_READ_TIMEOUT=11;

MYSQL_OPT_WRITE_TIMEOUT=12;

 

这两个,定义以后,可以使用 options 设置相应的值。

 

不过有个注意点,mysql内部实现:

1. 超时设置单位为秒,最少配置1秒

2. 但mysql底层的read会重试两次,所以实际会是 3 秒

 

重试两次 + 自身一次 = 3倍超时时间,那么就是说最少超时时间是3秒,不会低于这个值,对于大部分应用来说可以接受,但是对于小部分应用需要优化。

 

 

查看一个设置访问mysql超时的php实例:

 

<?php//自己定义读写超时常量

if (!defined(‘MYSQL_OPT_READ_TIMEOUT’)) {

define(‘MYSQL_OPT_READ_TIMEOUT’,  11);

}

if (!defined(‘MYSQL_OPT_WRITE_TIMEOUT’)) {

define(‘MYSQL_OPT_WRITE_TIMEOUT’, 12);

}

//设置超时

$mysqli = mysqli_init();

$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);

$mysqli->options(MYSQL_OPT_WRITE_TIMEOUT, 1);

 

//连接数据库

$mysqli->real_connect(“localhost”, “root”, “root”, “test”);

if (mysqli_connect_errno()) {

printf(“Connect failed: %s/n”, mysqli_connect_error());

exit();

}

//执行查询 sleep 1秒不超时

printf(“Host information: %s/n”, $mysqli->host_info);

if (!($res=$mysqli->query(‘select sleep(1)’))) {

echo “query1 error: “. $mysqli->error .”/n”;

} else {

echo “Query1: query success/n”;

}

//执行查询 sleep 9秒会超时

if (!($res=$mysqli->query(‘select sleep(9)’))) {

echo “query2 error: “. $mysqli->error .”/n”;

} else {

echo “Query2: query success/n”;

}

$mysqli->close();

echo “close mysql connection/n”;

?>

 

延伸阅读:

http://blog.csdn.net/heiyeshuwu/article/details/5869813

 

 

 

 

【Memcached】

 

[PHP扩展]

php_memcache 客户端:

连接超时:bool Memcache::connect ( string $host [, int $port [, int $timeout ]] )

 

在get和set的时候,都没有明确的超时设置参数。

 

libmemcached 客户端:在php接口没有明显的超时参数。

 

说明:所以说,在PHP中访问Memcached是存在很多问题的,需要自己hack部分操作,或者是参考网上补丁。

 

[C&C++访问Memcached]

客户端:libmemcached 客户端

说明:memcache超时配置可以配置小点,比如5,10个毫秒已经够用了,超过这个时间还不如从数据库查询。

 

下面是一个连接和读取set数据的超时的C++示例:

 

//创建连接超时(连接到Memcached)

memcached_st* MemCacheProxy::_create_handle()

{

memcached_st * mmc = NULL;

memcached_return_t prc;

if (_mpool != NULL) {  // get from pool

mmc = memcached_pool_pop(_mpool, false, &prc);

if (mmc == NULL) {

__LOG_WARNING__(“MemCacheProxy”, “get handle from pool error [%d]”, (int)prc);

}

return mmc;

}

 

memcached_st* handle = memcached_create(NULL);

if (handle == NULL){

__LOG_WARNING__(“MemCacheProxy”, “create_handle error”);

return NULL;

}

 

// 设置连接/读取超时

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_HASH, MEMCACHED_HASH_DEFAULT);

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_NO_BLOCK, _noblock);  //参数MEMCACHED_BEHAVIOR_NO_BLOCK为1使超时配置生效,不设置超时会不生效,关键时候会悲剧的,容易引起雪崩

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, _connect_timeout);  //连接超时

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, _read_timeout);    //读超时

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_SND_TIMEOUT, _send_timeout);    //写超时

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, _poll_timeout);

 

// 设置一致hash

//      memcached_behavior_set_distribution(handle, MEMCACHED_DISTRIBUTION_CONSISTENT);

memcached_behavior_set(handle, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT);

 

memcached_return rc;

for (uint i = 0; i < _server_count; i++){

rc = memcached_server_add(handle, _ips[i], _ports[i]);

if (MEMCACHED_SUCCESS != rc) {

__LOG_WARNING__(“MemCacheProxy”, “add server [%s:%d] failed.”, _ips[i], _ports[i]);

}

}

 

_mpool = memcached_pool_create(handle, _min_connect, _max_connect);

if (_mpool == NULL){

__LOG_WARNING__(“MemCacheProxy”, “create_pool error”);

return NULL;

}

 

mmc = memcached_pool_pop(_mpool, false, &prc);

if (mmc == NULL) {

__LOG_WARNING__(“MyMemCacheProxy”, “get handle from pool error [%d]”, (int)prc);

}

//__LOG_DEBUG__(“MemCacheProxy”, “get handle [%p]”, handle);

return mmc;

}

 

//设置一个key超时(set一个数据到memcached)

bool MemCacheProxy::_add(memcached_st* handle, unsigned int* key, const char* value, int len, unsigned int timeout)

{

memcached_return rc;

 

char tmp[1024];

snprintf(tmp, sizeof (tmp), “%u#%u”, key[0], key[1]);

//有个timeout值

rc = memcached_set(handle, tmp, strlen(tmp), (char*)value, len, timeout, 0);

if (MEMCACHED_SUCCESS != rc){

return false;

}

return true;

}

 

//Memcache读取数据超时 (没有设置)

libmemcahed 源码中接口定义:

LIBMEMCACHED_API char *memcached_get(memcached_st *ptr,const char *key, size_t key_length,size_t *value_length,uint32_t *flags,memcached_return_t *error);

LIBMEMCACHED_API memcached_return_t memcached_mget(memcached_st *ptr,const char * const *keys,const size_t *key_length,size_t number_of_keys);

 

从接口中可以看出在读取数据的时候,是没有超时设置的。

 

延伸阅读:

http://hi.baidu.com/chinauser/item/b30af90b23335dde73e67608

http://libmemcached.org/libMemcached.html

 

 

 

【如何实现超时】

 

程序中需要有超时这种功能,比如你单独访问一个后端Socket模块,Socket模块不属于我们上面描述的任何一种的时候,它的协议也是私有的,那么这个时候可能需要自己去实现一些超时处理策略,这个时候就需要一些处理代码了。

 

[PHP中超时实现] 

 

一、初级:最简单的超时实现 (秒级超时)

 

思路很简单:链接一个后端,然后设置为非阻塞模式,如果没有连接上就一直循环,判断当前时间和超时时间之间的差异。

 

php socket 中实现原始的超时:(每次循环都当前时间去减,性能会很差,cpu占用会较高)

<?    $host = “127.0.0.1”;

$port = “80”;

$timeout = 15;  //timeout in seconds

 

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)

or die(“Unable to create socket\n”);

 

socket_set_nonblock($socket)     //务必设置为阻塞模式

or die(“Unable to set nonblock on socket\n”);

 

$time = time();

//循环的时候每次都减去相应值

while (!@socket_connect($socket, $host, $port))    //如果没有连接上就一直死循环

{

$err = socket_last_error($socket);

if ($err == 115 || $err == 114)

{

if ((time() – $time) >= $timeout)    //每次都需要去判断一下是否超时了

{

socket_close($socket);

die(“Connection timed out.\n”);

}

sleep(1);

continue;

}

die(socket_strerror($err) . “\n”);

}

socket_set_block($this->socket)    //还原阻塞模式

or die(“Unable to set block on socket\n”);

?>

 

二、升级:使用PHP自带异步IO去实现(毫秒级超时)

 

说明:
异步IO:异步IO的概念和同步IO相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。异步IO将比特分成小组进行传送,小组可以是8位的1个字符或更长。发送方可以在任何时刻发送这些比特组,而接收方从不知道它们会在什么时候到达。

多路复用:复用模型是对多个IO操作进行检测,返回可操作集合,这样就可以对其进行操作了。这样就避免了阻塞IO不能随时处理各个IO和非阻塞占用系统资源的确定。

 

使用 socket_select() 实现超时

socket_select(…, floor($timeout), ceil($timeout*1000000));
select的特点:能够设置到微秒级别的超时!

使用socket_select() 的超时代码(需要了解一些异步IO编程的知识去理解)

### 调用类 ####

<?php

$server = new Server;

$client = new Client;

 

for (;;) {

foreach ($select->can_read(0) as $socket) {

 

if ($socket == $client->socket) {

// New Client Socket

$select->add(socket_accept($client->socket));

}

else {

//there’s something to read on $socket

}

}

}

?>

 

### 异步多路复用IO & 超时连接处理类 ###

<?php

class select {

var $sockets;

 

function select($sockets) {

 

$this->sockets = array();

 

foreach ($sockets as $socket) {

$this->add($socket);

}

}

 

function add($add_socket) {

array_push($this->sockets,$add_socket);

}

 

function remove($remove_socket) {

$sockets = array();

 

foreach ($this->sockets as $socket) {

if($remove_socket != $socket)

$sockets[] = $socket;

}

 

$this->sockets = $sockets;

}

 

function can_read($timeout) {

$read = $this->sockets;

socket_select($read,$write = NULL,$except = NULL,$timeout);

return $read;

}

 

function can_write($timeout) {

$write = $this->sockets;

socket_select($read = NULL,$write,$except = NULL,$timeout);

return $write;

}

}

?>

 

 

[C&C++中超时实现] 

 

一般在Linux C/C++中,可以使用:alarm() 设置定时器的方式实现秒级超时,或者:select()、poll()、epoll() 之类的异步复用IO实现毫秒级超时。也可以使用二次封装的异步io库(libevent, libev)也能实现。

 

一、使用alarm中用信号实现超时 (秒级超时)

 

说明:Linux内核connect超时通常为75秒,我们可以设置更小的时间如10秒来提前从connect中返回。这里用使用信号处理机制,调用alarm,超时后产生SIGALRM信号 (也可使用select实现)

 

用 alarym 秒级实现 connect 设置超时代码示例:

 

//信号处理函数static void connect_alarm(int signo)

{

debug_printf(“SignalHandler”);

return;

}

 

//alarm超时连接实现

static void conn_alarm()

{

Sigfunc * sigfunc ; //现有信号处理函数

sigfunc=signal(SIGALRM, connect_alarm); //建立信号处理函数connect_alarm,(如果有)保存现有的信号处理函数

int timeout = 5;

 

//设置闹钟

if( alarm(timeout)!=0 ){

//… 闹钟已经设置处理

}

 

//进行连接操作

if (connect(m_Socket, (struct sockaddr *)&addr, sizeof(addr)) < 0 ) {

if ( errno == EINTR ) { //如果错误号设置为EINTR,说明超时中断了

debug_printf(“Timeout”);

m_connectionStatus = STATUS_CLOSED;

errno = ETIMEDOUT; //防止三次握手继续进行

return ERR_TIMEOUT;

}

else {

debug_printf(“Other Err”);

m_connectionStatus = STATUS_CLOSED;

return ERR_NET_SOCKET;

}

}

alarm(0);//关闭时钟

signal(SIGALRM, sigfunc); //(如果有)恢复原来的信号处理函数

return;

}

 

//读取数据的超时设置

同样可以为 recv 设置超时,5秒内收不到任何应答就中断

signal( … );

alarm(5);

recv( … );

alarm(0);

static void sig_alarm(int signo){return;}

当客户端阻塞于读(readline,…)时,如果此时服务器崩了,客户TCP试图从服务器接收一个ACK,持续重传 数据分节,大约要等9分钟才放弃重传,并返回一个错误。因此,在客户读阻塞时,调用超时。

 

 

二、使用异步复用IO使用 (毫秒级超时)

 

异步IO执行流程:

1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数

2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。

3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct timeval *timeout)

4.调用select( socket, &rset, &wset, NULL, timeout )

返回0表示connect超时,如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。

 

//select 实现毫秒级超时示例:

static void conn_select() {

// Open TCP Socket

m_Socket = socket(PF_INET,SOCK_STREAM,0);

if( m_Socket < 0 )

{

m_connectionStatus = STATUS_CLOSED;

return ERR_NET_SOCKET;

}

 

struct sockaddr_in addr;

inet_aton(m_Host.c_str(), &addr.sin_addr);

addr.sin_port = htons(m_Port);

addr.sin_family = PF_INET;

 

// Set timeout values for socket

struct timeval timeouts;

timeouts.tv_sec = SOCKET_TIMEOUT_SEC ;   // const -> 5

timeouts.tv_usec = SOCKET_TIMEOUT_USEC ; // const -> 0

uint8_t optlen = sizeof(timeouts);

 

if( setsockopt( m_Socket, SOL_SOCKET, SO_RCVTIMEO,&timeouts,(socklen_t)optlen) < 0 )

{

m_connectionStatus = STATUS_CLOSED;

return ERR_NET_SOCKET;

}

 

// Set the Socket to TCP Nodelay ( Send immediatly after a send / write command )

int flag_TCP_nodelay = 1;

if ( (setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY,

(char *)&flag_TCP_nodelay, sizeof(flag_TCP_nodelay))) < 0)

{

m_connectionStatus = STATUS_CLOSED;

return ERR_NET_SOCKET;

}

// Save Socket Flags

int opts_blocking = fcntl(m_Socket, F_GETFL);

if ( opts_blocking < 0 )

{

return ERR_NET_SOCKET;

}

//设置为非阻塞模式

int opts_noblocking = (opts_blocking | O_NONBLOCK);

// Set Socket to Non-Blocking

if (fcntl(m_Socket, F_SETFL, opts_noblocking)<0)

{

return ERR_NET_SOCKET;

}

// Connect

if ( connect(m_Socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)

{

// EINPROGRESS always appears on Non Blocking connect

if ( errno != EINPROGRESS )

{

m_connectionStatus = STATUS_CLOSED;

return ERR_NET_SOCKET;

}

// Create a set of sockets for select

fd_set socks;

FD_ZERO(&socks);

FD_SET(m_Socket,&socks);

// Wait for connection or timeout

int fdcnt = select(m_Socket+1,NULL,&socks,NULL,&timeouts);

if ( fdcnt < 0 )

{

return ERR_NET_SOCKET;

}

else if ( fdcnt == 0 )

{

return ERR_TIMEOUT;

}

}

//Set Socket to Blocking again

if(fcntl(m_Socket,F_SETFL,opts_blocking)<0)

{

return ERR_NET_SOCKET;

}

 

m_connectionStatus = STATUS_OPEN;

return 0;

}

 

说明:在超时实现方面,不论是什么脚本语言:PHP、Python、Perl 基本底层都是C&C++的这些实现方式,需要理解这些超时处理,需要一些Linux 编程和网络编程的知识。

 

延伸阅读:

http://blog.sina.com.cn/s/blog_4462f8560100tvgo.html

http://blog.csdn.net/thimin/article/details/1530839

http://hi.baidu.com/xjtdy888/item/93d9daefcc1d31d1ea34c992

http://blog.csdn.net/byxdaz/article/details/5461142

http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/

http://hi.baidu.com/suyupin/item/df10004decb620e91f19bcf5

http://stackoverflow.com/questions/7092633/connect-timeout-with-alarm

http://stackoverflow.com/questions/7089128/linux-tcp-connect-with-select-fails-at-testserver?lq=1

http://cppentry.com/bencandy.php?fid=54&id=1129

 

 

 

【 总结 】

 

1. PHP应用层如何设置超时?

PHP在处理超时层次有很多,不同层次,需要前端包容后端超时:

浏览器(客户端) -> 接入层 -> Web服务器  -> PHP  -> 后端 (MySQL、Memcached)

 

就是说,接入层(Web服务器层)的超时时间必须大于PHP(PHP-FPM)中设置的超时时间,不然后面没处理完,你前面就超时关闭了,这个会很杯具。还有就是PHP的超时时间要大于PHP本身访问后端(MySQL、HTTP、Memcached)的超时时间,不然结局同前面。

 

2. 超时设置原则是什么?

如果是希望永久不超时的代码(比如上传,或者定期跑的程序),我仍然建议设置一个超时时间,比如12个小时这样的,主要是为了保证不会永久夯住一个php进程或者后端,导致无法给其他页面提供服务,最终引起所有机器雪崩。

如果是要要求快速响应的程序,建议后端超时设置短一些,比如连接500ms,读1s,写1s,这样的速度,这样能够大幅度减少应用雪崩的问题,不会让服务器负载太高。

 

3. 自己开发超时访问合适吗?

一般如果不是万不得已,建议用现有很多网络编程框架也好、基础库也好,里面一般都带有超时的实现,比如一些网络IO的lib库,尽量使用它们内置的,自己重复造轮子容易有bug,也不方便维护(不过如是是基于学习的目的就当别论了)。

 

4. 其他建议

超时在所有应用里都是大问题,在开发应用的时候都要考虑到。我见过一些应用超时设置上百秒的,这种性能就委实差了,我举个例子:

比如你php-fpm开了128个php-cgi进程,然后你的超时设置的是32s,那么我们如果后端服务比较差,极端情况下,那么最多每秒能响应的请求是:

128 / 32 = 4个

你没看错,1秒只能处理4个请求,那服务也太差了!虽然我们可以把php-cgi进程开大,但是内存占用,还有进程之间切换成本也会增加,cpu呀,内存呀都会增加,服务也会不稳定。所以,尽量设置一个合理的超时值,或者督促后端提高性能。

本文有部分经验值,还有部分参考的内容,如果不足之处,还请指正。

 

最近遇到的一个需求是用户列表根据不同信息排序的问题:获取当前登录者相关的用户信息,包括多种属性字段,并且可以按照某些属性字段进行排序。这里相关的用户可能是10w数量级的,其属性需要从另外两个项目的API获取。即其处理流程为:

  1. 从数据库中查询当前登录者相关的用户IDs
  2. 从API-1获取IDs的相关属性(该API每次最多获取500条)
  3. 按照属性进行排序,获取查询当前页的用户IDs
  4. 从API-2获取当前页用户的其他属性
  5. 展示

由于用户IDs可能数量较多,导致第二步耗时较长,第三步排序也较为麻烦并消耗内存。所以考虑使用并发的思想减少耗时,并且采取一些排序优化手段减少内存消耗。

并发

针对第二步而言,可以描述为:发起多次http请求,并且等待API server端的响应,整合数据。其实每次API处理时间并不长,但是串行起来就比较久了,所以考虑改为并行:

  1. 发起多个socket连接
  2. 等待某socket可写,则发送http请求包
  3. 等待某socket可读,则读取http响应,存储在共享内存或全局变量等

以上自然会联想到使用epoll来监听socket的读写状态,并且采取事件驱动的开发模式(将读和写都封装为callback函数)。所以尝试了libevent的PHP扩展封装。

这里直接使用了http://www.ooso.net/archives/597里封装的异步的http请求类作为demo,发起对测试API的多次请求(该API内sleep 3秒,然后echo退出)。测试的结果是,耗时减半,因为同一来源同一目的地同时仅允许2个连接。对应到我们的应用场景,由于API server是分布式的,所以时间应该会降低的更多。

由于libevent是单进程单线程(应该是,记不清楚了,待确认),所以,这里读取响应后的存储不涉及到竞争和锁。

排序

该需求的目的是排序和分页,所以第二步读取http响应时,可以先排序,仅保留per-page个元素,并且仅保留必须的属性字段,释放不需要的内存。第三步时,仅针对N*per-page个元素进行排序即可。从而降低内存的使用率。

 

现在的问题是,如何提炼出抽象模型,使之适用于更广泛的应用场景呢?

CPM:基于广告显示次数的CPM(千人成本)计价法

SME:中小企业

KA:大客户

ROI:Return On Investment ,投资回报率

ARPU:Average Revenue Per User,即每用户平均收入

 

从一个人coding,到合作,甚至主导技术方向的coder,近3个月的感触颇深。但现在,还没出成果,所以未到总结的时候,需要的是梳理问题,并解决它!

软技能方面:

  • 思考方法论,通过观察leader的做事方式,mail里别人阐述问题的方式,更重要的是打坐,建立属于我自己的方法论。切记,不要沾染太多的进攻性,平和的心态胜于一切。
  • 项目管理,怎样调动大家的积极性,怎样协调资源?
  • 并发工作下,怎样分配时间。我目前的角色很奇怪,不是单纯的programmer,也不是单纯的architecture,更不是PM,但是我需要提出架构,思考方向,写项目文档,也得参与编码。在主线项目外,可能还会有其他事情插入,所以时间的分配很重要。
  • 沟通,一练胆,二练方式。我没讲明白,那没关系,我尝试从另一个角度阐述,直到说清楚为止。说的过程,也是检验我是否理解透彻的过程。

技术方面:

  • 架构知识,通用的系统和软件架构和思想有哪些?各自的利弊,应用的场景?设计模式?亟待这些理论知识与之前看到的代码结合!因为之前,我只需知道该怎样做,而现在需要的是列出有哪些做法,比较优缺点,提出建议,并接纳他人的思想,整合出最适合项目需求的架构。书目:超越软件架构、架构之美、软件系统架构、设计模式。
  • NoSQL知识,并行计算,随着数据量的增大,跨项目交互的增多,传统的存储与计算方式肯定不能满足需求,需要未雨绸缪。我之前了解的cabinet可能偏小众,需要扩大视野,了解key-value、列存储、文档存储、图形关系存储多种示例的优劣和应用场景。Hadoop之前的使用并不深入,如果有合适的需求,可以继续尝试。
  • PHP源码和扩展,Nginx和Apache源码,MySQL原理。
  • 网络通信,从socket的异常处理,到应用层的多种打包协议。

 

数据库事务在百度百科中的解释如下:

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。

而大中型网站架构中,一般会采取横向分层的方式,将业务、数据等隔离开,并分别部署,相互间通过网络API的形式访问。这就存在一个问题,数据层能否支持事务呢?在某些复杂逻辑的项目里,如果不能保持数据事务,则无法满足业务需求。而如果为了保证事务,而将复杂业务逻辑引入数据层,则失去了分层的价值。

在同几位朋友的交谈中,得知.net和java是可以支持API事务的,但是PHP没有现成可用的(当然,也有可能是我孤陋寡闻)。考虑了一种实现方式,即在数据层和业务层间建立socket连接,由业务层发出事务启动命令、db操作、事务提交或回滚命令,而数据层只需关注与存储结构的交互、性能、缓存处理等与业务无关的功能。

数据层有两种实现方法:

  1. 采用libevent等框架,使用C语言开发。该方法性能较高,但维护和扩展功能较为麻烦,不支持热插拔。
  2. 基于apache等web server,使用php语言开发。该方法性能略低,但是符合web项目快速迭代的需求。所以,做了一个demo,验证其可行性。
数据层事务流程
demo由service.php和client.php两部分组成,前者模拟数据层行为,后者模拟业务层等调用者,事件由调用者发起。具体流程如下:
  1. client.php在本机内网ip和随机port上初始化监听socket
  2. client.php将内网ip和port作为参数,通过server.php所在服务器的httpd端口发送给server.php,并不read server.php的返回数据,立刻关闭该http连接
  3. server.php fsockopen连接到client.php发送来的ip和port对应的socket上
  4. client.php accept连接后,发送事务启动命令给server.php
  5. server.php read数据,进行db 操作
  6. client.php发送db操作请求
  7. server.php read数据,进行db 操作
  8. 重复6-7操作,直至完成db操作
  9. client.php接收到正确返回值,则发送commit命令;否则发送rollback命令
  10. server.php read数据,进行db 操作
  11. client.php关闭socket
以上方式确实能够实现数据层的事务,但是它也有不足,后续将继续考虑优化方案:
  1. 需要约定数据交互协议
  2. 需要多消耗一倍的socket资源
  3. client.php里的socket连接,如果不采取PHP扩展的方式,是无法实现连接池的

另外,今天还调研了HTTP 1.1的encoding=chunked分块传输模式,该方式下,虽然数据是分块发送的,但是apache会等到接收完所有的chunk,建立完成的request struct之后,才将处理权传递给PHP,所以还是无法完成双向通信和交互。

那么HTTP的长连接呢?后续也将进行调研。

 

zz from: http://www.phpben.com/?post=70

要深入研究mysql那首先对mysql的一些系统/扩展变量有一定的了解,因为这些变量不仅决定mysql一些配置信息,还影响了mysql的性能优化提升,其中包括安全、优化、并发、复制等等。

笔者上网查了一下,这些资料有限,以及官网的一个中文文档介绍的内容简短(不包括值域,作用域,有些变量压根没翻译只是给出值)所以想写篇文章,一来学习巩固一下mysql,二来方便以后查阅。其中内容笔者前后用了14天,尽量查阅大量资料(问人,网上查阅,自己测试)以确保尽可能正确,且有些直接从官网英文文档翻译过来,但难免会出现因为知识结构不全面而有什么纰漏。

PS

一、想知道有那些变量(系统变量、状态变量、集群变量、日志变量…),在mysqladmin 中输入:“mysqladmin –u 用户 –p 密码 variable” 或者在mysql命令端用“show variables”显示

二、以下所有测试的环境:win7、mysql 5.1.49-community-log

三、以下变量中的作用域有全局、会话,值域表示变量值的范围(这些是中文文档锁没有的)

1 log_slow_queries                        | OFF/ON

慢查询记录日志,慢查询是指查询时间超过设定时间(如下面设为2秒)的查询,(还有个指标是第29点的min_examined_row_limit)这个可以记录那些查询语句比较慢,然后通过分析语句而优化数据库或查询语句。具体配置在my.ini加入:

log_show_queries = “日志路径/文件名”   #保存日志的路径和文件名,确保权限可写

long_query_time = 2                   #超过多少秒则保存查询数据

log-queries-not-using-indexs             #不使用使用索引

PS加上代码后重启mysql后log_slow_queries=ON状态(默认OFF)

测试:select  * from zd_ask;

结果:在指定的文件里面记录如下

C:\Program Files\MySQL\MySQL Server 5.1\bin\mysqld, Version: 5.1.49-community-log (MySQL Community Server (GPL)). started with:

TCP Port: 3306, Named Pipe: (null)

Time                 Id Command    Argument

# Time: 120425 20:40:49

# User@Host: root[root] @ localhost [127.0.0.1]

# Query_time: 0.452026  Lock_time: 0.187010 Rows_sent: 12408  Rows_examined: 12408

use bus7zd;

SET timestamp=1335357649;

select * from zd_ask;

说明:超过时间的查询语句:select * from zd_ask; 查到的结果数:12408 时间:0.452026 其他就是环境信息。

作用域:全局

————————————————-

2log_warnings                            | 1

默认值为1,表示在错误日志当中添加更多日志,日至格式:

120426 11:55:09 [Worning]内容,上网查了一下,国内这个变量的资料少得可怜,查看官网英文文档,会把一些断开链接的错误写进错误日志里面。

可以在配置文件my.ini 加入skip-log-warnings=1来停止log_warning 的使用, skip-log-warnings=1后在mysqladmin 里面用”mysqladmin –u 用户名 –p 密码 variables”查看,会发现log_warning的值是0而不是默认的1.

作用域:全局

————————————————–

3long_query_time                        | 10.000000

这是和log_slow_queries一起使用的,它是设置慢查询时间,若值是0.2,则查询大于0.2秒的定为慢查询。如果启用了慢查询日志,则会把慢查询的信息写如慢查询日志文件中。具体可以查看

作用域:全局  、会话

本文第一点。慢查询:http://www.phpben.com/?post=67

————————————————-

4 low_priority_updates                    | OFF

这个变量是降低mysql写数据的权限的,mysql默认情况下写操作权限高于读操作。附加一些知识:在mysql MYISAM表中读写是串行,即是select时锁表,insert等待释放再,反之一样。然后为了减少锁存和锁读的频率,则引入了concurrent_insert这个变量,使读写能并行操作(具体根据concurrent_insert值还有mysql版本而定)

作用域:全局  、会话

在mysql5.06版本之后,concurrent_insert=0则读(select)的时候不能执行写(insert)concurrent_insert=1则select时写操作把数据写在文件,concurrent_insert=2和1差不多,不同的是:1在数据没内存碎片(洞)才能写在文件尾,否则还是写在洞里;而2则是在select时并发写入文件尾,当select释放读锁时,数据写入洞里面。—推荐用current_insert=2

官网描述:

Value

Description

0

Disables concurrent inserts

1

(Default) Enables concurrent insert for MyISAM tables that do not have holes

2

Enables concurrent inserts for all MyISAM tables, even those that have holes. For a table with a hole, new rows are inserted at the end of the table if it is in use by another thread. Otherwise, MySQL acquires a normal write lock and inserts the row into the hole.

回正题:

low_priority_updates=1则是比上述方法更极端,直接给读操作优先与写操作。(不推荐)

———————————————————-

5lower_case_file_system                  | ON

这是控制mysql数据库文件名在文件系统中是否对大小写敏感,默认是ON对大小写不敏感,OFF的话就是对大小写敏感。

作用域:全局

———————————————————-

6lower_case_table_names                 | 1

此变量是设置数据库名或表别名是否大小写敏感。

作用域:全局

0:存储时按照指定的表名,比较时对大小写敏感。

1:存储时按照小写(不管表是否有大写),比较时对大小写不敏感。

2:存储时按给定的表名,比较时用小写。

对于windows和Mac OX S 这些文件系统对大小写敏感的系统一般不设0,windows默认设置为1,Mac OX S设置为2。

————————————————————

7max_allowed_packet                      | 1048576

8net_buffer_length                       | 16384

先介绍net_buffer_length,它是每个客户端线程的连接缓存区和结果缓冲区都是通过net_buffer_length来初始化,net_buffer_length默认初始值是16384(16K),但其值最大可以达到max_allowed_packet设定值,max_allowed_packe默认值是1M,最大达到1073741824(1G),其值必须是1024的倍数,否则回落到最靠近1024倍数值(如1025则值是1024),在内存允许的情况下,max_allowed_packe越大越好。

若max_allowed_packe设置的小,当增改(insert/update/load data infile…)数据库时,若出现大字符串或blob类型列且大小大于max_allowed_packe值则会出现以下问题。

My.ini加入配置

net_buffer_length=1024  #默认是16384,这里改小为了测试

max_allowed_packet=1025#默认是1M,这里虽然是1025而事实上值是1024

笔者更新表某列(值大于1024)则出现:

ERROR 1153 (08S01): Got a packet bigger than ‘max_allowed_packet’ bytes

注意:在version()<5.0.84 net_buffer_length可以设置但没有效,version()=5.0.84是只读

————————————————————

9 max_binlog_cache_size                   | 4294963200

这是设置最大二进制日志的缓存区大小的变量。若处理多语句事务时需要的内存大小比设置值大的话就会提示一个error:Multi-statement transaction required more than ‘max_binlog_cache_size’ bytes of storage 。

这个变量最小值是4096(4K),最大值,在32位的系统中是4G,64位的是16P。

作用域:全局

在mysql5.0中,max_binlog_cache_size一修改则所有会话都受影响(可能之前的受延迟,笔者没查证过)

————————————————————–

10 max_binlog_size                         | 1073741824

这是设置每个二进制日志文件内容大小的变量,如果当前文件的数据量大于max_binlog_size的值时,则会关闭此文件,新建下个文件写入数据。

但是,当处理多语句事务(大事务)时,会出现文件数据大小比此值设置值大的情况。这是因为事务的二进制日志是块存储的,也就是说不会分割出来存放在两个日志文件中。

作用域:全局

——————————————————————

11 max_connect_errors                      | 10

设置某客户端链接mysql服务器失败次数,若次数超过此值,则锁定禁止该客户端链接服务器且提示错误,若在未超过此值有一次成功链接,则计数器会清零。

这是一个与性能无关的变量,而是安全方面考虑的,主要防止穷举法破解数据库用户和密码。

作用域:全局

默认值是10,32位系统1~ 4294967295,64位的是1~18446744073709547520

官方说:一旦锁定,要解锁只有方法:在mysql客户端flush hosts ;在mysqladmin中用mysqladmin flush-host

笔者在本机测试过:这个功能用不了 。

——————————————————————

12 max_connections                         | 100

这个设置数据库并发可连接的数量

作用域:全局

值域:

Version()<=5.1.14 :默认100

Version()>=5.1.15 :默认151  1~16384

Version()>=5.1.17 :默认151  1~100000

这是网站成长必要修改的一个变量,允许多少人在网站上并发操作。

——————————————————————

13max_delayed_threads                    | 20

延迟操作Delay_insert最大线程数

作用域:全局  、会话

默认20 值域:0~16384

—————————————————————–

14 max_error_count                         | 64

Show warning 或show error 显示warning或Error显示的最大个数,默认是64,值域0~65535.此值不能改太小,否者若错误提示个数比此值多的话不方便调试。

作用域:全局  、会话

注意:此值不要调太小;对于已经运行系统,可设为0,不会提示错误。

—————————————————————–

15max_heap_table_size                     | 16777216

内存表最大行数。

作用域:全局  、会话

值域:32位操作系统16384~4294967295  64位操作系统16384 ~ 1844674407370954752

默认值都是16777216

更新设置此值对已存在的内存表没影响(重启mysql服务器就有),对create/update/truncate语句有影响。

——————————————————————-

16max_insert_delayed_threads              | 20

是max_delayed_threads的别名,看第13点。

作用域:全局  、会话

———————————————————————–

17 max_join_size                           | 18446744073709551615

18 sql_big_selects                        | ON

max_join_size和sql_big_selects

作用域:全局  、会话

sql_big_selects默认值是1,表示所有select查询都执行(不管时间长短)。

sql_big_selects=0/OFF时,mysql先估算单表查询结果行数或多表查询组合行数的大小,若比max_join_size大时,就会放弃该查询语句。

max_join_size默认是4294967295,值域:1~4294967295

注意:sql_big_selects=0/OF的情况下,max_join_size不齐作用,且当max_join_size设置为非默认值时,sql_big_selects会被重置为0.

————————————————————————

19 max_length_for_sort_data                | 1024 ====

确定使用的filesort算法的索引值大小的限值。

作用域:全局  、会话

=========以下引用网上内容这是地址:http://www.itpub.net/thread-1417429-1-1.html

mysql的filesort算法有两种:

一种是最初的算法,在MySQL 4.1以前只有这种算法,一种是改进的filesort算法,它出现在MySQL 4.1以后(blob和text类型的字段不能采用这种改进算法)

 

“最初的算法”流程如下:

1.读取所有的满足条件的数据,只包含sort key和row pointer两种数据

2.在buffer中执行qsort排序

3.排完序后,再根据row pointer去读取相应的行数据

从中可以看出,每次排序都需要读两次表,而根据row pointer去读表往往都是随机离散读的,所有其开销非常大。

 

改进后的filesort算法是:

1.读取所需要的数据,包含sort key,row pointer和查询所需要访问的字段

2.根据sort key排序

3.按排序后的顺序读取数据,由于sort_buffer_size中包含了所需要的字段,因此不需要再回表了,可以直接返回结果给客户端。

很明显,这种改进的方法对sort_buffer_size的需求也大大增加.

 

所以为了防止性能下降,mysql增加了一个参数max_length_for_sort_data,当第一步中除了sort key以外的字段内容大于max_length_for_sort_data这个参数时,mysql将采用第一种排序算法。

——————————————————————–

20max_prepared_stmt_count                 | 16382

该变量设置预处理语句限制数。这个功能能防止拒绝服务攻击,因为攻击可以通过大量的预处理语句致使服务器内存溢出来攻击。设置此变量就是一道安全屏障,此变量对原有的预处理语句不影响,但若是预处理语句的数量超过该变量的值,则不会新增预处理语句,而是等到预处理语句的值小于max_prepared_stmt_count的值才增加新语句。

作用域:全局

默认值:16382 值域:0~1048576

若设为0则表示不允许预处理语句。

注意:该变量是version()>5.0.21才有

—————————————————————–

21max_relay_log_size                     | 0

中继日志大小,和第10点的max_binlog_size类同,只不过中继日志是保存从服务器的日志,是从主服务器复制过来的二进制日志。

当max_relay_log_size =0则max_relay_log_size=max_binlog_size

当max_relay_log_size >0则中继日志大小是max_relay_log_size设定的值

作用域:全局

默认值:0 值域:0~1073741824

—————————————————————–

22max_seeks_for_key                      | 4294967295

此变量假定索引搜索行数最大值。也就是说这个值是索引搜索最大值。查询优化器会忽略索引基数(用show index from table 可看到基数cardinality),它假定扫描索引匹配的行数不会超过max_seeks_for_key设定值。

官网:可以通过改小这个值来强制mysql使用索引来代替全表扫描。

作用域:全局  、会话

在32位系统:默认4294967295,值域:1~ 4294967295

在64位系统:默认18446744073709547520,值域1~18446744073709547520

——————————————————————–

23 max_sort_length                         | 1024

当排序BLOB或者TEXT类型列数据时用的字节数。当数据长度> max_sort_length设定值,排序就用max_sort_length的长度来排序,后面的数据被忽略。

作用域:全局  、会话

默认是1024 值域:4~ 8388608

———————————————————————-

25max_sp_recursion_depth                  | 0

设定存储过程(sp=>save procedures)最大递归数。

作用域:全局  、会话

默认0,禁止存储过程递归,最大值255

PS此变量在version()=5.0.17引入

———————————————————————-

26、 max_tmp_tables                          | 32

设定客户端同时能打开临时表个数的最大值

作用域:全局  、会话

32位系统:默认32 值域:1~4294967295

64位系统:默认32 值域:1~18446744073709547520

PS: 官网:This variable does not yet do anything(该变量还没生效)

————————————————————

27max_user_connections                   | 0

Mysql每个用户能同时链接服务器最大值。0表示没有限制

默认值:0 值域:1~ 4294967295

作用域:全局  、会话

———————————————————————-

28max_write_lock_count                    | 4294967295

设定数据表写锁定最大数,注意:这是对同一个表来说的。

作用域:全局

值域:

32位系统:默认4294967295 值域:1~ 4294967295

64位系统:默认18446744073709547520 值域:1~18446744073709547520

网上有人说:当对同一个表锁定个数超过设定值的时候,服务器会释放读锁定。

笔者有些怀疑,做了个测试:

max_write_lock_count =4294967295

开启三个客户端,第一个锁定写,第二个select读取,第三个有加一个锁定,顺序1、2、3

当笔者开第一个锁定时,读客户端还在等待。

max_write_lock_count =2

第一锁定表,第二selcet语句,第三锁定表

1、  解开第一个锁,select这边没反应

2、  再加一个锁定(三个,解开一个还有两个),selcct这边还是没反应

3、  加一个客户端insert数据,即时3锁1插入1查找,当解开一个锁时,selcet和插入都有了反应且正常运行。

笔者结论是

应该是:当写锁定超过限制且有其他客户端写操作时,部分读操作被释放。

——————————————————————

29min_examined_row_limit                 | 0

这也是判断一个查询是否是慢查询的一个变量,参考第1点的log_slow_queries

若查询的结果集行数大于min_examined_row_limit值,则查询被当作慢查询写入慢查询日志。

作用域:全局  、会话

值域:

32位系统:默认4294967295值域:1~ 4294967295

64位系统:默认18446744073709547520 值域:1~18446744073709547520

——————————————————————-

30multi_range_count                      | 256

veriosn=5.03加入该变量

设定查询语句中range范围最大个数,如“where id>100 and userId<50”是两个范围。

默认是256

作用域:全局  、会话

值域:1~ 4294967295

一般不改此参数。

———————————————————————

31 myisam_data_pointer_size                | 6

默认指针大小,单位是字节, MAX_ROWS不指定时,CREATE TABLE使用该变量创建MyISAM表。默认值是6。值域:2~7

作用域:全局

——————————————————————–

32 myisam_max_sort_file_size               | 107374182400

当用到REPAIR TABLE, ALTER TABLE, LOAD DATA INFILE的时候,相应的索引会被重建,然后要用到临时文件,此变量就是设置临时文件大小的。如果索引文件大小比此值小,系统则调用速度更慢的键值创建索引。

作用域:全局

默认是2G

官网建议:如果MyISAM索引文件大于2G且硬盘空间允许,增大该值可以提高性能。注意的是增加的空间是包含原来索引文件空间的。

———————————————————————–

33 myisam_mmap_size                        | 4294967295

Mmp:memory mapping 内存映射

设置使用内存映射压缩MyISAM表文件的最大内存量的变量。

如果许多压缩MyISAM表使用,可以通过降低该值来减低内存交换问题出现的可能性。

作用域:全局

值域:

32位系统:默认4294967295值域:1~ 4294967295

64位系统:默认18446744073709547520 值域:1~18446744073709547520

——————————————————————-

34myisam_recover_options                  | OFF

设置MyISAM存储模式,它的值可以是OFF, DEFAULT, BACKUP, FORCE, QUICK任意组合,组合值则用‘,’隔开。

默认是OFF。

若非OFF的话,表示每次打开MyISAM表都检查表是否崩溃或者非正常保存,否则和尝试修复表。

修复按照值选项而定:

OFF:关闭

DEFAULT:修复中没有BACKUP, FORCE, QUICK

BACKUP:如果修复过程中用户修改数据,则把“表名.MYD”文件备份成“表名-时间.BAK”文件

FORCE:继续修复数据即便是丢失大量数据

QUICK:不检查表中的行,如果没有任何删除块。

还有的是,修复之前,mysql会在错误日志中写入note,这个note关于修复的。

官网建议:如果想在不受用户打扰的情况下修复数据,则设置为“BACKUP, FORCE”。这样的话,就强制修复即便有人删除数据,修复完了还可以用备份数据查看发生情况。

作用域:全局

———————————————————————-

35 myisam_repair_threads                   | 1

myisam_repair_threads =1 则在repair by sort时,MyISAM表索引在各自线程中并发创建。

作用域:全局|会话

值域:

32位系统:默认1 值域:1~ 4294967295

64位系统:默认1 值域:1~18446744073709547520

————————————————————————

36 myisam_sort_buffer_size                 | 31457280

REPAIR TABLE或则 CREATE INDEX 和 ALTER TABLE创建索引的时候,.给分配的缓冲区的大小。

作用域:全局|会话

值域:

32位系统:默认8388608 值域:4~ 4294967295

64位系统:默认8388608  值域:4~18446744073709547520

————————————————————————

37myisam_stats_method                     | nulls_unequal

该变量告诉服务器,在服务器收集有关MyISAM表的索引值的分布统计时如何处理NULL值。变量可选三个值:nulls_equal, nulls_unequal, nulls_ignored.

Nulls_equal 时,所有null值都被当成一样,形成一个大小是null值个数的单值组。

nulls_unequal时,null被认为是不一样的(尽管我们看来是一样),每个null形成一个大小为1的不同值组。

nulls_ignored时,值被忽略

PS至于为什么要这样区别对待,这里有讲解http://www.phpben.com/?post=69

———————————————————————–

38myisam_use_mmap                        | OFF

这个变量开启的话,就利用内存映射来读和写myisam表,默认是关闭的OFF,一般内存服饰很大的情况下是不会开启这一项

作用域:全局

—————————————————————————

39named_pipe                              | OFF

该变量指示mysql服务器是否支持管道连接。

只使用windows系统

作用域:全局

—————————————————————————

40 net_read_timeout                        | 30

设置服务器放弃读前多少秒以等到更多的连接数据,当服务器从客户端读取,net_read_timeout是设施多少秒后终止读,而类是的变量net_write_timeout设置终止写。也就是mysql为了保证连接不被浪费在无尽的等待中,mysql 通过net_read_timeout、net_write_timeout来主动终止连接。

作用域:全局、会话

值域:默认30 最小是1

—————————————————————————-

41net_write_timeout                       | 60

看上。

作用域:全局、会话

值域:默认60 最小是1

—————————————————————————-

42net_retry_count                         | 10

如果读或写一个通信端口中断,mysql放弃前尝试连接的次数。在FreeBSD系统中此值应设置很高,因为FreeBSD内部中断被发送到所有线程去。

作用域:全局|会话

值域:

32位系统:默认10 值域:1~ 4294967295

64位系统:默认10  值域:1~18446744073709547520

—————————————————————————–

43 new                                     | OFF

该变量用于mysql4.0启用mysql4.1一些新功能,和为了保持向后兼容性。在mysql5.6中,这个变量的值都是OFF。

作用域:全局|会话

默认是False

—————————————————————————–

44 old                                     | OFF

Old是兼容性变量。默认被禁用,在旧版本的服务器可以通过重启服务器时启用。

目前,old被启用时,它改变使用索引提示的默认范围到MySQL5.1.17之前。也就是说,没有FOR子句仅适用于如何使用索引检索行,而不是解决ORDER BY或GROUP BY子句的索引提示。在复制设置启用这个变量时要注意些,基于语句的二进制日志,主从服务器有不同的模式可能会导致复制错误。

作用域:全局

默认是:OFF

——————————————————————————-

45old_alter_table                        | OFF

当该变量被启用,则mysql服务器不会使用alert table 优化方法。在mysql5.0和更早版本,先用个临时表,复制数据进去,然后重命名到原始的临时表。

作用域:全局

默认值:OFF

———————————————————————————-

46old_passwords                          | OFF

该变量设置是否启用mysql4.1之前的账户密码类型。

作用域:全局

默认值:OFF

———————————————————————————

47 open_files_limit                        | 622

设置操作系统允许mysqld允许打开的文件数。这是系统允许的真正值,可能和你用–open-files-limit选项给mysqld或mysqld_safe设置的值不同。该值是0的系统上,MySQL不能更改打开的文件数

作用域:全局

默认值:0 值域:0-65535

——————————————————————————

48optimizer_prune_level                  | 1

该变量为1,控制启发式应用在查询优化过程中,从优化空间中剪去不太有用的部分计划。

值0禁用启发式优化执行穷举搜索。

值1时让优化器根据被检索的行数通过中间计划来剪去不太有用的计划。

作用域:全局、会话

默认值:1

值域是:0或1

———————————————————————————

49 optimizer_search_depth                  | 62

查询优化器进行的搜索的最大深度。如果值大于查询中的关系数则查询方案比较佳,但生成查询执行方案需要的时间更长。值大于查询中的关系数则返回的执行方案更快,但方案远没有优化。如果设置为0, 系统自动选择合理的值。

作用域:全局、会话

默认值:62

值域是:0-62

ps:上述的关系数即时join连结中的表数。

如果optimizer_search_depth设置过大,那么join时,获取最优执行计划的代价十分巨大。

optimizer_search_depth = join tables的数量,一定能获得最优执行计划(根据mysql的代价估计模型),但是计算代价大。

optimizer_search_depth < join tables的数量,获取的执行计划,是局部最优,但是计算代价小。

optimizer_search_depth参数,对于单表查询无意义。

———————————————————————————-

50 optimizer_switch                        | index_merge=on,index_merge_union=on,

index_merge_sort_union=on,index_merge_intersection=on

优化器选项,有很多选项。

batched_key_access Controls use of BKA join algorithm
block_nested_loop Controls use of BNL join algorithm
engine_condition_pushdown Controls engine condition pushdown
index_condition_pushdown Controls index condition pushdown
index_merge Controls all Index Merge optimizations
index_merge_intersection Controls the Index Merge Intersection Access optimization
index_merge_sort_union Controls the Index Merge Sort-Union Access optimization
index_merge_union Controls the Index Merge Union Access optimization
mrr Controls the Multi-Range Read strategy
mrr_cost_based Controls use of cost-based MRR if mrr=on
semijoin Controls all semi-join strategies
firstmatch Controls the semi-join FirstMatch strategy
loosescan Controls the semi-join LooseScan strategy (not to be confused with LooseScan for GROUP BY)
materialization Controls materialization (including semi-join materialization)

————————————————————————————–

51pid_file                               | C:\ProgramData\MySQL\MySQL Server 5.1\Data\Bsky-PC.pid

进程ID (PID)文件的路径名。可以用–pid-file选项设置该变量

作用域:全局

值域是:文件目录,字符串

————————————————————————————-

52 plugin_dir                             | C:\Program Files\MySQL\MySQL Server

5.1\lib/plugin

插件目录的路径。在MySQL 5.1.2中加入了该变量。

如果插件目录对服务器可写,则有可能给用户通过“SELECT … INTO DUMPFILE”在目录中写可执行代码。可以通过设置插件目录只读来阻止或者给目录设置–secure-file-priv select可写老保持安全 。

类型:目录名

默认是:mysql安装目录/lib/pligin

—————————————————————————————-

53 port                                    | 3306

Mysql监听tcp/ip端口号

默认3306

—————————————————————————————-

54 preload_buffer_size                     | 32768

重载索引时分配的缓冲区大小

作用域:全局、会话

默认值:32768

值域是:1024~1073741824

55 profiling                               | OFF

设置show profile 命令是否可用。

当profiling=0/OFF 则show profile不可用

当profiling=1/ON  则show profile可用

ps: show profile是显示查询一些信息。

———————————————————————————————–

56profiling_history_size                  | 15

设置show profile 命令显示多少条查询的。

默认是15,最大值是100

若此变量的值是0则profiling=0/OFF

——————————————————————————————-

57protocol_version                        | 10

MySQL服务器使用的客户端/服务器协议的版本

作用域:全局

——————————————————————————————-

58 pseudo_thread_id                        | 0

这个变量是内部服务器使用。

——————————————————————————————–

59query_alloc_block_size                 | 8192

语句解析和执行过程中创建的对象分配的内存块分配大小。如果你有内存碎片的问题,它可能有助于提高此参数。

作用域:全局,会话

值域:

32位系统:默认8192 值域:1024~ 4294967295

64位系统:默认8192 值域:1024~18446744073709547520

———————————————————————————————-

60query_cache_limit                      | 1048576

不要缓存大于该值的结果。默认值是1048576(1MB)。

作用域:全局,会话

值域:

32位系统:默认1048576 值域:0~ 4294967295

64位系统:默认1048576 值域:0~18446744073709547520

——————————————————————————————–

61 query_cache_min_res_unit                | 4096

查询缓存分配的最小块的大小(字节)。 默认值是4096(4KB)

作用域:全局

值域:

32位系统:默认4096 值域:512~ 4294967295

64位系统:默认4096 值域:512~18446744073709547520

——————————————————————————————-

62query_cache_size                        | 104857600

为缓存查询结果分配的内存的数量。默认值是0,即禁用查询缓存。

请注意即使query_cache_type设置为0也将分配此数量的内存。

作用域:全局

值域:

32位系统:默认0 值域:0~ 4294967295

64位系统:默认0 值域:0~18446744073709547520

——————————————————————————————–

63query_cache_type                        | ON

设置查询缓存类型。设置GLOBAL值可以设置后面的所有客户端连接的类型。客户端可以设置SESSION值以影响他们自己对查询缓存的使用。下面的表显示了可能的值。

0或OFF

不要缓存或查询结果。请注意这样不会取消分配的查询缓存区。要想取消,你应将query_cache_size设置为0。

1或ON

缓存除了以SELECT SQL_NO_CACHE开头的所有查询结果。

2或DEMAND

只缓存以SELECT SQL_NO_CACHE开头的查询结果。

—————————————————————————————-

64query_cache_wlock_invalidate           | OFF

一般情况,当客户端对MyISAM表进行WRITE锁定时,如果查询结果位于查询缓存中,则其它客户端未被锁定,可以对该表进行查询。将该变量设置为1,则可以对表进行WRITE锁定,使查询缓存内所有对该表进行的查询变得非法。这样当锁定生效时,可以强制其它试图访问表的客户端来等待。

作用域:全局

值域:

默认FALSE

————————————————————————————-

65query_prealloc_size                     | 8192

用于查询分析和执行的固定缓冲区的大小。在查询之间该缓冲区不释放。如果你执行复杂查询,分配更大的query_prealloc_size值可以帮助提高性能,因为它可以降低查询过程中服务器分配内存的需求。

作用域:全局、会话

值域:

32位系统:默认8192 值域:8192~ 4294967295

64位系统:默认8192 值域:8192~18446744073709547520

————————————————————————————

66rand_seed1                             |

67rand_seed2                              |

这两个变量只作用域只是会话层,可以可写不可读,所以用show vriabales是显示不了变量的值。

这两个变量是为了使rand()函数支持被复制。在含有rand()查询中,主服务器必须给从服务器传递两个值,它们用于种子随机数发生器。从服务器使用这些值来设置会话变量rand_seed1和rand_seed2 以至从服务器产生与主服务器相同的值。

————————————————————————————–

68range_alloc_block_size                 | 4096

该变量是设置范围优化时分配的块的大小。

作用域:全局、会话

默认8192

值域:8192~ 4294967295

————————————————————————————-

69 read_buffer_size                        | 2097152

每个线程连续扫描时为扫描的每个表分配的缓冲区的大小(字节)。如果进行多次连续扫描,可能需要增加该值, 默认值为131072。该值应是4K的倍数,如果不是4k的倍数,则回滚到最接近4k倍数的值。

值域:4K~2G

—————————————————————————————

70read_only                               | OFF

当变量对复制从服务器设置为ON时,从服务器不允许更新,除非通过从服务器的线程或用户拥有SUPER权限。可以确保从服务器不接受客户端的更新命令。

READ_ONLY不适用临时表,也防止服务器日志表插入行,这个变量并不妨碍分析TABLE或OPTIMIZE TABLE命令语句的使用,因为其目的是为了防止表的结构或内容的变化。

READ_ONLY只存在一个全局变量,所以需要SUPER权限才能改变其值。在主服务器上的设置为READ_ONLY不会被复制到从服务器。可以在主从服务器上分开、独立的设置READ_ONLY的值。

作用域:全局

默认是:false

——————————————————————————————

71 read_rnd_buffer_size                    | 262144

当排序后按排序后的顺序读取行时,则通过该缓冲区读取行,避免搜索硬盘。将该变量设置为较大的值可以大大改进ORDER BY的性能。但是,这是为每个客户端分配的缓冲区,因此你不应将全局变量设置为较大的值。相反,只为需要运行大查询的客户端更改会话变量。

作用域:全局、会话

默认262144

值域:8200~ 4294967295

——————————————————————————————

72relay_log_index                         |

使用的中继日志索引文件的名称。默认名称是HOST_NAM_relay_bin.index数据目录中,其中host_name是从服务器的名称。

如果指定此选项,指定的值也被用作中继日志的主档名。

作用域:全局、会话

值:文件名

ps笔者这里没有中继日志,所以为空。

——————————————————————————————

73relay_log_info_file                    | relay-log.info

这是从服务器保存中继日志有关信息的文件名。

默认是relay-log.info

——————————————————————————————

74 relay_log_purge                         | ON

当不再需要中继日志时禁用或启用自动清空中继日志。默认值是1(启用)。

这是一个全局变量且可以通过SET GLOBAL relay_log_purge = N.来动态改变。

——————————————————————————————

75 relay_log_space_limit                   | 0

所有中继日志空间大小。

作用域:全局

值域:

32位系统:默认0 值域:0~ 4294967295

64位系统:默认0 值域:0~18446744073709547520

——————————————————————————————

76 report_host                             |

— report_host 选项的值

作用域:全局

字符串类型值

——————————————————————————————

77 report_password                         |

— report_password 选项的值 ,与MySQL的复制用户帐户使用的密码不相同。

作用域:全局

字符串类型值

——————————————————————————————

78 report_port                             | 3306

— report_port 选项的值

作用域:全局

默认是0

Ps:version()>5.6.5

——————————————————————————————

79 report_user                             |

— report_user 选项的值 ,与MySQL的复制用户帐户使用的账户不相同。

作用域:全局

——————————————————————————————

80 rpl_recovery_rank                       | 0

——————————————————————————————

81 secure_auth                             | OFF

如果用–secure-auth选项启动了MySQL服务器,它将阻塞有旧格式(4.1之前)密码的所有账户所发起的连接。在这种情况下,该变量的值为ON,否则为OFF。

 

如果你想要防止使用旧格式的密码(致使网络通信不安全),你应启用该选项。

Version()<=5.6.4默认是OFF

Version()>=5.6.5 默认是ON

——————————————————————————————

82 secure_file_priv                        |

该变量默认为空,若给该变量赋值(目录),则限制函数load_file(),load data,和select … into outfile 语句只有在相应目录下起作用。

作用域:全局

默认为空

——————————————————————————————

83server_id                              | 0

–server-id选项的值。用于主复制服务器和从复制服务器。

默认值:0

值域:0~ 4294967295

——————————————————————————————

84 shared_memory                           | OFF

(只用于Windows)服务器是否允许共享内存连接。

作用域:全局

——————————————————————————————

85shared_memory_base_name                 | MYSQL

(只用于Windows)说明服务器是否允许共享内存连接,并为共享内存设置识别符。当在单台机器上运行多个MySQL实例时很有用。

作用域:全局

——————————————————————————————

86skip_external_locking                  | ON

如果mysqld使用外部锁定,该值为OFF,否则是ON。这个在MYISAM表中有作用

——————————————————————————————

87skip_name_resolve                       | OFF

这是变量是通过选项—skip-name-resolve设置。

若是ON,在检查客户端连接时,mysqld会解析主机名。

若是OFF,mysqld使用唯一的IP号码和所有在授权表的Host列值必须是IP地址或localhost

——————————————————————————————

88skip_networking                        | OFF

如果服务器只允许本地(非TCP/IP)连接,该值为ON。在Unix中,本地连接使用Unix套接字文件。在Windows中,本地连接使用命名管道或共享内存。在NetWare中,只支持TCP/IP连接,因此不要将该变量设置为ON。

——————————————————————————————

89 skip_show_database                      | OFF

防止不具有SHOW DATABASES权限的人们使用SHOW DATABASES语句。如果你担心用户能够看见属于其它用户的数据库,这样设置可以提高安全性。其效果取决于SHOW DATABASES权限:如果变量值为ON,只允许具有SHOW DATABASES权限的人们使用SHOW DATABASES 语句,并且该语句将显示所有数据库名。如果值为OFF,允许所有用户执行SHOW DATABASES,但只显示用户具有SHOW DATABASES或其它权限的数据库的名称。

ps:这个对mysql服务器安全性能提升很有用

——————————————————————————————

90 slave_compressed_protocol               | OFF

如果ON,则在主、从服务器均支持,使用从/主压缩协议。

默认是OFF

——————————————————————————————

91 slave_exec_mode                         | STRICT

控制在复制的冲突解决和错误检查中是使用IDEMPOTENT模式还是STRICT模式。

IDEMPOTENT模式会发生抑制重复键和no-key-found错误,这种模式下,应采用多主复制,循环复制,和其他一些特殊的复制场景。

是默认模式,并适用于其他大多数情况下。

——————————————————————————————

92slave_load_tmpdir                      | C:\Windows\TEMP

这是从服务器复制load data infile语句时在哪里生成临时文件的目录。

默认是是系统的tmp文件夹。

——————————————————————————————

93slave_net_timeout                      | 3600

放弃读操作前等待主/从连接的更多数据的等待秒数。

作用域:全局

默认3600

最小值1

——————————————————————————————

94、 slave_skip_errors                       | OFF

正常的来说,当出现错误的时候,复制就会停止。

该变量为ON的时候,则告诉服务器复制不管在任何错误提示的情况下都继续进行下去。

默认:OFF

值有以下:

[list of error codes]

all

ddl_exist_errors

——————————————————————————————

95slave_transaction_retries              | 10

如果因为InnoDB出现死锁或超过InnoDB的innodb_lock_wait_timeout设置的时间,复制从服务器SQL线程未能执行事务,在提示错误并停止前它自动重复slave_transaction_retries次。 默认值是10。

——————————————————————————————

96 slow_launch_time                        | 2

当创建线程的时间超过该秒数,服务器则增加Slow_launch_threads状态变量。

——————————————————————————————

97slow_query_log                          | OFF

98slow_query_log_file                    | C:\ProgramData\MySQL\MySQL Server 5.

1\Data\Bsky-PC-slow.log

slow_query_log是否开启慢查询日志。slow_query_log_file是慢查询日志的路径。

这个和第一点类似

——————————————————————————————

99 socket                                  | MySQL

在uninx平台上,该变量的值是用于本地客户端连接的socket文件的名字,默认是‘tmp/mysql.socket’(对于一些分布式中,比较特殊,如RPMs 中是/var/lib/mysql)

在windows,则是本地客户端命名管道连接的文件名,默认是mysql(不区分大小写)

——————————————————————————————

100 sort_buffer_size                        | 262144

每个排序线程分配的缓冲区的大小。增加该值可以加快ORDER BY或GROUP BY操作。

当用show global status输出信息后,看到很多Sort_merge_passes输出,则要增加sort_buffer_size 的值来提高order by 、group by 的性能,这种情况通过优化器优化和索引是不起作用。

默认2G 最大4G

作用域:全局、会话

值域:

32位系统:默认2097144 值域:0~ 4294967295

64位系统:默认2097144 值域:0~18446744073709547520

——————————————————————————————

101 sql_auto_is_null                        | ON

如果sql_auto_is_null=1/ON,则会自动的插入给自动增长列插入值。

该值可以通过一下来获取

SELECT * FROM tbl_name WHERE auto_col IS NULL

如果有返回行数据,则插入的数值和last_insert_id()函数返回的值是一致。

默认是0

——————————————————————————————

102 sql_big_tables                          | OFF

保存所有临时值在文件中来启用大型结果集,此选项可防止最“表已满”的错误,而且还减慢查询内存中的表就足够了。自MySQL3.23.2中,服务器能够处理大的结果,小临时表使用内存和切换到磁盘表在必要时自动设置。

——————————————————————————————

103 sql_buffer_result                       | OFF

若是1,sql_buffer_result强迫用select语句返回的结果保存在临时表。这样可以提前解开表的锁定,且当给客户端发送结果集要很久的情况下很有用。

默认值0

作用域:全局,会话

——————————————————————————————

104sql_log_bin                            | ON

该变量控制语句是否写进二进制日志。

默认是开启。通过改变此变量来改变会话值,不过要有super权限

Ps:在version 5.6中没交易或子查询的情况下不可以通过set @@session.sql_log_bin来设置

——————————————————————————————

105sql_log_off                             | OFF

该变量控制是否写进常规日志。默认是OFF表示写,通过改变此变量来改变会话值,不过要有super权限

——————————————————————————————

106 sql_log_update                          | ON

是否开启更新日志。详情可以看http://www.phpben.com/?post=67

作用域:全局

——————————————————————————————

107 sql_low_priority_updates                | OFF

该控制控制读写优先级。

若值为1/ON,则读优先于写。即是所有INSERT, UPDATE, DELETE和 LOCK TABLE WRITE 语句都要等没有 SELECT或LOCK TABLE READ作用于表上

ps:一般情况下写优先于读

——————————————————————————————

108sql_max_join_size                       | 18446744073709551615

不允许可能需要检查多于max_join_size行(为单个表语句)或行组合(为多个表语句)或可能执行大于max_join_size次硬盘查询的SELECT语句。通过设置该值,你可以捕获键使用不正确并可能花很长时间的SELECT语句。如果用户想要执行没有WHERE子句的花较长时间或返回数百万行的联接,则设置它。

将该变量设置为DEFAULT之外的值,将SQL_BIG_SELECTS的值重设为0。如果你重新设置SQL_BIG_SELECTS值,sql_max_join_size变量被忽略。

如果查询结果位于查询缓存中,则不检查结果大小,因为前面已经计算了结果,不会要求服务器将它发送给客户端。

ps: max_join_size等同于sql_max_join_size

——————————————————————————————

109sql_mode       | STRICT_TRANS_TABLES,NO_AUTO_CREATE_U

SER,NO_ENGINE_SUBSTITUTION

——————————————————————————————

110 sql_notes                               | ON

若是1/on,warning_count数会增加且服务器会记录警告内容,否者不会。

mysqldump输出内容到这个变量设置为0,使重载转储文件不会产生警告事件不影响重载操作的完整性。

——————————————————————————————

111sql_quote_show_create                   | ON

若值为1,则会给SHOW CREATE TABLE和SHOW CREATE DATABASE添加服务器引号表示符

否则引号被禁用。

——————————————————————————————

112 sql_safe_updates                        | OFF

值若是1,则mysql则退出在where和limit字句中没关键字的update或delete语句。这有利于捕抓到键使用不当的update或delete语句。

默认值是0

——————————————————————————————

113sql_select_limit                       | 18446744073709551615

这是设置select查询语句返回数据最大行数。一个新的连接的默认值是服务器允许每个表的最大行数。如果你已经改变了极限,默认值可以通过指定一个DEFAULT值恢复。

——————————————————————————————

114sql_slave_skip_counter                 |

从服务器应跳过的从主服务器传来的事件的数量。

——————————————————————————————

115 sql_warnings                            | OFF

该变量操作单行插入数据出现warning错误时是否产生一个warning字符串信息。

默认值是0,1的话就产生信息。

——————————————————————————————

116 ssl_ca                                  |

一个受信任的SSL的CA列表中的文件路径。

作用域:全局

——————————————————————————————

117ssl_capath                             |

包含受信任的SSL PEM格式的CA证书目录的路径。

作用域:全局

——————————————————————————————

118ssl_cert                                |

为建立一个安全的连接使用的SSL证书文件的名称。

作用域:全局

——————————————————————————————

119 ssl_cipher                              |

允许使用SSL加密的密码列表。

作用域:全局

——————————————————————————————

120ssl_key                                |

为建立一个安全的连接使用的SSL密钥文件的名称。

作用域:全局

——————————————————————————————

121storage_engine                          | InnoDB

默认的存储引擎。

——————————————————————————————

122sync_binlog                             | 0

当值>0,则每一个sync_binlog写二进制日志后mysql都同步该日志到磁盘中(fddatasync()).

作用域:全局

值域:

32位系统:默认0 值域:0~ 4294967295

64位系统:默认0 值域:0~18446744073709547520

——————————————————————————————

123sync_frm                                | ON

若值为1,任何非临时表在创建其.frm文件时会同步到磁盘。这会速度变慢但数据奔溃时安全点。

作用域:全局变量。

默认是:true

——————————————————————————————

124system_time_zone                       |

服务器系统时区。当 服务器开始执行时,它继承机器默认时区设置值,可以由运行服务器的账户或在启动脚本中进行修改。该值用来设置system_time_zone。典型情况用TZ环境变量来指定时区。还可以用mysqld_safe脚本的–timez选项来指定。

作用域:全局

——————————————————————————————

125table_definition_cache                  | 256

可以存储在定义缓存的表定义的数目,如果使用大量的表,你可以创建一个大表的定义缓存,加快开放表,他表定义缓存占用较少的空间,并且不使用文件描述符,不像正常的表缓存。最低和默认值均为400。

作用域:全局

默认值:400

值域:0~ 524288

——————————————————————————————

126 table_lock_wait_timeout                 | 50

这个参数已经没用了

——————————————————————————————

127 table_open_cache                        | 256

所有线程一共能打开的表的数量,增加该值增加mysqld要求的文件描述符的数量。

可以通过检查Opened_tables状态变量来检查是否要增加该值。

如果Opened_tables状态变量很大则不需要用flush tables,而是怎么该变量的值。

作用域:全局

默认值:400

值域:400~52488

——————————————————————————————

128table_type                              | InnoDB

默认创建表时用到的引擎

——————————————————————————————

129thread_cache_size                       | 8

该变量设置多少个线程服务器重用缓存。当一个客户端断开连接的时候,该客户端的线程总数还没超过该值数时,则还是保存在缓冲区内。

如果有很多新的连接,则可以通过增加该值来提交性能。

通常情况下,这并不能提供一个显着的性能改进,除非你有一个很好的线程执行。

但是,如果服务器每秒有成千新连接的话,则需要确保该值足够大以至于新的连接的线程可以保存在缓存区内。

默认值:0

值域:0~16384

——————————————————————————————

130thread_handling                        | one-thread-per-connection

服务器用什么线程句柄来控制连接线程。

当值是no-theads,服务器使用单独的线程

当值是one-thread-per-connection,服务器用一个线程控制每一个客户连接。

当值是no-threads,在linux下debug是很有用的。

作用域:全局

——————————————————————————————

131thread_stack                           | 196608

每个线程的栈的大小。crash-me测试检测到的限制,很多都是依赖于这个值。

如果线程的堆栈大小是太小了,它限制了复杂的服务器可以处理的SQL语句,存储过程的递归深度,和其他消耗内存的行动。

作用域:全局

值域:

32位系统:默认196608 值域:131072~ 4294967295

64位系统:默认262144 值域:262144 ~18446744073709547520

——————————————————————————————

132 time_format                             | %H:%i:%s

该变量被弃用

——————————————————————————————

133time_zone                               | SYSTEM

当前的时区。初使值是’SYSTEM'(使用system_time_zone的值),但可以用–default-time-zone选项在服务器启动时显式指定。

作用域:全局、会话

——————————————————————————————

134timed_mutexes                          | OFF

——————————————————————————————

135 timestamp                               | 1335315763

时间戳

 

设置此客户端的时间。这是用来取得原始时间戳,如果您使用的二进制日志恢复行。 timestamp_value应该是一个Unix纪元时间戳,而不是一个MySQL时间戳。

——————————————————————————————

136 tmp_table_size                          | 15728640

如果内存内的临时表超过该值,MySQL自动将它转换为硬盘上的MyISAM表。如果你执行许多高级GROUP BY查询并且有大量内存,则可以增加tmp_table_size的值。

作用域:全局、会话

默认值:0

值域:1024~ 4294967295

——————————————————————————————

137 tmpdir                                  | C:\Windows\TEMP

临时目录的路径

——————————————————————————————

138 transaction_alloc_block_size            | 8192

将保存到二进制日志中的事务的查询而分配的内存块的大小

作用域:全局、会话

值域:

32位系统:默认8192 值域:1024~ 4294967295

64位系统:默认8192值域:1024 ~18446744073709547520

——————————————————————————————

139transaction_prealloc_size              | 4096

为transaction_alloc_blocks分配的固定缓冲区的大小(字节),在两次查询之间不会释放。使该值足够大,将所有查询固定到一个事务中,可以避免多次malloc()调用。

作用域:全局、会话

值域:

32位系统:默认4096 值域:1024~ 4294967295

64位系统:默认4096值域:1024 ~18446744073709547520

——————————————————————————————

140 tx_isolation                            | REPEATABLE-READ

默认事务隔离级别。默认值为REPEATABLE-READ

该变量可以被直接设置(全局),也可以通过set transaction=值 语句来设置。

值可以是:

READ-UNCOMMITTED

READ-COMMITTED

REPEATABLE-READ

SERIALIZABLE

——————————————————————————————

141unique_checks                                 | ON

该变量控制是否在InnoDB表的辅助索引的唯一性进行检查。

当值是0/OFF,则服务器假设输入的数据不存在重复键,储存引擎则跳过运行。(这个是你要储存的数据不用唯一性)

作用域:全局、会话

默认值是1

——————————————————————————————

142updatable_views_with_limit             | YES

该变量控制如果更新包含LIMIT子句,是否可以在当前表中使用不包含主关键字的视图进行更新。(通常用GUI工具生成这类更新)。更新指UPDATE或DELETE语句。这儿主关键字指PRIMARY KEY,或一个UNIQUE索引,其中任何列不可以包含NULL。

该变量有两个值:

值是1或YES:只发出警告(没有错误消息)。这是 默认值。

值是0或NO:禁止更新。

作用域:全局、会话

默认值是1

——————————————————————————————

143version                                 | 5.1.49-community

服务器的版本号

——————————————————————————————

144version_comment                         | MySQL Community Server (GPL)

configure脚本有一个–with-comment选项,当构建MySQL时可以进行注释。该变量包含注释值

作用域:全局

——————————————————————————————

145version_compile_machine                 | ia32

该Mysql程序是用什么工具编译出来的

——————————————————————————————

146version_compile_os                      | Win32

该Mysql程序是编译时的操作系统

——————————————————————————————

147wait_timeout                            | 28800

服务器关闭非交互连接之前等待活动的秒数

作用域:全局、会话

值域:

32位系统:默认28800 值域:1~ 4294967295

64位系统:默认28800 值域:1 ~18446744073709547520

——————————————————————————————

148 warning_count                           | 1

上一个查询语句出现的errors, warnings, notes错误的数目。

 

 

来自写于1971年的《程序开发心理学(The Psychology of Computer Programming)》,下面就是这无私编程十条诫律:

  1. 理解和接受自己会犯错误。关键是要尽早发现,在错误进入到最终产品前发现它们。幸运的是,除了我们少数几个在喷气推进实验所开发火箭导航系统的人外,在软件行业中犯错误通常不会导致灾难性事故。我们可以,也应该从错误中吸取教训,微笑,并继续前进。
  2. 你不是你的代码。记住代码审查的全部目的就是去发现问题,相信问题会被我们发现。当有问题疏漏时不要自责。
  3. 不管你对“空手道”有多了解,一定会有人知道的更多。如果你去问,这样的人可以告诉你一些新的招数。从别人那里寻找和接受新的知识,特别是那些你认为不需要的知识。
  4. 不要在没有讨论的情况下重写代码。在“调整代码”和“重写代码”之间有一条很细致的界限,你应该在代码审查的制度下做风格上的调整,不要独断专行。
  5. 对那些不如你的人要尊敬,礼遇,有耐心。经常跟开发人员打交道的非技术人士通常持有这样的观点:程序员凭借一技之长狂放不羁。不要让你的发怒和缺乏耐性让他们心中的这种形象加深。
  6. 这世界上唯一不变的就是变化。开放思考,面带微笑的接受它。把需求上、平台或工具里的每个改变都视作一种新的挑战,而不是把它们当作大麻烦来抵制。
  7. 真正的权威来自知识,而不是职位。知识造就权威,权威带来尊敬——所以,如果你想在一个无私的环境中获得尊敬,去培养自己的知识吧。
  8. 为信仰奋斗,但我文雅的接受失败。要理解,有时候你的想法会被拒绝。即使你是对的,你也不要报复或说“I told you so.”千万不要让你心爱的被抛弃的想法变成殉道者或抱怨素材。
  9. 不要成为“角落里的程序员。”不要成为隐藏在黑暗办公室里、只因为口渴才出现的人。藏在角落的里程序员短视、与世隔绝、不受控制。这样的人在公开的、合作的工作环境中发不出声音。参与到交流中,成为你的办公室团体中的一员。
  10. 批评代码而不是人——对编码人友善,但不要对代码友善。尽可能的让你的批评具有积极性,以改进代码为目标。批评要联系本地标准,编程规格文档和提高后的性能等。

今天在外刊IT评论网看到这样一篇文章:

 

命令,不要去询问(Tell, Don’t Ask)

http://www.aqee.net/tell-dont-ask/

前些时间我曾经翻译过一篇叫做《这里我说了算!》的文章,里面作者讲述了关于“命令,不要去询问(Tell, Don’t Ask)”原则:

我看到的最多被违反的原则是“命令,不要去询问(Tell, Don’t Ask)”原则。这个原则讲的是,一个对象应该命令其它对象该做什么,而不是去查询其它对象的状态来决定做什么(查询其它对象的状态来决定做什么也被称作‘功能嫉妒(Feature Envy)’)。

这篇文章里有个很生动的例子,我至今记忆犹新:

if (person.getAddress().getCountry() == “Australia”) {

这违反了得墨忒耳定律,因为这个调用者跟Person过于亲密。它知道Person里有一个Address,而Address里还有一个country。它实际上应该写成这样:

if (person.livesIn(“Australia”)) {

非常的明了。今天我又看到一个关于“Tell, Don’t Ask”原则的文章,里面提供了4个关于这个原则的例子,都很有价值。

例一

不好:

<% if current_user.admin? %>
  <%= current_user.admin_welcome_message %>
<% else %>
  <%= current_user.user_welcome_message %>

<% end %>

好:
5997caf39e2611_

例二

不好:

def check_for_overheating(system_monitor)

  if system_monitor.temperature > 100
    system_monitor.sound_alarms
  end

end

好:
system_monitor.check_for_overheating

class SystemMonitor
  def check_for_overheating

    if temperature > 100
      sound_alarms
    end
  end

end

例三

不好:

class Post
  def send_to_feed

    if user.is_a?(TwitterUser)
      user.send_to_feed(contents)
    end

  end
end

好:
class Post
  def send_to_feed

    user.send_to_feed(contents)
  end
end

class TwitterUser
  def send_to_feed(contents)

    twitter_client.post_to_feed(contents)
  end
end

class EmailUser
  def send_to_feed(contents)

    # no-op.
  end
end

例四

不好:

def street_name(user)

  if user.address
    user.address.street_name
  else

    'No street name on file'
  end
end

好:
def street_name(user)

  user.address.street_name
end

class User
  def address

    @address || NullAddress.new
  end
end

class NullAddress

  def street_name
    'No street name on file'
  end
end

好的面向对象编程是告诉对象你要做什么,而不是询问对象的状态后根据状态做行动。数据和依赖这些数据的操作都应该属于同一个对象。

命令,不要去询问!

其中最核心的是:好的面向对象编程是告诉对象你要做什么,而不是询问对象的状态后根据状态做行动。数据和依赖这些数据的操作都应该属于同一个对象。我的理解其实这也就是解耦,解除对象与对象间过多的依赖关系,同时,用面向对象的思路替代面向过程,尤其是在多分支if的情况下。其实重构很简单,关键是能不能看到需要重构的点,并且选择何时的重构方式。

但是,在现实开发中,有太多例子是违反这条“tell,don’t ask”规则了。

比如,在我们的项目中,有一个登录函数,其中需要根据不同的条件,选择不同的登录方式,验证码、密码判断规则等等,而这不同的登录方式,在失败的情况下,每一种都会返回多种不同的错误码,需要进行不同的错误处理。这其实是一个利用多态的好场景,或者说的专业一点,可以利用策略模式。而我们之前的做法是声明了不同的类,而类中处理方法的主体其实是一样的,但是repeat myself了!然后在登录函数中,用if分支调用这些类,并且接收返回值,进行处理。这个登录函数有374行。这也造成了当我们需要在通用逻辑里添加一些小功能的时候,需要修改每一个处理类。而,如果我们采用简单工厂和策略的方式,一个是代码逻辑会很清晰;再一个将公共部分抽取出来,是可以复用的;而今后对公共部分的修改也控制在一个地方,减少人力和减少出错的可能性。

附策略模式定义:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.(策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。)