July 22nd, 2010 | Tags: , , , ,

用rotatelogs实现日志轮循

Apache 提供了不把日志直接写入文件,而是通过管道发送给另外一个程序的能力。
这样就大大加强了对日志进行处理的能力。这个通过管道得到的程序可以是任何程序,如日志分析、压缩日志等。
要实现将日志写到管道的操作,只需要将配置中日志文件部分的内容替换为“|程序名”即可,例如:

# compressed logs
$ CustomLog “|/usr/bin/gzip -c >> /var/log/access_log.gz” common

这样就可以使用Apache自带的轮循工具rotatelogs来对日志文件进行轮循。rotatelogs基本是按时间或大小来控制日志的。

$ CustomLog “|/www/bin/rotatelogs /www/logs/secfocus/access_log 86400″ common

上面的示例中,Apache访问日志被发送给程序rotatelogs;rotatelogs将日志写入 /www/logs/secfocus/access_log,
并每隔86400秒(1天)对日志进行一次轮循。轮循以后的文件名为 /www/logs/secfocus/access_log.nnn,
这里nnn是开始记录日志的时间。因此,为了将日志按天对齐需要在凌晨00:00 启动服务,
使得每天轮循得到的日志刚好是完整一天的日志,以提供给访问统计分析程序进行处理。
如果是00:00开始生成新的日志,那么轮循得到的日志就是 access_log.0000。

用cronolog实现日志轮循

www.cronolog.org
Cronolog是一个小巧高效的日志文件处理工具,可以实现自动的按规则生成周期性的日志文件

首先需要下载和安装cronolog,可以到http://www.cronolog.org下载最新版本的cronolog。
下载完毕以后,解压安装即可。方法如下所示:

tar xvfz cronolog-1.6.2.tar.gz
cd cronolog-1.6.2
./configure
make
make check
make install

这样就完成了cronolog的配置和安装,默认情况下cronolog是安装在/usr/local/sbin下。

修改Apache日志配置命令如下所示:

$ CustomLog “|/usr/local/sbin/cronolog /www/logs/secfocus/%w/access_log” combined

这里%w表示按照日期在不同的目录下保存日志,这种方式会保存一周的日志。

为了进行日志分析,需要每天将该日志文件拷贝(或移动,如果不希望保存一周的日志)到一个固定的位置,
以方便日志分析统计文件进行处理(使用crontab -e)。添加定时任务如下:

$ 5 0 * * * /bin/mv /www/logs/secfocus/`date -v-1d +\%w`/access_log /www/logs/secfocus/access_log_yesterday

再使用日志统计分析程序,对文件access_log_yesterday进行处理。

对于使用负载均衡技术的大型站点,就存在多个服务器的访问日志的合并处理问题。对于这种情况,
各个服务器定义或移动日志文件时就不能使用 access_log_yesterday了,
而应该带上服务器编号(例如服务器IP地址等信息)加以区分。然后在各个服务器上运行网站镜像和备份服务 rsyncd,
再将每个服务器每天的安装配置文件通过rsync下载到专门进行访问统计分析的服务器上进行合并。

合并多个服务器的日志文件(如log1、log2、log3),并输出到log_all中的方法是:

$ sort -m -t ” ” -k 4 -o log_all log1 log2 log3

-m表示使用merge优化算法;-k 4表示根据时间进行排序;-o表示将排序结果存放到指定的文件中

%    %字符
n    换行
t    水平制表符
时间域:
H    小时(00..23)
I    小时(01..12)
p    该locale下的AM或PM标识
M    分钟(00..59)
S    秒 (00..61, which allows for leap seconds)
X    该locale下时间表示符(e.g.: “15:12:47″)
Z    时区。若时区不能确定,则无意义
日期域:
a    该locale下的工作日简名(e.g.: Sun..Sat)
A    该locale下的工作日全名(e.g.: Sunday .. Satur-ay)
b    该locale下的月份简称(e.g.: Jan .. Dec)
B    该locale下的月份全称(e.g.: January .. December)
c    该locale下的日期和时间(e.g.: “Sun Dec 15 14:12:47 GMT 1996″)
d    当月中的天数 (01 .. 31)
j    当年中的天数 (001 .. 366)
m    月数 (01 .. 12)
U    当年中的星期数,以周日作为一周开始,其中第一周为首个含星期天的星期(00..53)
W    当年中的星期数,以星期一作为一周的开始,其中第一周为首个含星期天的星期(00..53)
w    工作日数(0 .. 6, 0表示星期天)
x    该locale下的日期表示(e.g. “13/04/97″)
y    两位数的年份(00 .. 99)
Y    四位数的年份(1970 .. 2038)

webalizer

webalizer是一个高效、免费的Web服务器日志分析程序。其分析结果是HTML文件格式的,
从而可以很方便地通过Web服务器进行浏览。Internet上的很多站点都使用webalizer进行Web服务器日志分析。
Webalizer具有以下一些特性。

◆ 它是用C语言写的程序,具有很高的运行效率。在CPU主频为200MHz的机器上,webalizer每秒钟可以分析1万条记录,
所以分析一个40MB大小的日志文件只需要15秒。

◆ webalizer支持标准的一般日志文件格式(Common Logfile Format)。除此之外,也支持几种组合日志格式的变种,
从而可以统计客户情况及客户操作系统类型。现在webalizer已经可以支持wu-ftpd xferlog日志格式及squid日志文件格式。

◆ 支持命令行配置及配置文件。

◆ 可以支持多种语言,也可以自己进行本地化工作。

◆ 支持多种平台,比如Unix、Linux、NT、OS/2和MacOS等。

1.安装

在安装以前,首先需要确保系统已经安装有gd库,可以使用下段代码:

# rpm -qa|grep gd
# gd-devel-1.8.4-4
# gdbm-devel-1.8.0-14
# gdbm-1.8.0-14
# sysklogd-1.4.1-8
# gd-1.8.4-4

用来确认系统已经安装有gd-deve和gd两个RPM包。

安装webalizer有两种方式:一种是下载源代码来安装;一种是直接使用RPM包来安装。

使用RPM包方式安装非常简单,从rpmfind.net找到webalizer包,下载以后运行以下代码,即可实现安装:

$ rpm -ivh webalizer-2.01_10-1.i386.rpm

对于源代码方式需要从http://www.mrunix.net/webalizer/下载,然后安装。首先解开源代码包:

$ tar xvzf webalizer-2.01-10-src.tgz

在生成的目录中有个lang目录。该目录中保存了各种语言文件,但是只有繁体中文版本,
可以自己转换成简体,或者重新翻译一下,然后进入生成的目录:

$ cd webalizer-2.01-10 $ ./configure $ make –with-language=Chinese $ make install

编译成功后,会在/usr/local/bin/目录下安装一个webalizer可执行文件

2.配置和运行

对webalizer运行的控制可以通过配置文件或在命令行指定参数的两种方式进行。
使用配置文件方式比较简单和灵活,适用于自动Web服务器日志统计分析的应用环境。

webalizer 的默认配置文件为/etc/webalizer.conf,当启动webalizer时没有使用“-f“选项时,
webalizer就会寻找文件 /etc/webalizer.conf,也可以使用“-f”来指定配置文件(当服务器有虚拟主机时,
需要配置多份不同的webalizer配置文件。不同的虚拟主机的webalizer使用不同的配置文件。
webalizer.conf配置文件中需要修改的配置选项如下:

LogFile /www/logs/secfocus/access_log

用来指示配置文件的路径信息,webalizer会将该日志文件作为输入进行统计分析:

OutputDir /www/htdocs/secfocus/usage

用来指示生成的统计报表的保存目录,在前面使用alias,使用户可以使用http://www.secfocus.com/usage/来访问统计报 表。

HostName www.secfocus.com

上述代码用来指示主机名,统计报表中会引用该主机名。

其它选项无需修改。配置文件修改完毕以后,需要定时webalizer,每天生成当日的统计分析。

以root身份运行crontab -e进入定时运行任务编辑状态,加入如下任务:

$ 5 0 * * * /usr/local/bin/webalizer -f /etc/secfocus.webalizer.conf
$ 15 0 * * * /usr/local/bin/webalizer -f /etc/tomorrowtel.webalizer.conf

这里假设系统运行有两个虚拟主机,并分别定义了日志分析配置文件secfocus.webalizer.conf和 tomorrowtel.webalizer.conf。
这样定义在凌晨00:05对secfocus的日志进行统计分析;在凌晨00:15对 tomorrowtel的日志进行统计分析。

第二天分别使用http://www.secfocus.com/usage和http://www.tomorrowtel.com/usage来查看 各自的日志分析报表。

保护日志统计分析报告不被未授权用户访问

我们都不希望自己网站访问统计信息随意被别人浏览,因此需要将usage目录保护起来,只允许合法的用户访问。
这里可以采用Apache自带的基本认证机制。

1.条件

在配置文件中对目录“/”应该设置为:

DocumentRoot /www/htdocs/secfocus/
AccessFileName .htaccess
AllowOverride All

2.需求

需求是限制对http://www.secfocus.com/usage/的访问,要求用户认证才能访问。这里设置用户为“admin”,口令为 “12345678”。

使用htpasswd建立用户文件:

$ htpasswd -c /www/.htpasswd admin

此程序会询问用户“admin”的口令,输入“12345678”两次生效。

3.建立.htaccess文件

用vi在/www/logs/secfocus/usage/目录下建立一个文件.htaccess,写入以下几行代码:

AuthName admin-only
AuthType Basic
AuthUserFile /www/.htpasswd
require user admin

测试

通过浏览器访问http://www.secfocus.com/usage,就会弹出框请求输入用户名和口令,
输入“admin”、“12345678”就可以访问访问日志统计分析报表。

via:http://hi.baidu.com/24xinhui/blog/item/96bca4da7e859dddb6fd48aa.html

July 22nd, 2010 | Tags: ,

LogFormatCustomLog指 令的格式化参数是一个字符串。这个字符串会在每次请求发生的时候,被记录到日志中去。它可以包含将被原样写入日志的文本字符串以及C风格的控制字 符”\n”和”\t”以实现换行与制表。文本中的引号和反斜杠应通过”\”来转义。

请求本身的情况将通过在格式字符串中放置各种”%“转义符的方法来记录,它们在写入日志文件时,根据下表的定义 进行转换:

格式字符串 描述
%% 百分号(Apache2.0.44或更高的版本)
%a 远端IP地址
%A 本机IP地址
%B 除HTTP头以外传送的字节数
%b 以CLF格式显示的除HTTP头以外传送的字节数,也就是当没有字节传送时显示’-‘ 而不是0。
%{Foobar}C 在请求中传送给服务 端的cookieFoobar的内容。
%D 服务器处理本请求所用时间,以微为单位。
%{FOOBAR}e 环境变量FOOBAR的 值
%f 文件名
%h 远端主机
%H 请求使用的协议
%{Foobar}i 发送到服务器的请求 头Foobar:的内容。
%l 远端登录名(由identd而来,如果支持的话),除非IdentityCheck设 为”On“,否则将得到一个”-”。
%m 请求的方法
%{Foobar}n 来自另一个模块的注解Foobar的 内容。
%{Foobar}o 应答头Foobar:的 内容。
%p 服务器服务于该请求的标准端口。
%P 为本请求提供服务的子进程的PID。
%{format}P 服务于该请求的PID或TID(线程ID),format的 取值范围为:pidtid(2.0.46及以后版本)以及hextid(需 要APR1.2.0及以上版本)
%q 查询字符串(若存在则由一个”?” 引导,否则返回空串)
%r 请求的第一行
%s 状态。对于内部重定向的请求,这个状态指的是原始请 求的状态,—%>s则指的是最后请求的状态。
%t 时间,用普通日志时间格式(标准英语格式)
%{format}t 时间,用strftime(3)指 定的格式表示的时间。(默认情况下按本地化格式)
%T 处理完请求所花时间,以秒为单位。
%u 远程用户名(根据验证信息而来;如果返回status(%s) 为401,可能是假的)
%U 请求的URL路径,不包含查询字符串。
%v 对该请求提供服务的标准ServerName
%V 根据UseCanonicalName指 令设定的服务器名称。
%X 请求完成时的连接状态:

X= 连接在应答完成前中断。
+= 应答传送完后继续保持连接。
-= 应答传送完后关闭连接。

(在1.3以后的版本中,这个指令是%c,但这样就和过去的SSL语法:%{var}c冲 突了)

%I 接收的字节数,包括请求头的数据,并且不能为零。要使用这个 指令你必须启用mod_logio模 块。
%O 发送的字节数,包括请求头的数据,并且不能为零。要使用这个 指令你必须启用mod_logio模 块。

修饰符

可以紧跟在”%”后面加上一个逗号分隔的状态码列表来限制记录的条目。例如,”%400,501{User-agent}i” 只记录状态码400和501发生时的User-agent头内容;不满足条件时用”-“代替。状态 码前还可以加上”!“前缀表示否定,”%!200,304,302{Referer}i“记录所有不 同于200,304,302的状态码发生时的Referer头内容。

“<”和”>”修饰符可以用来指定对于已被内部重定向的请求是选择原始的请求还是选择最终的请求。默认情况下,%s, %U, %T, %D, %r 使用原始请求,而所有其他格式串则选择最终请求。例如,%>s 可以用于记录请求的最终状态,而 %<u 则记录一个已经被内部重定向到非认证资源的请求的原始认证用户。

ps:时间格式还可以这样,比如%{%Y-%m-%d}t  这样显示的格式是2010-07-22

via:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_log_config.html#formats

July 19th, 2010 | Tags: ,

表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值:

1) application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单 会将表单域的值处理成URL编码方式。

2) multipart/form-data:这种编码方式的表单会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数 里。

3) text/plain:这种方式主要适用于直接通过表单发送邮件的方式。

文件上传是web应用经常用到的一个知识。原理是,通过为表单元素设置enctype=”multipart/form-data”属性,让表单提交 的数据以二进制编码的方式提交,在接收此请求的Servlet中用二进制流来获取内容,就可以取得上传文件的内容,从而实现文件的上传

在Java领域中,有两个常用的文件上传项目:一个是Apache组织Jakarta的Common-FileUpload组件 (http://commons.apache.org/fileupload/),另一个是Oreilly组织的COS框架(http: //www.servlets.com/cos/)。利用这两个框架都能很方便的实现文件的上传。

via:http://bluelzx.javaeye.com/blog/195264

July 18th, 2010 | Tags: ,

vim小技巧

打开文件后,不用任何鼠标、菜单,只须在键盘上按下“ggguG”就行了。

极品软件就是这样:唯有功能强到极致,操作才能简到极致!

解释一下:ggguG分作三段gg gu G

gg=光标到文件第一个字符

gu=把选定范围全部小写

G=到文件结束

Vim 正则匹配次数需要 a/{2} 而不仅仅是 a{2}

单独使用guu将当前行转小写。
单独使用gUU将当前行转大写。

光标控制命令

命令 光标移动
h或^h 向左移一个字符
j或^j或 ^n 向下移一行
k或^p 向上移一行
l或空格 向右移一个字符
G 移到文件的最后一行
nG 移到文件的第n行
w 移到下一个字的开头
W 移到下一个字的开头,忽略标点符号
b 移到前一个字的开头
B 移到前一个字的开头,忽略标点符号
L 移到屏幕的最后一行
M 移到屏幕的中间一行
H 移到屏幕的第一行
e 移到下一个字的结尾
E 移到下一个字的结尾,忽略标点符号
( 移到句子的开头
) 移到句子的结尾
{ 移到段落的开头
} 移到下一个段落的开头
0或| 移到当前行的第一列
n| 移到当前行的第n列
^ 移到当前行的第一个非空字符
$ 移到当前行的最后一个字符
+或return 移到下一行的第一个字符
- 移到前一行的第一个非空字符

在vi中添加文本

命令 插入动作
a 在光标后插入文本
A 在当前行插入文本
i 在光标前插入文本
I 在当前行前插入文本
o 在当前行的下边插入新行
O 在当前行的上边插入新行
:r file 读入文件file内容,并插在当前行后
:nr file 读入文件file内容,并插在第n行后
escape 回到命令模式
^v char 插入时忽略char的指定意义,这是为了插入特殊字符

在vi中删除文本

命令 删除操作
x 删除光标处的字符,可以在x前加上需要删除的字符数目
nx 从当前光标处往后删除n个字符
X 删除光标前的字符,可以在X前加上需要删除的字符数目
nX 从当前光标处往前删除n个字符
dw 删至下一个字的开头
ndw 从当前光标处往后删除n个字
dG 删除行,直到文件结束
dd 删除整行
ndd 从当前行开始往后删除
db 删除光标前面的字
ndb 从当前行开始往前删除n字
:n,md 从第m行开始往前删除n行
d 或d$ 从光标处删除到行尾
dcursor_command 删除至光标命令处,如dG将从当产胆行删除至文件的末尾
^h或backspace 插入时,删除前面的字符
^w 插入时,删除前面的字

修改vi文本

每个命令前面的数字表示该命令重复的次数
命令 替换操作
rchar 用 char替换当前字符
R text escape 用text替换当前字符直到换下Esc键
stext escape 用 text代替当前字符
S或cctext escape 用text代替整行
cwtext escape 将当前字改为text
Ctext escape 将当前行余下的改为text
cG escape 修改至文件的末尾
ccursor_cmd text escape 从当前位置处到光标命令位置处都改为text

在vi中查找与替换

命令 查找与替换操作
/text 在文件中向前查找text
?text 在文件中向后查找text
n 在同一方向重复查找
N 在相反方向重复查找
ftext 在当前行向前查找text
Ftext 在当前行向后查找 text
ttext 在当前行向前查找text,并将光标定位在text的第一个字符
Ttext 在当前行向后查找text,并将光标定位在text的第一个字符
:set ic 查找时忽略大小写
:set noic 查找时对大小写敏感
:s/oldtext/newtext 用newtext替换oldtext
:m,ns/oldtext /newtext 在m行通过n,用newtext替换oldtext
& 重复最后的:s命令
:g/text1 /s/text2/text3 查找包含text1的行,用text3替换text2
:g/text/command 在所有包含text的行运行command所表示的命令
:v/text/command 在所有不包含text的行运行command 所表示的命令

在vi中复制文本

命令 复制操作
yy 将当前行的内容放入临时缓冲区
nyy 将n行的内容放入临时缓冲区
p 将临时缓冲区中的文本放入光标后
P 将临时缓冲区中的文本放入光标前
“(a-z)nyy 复制n行放入名字为圆括号内的可命名缓冲区,省略n表示当前行
“(a-z)ndd 删除n行放入名字为圆括号内的可命名缓冲区,省略n表示当前行
“(a- z)p 将名字为圆括号的可命名缓冲区的内容放入当前行后
“(a-z)P 将名字为圆括号的可命名缓冲区的内容放入当前行前

在vi中撤消与重复

命令 撤消操作
u 撤消最后一次修改
U 撤消当前行的所有修改
. 重复最后一次修改
, 以相反的方向重复前面的f、F、t或T查找命令
; 重复前面的f、F、t或T查找命令
“np 取回最后第n次的删除(缓冲区中存有一定次数的删除内容,一般为9)
n 重复前面的/或?查找命令
N 以相反方向重复前面的/或?命令

保存文本和退出vi

命令 保存和/或退出操作
:w 保存文件但不退出vi
:w file 将修改保存在file中但不退出vi
:wq或ZZ或:x 保存文件并退出vi
:q! 不保存文件,退出vi
:e! 放弃所有修改,从上次保存文件开始再编辑

vi中的选项

选项 作用
:set all 打印所有选项
:set nooption 关闭option选项
:set nu 每行前打印行号
:set showmode 显示是输入模式还是替换模式
:set noic 查找时忽略大小写
:set list 显示制表符(^I)和行尾符号
:set ts=8 为文本输入设置tab stops
:set window=n 设置文本窗口显示n行

vi的状态

选项 作用
:.= 打印当前行的行号
:= 打印文件中的行数
^g 显示文件名、当前的行号、文件的总行数和文件位置的百分比
:l 使用字母”l”来显示许多的特殊字符,如制表符和换行符

在文本中定位段落和放置标记

选项 作用
{ 在第一列插入{来定义一个段落
[[ 回到段落的开头处
]] 向前移到下一个段落的开头处
m(a-z) 用一个字母来标记当前位置,如用mz表示标记z
‘(a-z) 将光标移动到指定的标记,如用’z表示移动到z

在vi中连接行

选项 作用
J 将下一行连接到当前行的末尾
nJ 连接后面n行

光标放置与屏幕调整

选项 作用
H 将光标移动到屏幕的顶行
nH 将光标移动到屏幕顶行下的第n行
M 将光标移动到屏幕的中间
L 将光标移动到屏幕的底行
nL 将光标移动到屏幕底行上的第n行
^e(ctrl+e) 将屏幕上滚一行
^y 将屏幕下滚一行
^u 将屏幕上滚半页
^d 将屏幕下滚半页
^b 将屏幕上滚一页
^f 将屏幕下滚一页
^l 重绘屏幕
z- return 将当前行置为屏幕的顶行
nz-return 将当前行下的第n行置为屏幕的顶行
z. 将当前行置为屏幕的中央
nz. 将当前行上的第n行置为屏幕的中央
z- 将当前行置为屏幕的底行
nz- 将当前行上的第n行置为屏幕的底行

vi中的shell转义命令

选项 作用
:!command 执行shell的command命令,如:!ls
:!! 执行前一个shell命令
:r!command 读取command命令的输入并插入,如:r!ls会先执行ls,然后读入内容
:w!command 将当前已编辑文件作为command命令的标准输入并执行command命令,如:w!grep all
:cd directory 将当前工作目录更改为directory所表示的目录
:sh 将启动一个子shell,使用^d(ctrl+d)返回vi
:so file 在 shell程序file中读入和执行命令

vi中的宏与缩写
(避免使用控制键和符号,不要使用字符K、V、g、q、 v、*、=和功能键)

选项 作用
:map key command_seq 定义一个键来运行 command_seq,如:map e ea,无论什么时候都可以e移到一个字的末尾来追加文本
:map 在状态行显示所有已定义的宏
:umap key 删除该键的宏
:ab string1 string2 定义一个缩写,使得当插入string1时,用string2替换string1。当要插入文本时,键入string1然后按Esc键,系统就插入了string2
:ab 显示所有缩写
:una string 取消string的缩写

在vi中缩进文本

选项 作用
^i(ctrl+i)或tab 插入文本时,插入移动的宽度,移动宽度是事先定义好的
:set ai 打开自动缩进
:set sw=n 将移动宽度设置为n个字符
n<< 使n行都向左移动一个宽度
n>> 使n行都向右移动一个宽度,例如3>>就将接下来的三行每行都向右移动一个移动宽度

这称得上是一个 Vim 的杀手级 Tip,利用该 Tip,你可以快速处理 ‘、”、()、[]、{}、<> 等配对标点符号中的文本内容,包括更改、删除、复制等。

* ci’、ci”、ci(、ci[、ci{、ci< – 分别更改这些配对标点符号中的文本内容
* di’、di”、di(、di[、di{、di< – 分别删除这些配对标点符号中的文本内容
* yi’、yi”、yi(、yi[、yi{、yi< – 分别复制这些配对标点符号中的文本内容

对于经常用 Vim 写代码的朋友来说,善用此 Tip 将极大的提高编码效率。

July 16th, 2010 | Tags: , ,

昨晚花了一个晚上时间hll的写了这个存储过程,刚好也复习下存储过程的语法。这个存储过程是为西瓜猫下配送订单的时候作的,实现扣卡金额,减少商品数量,生成配送单,插入配送单详情的一系列操作。

drop procedure if exists createOrder;

create procedure createOrder (IN uid int, IN goods varchar(800), IN orderNo varchar(25), IN orderType tinyint, IN rate smallint, IN cid int, OUT goMoney int)
soone_pro:BEGIN
DECLARE allPrice int DEFAULT 0;
DECLARE theFlag int DEFAULT 0;
DECLARE oRate int DEFAULT 0;
DECLARE leaInfo varchar(255);
DECLARE gInfo varchar(20);
DECLARE gid int;
DECLARE gNum int DEFAULT 0;
DECLARE gp int DEFAULT 0;
DECLARE gl int DEFAULT 0;
DECLARE gi tinyint;
DECLARE gn varchar(30);
DECLARE cls tinyint;
DECLARE cle datetime;
DECLARE cia int;

IF (orderType=1 OR orderType=2) AND cid IS NULL THEN
SET goMoney = 0;
LEAVE soone_pro;
END IF;

IF rate IS NOT NULL THEN
SET oRate = rate;
END IF;

SET theFlag = locate(‘|’, goods);
SET leaInfo = goods;
SET AUTOCOMMIT = 0;
soone_loop:WHILE(theFlag >= 0) do
SET gInfo = SUBSTRING_INDEX(leaInfo, ‘|’, 1);
SET gid = SUBSTRING_INDEX(gInfo, ‘,’, 1);
SET gNum = SUBSTRING_INDEX(gInfo, ‘,’, -1);

SELECT gl_mprice, gl_leaves, gl_isspec, gl_name INTO gp, gl, gi, gn FROM xgm_goodlib WHERE gl_id = gid FOR UPDATE;
IF gl < gNum THEN
SET goMoney = 1;
LEAVE soone_pro;
END IF;

IF gi = 1 THEN
SET allPrice = allPrice+(gp*gNum);
ELSE
SET allPrice = allPrice+(gp*gNum*(100-oRate));
END IF;

UPDATE xgm_goodlib SET gl_leaves = gl_leaves-gNum WHERE gl_id = gid;
INSERT INTO xgm_goinfo SET gl_id = gid, goi_nums = gNum, gl_name = gn, go_order = orderNo;

IF theFlag = 0 THEN
LEAVE soone_loop;
END IF;
SET leaInfo = SUBSTRING(leaInfo, theFlag+1);
SET theFlag = locate(‘|’, leaInfo);
SET gInfo = NULL;
SET gid = 0;
SET gNum = 0;
SET gp = NULL;
SET gl = NULL;
SET gi = NULL;
SET gn = NULL;
END WHILE soone_loop;

IF orderType=1 OR orderType=2 THEN
IF cid IS NULL THEN
SET goMoney = 0;
ROLLBACK;
LEAVE soone_pro;
END IF;

SELECT cl_state, cl_expire, ci_balance INTO cls, cle, cia FROM xgm_cardlib WHERE cl_id = cid FOR UPDATE;
IF cls = 0 OR cle < now() OR cia = 0 THEN
SET goMoney = 0;
ROLLBACK;
LEAVE soone_pro;
END IF;

IF orderType = 1 OR (orderType = 2 AND allPrice > cia) THEN
UPDATE xgm_cardlib SET ci_balance = 0 WHERE cl_id = cid;
ELSEIF orderType = 2 THEN
UPDATE xgm_cardlib SET ci_balance = ci_balance – allPrice WHERE cl_id = cid;
END IF;
ELSE
SET cid = 0;
END IF;

INSERT INTO xgm_goodorder SET ou_id = uid, go_order = orderNo, go_date = now(), go_status = 1, cl_id = cid, go_type = orderType, go_allprice = allPrice, go_rate = oRate;

SET goMoney = allPrice;
IF @@ERROR_COUNT > 0 OR allPrice <= 0  OR goMoney = 0 THEN
SET goMoney = 3;
ROLLBACK;
ELSE
COMMIT;
END IF;
END soone_pro;

调用方式
call createOrder(1, ’1,1′, ’3213213213213′, 2, 0,1,@g);select @g;

July 15th, 2010 | Tags: ,

1)这种情况是自己碰到的,我把代码精简了一下,举个列子

>>> def max(a):
...     if a > 0:
...         b = 1
...     print b
...
>>> max(1)
1
>>> max(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in max
UnboundLocalError: local variable 'b' referenced before assignment

上面的代码中,当a大于 0的时候,不会出现问题,但当a不大于0的时候,就报错了。
这种错误当代码少的时候容易发现,比较难办的就是,当你的代码很多,然后中间隔了很多 行以后,再去调用b这个变量的时候,很难去发现这个问题。

解决办法:
1.把if-else写全,这样每种情况都会对b进行定义
2. 在if之前给b一个默认值。这样的好处就是代码量小。

2)这种情况是局部变量和全局变量访问的问题。
首先看一个列子

#!/usr/bin/python

#global varibale
USER_COUNT = 0

#function
def main():
adduser()

def adduser():
print ‘There are’, USER_COUNT, ‘users so far’

# actually run main()
main()

这段程 序可以正常工作,函数adduser调用全局变量USER_COUNT

再看这一段,注意函数adduser()

#!/usr/bin/python

#global varibale
USER_COUNT = 0

#function
def main():
adduser()

def adduser():
USER_COUNT = USER_COUNT + 1
print ‘There are’, USER_COUNT, ‘users so far’

main()

这段程 序的结果是”UnboundLocalError: local variable ‘USER_COUNT’ referenced before assignment“
想明白这点,就要知道python对变量访问的规则
当搜索一个变量的时候,python先从局部作用域开始搜索,如果在局部作用域没有找到那个变量,那样python就在全局变量中找这个 变量,如果找不到抛出异常(NAMEERROR 或者 Unbound-
LocalError,这取决于你使用的python 版本。)

知道了对变量的访问规则,那就开始我们的解决办法
1.在函数adduser中加”global USER_COUNT“,就可以对全局变量进行操作。

def adduser():
global USER_COUNT
USER_COUNT = USER_COUNT + 1
print 'There are', USER_COUNT, 'users so far'

2. 在函数adduser中对变量”USER_COUNT“进行定义(这种情况,相当于使用一个新的变量,但是一个局部变量和一个全局变量同名是一件很不好的 事情)

def adduser():
USER_COUNT = 0
USER_COUNT = USER_COUNT + 1
print 'There are', USER_COUNT, 'users so far'

3) 先把例子留到这里吧,因为自己还不是太明白这个,希望高手帮忙

def bankAccount():
bal=0
def credit(amount):
bal=bal+amount
def debit(amount):
bal=bal-amount
def balance():
return bal
return (lambda x: {"credit":credit,
"debit":debit,
"balance":balance
}[x])
b=bankAccount()
print b("balance")()
b("credit")(100)

via:http://blog.chinaunix.net/u2/82912/showart_2191787.html

July 15th, 2010 | Tags:

以 #! 开头的称为组织行,这行告诉你的Linux/Unix系统当你 执行 你的程序的时候,它应该运行哪个解释器。例如:#!/usr/bin/python

以 # 开头的称为注释行。

数的4种类型:整数、长整数、浮点数和复数。


字符串
: 单引号(‘)和双引号(”)的作用相同,转义符是(\),以三引号(如:”’或者”"”)括起来的字符串中可以直接使用任意多个单引号(‘)和双引号 (”)而无需转义符(\)。

自然字符串:在字符串前加R(或r)指示某些不需要如转义符那样的特别处 理的字符串,如:print R“Hello\n World”,将直接输出“Hello\n World”而不会出现换行的情况。

Unicode 字符串:在字符串前加U(或u)。

缩进:Python没有类似 Begin……End 的语句来标识语句块,它依靠缩进来标识语句块,因此错误的缩进将会导致解释程序报错。

运算符与表 达式:基本上与其它语言相类似,只是有以下几点不同。
x*y:乘法。2 * 3得到6。’la’ * 3得到’lalala’。
x**y:幂运算,返回 x 的 y 次幂。
x/y:x 除以 y,4/3得到1(整数的除法得到整数结果)。4.0/3或4/3.0得到1.3333333333333333。
x//y: 取整除。返回商的整数部分。4 // 3.0得到1.0。

控制流语句
if-elif-else:(Python 没有 switch-case 语句,可以通过 if 语句配合字典完成同样的工作)
if something == 1:
doSomething1()
elif something == 2:
doSomething2()
else:
doSomething3()

while-else:
while something:
doSomething1()
else:
doSomething2()

for-else:
for i in range(1, 10, 2):   # i 值从 1 到 10,步长为2
print i
else:
print 'The for loop is over'

break 和 continue:用于中断和继续循环。

函数

def say(message, times = 1):  # time 的默认参数值是 1
print message * times
return time               # 无返回值的函数可省掉 return,等同于return None

只有在形 参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。这是因为赋给形参的值是根据位置而 赋值的。例如,def func(a, b=5)是有效的,但是def func(a=5, b)无效 的。

DocStrings

说白了就是类似于JavaDoc的东西。

文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。可以使用__doc__(注 意双下划线)调用函数的文档字符串属性(属于函数的名称)。Python把 每一样东西 都作为对象,包括这个函数。

Python中的help(),它所做的只是抓取函数的__doc__属性,然后整洁地展示 给你。

自动化工具也可以以同样的方式从你的程序中提取文档。随Python发行版附带的pydoc命令,与help()类 似地使用DocStrings。

def printMax(x, y):
'''Prints the maximum of two numbers.      # 这里是文档字符串

The two values must be integers.”’
print "DocStrings"                         # 这里是函数体

命令行参 数

# Filename: using_sys.py
import sys

print 'The command line arguments are:'
for i in sys.argv:         # sys.argv变量是一个字符串的列表,用于保存命令行参数。
print i

执行 Python using_sys.py we are argvs 的输出结果是:
The command line arguments are:
d:\My Documents\Python\using_sys.py   # sys.argv[0]
we
# sys.argv[1]
are # sys.argv[2]
argvs # sys.argv[3]

模块的__name__名称
每 个Python模块都有它的__name__,如果它是'__main__',这说明这个模块被用 户单独运行,我们可以进行相应的恰当操作。

via:http://kjava.javaeye.com/blog/206698

July 15th, 2010 | Tags: , ,

为准备公司网站的重构,前端时间研究Memcached分布式集群 和 Hiphop-php(Facebook的一个开源项目)的搭建 ,花了不少时间和精力,下边进行一下整理。。。

一、Memcached客户端库算法研究

取模算法与一致性算法
Memcached虽然被称为”分布式”缓存服务器,但是服务器 段并没有分布式功能,实现分布式主要是通过客户端库来实现。无论使用哪种语言实现的客户端库都会包含至少一种分布算法来实现Memcached分布式。

因此笼统来说客户端库是 通过一个分布算法和维护的一个服务器列表来实现Memcached分布式的,关于分布算法目前有两种选择:取模算法(modula hashing)和一致性算法(consistent hashing)。

取模算法(modula hashing)是当前多数客户端库默 认算法 [Hash($key) % $svrNum ],就是根据服务器节点数的余数来进行分散,就是通过hash函数求得的Key的整数哈希值再除以服 务器节点数并取余数来选择服务器。这种算法取余计算简单,分散效果好,但是缺点是如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这 时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;如果新增一台机器,会有N/(N+1)的服务器的缓存数据需 要进行重新计算。对于系统而言,这通常是不可接受的颠簸(因为这意味着大量缓存的失效或者数据需要转移)。

一致性算法(consistent hashing)来源于p2p网络的路由算法,算法描述:hash值一般为unsigned int型,因此对于hash函数的结果应该均匀分布在[0,2^32-1]间,把一个圆环用2^32  个 点来进行均匀切割,首先按照hash()函数算出服务器(节点)的哈希值, 并将其分布到0~2^32的圆上。用同样的hash()函数求出需要存储数据的键的哈希值,并映射到圆上。然后从数据 映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器(节点)上,新增一个节点的时候,只有在圆环上新增节点逆时针方向的第一个节点的数据会受到 影响。删除一个节点的时候,只有在圆环上原来删除节点顺时针方向的第一个节点的数据会受到影响,因此通过Consistent Hashing很好地解决了负载均衡 中由于新增节点、删除节点引起的hash值颠簸问题。

PHP的 Memcached客户端库目前有两个:PECL::memcache 和PECL::memcached,下边是两个库的比较:

PECL::memcache PECL::memcached
第一个版本时间 2004-06-08 2009-01-29(beta)
外部依赖 libmemcached
二进制协议 3.0.0以上版本 可选
当前最新稳定版本 2.2.5 1.0.1
通讯超时支持 仅connect支持 多种选项
一致性算法 支持 支持
储存数值类型 转化为字符串 支持
UDP支持 3.0.0以上版本支持 不支持

两个库的稳定版本都是使用取模算法作为默认的分布算法,根据上面两个算法的解释可以看 出,一致性算法是做memcached分布集群的最佳算法,因此我们需要将客户端库的默认分布算法改为一致性算法:

PECL::memcache库启用consistent一致性算法:

修改php.ini添加:

[Memcache]

memcache.allow_failover= 1

memcache.max_failover_attempts  = 20

memcache.chunk_size= 32768

memcache.hash_strategy = consistent
memcache.hash_function= crc32

或在PHP中使用ini_set方法:

ini_set(‘memcache.hash_strategy’,’ consistent’);

ini_set(‘memcache.hash_function ‘,’ crc32′);

PECL::memcache模块使用手册

http://www.php.net/manual/en/book.memcache.php

PECL::memcached(libmemcached)库启用consistent一致性算法:

$mc = newMemcached();

$mc->setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT);
$mc->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

PECL::memcached模块使用手册

http://www.php.net/manual/en/book.memcached.php

二、两 个客户端库的性能测试

从上面的表格我们看出pecl::memcached库是基于 libmemcached工具库的,我使用facebook的xprof库对二者进行了一下测试,基于libmemcached的 pecl::memcached库性能要比pecl::memcache库高出很多,数据这里就不给了。

综上两点使 用pecl::memcached库,并使用一致性算法并同时设置LIBKETAMA_COMPATIBLE 选项为true,这是我们做memcached分布集群的最佳选择,即提高了性能,又减少了由增删节点而引起的大量数据迁移的风险。

下 面记录一下xprof的用法:

使用facebook的xprof模块测试PHP程序性能:

从Facebook开源项目中下载xprof

http://github.com/facebook

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

安装过程:

# tar zxvf xhprof-0.9.2.tar.gz

# cd xhprof-0.9.2/extension

# /usr/local/webserver/php/bin/phpize

# ./configure–with-php-config=/usr/local/webserver/php/bin/php-config

# make && make install

Xhprof.so模块将安装在

/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/目录中

手动在php.ini里面添加xprof段:

[xhprof]

extension=xhprof.so

xhprof.output_dir=/data0/htdocs/test.letv.com/logs/xhprof/

用法:

<?php

//启用初始化
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

…….测试程序放在这里

//生成性能分析数据文件

$xhprof_data= xhprof_disable();

//调用xhprof提供的web接口,通过Web方式查看性能数据

include_once”xhprof_lib/utils/xhprof_lib.php”;

include_once”xhprof_lib/utils/xhprof_runs.php”;

$xhprof_runs= new XHProfRuns_Default();

$run_id= $xhprof_runs->save_run($xhprof_data, “xhprof_testUDP”);

echo”—————\n”.

“Assuming you have set up the httpbased UI for \n”.

“XHProf at some address, you can viewrun at \n”.

“http://10.57.30.70/xhprof_html/index.php?run=$run_id&source=xhprof_testUDP\n”.

“—————\n”;

?>

xhprof参考文档:

xhprof手册:http://mirror.facebook.net/facebook/xhprof/doc.html#installation

via:http://jianzi0307.blog.163.com/blog/static/208120020104170361734/

July 15th, 2010 | Tags: , ,

1. 如果你安装了PHP的memcache模块,则使用phpinfo()函数可以看到如下信息

memcache supportenabledActive persistent connections10Revision$Revision: 1.62 $

DirectiveLocal ValueMaster Valuememcache.allow_failover11memcache.chunk_size81928192memcache.default_port1121111211memcache.max_failover_attempts2020

其中:Active persistent connections 代表是的已建立的长连接的个数; 注意,该值是当前进程的,因为长连接在进程间是无法共享的。

2. php.ini 中配置解释

[Memcache]

; 一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,

; 它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。

; 是否在遇到错误时透明地向其他服务器进行故障转移。

memcache.allow_failover = On

; 接受和发送数据时最多尝试多少个服务器,只在打开memcache.allow_failover时有效。 memcache.max_failover_attempts = 20

; 数据将按照此值设定的块大小进行转移。此值越小所需的额外网络传输越多。

; 如果发现无法解释的速度降低,可以尝试将此值增加到32768。

memcache.chunk_size = 8192

; 连接到memcached服务器时使用的默认TCP端口。

memcache.default_port = 11211

; 控制将key映射到server的策略。默认值”standard”表示使用先前版本的老hash策略。

; 设为”consistent”可以允许在连接池中添加/删除服务器时不必重新计算key与server之间的映射关系。

;memcache.hash_strategy = “standard”; 控制将key映射到server的散列函数。 默认值”crc32″使用CRC32算法,而”fnv”则表示使用FNV-1a算法。

; FNV-1a比CRC32速度稍低,但是散列效果更好。

;memcache.hash_function = “crc32″

3. 通过下面一段简单的代码来测试上面配置的含义

<?php

ini_set(“memcache.allow_failover”,1);

ini_set(“memcache.max_failover_attempts”, 2);

$a = new Memcache();

$a->addServer(“10.1.1.181″,11251);

$a->addServer(“10.1.1.181″,11252);

$a->addServer(“10.1.1.181″,11253);

$a->addServer(“10.1.1.181″,11254);

$a->add(“a”,”A”,0);

?>

其中: 10.1.1.181 是一个不存在的IP,就算是存在,相应的端口也没有提供服务,目的就是要让连接失败。

当:

ini_set(“memcache.allow_failover”,0);

时, 我们可以通过tcpdump发现,只连接了一次,失败后就退出了

当:

ini_set(“memcache.allow_failover”,1);

ini_set(“memcache.max_failover_attempts”, 20);

时,我们可以通过tcpdump发现,四个端口都被尝试了一次

当:

ini_set(“memcache.allow_failover”,1);

ini_set(“memcache.max_failover_attempts”, 2);

时: 我们可以通过tcpdump发现,两个端口都被尝试失败后退出

4. PHP以前的memcache模块没有使用一致性hash,后来添加了该hash算法,但是默认没有使用,需要配置,如:

memcache.hash_strategy = consistent

或者使用ini_set(“memcache.hash_strategy”,”consistent”);

可以通过下面代码来验证一致性hash的好处:

<?php

//ini_set(“memcache.hash_strategy”,”consistent”);

$a = new Memcache();

$a->addServer(“10.55.38.18″,11271);

$a->addServer(“10.55.38.18″,11272);

$a->addServer(“10.55.38.18″,11273);

$a->addServer(“10.55.38.18″,11274);

$a->addServer(“10.55.38.18″,11275);

$a->addServer(“10.55.38.18″,11276);

for($i = 0; $i < 1000; $i++) {

$a->set(“key”.$i,$i,0);

}

$b = new Memcache();

$b->addServer(“10.55.38.18″,11271);

$b->addServer(“10.55.38.18″,11272);

$b->addServer(“10.55.38.18″,11273);

$b->addServer(“10.55.38.18″,11274);

$b->addServer(“10.55.38.18″,11275);

for($i = 0; $i < 1000; $i++) {

if($b->get(“key”.$i)) $m++;

}

echo “all: $in”;

echo “hits: $mn”;

for($i = 0; $i < 1000; $i++) {

$a->delete(“key”.$i);

}

?>

未使用一致性hash的结果为:

all: 1000

hits: 134

使用一致性hash的结果为:

all: 1000

hits: 838

6个节点中,损坏一个节点后,损失数据为: 16.2 约等于 1/6

5. PHP还有一个libmemcached的模块, 也实现了一致性的hash,效果和memcache中实现的基本一样(似乎不同,为测试,因为现在还没有这个需求); 而且还可以设置OPT_LIBKETAMA_COMPATIBLE, libmemcached下载: http://pecl.php.net/package/memcached

下面是关于libmemcached的一致性hash的测试, 从这里我们也发现,CONSISTENT不是一种hash算法,而是一种DISTRIBUTION

<?php

$a = new Memcached();

$a->setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT);

$a->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

$a->addServer(“10.55.38.18″,11271);

$a->addServer(“10.55.38.18″,11272);

$a->addServer(“10.55.38.18″,11273);

$a->addServer(“10.55.38.18″,11274);

$a->addServer(“10.55.38.18″,11275);

$a->addServer(“10.55.38.18″,11276);

for($i = 0; $i < 1000; $i++) {

$a->set(“key”.$i,$i,0);

}

$b = new Memcached();

$b->setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT);

$b->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

$a->addServer(“10.55.38.18″,11271);

$b->addServer(“10.55.38.18″,11271);

$b->addServer(“10.55.38.18″,11272);

$b->addServer(“10.55.38.18″,11273);

$b->addServer(“10.55.38.18″,11274);

$b->addServer(“10.55.38.18″,11275);

for($i = 0; $i < 1000; $i++) {

if($b->get(“key”.$i)) $m++;

}

echo “all: $in”;

echo “hits: $mn”;

for($i = 0; $i < 1000; $i++) {

$a->delete(“key”.$i);

}

?>

6. 关于CONSISTENT 的使用也要慎用,这个算法是比较消耗cpu的,我们的一个业务在使用CONSISTENT 算法时,服务器每秒处理20个请求; 而去掉该算法后,每秒可以处理300多个请求,所以说这个算法对性能的影响还是蛮大的;

关于CONSISTENT的用法在网上说的比较少,我这些都是从源码里发现的,分享给大家。

7. 关于 OPT_COMPRESSION 的一点说明:

在libmemcached里面可以根据该选项来指定压缩或不压缩,但是如果原始内容小于100字节,就算指定压缩了,也不会压缩的(源码 里面就是这么写的,文档中也这么说明了),因为太小了; 这似乎是一种明智的做法;

在memcache中也可以通过函数来设置setCompressThreshold( int threshold [, float min_savings] ); 但是如果不设置,则默认值为0; 即:不管原始内容是多少都要压缩的。好像就有些不够明智了。不过也可能正好能满足某些人的需求。

via:http://b.qzone.qq.com/cgi-bin/blognew/simpleqzone_blog_data?hostuin=7507097&r=0&idm=qzs.qq.com&bdm=b.qzone.qq.com&mdm=m.qzone.qq.com&blogid=1272673045&numperpage=15

July 10th, 2010 | Tags: ,

一个最好的剖析服务器的方法是,用SHOW STATUS来查看什么占用了它大量的处理时间。SHOW STATUS显示了很多的信息,我们仅仅关心其中的一小部分。

为了查看最近服务器的表现。你可以周期性的抽取SHOW STATUS并且把它和先前的结果进行比较。命令如下:

mysqladmin extended -r -i 10(注:要连接服务器所以要加 -u -p 参数:mysqladmin -u root -p extended -r -i 10)

这些变量并不是一直增长的。因此你可能看到一些奇怪的输出,比如Threads_running有的时候是负数。不必担心这个,意思就是相对于上一 个例子,这个计数在减少。

因为这个输出是非常大的。我们可以使用grep(windows 强烈推荐cygwin)来查取一些想要的变量。也可以使用Innotop或其他的一些工具来查看这些结果。这个将在以后章节说明。下面就说一下比较有用的 变量。

  • Bytes_received ,Bytes_sent:服务器进出的流量。
  • Com_*:服务器执行的命令。
  • Created_*:在语句执行的时候,临时表和文件的创建。
  • Handler_*:存储引擎的操作。
  • Select_*:多种类连接的执行安排。
  • Sort_*:多种类排序的信息。
你可以使用这个方法来监控MySQL内部的操作。比如Key(键)的访问次数,对于MyISAM,从硬盘的Key(键)的读取,数据访问的频率 以及等等。这样才能帮助你知道在系统中哪些是潜在的瓶颈。而不用去查看一个单独的语句。你也可以使用单独的工具去分析SHOW STATUS,如mysqlreport.这样是为了得到一个总的服务器”健康”信息.
我们不会详细解释每个状态变量(status variables)的意思,但是当我们在例子中使用它们的时候,会详细说明。因此现在没必要担心我们对这些变量一无所知。
另一个剖析服务器的方法是使用SHOW PROCESSLIST.使用它不仅仅能看到什么类型的语句正在执行,也能知道你连接的状态。一些如在锁的状态下,连接数过高,是显而易见的瓶颈。与 SHOW STATUS一样,SHOW PROCESSLIST的信息量很大,我们也需要工具取代用手工查看结果的方法,比如INNOTOP。

via:http://xiayuanfeng.javaeye.com/blog/411453