Perfil de zzzMagic 's Forest , ...FotosBlogListasMás Herramientas Ayuda

Blog


26 noviembre

NTP配置

NTP客户端

 

> service ntpd stop

> ntpdate {服务器IP}
3遍

>crond –e
    0-59/10 * * * * /usr/sbin/ntpdate {IP}

每隔10分钟同步一次时间

 

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

 

NTP服务端

    ntp-4.2.2p1-9.el5.centos.2.i386

 

> vi /etc/ntp.conf

  restrict 10.0.10.0 mask 255.255.255.0 nomodify notrap  #允许client端
  server cn.pool.ntp.org    #与国际NTP server同步时间

>service ntpd restart

 

~~~~~~~~~~~~~~~~

 

一些可以用的NTP服务器

cn.pool.ntp.org
ntp.sjtu.edu.cn (上海交通大学网络中心NTP服务器地址)202.120.2.101

133.100.11.8 prefer
210.72.145.44
203.117.180.36
131.107.1.10
time.asia.apple.com
64.236.96.53
130.149.17.21
66.92.68.246
www.freebsd.org
18.145.0.30
clock.via.net
137.92.140.80
133.100.9.2
128.118.46.3
ntp.nasa.gov

Memcached

wget http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz

有可能还要libevent-devel的包

wget http://memcached.googlecode.com/files/memcached-1.4.3.tar.gz

 

memcached有用到libevent包,所以要先装下。

编译都没什么花头,

./configure && make && make install

默认是安装到/usr/local/bin下面

 

自己做个启动脚本

 

start() {
        /usr/local/bin/memcached -p 11211 -m 128m -d -u memcached -P /tmp/memcached.pid > /var/log/memcached.log &
}

stop() {
        kill -9 `cat /tmp/memcached.pid`

 

启动脚本里面如果要调试信息就加一个 –vv 的参数。

 

-p    端口11211

-m   使用的缓存大小

-d    作为后台运行

-u    指定用户,由于不能用root启动 所以要adduser

-P    记录下pid,给stop用

-vv  详细信息显示

基本的 service 脚本

#!/bin/sh

RETVAL=0

start() {
        service memcached start
        ~/xxx/user.sh
        ~/xxx/server.sh
}

stop() {
       ~/xxx/server_stop.sh
        service memcached stop
}

restart() {
        stop
        start
}
# See how we were called.
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;

  restart|reload)
        restart
        ;;

  *)
        echo $"Usage: xxx {start|stop|restart}"
        exit 1
esac

exit $RETVAL

 

这是一个最基本的service脚本 只要把要做的事情放到start和stop函数里面去就OK了。

更完善一点么就把路径什么的做成变量,做一些判断。

Java Installer Builder

这2天做掉一个大项目,忙的这是~ 今天似乎没什么后续的任务 大概比计划完成的提早了吧 呵呵

领导们在开会,那就抓紧时间写点小结吧~

先从小的项目开始

 

 

Java Installer Builder

 

打包程序,还蛮好玩的~

   就是制作安装程序的程序,我们以前装的游戏啊、程序啊 原来都是这么打包出来的,蛮好玩的~呵呵

 

用到的工具,Install4j,破解版下载地址

http://down1.3ddown.com//Crack/2009/05/EJ.Technologies.Install4j.MultiPlatform.Edition.v4.2.2.Incl.Keygen-FALLEN.rar

这个东东破解竟然还用到java代码,crack目录下面有个keygen.class 拷到安装路径

运行java keygen 就会有注册码出来了

我用的是这个

L-FLN#77002-1sx2e2c1spj1zb#325

 

………………………………………………

 

其实只要跟着一路next就ok了,不过在实际操作过程中还是有碰到些问题。

 

 

   第一页 General Settings

      这个是安装程序的名字,起的体面一点比较好。全小写的难看

      Java版本,如果后面选择打包里面自带Java,就无所谓了。

      安装过程用的Language,第一个是默认,下面可以增加多选,记得不要把默认的选进去

           每个语言的文档其实都在${install4j}\resource\messages路径下面

           可以把里面的install4j替换成想要的文字

      打包好的安装程序放置的路径,下面还有默认生成文件名的格式、压缩方式、timestamp等

      项目变量的设置 ~应该一般用不到吧。。

 

 

   第二页 Files

      要打包的文件夹,Add Files 然后选上整个目录

      预览一下 readonly~

      指定要打包进去的文件 当然全选的话就不用改了

 

 

   第三页 Launchers

 

      New Launcher->

         我是用Generated Launcher的

           执行安装的方式,其中有可以把这个程序做成Service的选项

             输入执行程序的名字 这里就可以用一般文件名的格式了~还有设置执行的目录等。

             下面有个Advanced Options,有一些细节的东西可以设置,

               比如安装日志、服务启动的方式、Dependency等

 

         icon

            选择图标 要准备2个,16*16的和32*32的。大小不符合它会用自带那个,狠难看~

 

        Java invocation

           这个是最麻烦的地方了

           先选Class Path,把根目录选进去。

              然后记得把Main class要用到的Jar文件指定添加进去,指定目录的话是不会自动搜索的~

           然后选程序的Main class 下面可以填它的Parameters

           下面有个Advanced Options,如果有的话 记得还要把Native Library Directory选进去

 

        splash screen

           启动程序时用的画面,就是那种刚启动时,屏幕中间会出来一段版权所有的这种半透明淡入淡出的图片

 

 

    第四页 Installer

        这个是安装过程的每个页面设置。

          看是很多,其实仔细研究了一下基本没什么地方可以改动的,直接next好了

        Custom Code,JAR文件的自定义代码

        Application ID,Update用的

        GUI 的一些选项 比如窗口大小、标题栏之类的

          下面竟然有个 add install4j watermark to installer screens 的多选项。。记得去掉~

          Installer Icon也可以自定义

         Advanced里面有用console方式安装的后门参数等设置

 

 

   第五页 Media

        选For Windows还是For Mac、Unix/Linux 的

          或者下面的archive 可以打包安装的那种,不用图形化。

        安装路径 先勾上custom installation base directory的选项 后面填入C:\program File或者D:\之类的

                    上面填后续的程序目录名

        中间没有什么 一直到第6部分 Bundled JRE

          可以把JRE的包打在安装程序里,省的客户端没有安装环境什么的还要自己去找

            先下载 然后就可以在选项里面选择了。

        最后有个全面自定义的地方 几乎什么都可以再改一下。

 

 

    第六页 Bulid

        好,OK了 在这里Start就可以了。要看过程么可以把Enable extra verbose output勾出来看一看

             Test Build貌似没什么用 还特费时间 不做也罢。

20 noviembre

快进生命。

时间在快进。

 

最近哈忙,每天一个项目接着一个项目。而且每个项目似乎都很急 每个项目都马上要上马。

我也就尽力而为了。

 

突然发现 碰到一个下不去的障碍 再怎么折腾、绞尽脑汁,试图的东西还总是浮于表面。

  而到外面走一走,吃点东西 擦把脸 休息一下,然后整理一下曾经走过的思路 忘记做过的一切 寻找一个新的起点重新来过~

    问题似乎会变得很容易 就迎刃而解了。

 

另外又发现 越是到下班的时间 项目解决的几率就越低。

  以前我记得不是这样的 自己总是会到最后准点之前的几十分钟把手上的事情都解决了 然后喘口气 悠闲地等待着下班。

 

说明什么呢,也许现在的所做 确实有些超出自己所能掌控的范围了。

    不过1900最后的那个决定 我是绝对不会做的。超过那88个键就是不能承受之重了吗?

 

  连着2天,下班收尾的项目都解决不了~ 非常无奈地做到7点才离开公司。

       到了家里 休息足了 再奋起精神登上服务器 发现竟然很顺利地就解决了

 

  看来 加班 是没什么意义的~我如此认为。。 哈哈

 

    公司的项目都在外网服务器上 这倒是件很方便的事情。。随时随地都能上去折腾

       只是前几天还有空在每个项目做掉之后写一个总结,这几天一个接一个 连回头看一眼的机会也没有了

           希望过几天不要忘记。这些笔记 是我心中的财富。

 

 

*************************

 

    前面刚弄完项目,在看女子9球世锦赛。突然发现一个叫潘晓婷的中国女孩子打的哈好呀

         看全了整场,有潜力啊~~还戴了一副很夸张的耳环 太赞了。

 

。^^   ^^^   ^^^   ^^^   ^^^

 

 

下班的时候漫步在常熟路上  似乎已经入了深夜。

   上班 做项目 下班 做项目 睡觉

   时间似乎不要钱似地在我面前一晃就过去了

  

   现实么? 快进的生命 快进的收入 少去了本该属于自己的思维 属于自己的生活

    不过竟然还觉得很充实呢 或许是 喜欢这份事业么?

                                            喜欢那四四方方服务器里的一切么?

                                             喜欢解决了问题之后那一刹那的成就感和轻松的喜悦么?

 

              尽全力燃烧自己   或许就是喜欢着这种感觉吧

 

 

       总之 翻天覆地的生活 竟然一点都没有觉得不适

         没有腻味之前 就这么随他快进吧 反正今年的目标也差不多都完成了。让自己全神贯注的工作 也不错。

 

           >> x 64

18 noviembre

Apache停止和重启(转)


 

本文档叙述了在类Unix系统上如何停止和重启Apache 。 Windows NT/2000/XP/2003的用户请参见以服务方式运行Apache ,Windows 9x/ME用户则参见在控制台中运行Apache

top

简介

为了停止或者重新启动Apache ,你必须向正在运行的httpd进程发送信号。有两种发送信号的方法。第一种方法是直接使用UNIX的kill命令向运行中的进程发送信号。你也许你会注意到你的系统里运行着很多httpd进程。但你不应该直接对它们中的任何一个发送信号,而只要对已经在PidFile中记载下了自身PID的父进程发送信号。也就是说,你不必对父进程以外的任何进程发送信号。你可以向父进程发送三种信号:TERMHUPUSR1 ,我们过一会儿再进行详细的说明。

你可以用下面这样的命令来向父进程发送信号:

kill -TERM `cat /usr/local/apache2/logs/httpd.pid`

第二种方法是使用下面将要描述的httpd二进制可执行文件的 -k 命令行选项:stoprestartgracefulgraceful-stop 。不过我们推荐你使用apachectl控制脚本来向httpd二进制可执行文件传递这些选项。

当你向httpd发送信号后,你可以这样来读取它的进行过程:

tail -f /usr/local/apache2/logs/error_log

你可以修改这些示例以适应你的ServerRootPidFile设置。

 

立即停止

信号:TERM
apachectl -k stop

发送TERMstop信号到父进程可以使它立刻杀死所有子进程。这将花费一些时间来杀死所有子进程。然后父进程自己也退出。所有进行中的请求将被强行中止,而且不再接受其它请求。

 

优雅重启

信号:USR1
apachectl -k graceful

USR1graceful信号使得父进程建议子进程在完成它们现在的请求后退出(如果他们没有进行服务,将会立刻退出)。父进程重新读入配置文件并重新打开日志文件。每当一个子进程死掉,父进程立刻用新的配置文件产生一个新的子进程并立刻开始伺服新的请求。

重启代码的设计能够确保MPM进程控制指令的正常运作,也就是在重启过程中确保有适当数量的进程和线程以响应客户端的请求。它是这样StartServers的:如果在一秒钟以后还没有新创建StartServers个子进程,则创建出足够完成现在任务的子进程个数。因此,代码除了保有能够维持服务器的现有负载数量的子进程外,也确保StartServers按你的意愿运作。

使用mod_status的用户会注意到在USR1信号发出后,服务器的统计信息没有被清零。代码被写成既能将你服务器无法伺服新请求的时间降至最少(这些请求将被操作系统放到队列里,使得它们不会丢失),又能遵从你的参数优化。为了做到这一点,它将在重新生成子进程的过程中,在scoreboard上保存所有子进程的状态。

mod_status还会将那些在优雅重启前就已经开始而没有结束伺服请求的子进程用一个"G"来标志。

目前,日志滚动脚本还无法使用USR1来确定所有写入预重启日志的子进程都已结束。我们建议你在发出了USR1信号后等待一个适当的时间,然后再对旧的日志做处理。比如说如果对于一个窄带用户来说,大部分的点击处理将在10分钟之内完成,那么你应该在处理旧的日志前等待15分钟。

如果Apache重启时发现配置文件有误,那么父进程将不会重启,而是报错并退出。在优雅重启的情况下,它将在处理中的子进程存在的情况下维持它的存在(就是那些被要求在处理完它们的请求后"优雅退出"的子进程)。如果你要重启服务器,这将导致一些问题:它将不能绑定到它的监听端口。在执行重启之前,你可以用 -t 命令行参数来检查配置文件语法的正确性(参见httpd)。但这仍然不能保证服务器一定可以正确的重启。为了从语法和语义两方面检查配置文件,你可以用一个非root用户来启动httpd。如果没有错误,它将尝试去打开套接字和日志文件,继而因没有root权限而失败(或是因为现在运行的httpd已经绑定了这些端口)。如果是因为其他原因那么就可能是一个配置文件产生的错误,你就应当在进行优雅重启之前改正这个错误。

 

立即重启

信号:HUP
apachectl -k restart

向父进程发送HUPrestart信号会使它象收到TERM信号一样杀掉所有的子进程,不同之处在于父进程本身并不退出。它重新读入配置文件、重新打开日志文件。然后产生一系列新的子进程来继续服务。

使用mod_status的用户会注意到在HUP信号发出后,服务器统计信息会被清零。

如果你重启时配置文件有误,那么父进程将不会重启,而是报错并退出。参见上文中避免的方法。

 

优雅停止

信号:WINCH
apachectl -k graceful-stop

WINCHgraceful-stop信号使得父进程建议子进程在完成它们现在的请求后退出(如果他们没有进行服务,将会立刻退出)。然后父进程删除PidFile并停止在所有端口上的监听。父进程仍然继续运行并监视正在处理请求的子进程,一旦所有子进程完成任务并退出或者超过由GracefulShutdownTimeout指令规定的时间,父进程将会退出。在超时的情况下,所有子进程都将接收到TERM信号并被强制退出。

在"优雅"状态下,TERM信号将会立即中止父进程和所有子进程。由于PidFile已经被删除,你将无法使用apachectlhttpd发送该信号。

graceful-stop允许你同时运行多个相同配置的httpd实例。这在对Apache进行平滑升级的时候是一个非常有用的特性。不过它在某些配置的情况下同样可能会导致死锁和竞争条件。

必须注意确保诸如LockfileScriptSock之类的磁盘文件包含服务器的PID ,并且能够安全的共存。然而如果一个配置指令、第三方模块或持久CGI使用任何磁盘锁或状态文件,必须注意确保多个httpd运行实例之间不会争抢文件。

你还必须防止潜在的竞争条件,比如使用rotatelogs风格的管道日志。运行中的多个rotatelogs实例企图同时滚动同一个日志文件可能会导致互相破坏对方的日志文件。

 

附录:信号和竞争条件

在Apache 1.2b9 之前,有很多关于重启和死亡信号的竞争条件。关于竞争条件的一个简单描述是:一个时间敏感的问题,如果一些事情在不适当的时间或以不恰当的顺序发生,它将作出你不期望的反应;如果同样的事情在恰当的时间发生,则不会出现异常。凭借那些拥有"正确"特性设置的体系结构,我们尽量避免了它们的出现。但值得注意的是,仍然有一些竞争条件存在于这样的体系结构中。

使用物理磁盘的ScoreBoardFile就有损坏ScoreBoard的潜在危险。这将发生在"bind: Address already in use"(HUP之后)或"long lost child came home!"(USR1之后)时。前者是一个致命错误,而后者则会使服务器丢失ScoreBoard的一个记录。所以我们建议多使用优雅重启,偶尔使用硬重启。这些问题很难解决,但幸运的是大多数结构并不需要ScoreBoard文件。而如果你需要这样的结构,你可以参考ScoreBoardFile文档。

当每个子进程在一个HTTP的持续连接(KeepAlive)中涉及到第二个并发的请求时,所有的结构都会或多或少存在竞争状态的问题。它将在读取了请求而没有读取任何请求头之后立刻退出。这个修复对于1.2来说来得太晚了。但因为持续连接的客户端已经考虑到网络延时和服务器超时会造成类似的情况,所以理论上说,这不是一个太大的问题。而实际上似乎也没有任何影响:在一个测试案例中服务器在一秒之内被重启了20次,而客户端却成功的浏览了网站,而且没有任何破损的图片或空文档。

16 noviembre

evasive limitipconn bandwidth 模块 (apache安全性,转)

 

mod_evasive防DDoS攻击

  为了防止Web服务器被DDoS攻击,我们需要安装mod_evasive这个防DDoS的模块

mod_evasive 1.10.x防DDoS模块的下载与安装
下载地址:http://www.zdziarski.com/projects/mod_evasive/

解压后进入解压目录,执行
/home/apache/bin/apxs -cia mod_evasive20.c

编译完成后,/home/apache/modules下会生成一个mod_evasive20.so文件

然后kate /home/apache/conf/httpd.conf
加入以下选项(如果没有的话)

#启用mod_evasive for Apache 2.x防DDoS模块
LoadModule evasive20_module modules/mod_evasive20.so (这一句通常会被自动加入)

<IfModule mod_evasive20.c>
#记录和存放黑名单的哈西表大小,如果服务器访问量很大,可以加大该值
DOSHashTableSize 3097
#同一个页面在同一时间内可以被统一个用户访问的次数,超过该数字就会被列为攻击,同一时间的数值可以在DosPageInterval参数中设置。
DOSPageCount 3
#同一个用户在同一个网站内可以同时打开的访问数,同一个时间的数值在DOSSiteInterval中设置。
DOSSiteCount 40
#设置DOSPageCount中时间长度标准,默认值为1。
DOSPageInterval 2
#DOSSiteInterval 2 设置DOSSiteCount中时间长度标准,默认值为1。
DOSSiteInterval 2
#被封时间间隔秒,这中间会收到 403 (Forbidden) 的返回。
DOSBlockingPeriod 10
#设置受到攻击时接收攻击信息提示的邮箱地址。
#DOSEmailNotify you@yourdomain.com
#受到攻击时Apache运行用户执行的系统命令
#DOSSystemCommand “su - someuser -c ‘/sbin/… %s …’”
#攻击日志存放目录,BSD上默认是 /tmp
#DOSLogDir “/var/lock/mod_evasive”
</IfModule>

 

 

mod_limitipconn限制Apache的并发连接数

  mod_limitipconn可以控制每个IP地址同时连接服务器某一个目录的并发连接数,是一个非常有用的模块,其官方网页是http: //dominia.org/djao/limitipconn.html,最新版本为for Apache 1.3.7的0.04,并且还有支持Apache 2.x的模块下载,由于本人使用Apache 1.3.7版本,所以请使用2.x版本Apache的朋友到其官方网站察看具体的使用方法。

  mod_limitipconn for Apache 1.3x提供三种安装方式,分别是tar包、rpm安装文件和rpm源文件,由于rpm包只能用在 RedHat 7.x 版本,并且不支持检测代理服务器,所以我们一般都使用tar包的安装方式。

  以管理员方式登陆服务器,然后在服务器上运行 wget http://dominia.org/djao/limit/mod_limitipconn-0.04.tar.gz 将mod_limitipconn的tar包下载到服务器,然后按照再运行tar zxvf mod_limitipconn-0.04.tar.gz将tar包解压缩,会在当前目录下生成mod_limitipconn-0.04目录,然后cd mod_limitipconn-0.04进入此目录,下一步就是使用apxs将目录中的mod_limitipconn.c编译。这时,我们需要确定自己的Apache安装在那个目录,并且找到apxs命令放在哪里。

  通过命令whereis apxs,我们可以确定apxs命令的路径,如我的apxs命令所在为/usr/sbin/apxs,则输入/usr/sbin/apxs -c -i -a mod_limitipconn.c对mod_limitipconn.c进行编译,此命令会自动在你Apache的配置文件httpd.conf中加入需要的信息,并且将生成的mod_limitipconn.so模块拷贝到Apache的模块目录。不过为了确认此命令是否正常运作,请首先检查自己的 Apache模块目录(我的是/usr/lib/apache),看内部是否含有mod_limitipconn.so文件,没有的话请将 mod_limitipconn-0.04目录中生成的文件拷贝到此处。

  刚才命令自动生成的httpd.conf可能有些错误,在我的系统中,它将LoadModule limitipconn_module modules/mod_limitipconn.so放在了

<IfDefine HAVE_PYTHON>
LoadModule python_module modules/mod_python.so
</IfDefine>
之间,而将AddModule mod_limitipconn.c放在了

<IfDefine HAVE_PYTHON>
AddModule mod_python.c
</IfDefine>
之间,直接造成了mod_limitipconn模块不能正常运行,所以请将这两行分别移动到没有<IfDefine>< /IfDefine>的相应行中,然后请确认mod_status模块已经加载,并且在mod_status下添加了ExtendedStatus On这一行。这时我们的mod_limitipconn模块就安装完毕,下一步就是对某个目录进行并发连接数的设置了。

  mod_limitipconn可以对全局和虚拟主机进行不同的限制,其语法结构都是

<IfModule mod_limitipconn.c>
<Location /> #所限制的目录所在,此处表示主机的根目录
MaxConnPerIP 3 #所限制的每个IP并发连接数为3个
NoIPLimit image/* #对图片不做IP限制
</Location>
<Location /mp3> #所限制的目录所在,此处表示主机的/mp3目录
MaxConnPerIP 1 #所限制的每个IP并发连接数为1个
OnlyIPLimit audio/mpeg video #该限制只对视频和音频格式的文件
</Location>
</IfModule>


  当对全局进行限制时,将这段代码放在httpd.conf文件没有VirtualHost的地方,若是对某个虚拟主机进行限制,请将其放在 <VirtualHost xxx.xxx.xxx.xxx>和</VirtualHost>之间,我们可以通过更改Location以及 MaxConnPerIP方便的控制所限制的目录和并发连接数。

  最后,只要重新启动Apache服务,并发连接数的限制就可以生效。

 

 

mod_bandwidth控制Apache的带宽

  Apache 1.3.7实际上带有mod_bandwidth支持,只是没有此模块的so文件,我们所做的就是下载mod_bandwidth的源文件进行编译,并对mod_bandwidth进行相应的设置。

  在下载之前,请先确认自己的Apache配置文件httpd.conf中是否含有

<IfDefine HAVE_BANDWIDTH>
LoadModule bandwidth_module modules/mod_bandwidth.so
</IfDefine>


以及

<IfDefine HAVE_BANDWIDTH>
AddModule mod_bandwidth.c
</IfDefine>


若是没有,请加上

LoadModule bandwidth_module
libexec/apache/mod_bandwidth.so
AddModule mod_bandwidth.c


  并且这两行必须分别加在相应区域的最前面,使得这个模块以最低的优先级运行。(不过1.3.7的Apache应该有,呵呵)。

 

  确认后,请输入 wget ftp://ftp.cohprog.com/pub/apache/module/1.3.0/mod_bandwidth.c 将源文件下载到服务器,然后请使用apxs对其进行编译,编译方法和mod_limitipconn的基本相同,如我输入/usr/sbin/apxs -c mod_bandwidth.c -o /usr/lib/apache(Apache的模块目录),编译程序会自动将编译成功的mod_bandwidth.so文件放到Apache的模块目录,您也可以自己确认一下,若是不正常,拷贝过去即可。

 

  mod_bandwidth运行时需要一些特定的目录,按照默认情况,请运行以下命令创建并更改目录的权限:

mkdir /tmp/apachebw
mkdir /tmp/apachebw/link
mkdir /tmp/apachebw/master
chmod -R 777 /tmp/apachebw


  然后再打开httpd.conf文件,加上以下内容

<IfModule mod_bandwidth.c>
BandWidthDataDir "/tmp/apachebw/"
BandWidthModule on
</IfModule>


  这时,我们就能够对所需要限制带宽的目录进行相应的设置,此处的目录请使用服务器的绝对路径。如我们想限制服务器 /home/www/thinkjam/download/soft目录的下载速度,也就是限制网址http: //download.thinkjam.org/soft目录下软件的下载速度,则为httpd.conf文件增加以下内容

<Directory /home/www/thinkjam/download/soft>
BandWidth thinkjam.org 0 #来自thinkjam.org的下载不受速度限制
BandWidth 210.51.21 0 #来自210.51.21网段的下载不受速度限制
BandWidth all 327680 #来自其它网段的速度都限制为327680Byte,即30KB/s
</Directory>


  设置完毕后,重新启动Apache服务,即可生效。

  mod_bandwidth还有许多其它有用的参数,如在中间加上MaxConnection 120则可以限制某个目录的最多连接数,当超过指定连接数时,拒绝新的连接,此参数与mod_limitipconn模块结合可以控制某个目录的最多连接人数。

  其它的参数请朋友们到其官方网站 http://www.cohprog.com/v3/bandwidth/doc-en.html 察看相关的文档。

  Apache的功能确实强大,很多功能都可以通过添加模块来实现,在 http://modules.apache.org/ 可以找到更多的模块,我们也可以编写自己的模块来实现相应的功能。

15 noviembre

工作二周 BOSS对于创业型公司的威力

   终于能上网了,哈哈。

   上班比想象中的有趣,每天都有明确需要完成的目标,一个个课题排列在面前等待着去被解决。

     从Mysql到Apache,前端网络、后端数据库、防攻击 似乎一应俱全~

       怎么看都觉得是一个实验大课堂,能学到的东西真是太多了。

    相比上一份工作到后期寥寥几件值得一提的鸟事相比 这里的工作内容明显充实而有趣的很多。

   

    相处的朋友越来越多,似乎大家都能方便的融洽到一处。我想 这应该是这里老总的功劳吧。

    上周请我们去看了他觉得很赞的《This is it.》这个礼拜又在开会的时候说了令我佩服的话。

      老总似乎还是那么一如既往地那么帅。

 

      几位领导也很有特色,尤其是市场部的领导,令人眼前一亮。

      老总的眼光真的蛮独到的,已经开始提拔80后做经理一职了。

     

 

    创业型的小公司 老总总能在恰当的时机出现在一个合适的地方。 管理的更到位 思路更明确。

      老总就是老总,那绝对不是中层管理人员所能企及的高度。

    所以说 这个应该是所谓的私营企业思路活跃、灵活能动的理由吧。现在有些了解了。

    扁平化的管理,有能力领导者的直接参与 这些应该是小公司充满活力的根本原因。我是如此认为的。

 

    那是不是说 一个小的公司 只要人才出类拔萃 分配各司其职,一样可以产出更大的效益。规模不能说明一切呢?

      这个还是有待考量的,不论是什么的发展,在初期 劳动力的多寡总归还是决定产出的根本因素。

     而一个好的领导者,他应该有明确的自知力 了解到自己所能掌控的团队人数的极限值。

    我在想 正好达到这么一个临界值的团体,或许就是这个团队的黄金时期。

 

    突破这个临界值继续扩大下去的公司,那就完全是另一套管理的方式了,需要完整彻底的转变,

     何时突破、如何转变,这又是一门高深值得研究的课题了,此乃后话。

    

     2个礼拜了。这个公司还是很有趣的,不管是人也好、做的事情也好,都很合我的口味

       就是远了点,现在搬到了常熟路,路上要花掉1个小时15分钟的路程,这是仅有的2个缺点之一。

       另一个就是上班几乎一直看着电脑屏幕~一不注意就到了下班时间,还是要注意用眼啊。

 

     明天写点公司里面的轶事吧。

13 noviembre

单服务器多Mysql服务配置

之前弄完了主从数据库的配置,考虑到每一台主服务器要一台从服务器好像有点夸张

于是接着准备在一台从服务器上备份多台服务器的工作。

 

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

 

Mysql确实提供了这样的命令 mysqld_multi

 

~   ~   ~   ~   ~

 

不过执行这个脚本的时候会调用几个其他mysql的脚本,所以先要把mysql/bin路径做到PATH变量里面

# vi ~/.bash_profile

     path=$path:/usr/local/mysql/bin

 

~   ~   ~   ~   ~

 

接着就是最重要的my.cnf配置,出错了很久,基本就是这里面配置的不对。

   我把现在配好的配置贴在这里~

 

[client]
#password    = your_password
#port        = 3306
#socket        = /tmp/mysql.sock

[mysqld1]
port        = 3306
socket        = /tmp/mysql.sock

pid-file=/opt/data/proxy.pid
datadir = /opt/data/
user = mysql

#log-slow-queries=/usr/local/mysql/data2/slowquery.log
#long_query_time = 10
skip-locking
key_buffer = 256M
max_allowed_packet = 1M
table_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
thread_concurrency = 8
log-bin=mysql-bin
server-id    = 10
replicate-do-db=222222

[mysqld2]
port = 3307
socket = /tmp/mysql.sock2
pid-file = /opt/222.22.2.185/185.pid
datadir = /opt/222.22.2.185/

#log=/usr/local/mysql/data2/net-app1.log
user = mysql
#log-slow-queries=/usr/local/mysql/data2/slowquery.log
#long_query_time = 10
key_buffer = 128M
max_allowed_packet = 1M
table_cache = 512
sort_buffer_size = 1M
read_buffer_size = 1M
myisam_sort_buffer_size = 32M
thread_cache = 32
query_cache_size = 16M
thread_concurrency = 2
max_connections=300
log-bin
log-bin=/opt/222.22.2.185/185-bin
server-id       = 10

replicate-do-db=22222

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates

[isamchk]
key_buffer = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[myisamchk]
key_buffer = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout

 

multi脚本是看my.cnf里面的[mysqldX] 下面的配置,所以这个配置名一定要改成相应。

 

加粗的几个文档路径是一定要配的,其余的比如relay-log之类的倒不是必要。而且要给予相应的权限,

这个配置已经做好了slave的从数据库命令,不过change master命令还是一定要登上去做的

 

接着初始化数据库,直接拉一个过来也可以。反正就和之前没有什么区别了。

 

好了,把脚本起一下

# /usr/local/mysq/bin/mysqld_multi   --config-file=/etc/my.cnf [start|stop|report] 1-X

 

接着登陆

# mysql -p -P3307 -uroot –h192.168.2.2

 

这里有一个问题,如果-h参数用localhost的话是登陆到3306端口的,即使是-P指定了也不行 这点现在也没有搞懂

     要注意的是现在登陆的是root@192.168.2.2的账号 和root@localhost账号权限是有区别的噢

 

登上去之后就和之前主从服务器一样操作了,结果就是一台服务器上起了多个mysql服务了咯。

 

~   ~   ~   ~

最后我们把几个服务都做到启动项里去

    # vi /etc/rc.local

/usr/local/mysql/bin/mysqld_multi   --config-file=/etc/my.cnf start 1-2 &
/usr/local/bin/mysql-proxy.sh &

 

 

OK了。

 

 

 

9

11 noviembre

Apache性能优化技巧

 

升级 Apache 到最新版本,新版本往往包含性能提升和安全更新。

在 httpd.conf 中设置 "HostNameLookups off" 能避免针对每个访问者的 DNS 域名的反向查询。

对于繁忙的网站,在 httpd.conf 中设置 "MaxClients 230" 或者更高。这项设置让更多的 httpd 进程同时响应请求,并避免了处理器排队的情况发生。

采用另外一台服务器处理图片文件。

缺保您的 Web 页面和 CGI 页面采用了浏览器缓冲技术。具体的文章可以参考本站:采用 mod_gzip 加速 Zope 和 Apache

保持您的 Apache 苗条,编译那些仅仅需要的模块,在编译之前,修改 src/Configuration 文件,在那些不需要的模块之前用 # 号注释掉。

如果不需要流量日志,那么把 httpd.conf 中的 TransferLog 指向到 /dev/null/

除非你确定使用 .htaccess 文件来控制一些目录的权限,否则设置 "AllowOverride None" ,这样就免去 Apache 在每个目录搜索 .htaccess 文件的劳役之苦。

不要让不需要的后台进程运行。

千万不要把页面或者日志文件写到网络磁盘上,例如 NFS。

不要让 Apache (httpd) 运行于 inetd 模式。

不要让 X Windows 运行在你的 Web 服务器上,用 Ctrl-Alt-Backspace 关闭 X 。

避免使用 SSI tag。

在 CGI 脚本中:

文件 I/O:打开的文件数目越少越好。
Shell 命令:采用全路径来调用 shell 命令。
如果你的网站主要以 CGI 来驱动,那么请使用 mod_perl。
在你的 Web 页面目录中,不要让文件数超过 1000 个,文件越多花费在定位上的时间也越多。

在 Web 服务器上的图片越少越好,保证每个图片都经由图片压缩器运行。

对你的网站做压力测试,建议采用 Apache 自带的 ab 命令来测试。

为了最好的性能,最好把网线拔掉,这样你的 Web 服务器就十分安全,而且负载马上降为 0,

Apache优化管理(另一篇,还是有些区别,转)

版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://www.chedong.com/tech/apache_install.html

 

     Apache是一个历史悠久并且功能十分强大的WEB服务器,但其丰富的功能对于一个新手来说往往不知道从何下手。我个人感觉Apache的设计充分体现了模块化设计的优势,通过在动态模块加载(DSO)模式下的安装,任何子应用模块都可以通过配置文件的简单修改进行积木式的灵活配置。安装的过程可以从简单的静态html服务开始,一个模块一个模块的学习使用。从单纯的HTML静态服务(core),到复杂的动态页面服务(core + php, core + resin, core + php + mod_gzip, core + resin + mod_expire)。

     本文主要从简化安装==>性能调优==>维护方便的角度,介绍了WEB服务的规划、HTTPD安装/应用模块配置、升级/维护等过程。让Apache和PHP,Resin等应用模块的独立升级,完全互不影响。

  1. WEB应用容量规划:根据硬件配置和WEB应用的特点进行WEB服务的规划及一些简单的估算公式;
  2. Apache安装过程:apache的通用的简化安装选项,方便以后的应用的模块化配置;
    修改 HARD_SERVER_LIMIT:
    vi /path/to/apache_src/src/include/httpd.h
    #define HARD_SERVER_LIMIT 2560 <===将原来的 HARD_SERVER_LIMIT 256 后面加个“0”
    apache编译:
    ./configure --prefix=/home/apache --enable-shared=max --enable-module=most
  3. 可选应用模块/工具的安装:php resin mod_gzip mod_expire及各个模块之间的配合;
    mod_php安装:./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql
    mod_resin安装:./configure --with-apxs=/home/apache/bin/apxs
    mod_gzip安装:修改Makefile中的 apxs路径:然后make make install
    工具:日志轮循工具cronolog安装:http://www.cronolog.org
  4. 升级/维护:看看通用和模块化的安装过程如何简化了日常的升级/维护工作;
    按照以上的方法:系统管理员和应用管理员的职责可以清楚的分开,互相独立。
    系统安装:系统管理员的职责就是安装好一台DSO模式的Apache,然后COLON即可,
    应用安装:由应用管理员负责具体应用所需要的模块,比如PHP Resin等,并设置httpd.conf中相关的配置。
    系统升级:系统管理员:升级操作系统/升级Apache
    应用升级:应用管理员:升级应用模块,PHP Resin等。

 

WEB应用的容量规划

     Apache主要是一个内存消耗型的服务应用,我个人总结的经验公式:
apache_max_process_with_good_perfermance < (total_hardware_memory / apache_memory_per_process ) * 2
apache_max_process = apache_max_process_with_good_perfermance * 1.5

     为什么会有一个apache_max_process_with_good_perfermance和apache_max_process呢?原因是在低负载下系统可以使用更多的内存用于文件系统的缓存,从而进一步提高单个请求的响应速度。在高负载下,系统的单个请求响应速度会慢不少,而超过 apache_max_process,系统会因为开始使用硬盘做虚拟内存交换空间而导致系统效率急剧下降。此外,同样的服务:2G内存的机器的 apache_max_process一般只设置到1G内存的1.7倍,因为Apache本身会因为进程过多导致性能下降。

例子1:
一个apache + mod_php的服务器:一个apache进程一般需要4M内存
因此在一个1G内存的机器上:apache_max_process_with_good_perfermance < (1g / 4m) * 2 = 500
apache_max_process = 500 * 1.5 = 750
所以规划你的应用让服务尽量跑在500个进程以下以保持比较高的效率,并设置Apache的软上限在800个。

例子2:
一个apache + mod_resin的服务器: 一个apache进程一般需要2M内存
在一个2G内存的机器上:
apache_max_process_with_good_perfermance < (2g / 2m ) * 2 = 2000
apache_max_process = 2000 * 1.5 = 3000

     以上估算都是按小文件服务估算的(一个请求一般大小在20k以下)。对于文件下载类型站点,可能还会受其他因素:比如带宽等的影响。

 

Apache安装过程

     服务器个数的硬上限HARD_SERVER_LIMIT的修改:

在Apache的源代码中缺省的最大进程数是256个,需要修改apache_1.3.xx/src/include/httpd.h
#ifndef HARD_SERVER_LIMIT
#ifdef WIN32
#define HARD_SERVER_LIMIT 1024
#elif defined(NETWARE)
#define HARD_SERVER_LIMIT 2048
#else
#define HARD_SERVER_LIMIT 2560 <===将原来的HARD_SERVER_LIMIT 256 后面加个“0”
#endif
#endif

     解释:
     Apache缺省的最大用户数是256个:这个配置对于服务器内存还是256M左右的时代是一个非常好的缺省设置,但随着内存成本的急剧下降,现在大型站点的服务器内存配置一般比当时要高一个数量级不止。所以256个进程的硬限制对于一台1G内存的机器来说是太浪费了,而且 Apache的软上限 max_client是受限于HARD_SERVER_LIMIT的,因此如果WEB服务器内存大于256M,都应该调高Apache的 HARD_SERVER_LIMIT。根据个人的经验:2560已经可以满足大部分小于2G内存的服务器的容量规划了(Apache的软上限的规划请看后面)。

 

 

     Apache的编译:以下通用的编译选项能满足以后任意模块的安装

./configure --prefix=/another_driver/apache/ --enable-shared=max --enable-module=most
比如:
./configure --prefix=/home/apache/ --enable-shared=max --enable-module=most

 

     解释:
     --prefix=/another_driver/apache/:建议将apache服务安装在另外一个驱动设备上的目的在于硬盘往往是一个系统使用寿命最低的设备,因此:将服务数据和系统完全分开,不仅能提高了数据的访问速度,更重要的,大大方便系统升级,应用备份和恢复过程。

     --shared-module=max:使用动态加载方式载入子模块会带来5%的性能下降,但和带来的配置方便相比更本不算什么:比如模块升级方便,系统升级风险降低,安装过程标准化等

     --enable-module=most:用most可以将一些不常用的module编译进来,比如后面讲到的mod_expire是就不在 apache的缺省常用模块中

如果不想build so, 也可以这样:
./configure \
"--with-layout=Apache" \
"--prefix=/path/to/apache" \
"--disable-module=access" \
"--disable-module=actions" \
"--disable-module=autoindex" \
"--disable-module=env" \
"--disable-module=imap" \
"--disable-module=negotiation" \
"--disable-module=setenvif" \
"--disable-module=status" \
"--disable-module=userdir" \
"--disable-module=cgi" \
"--disable-module=include" \
"--disable-module=auth" \
"--disable-module=asis"

     但结果会发现,这样编译对服务性能只能有微小的提高(5%左右),但却失去了以后系统升级和模块升级的灵活性,无论是模块还是Apache本身升级都必须把Apache和PHP的SOURCE加在一起重新编译。

     apache的缺省配置文件一般比较大:可以使用去掉注释的方法精简一下:然后再进入具体的培植过程能让你更快的定制出你所需要的。
grep -v "#" httpd.conf.default >httpd.conf

 

     需要修改的通用项目有以下几个:

#服务端口,缺省是8080,建议将整个Apache配置调整好后再将服务端口改到正式服务的端口
Port 8080 => 80

#服务器名:缺省没有
ServerName name.example.com
#最大服务进程数:根据服务容量预测设置
MaxClients 256 => 800

#缺省启动服务后的服务进程数:等服务比较平稳后,按平均负载下的httpd个数设置就可以
StartServers 5 => 200

不要修改:
以前有建议说修改:
MinSpareServers 5 => 100
MaxSpareServers 10 => 200

但从我的经验看来:缺省值已经是非常优化的了,而且让Apache自己调整子共享进程个数还是比较好的。

特别修改:
在solaris或一些比较容易出现内存泄露的应用上:
MaxRequestsPerChild 0 =>3000

 

 

应用模块和工具的安装配置:

     由于使用模块动态加载的模式,所以可以方便的通过简单的配置调整来把Apache定制成你需要的:最好把不常用模块全部清除(无论处于安全还是效率)。
比如:对于静态页面服务器:就什么其他子模块都不加载,对于PHP应用就加上PHP模块,对于JAVA应用就把Resin模块加载上。而且各种模块的插拔非常简单,这样调试过程中就可以简单的通过注释掉不需要的模块,而不用重新编译。

     一般说来,可以不需要的模块包括:

#LoadModule env_module libexec/mod_env.so
#LoadModule negotiation_module libexec/mod_negotiation.so
#LoadModule status_module libexec/mod_status.so
#server side include已经过时了
#LoadModule includes_module libexec/mod_include.so
#不需要将没有缺省index文件的目录下所有文件列出
#LoadModule autoindex_module libexec/mod_autoindex.so
#尽量不使用CGI:一直是Apache安全问题最多的地方
#LoadModule cgi_module libexec/mod_cgi.so
#LoadModule asis_module libexec/mod_asis.so
#LoadModule imap_module libexec/mod_imap.so
#LoadModule action_module libexec/mod_actions.so
#不使用安全认证可以大大提高访问速度
#LoadModule access_module libexec/mod_access.so
#LoadModule auth_module libexec/mod_auth.so
#LoadModule setenvif_module libexec/mod_setenvif.so

     最好保留的有:

#用于定制log格式
LoadModule config_log_module libexec/mod_log_config.so
#用于增加文件应用的关联
LoadModule mime_module libexec/mod_mime.so
#用于缺省index文件:index.php等
LoadModule dir_module libexec/mod_dir.so

     可用可不用的有:

#比如:需要在~/username/下调试php可以将
LoadModule userdir_module libexec/mod_userdir.so
#比如:需要将以前的URL进行转向或者需要使用CGI script-alias
LoadModule alias_module libexec/mod_alias.so

     常用的模块:

最常用的可能就是php和JAVA应用服务器的前端,此外,从性能上讲利用mod_gzip可以减少40%左右的流量,减少机器用于传输的负载,而 mod_expires可以减少10%左右的重复请求,让重复的用户对指定的页面请求结果都CACHE在本地,根本不向服务器发出请求。

     建议将所有MODULE的配置都放到相应模块的配置内部:<IfModule some_module.c>some_module config </IfModule>

 

PHP的安装:
/path/to/php_src/configure --with-apxs=/path/to/apache/bin/apxs --with-other-modules-you-need
需要修改的配置:
AddType application/x-httpd-php .php .php3 .any_file_in_php

resin的安装设置:
/path/to/resin/src/configure --with-apxs=/path/to/apache/bin/apxs
具体的resin设置放在另外一个文件中:比如/home/resin/conf/resin.conf
<IfModule mod_caucho.c>
CauchoConfigFile /path/to/apache/conf/resin.conf
</IfModule>

mod_expires的安装配置:
<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresByType image/gif "access plus 1 month"
    ExpiresByType text/css "now plus 1 month"
    ExpiresDefault "now plus 1 day"
</IfModule>

注释:
所有的.gif文件1个月以后过期
所有的文件缺省1天以后过期

mod_gzip的安装
http://www.chedong.com/tech/compress.html

 

日志的轮循:cronolog的安装和设置

     cronolog可以非常整齐的将日志按天轮循存储

     缺省编译安装到/usr/local/bin/下,只需要将配置改成:

CustomLog "|/usr/local/sbin/cronolog /home/apache/logs/%w/access_log" combined

     日志将按天截断并存放在以星期为目录名的目录下:比如:log/1是周一,log/5是周五, log/0是周日

用gzip压缩每天的日志:
30 4 * * * /usr/bin/gzip -f /home/apache/logs/`date -d yesterday +%w`/access_log

日志的定期删除:
30 5 * * */usr/bin/find /home/apache/logs/ -name access_log.gz -mtime +3 |xargs -r /bin/rm –f

 

升级维护

     由于使用动态模块加载方式(DSO模式)安装Apache,Apache的HTTPD核心服务和应用模块以及应用模块之间都变的非常灵活,建议将所有独立模块的配置都放在

<IfModule mod_name>
CONFIGURATIONS..
</IfModule>

     里,这样配置非常容易通过屏蔽某个模块来进行功能调整:比如:

#AddModule mod_gzip.c
就屏蔽了mod_gzip,而其他模块不首任何影响。

 

安装和维护过程:

  • 系统安装:系统管理员的职责就是安装系统和一个按照DSO模式安装的Apache,然后COLON。
  • 应用安装:由应用管理员负责具体应用所需要的模块并设置HTTPD。
  • 系统升级:系统管理员:升级系统/升级Apache
  • 应用升级:应用管理员:升级应用模块:PHP CAUCHO等
  • 系统备份/恢复:如果Apache不在缺省的系统盘上,只需要将Apache目录备份就可以了,遇到系统分区的硬件问题直接使用预先准备好的系统COLON,再直接将Apache所在物理盘恢复就行了。

 

系统管理员:Apache的最简化安装
OS + Apache (httpd core only)

 

应用管理员:应用模块定制
纯静态页面服务
core
PHP动态页面
core+so
+php
JAVA应用
core+so
+caucho
+ssl

 

应用例子:
www.example.com
image.example.com
bbs.example.com
mall.example.com

 

例子:Apache和PHP模块的独立升级。

如果Apache是按照以下方式安装:

./configure --prefix=/home/apache --enable-shared=max --enable-module=most

     PHP是按照以下方式安装:

./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql

     以后单独升级Apache的时候,仍然是:

./configure --prefix=/home/apache --enable-shared=max --enable-module=most
make
su
#/home/apache/bin/apachectl stop
#make install

     单独升级php时,仍然是:

./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql
make
su
#/home/apache/bin/apachectl stop
#make install
#/home/apache/bin/apachectl start

     基于反相代理的WEB加速:

squid和mod_proxy都可以实现反相代理加速。而基于缓存的代理加速比起原有WEB服务,速度会有数量级的提升。

 

小提示:

Apache安装后,缺省根目录下没有但很有用的2个文件:

  • favicon.ico: favicon.ico是一个16x16的站点图标文件,如果浏览器发现有这个文件,在地址栏中会用这个图标替换调浏览器的网页图标。IE6和 MOZILLA等主流浏览器都支持这个功能。
    例如: http://www.chedong.com/favicon.ico
  • robots.txt: 用于告诉搜索引擎的爬虫程序(spider)网站那些页面可以被索引,那些不可以。
    具体说明请参考:http://www.robotstxt.org/wc/robots.html

apache2配置优化以及性能测试小结(貌似还算基础的优化,转)

 

一、优化目的:

     公司中现有多个apache平台,其中网元管理系统、升级和注册授权系统、离线浏览系统和应用组所开发的系统都是运行在专用的服务器中,他们都是以业务为主的系统,所拥有的硬件资源比较多,可以着重优化apache的运行速度,以适当的资源换取更高的运行速度

     但是设备中运行的各个配置程序,他们是以性能为主的系统,所运行的环境就要相对恶劣,硬件资源限制非常多,不能供web程序随意使用,他们的优化方向应该是保证运行速度的基础上尽力压低资源消耗

     受限于此,很多外挂式加速程序都无法使用了,比如memcache、eaccelerator等,使用这些工具的前提就是内存足够大,或者资源足够多,通常是专用的apache服务器上才会用到,也就是我们的第一类系统中才可以使用的,在一个嵌入系统中使用其实是得不尝失的。下面将着重研究两种情况都使用的优化方法。

 

二、运行环境

     无论何时,apache所运行的硬件环境都是对性能影响最大的因素,即使不能对硬件进行升级,也最好给apache一个单独的主机以免受到其他应用的干扰。但很明显,我们的配置页面程序无法满足这个要求。

     各个硬件指标中,对性能影响最大的是内存,对于静态内容(图片、javascript文件、css文件等),它决定了apache可以缓存多少内容,它缓存的内容越多,在硬盘上读取内容的机会就越少,而存取硬盘上的特定文件是一件很费时的操作,大内存可以极大提高静态站点的速度;对动态高负载站点来说,每个请求保存的时间更多一些,apache的mpm模块会为每个请求派生出相应的进程或线程分别处理,而进程或线程的数量与内存的消耗近似成正比,因此增大内存对提高动态站点的负载和运行速度也极为有利

     其次是硬盘的速度,静态站点尤为突出,apache不断的在读取文件并发送给相应的请求,硬盘的读写是极其频繁的;动态站点也要不断的加载web程序(php等),一个请求甚至要读取十几个文件才能处理完成,因此尽可能的提高硬盘速度和质量对提高apache的性能是有积极意义的。

     最后是cpu和网络,cpu影响的是web程序执行速度,网络影响流量大小。

     影响性能的另一因素是操作系统,php程序在类unix环境中的执行速度仍然比windows中要快,我们的系统都能满足这个要求了。

 

三、apache普通配置参数

1、静态还是动态

  使用apache的动态载入模块非常方便,因为在需要时模块才会被载入。虽然有些性能开销,但同时有利于减少服务器对内存的需求。

     静态载入虽然一次性载入所有需要的模块,增加内存消耗。因此我们全部采用动态载入的方法。

2、hhostnamelookups off

     域名查找:这增加了处理每个请求的开销,首先,服务器会对dns系统做一个反向查询以找出客户系统的主机名,然后又进行正向查询看获得的主机名是否真实指向客户的ip。大多数情况下,你可以简单的关闭这个功能,如果你经常处理服务器日志,这个工作完全可以在以后进行。你可以通过在设置文件中加入指示hostnamelookups off来关闭这个功能。

3、options -followsymlinks

     符号连接:当打开这个选项时,apache将检查每个请求中是否包含对符号连接的引用,这将对请求中包含的每个路径调用一次lstat()系统调用。除非你准备使用符号连接,否则用 options -followsymlinks 来关掉它。

4、sethandler server-status

     服务器状态信息,默认已经关闭。该模块尽管这对测试与监控服务器很有用,但它也为服务器带来了额外的开销,你可以通过寻找任何类似sethandler server-status的指示来关闭,如果可能,你可以在安装apache时移除这个模块。

5、options -indexes

     关闭目录浏览

6、directoryindex index.php index.html

     在可以更精确的时候尽可能不要使用通配符之类的灵活选项,删除不需要的选项,明确的指定设置文件列表,最常用的放在最前。

7、cgi模块

     除非你有很好的理由否则就允许cgi的执行,将似有的cgi文件放到一个特定的目录并为之设定正确的权限,这避免了apache对每一个请求都要判断一次要求的是一个静态文件还是一个动态文件。

8、写入日志

     写入日志信息是一个很花费时间的工作,apache保持日志文件的打开状态以节省打开文件的时间,如果没有必要存储日志信息,你可以关闭这个选项以节省出更多的处理器时间,只需要在设置文件中把日志那一行注释掉就可以关掉它。

  如果必须保留日志,你可以关闭hostnamelookups选项(见上文)然后把日志文件拷备到另一台机器上做进一步分析。

9、allowoverride none

     .htaccess文件可以极大的扩展apache的设置参数,而无需每次你改变设计都要编辑apache主设置文件,但对这个文件的使用也降低了服务器的性能。

  如果使用这个文件,apache必需首先在当前目录中查找是否存在这个文件,如果存在就解析这个文件并在当前目录中应用文件中的设置。更坏的是,apache不仅要查看当前的目录,还要查看当前目录的所有上层目录是否包括htaccess文件以根据所有这些文件最终确定设置。

  如果你想最优化服务器的性能,你应该禁止使用htaccess文件,任何基本目录的设置都可以在主设置文件中进行,而主设置文件仅在服务器启动时解析一次。为了禁用htaccess文件,在任何节里加上指示allowoverride none。

10、timeout 5

     timeout 设置 apache 等待一个连接读写操作的时间长度,也就是连接建立后,apache 等待客户端完成请求发送的时间,或者是响应开始之后,apache 写出数据到客户端连接的时间长度。

     无论对于哪种应用来说,300秒的缺省值都有些过长了,因为这就意味着,如果客户端发生了某种未知因素导致的迟滞的话,服务器的一个连接和与之对应的所有资源都要维持 300 秒,这个对于重载的服务器来说是在是有些过长,所以,我建议将其设置得小一些,这个长度只要足够保证各种客户端的应用能够正常传递数据即可。这里需要考虑的因素主要有各种客户端的连接状况和服务器的繁忙程度。一般来说,我建议设置为 3~5。

11、keepalive on

     这个选项明确 httpd 进程对每个请求的链接是否保持长链接。如果保持长链接,则从同一个客户端的连续两次请求会使用同一个连接,而不用重复发送请求。

     对于下载类的应用,因为连接时间都比较长,因此这个值设置成 on 还是 off 关系不大,从节约每一滴资源角度考虑,可以设置为 off。

     对于网页类应用来说,如果你的静态页面上有一些图标、图片、和js、css等东西的话,并且如果有超过两个的资源的话,我建议是设置为 on。

12、maxkeepaliverequests 100

     最多保持多少个活动的长链接

13、 keepalivetimeout 5

     连接的保持时间,超过时间就回收

     apache进程在使用内存时,是“渐长”的。也就是说,直到这个进程死掉,使用内存的数量是一直增长而不会减少的。这样的话,apache进程使用内存的多少,就决定于你的应用程序最大使用内存量了。

     keepalivetimeout 这个参数决定了,在什么都不做之前,一个http进程能够等待多长时间?设想一下,如果keepalive设置为on,而 keepalivetimeout设置为一个比较大的数字,apache占用内存会很快的增长。这是因为,一个apache进程完成了一个任务(并达到了一定的内存占用,想一下“渐进”模式),并不会马上退出,而是等待一个keepalivetimeout时间。假设用户的链接请求持续不断的到来,则积累起来的无用的apache进程就会相当多,直到timeout,这些进程才会被杀死。

     但是,keepalive的确对于静态的文件,比如图像文件的传送是很有效的,因此,keepalive要设置为on,但是keepalvietimeout要设置的小些,比如5s

14、serversignature off

     默认情况下,很多apache安装时会显示版本号及操作系统版本,甚至会显示服务器上安装的是什么样的apache模块。这些信息可以为黑客所用,并且黑客还可以从中得知你所配置的服务器上的很多设置都是默认状态。

     所以,请加入如下两条:

serversignature off

servertokens prod

     serversignature 出现在apache所产生的像404页面、目录列表等页面的底部。servertokens目录被用来判断apache会在server http响应包的头部填充什么信息。如果把servertokens设为prod,那么http响应包头就会被设置成:server:apache

 

四、MPM模块

     多处理方式(multi-processing module/mpm)他允许特定平台处理多个并发连接

     apache的mpm模块可运行在多种模式之下,其中beos、mpmt_os2分别是beos和os/2上缺省的mpm, perchild主要设计目的是以不同的用户和组的身份来运行不同的子进程。这在运行多个需要cgi的虚拟主机时特别有用,会比1.3版中的suexec 机制做得更好。leader和threadpool都是基于worker的变体,还处于实验性阶段,某些情况下并不会按照预期设想的那样工作,所以 apache官方也并不推荐使用。因此,我们主要阐述prefork和worker这两种和性能关系最大的产品级mpm ( 有关其它的mpm详细说明,请参见apache官方文档:http://httpd.apache.org/docs-2.0/mod/)。

 

1、prefork的工作原理及配置

     prefork就是unix平台上缺省的mpm。它所采用的预派生子进程方式也是 apache 1.3中采用的模式。prefork本身并没有使用到线程,2.0版使用它是为了与1.3版保持兼容性;另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,这也使其成为最稳定的mpm之一。

  如果是使用debian的apt安装的apache,使用"apache2ctl -l"来确定当前使用的mpm,应该会看到prefork.c(如果看到worker.c说明使用的是worker mpm,依此类推),在apache2.conf中可以找到这一段配置

<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule>

     prefork的工作原理是,控制进程在最初建立"StartServers"个子进程后,为了满足"MinSpareServers"设置的需要创建一个进程,等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足 MinSpareServers设置的值为止。这就是预派生(prefork)的由来。这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。

     MaxSpareServers设置了最大的空闲进程数,如果空闲进程数大于这个值,apache会自动kill掉一些多余进程。这个值不要设得过大,但如果设的值比MinSpareServers小,apache会自动把其调整为MinSpareServers+ 1。如果站点负载较大,可考虑同时加大MinSpareServers和MaxSpareServers。

     MaxRequestsPerChild设置的是每个子进程可处理的请求数。每个子进程在处理了"MaxRequestsPerChild" 个请求后将自动销毁。0意味着无限,即子进程永不销毁。虽然缺省设为0可以使每个子进程处理更多的请求,但如果设成非零值也有两点重要的好处:

      可防止意外的内存泄漏;

      在服务器负载下降的时侯会自动减少子进程数。

      因此,可根据服务器的负载来调整这个值。但也不能太小,不然系统不断的开启新的apache进程,造成资源浪费。

     MaxClients是这些指令中最为重要的一个,设定的是apache可以同时处理的请求,是对apache性能影响最大的参数。其缺省值 150是远远不够的,如果请求总数已达到这个值(可通过ps -ef|grep http|wc -l来确认),那么后面的请求就要排队,直到某个已处理请求完毕。这就是系统资源还剩下很多而http访问却很慢的主要原因。系统管理员可以根据硬件配置和负载情况来动态调整这个值。虽然理论上这个值越大,可以处理的请求就越多,但apache默认的限制不能大于256。如果把这个值设为大于256,那么 apache将无法起动。事实上,256对于负载稍重的站点也是不够的。在apache 1.3中,这是个硬限制。如果要加大这个值,必须在“configure”前手工修改的源代码树下的src/include/httpd.h中查找 256,就会发现“#define hard_server_limit 256”这行。把256改为要增大的值(如4000),然后重新编译apache即可。在apache 2.0中新加入了serverlimit指令,使得无须重编译apache就可以加大maxclients。

<IfModule mpm_prefork_module>
StartServers 10
MinSpareServers 10
MaxSpareServers 15
ServerLimit 600
MaxClients 300
MaxRequestsPerChild 600
</IfModule>

2、worker的工作原理及配置

  相对于prefork,worker是2.0 版中全新的支持多线程和多进程混合模型的mpm。由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。但是, worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性。这种mpm的工作方式将是apache 2.0的发展趋势。

<IfModule mpm_worker_module>
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>

     worker的工作原理是,由主控制进程生成"startservers"个子进程,每个子进程中包含固定的"threadsperchild"线程数,各个线程独立地处理请求。同样,为了不在请求到来时再生成线程,minsparethreads和maxsparethreads设置了最少和最多的空闲线程数;而maxclients设置了所有子进程中的线程总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。

     minsparethreads和maxsparethreads的最大缺省值分别是75和250。这两个参数对apache的性能影响并不大,可以按照实际情况相应调节。

     threadsperchild是worker mpm中与性能相关最密切的指令。threadsperchild的最大缺省值是64,如果负载较大,64也是不够的。这时要显式使用 threadlimit指令,它的最大缺省值是20000。上述两个值位于源码树server/mpm/worker/worker.c中的以下两行:

     究竟是选取prefork还是worker需要具体分析,相对而言高负载下perfork拥有更高的稳定性和运行速度,而worker的资源消耗更小。也已经有人在对两种工作模式作了各种测试:http://jed.dzhope.com/read.php/298.htm

     实际情况看来,worker现在还没能达到所期望的效果,性能比frefork差一些,资源消耗少一点。更可惜的是debian下worker还不能与PHP5完美结合,所以只能选用perfork了。

 

五、性能测试

     为了获得优化有性能提高的幅度,评估优化工作的成效,需要对apache2服务器进行测试。

     测试环境:

apache2和php5服务器:debian4.0、apache2.2.3、 php5.2.0-8+etch0、256M内存

     在另一台机器上使用apachebench工具模拟多个浏览器向服务器的测试页面发起HTTP请求,为了减少网络带宽的影响,测试页面的返回值尽可能的小,此处只有1 byte,并为发起测试的机器和服务器组建了一个单独的局域网。每种并发测试11次,以后10次的结果为准,取平均值。

     以下是测试的数据:其中并发数是指apachebench同时发起的请求个数,优化前和优化后是指平均每个请求花费的处理时间,单位毫秒

并发数     优化前(毫秒)    优化后(毫秒)
10          2.048              1.7549
50          2.1389             1.927
100        2.2084             1.9238
200        2.7689             2.5915
400        3.0523             2.797

 

     由图中可以看出,优化后的效果还是很明显的,无论是在低并发还是高并发下,都有效的提高了请求的相应时间。

     需要指出的是,尽管高负载时优化后性能提高的百分比并不明显,但在并发数400时,测试18次失败7次,而优化后测试14次失败3次。优化不仅仅提高了服务器的性能,还提高了负载的能力。

 

六、结论

     优化可以有效的提高apache2的性能。

     对于WMS等设备上的配置页面,第三部分的“apache普通配置参数”可以应用,MPM主要是以资源换取速度的优化,可以酌情调整。

     对于EM     S、升级系统和应用系统,可以全面优化以提高性能和高负载能力。

06 noviembre

MySQL主从服务器+读写分离

花了三天时间,把MySQL的主从数据库+读写分离部署好了。感觉对缓解大数据流量的服务器压力还是很有效果的。

最近大把时间都花在了数据库上,幸好之前有自己研究过一段时间的数据库,貌似还是上大学的时候。。现在竟然还能回忆起来些

数据库确实是个值得花费精力的地方,很有用。

 

 

一、搭Mysql主、从服务器

                   安装Mysql不是很复杂。主从主要是备份、后续读写分布事务处理等用途

 

     useradd mysql –s /sbin/nologin                              #生成一个mysql的用户

     tar zxvf mysql-5.0.22.tar.gz

     cd mysql-5.0.22

     ./configure --prefix=/usr/local/mysql --localstatedir=/opt/data && make && make install

     cp support-files/my-large.cnf /etc/my.cnf               #配置文档
                                                                           #/etc/my.cnf 作为全局设置
                                                                            # mysql-data-dir/my.cnf 作为服务器指定设置                                                                                                                                          # ~/.my.cnf 作为用户设置

     cd /usr/local/mysql

     /usr/local/mysql/bin/mysql_install_db --user=mysql

     chown -R mysql:mysql /opt/data

     chown -R mysql:mysql /usr/local/mysql

从服务器修改/etc/my.cnf配置文档,server-id=10

     /usr/local/mysql/bin/mysqladmin –p shutdown            #停服务

     /usr/local/mysql/bin/mysqld_safe &                          #起服务,如果没有起来 多数是权限问题

     /usr/local/mysql/bin/mysqladmin –p password’111111’  #修改密码

     /usr/local/mysql/bin/mysql –p                                  #登陆,新安装应该没有密码

 

主服务器上:

     mysql>grant all privileges on *.* to back@192.168.x.x identified by ‘111111’;

                                                                               #新建一个给从服务器登陆的账号

     mysql> show master status;

+------------------+----------+--------------+------------------+
| File                    | Position    | Binlog_Do_DB | Binlog_Ignore_DB  |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |   235       |                    |                          |
+------------------+----------+--------------+------------------+

         记下file及position的值,做从服务器操作的时候需要。

 

   配置从服务器

     mysql> change master to master_host='192.168.x.x', master_user='back',
               master_password='111111', master_log_file='mysql-bin.000003', master_log_pos=235;

     mysql> start slave;                                                 #启用slave

     mysql> show slave status\G                                     #显示当前slave状态

         Slave_IO_Running: Yes
         Slave_SQL_Running: Yes                                     #都为Yes,则为正常

 

主数据库若有数据:

mysql> FLUSH TABLES WITH READ LOCK;                #数据库锁表操作,不让数据再进行写入动作。

mysql> show master status;                   

    把主服务器数据文件复制到从服务器,整个目录一起tar过去即可

 

    或者采用如下备份方法:

     mysqldump -u root -p testdb testtab>d:\testdb_testtab.sql

     恢复命令:

     create database testdb;use testdb;

     mysql>source d:\testdb_testtab.sql

 

mysql> UNLOCK TABLES;                                     #取消主数据库锁定

 

    配置从服务器,保证主服务器的position位置和备份保持一致即可

 

 

  以上主从服务器操作关键在于 备份数据position对应 以及change master命令。

 

  #关于/mysql-data/master.info文档,看my.cnf配置文档中的说明

#    Set the variables below. However, in case you choose this method, then
#    start replication for the first time (even unsuccessfully, for example
#    if you mistyped the password in master-password and the slave fails to
#    connect), the slave will create a master.info file, and any later
#    change in this file to the variables' values below will be ignored and
#    overridden by the content of the master.info file, unless you shutdown
#    the slave server, delete master.info and restart the slaver server.
#    For that reason, you may want to leave the lines below untouched
#    (commented) and instead use CHANGE MASTER TO (see above)

   也就是说还是推荐用change master to 命令来修改master.info文档。而不要用my.cnf的从服务器配置。
   在start slave前这个master.info一定要配置在一个正确的状态,除非他不存在。因为master.info为首选配置档

 

 

测试:

    主服务器上

mysql> create database testdb;
mysql> create table testtb(id int(3),name char(10));
mysql> insert into testtb values (001,’1’);
mysql> use testdb;
mysql> select * from testtb;

    从服务器上

mysql> show databases;
mysql> use testdb;
mysql> show tables;
mysql> select * from testtb;

    确认从服务器上有相同的记录即可。

 

 

二、读写分离

    这部分主要有点是用来给服务器做均衡负载的,其实还是蛮有趣的一个功能。

    搭建Mysql-proxy服务可就没那么简单了,如果能够yum一下就全都搞定那就太开心了!

    无所谓这台代理服务搭在哪里,主、从或者第三方都OK,我推荐可以在从上面做,测试比较清楚

        下面基本就用我history里的命令了,省的一句一句打。

 

     安装 lua      

628  wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
638  tar zxvf lua-5.1.4.tar.gz
639  cd lua-5.1.4
640  vi Makefile                                            #这里是修改  INSTALL_TOP= /usr/local/lua
641  make linux
643  make install

     安装 libevent              

644  cd ..
645  wget http://monkey.org/~provos/libevent-1.4.12-stable.tar.gz
647  tar zxvf libevent-1.4.12-stable.tar.gz
648  cd libevent-1.4.12-stable
649  ./configure --prefix=/usr/local/libevent
650  make
651  make install

     安装check

644  cd ..
652  wget ftp://ftp.eenet.ee/pub/FreeBSD/distfiles/check-0.9.6.tar.gz
655  tar zxvf check-0.9.6.tar.gz
656  cd check-0.9.6
657  ./configure
658  make
659  make install

     安装glib2

681  cd ..
682  wget http://ftp.gnome.org/pub/gnome/sources/glib/2.22/glib-2.22.1.tar.gz
683  tar zxvf glib-2.22.1.tar.gz
684  cd glib-2.22.1
685  ./configure --prefix=/usr/local/glib2
686  make
687  make install

     安装mysql-proxy

660  cd ..
662  wget ftp://ftp.swin.edu.au/freebsd/ports/distfiles/mysql-proxy-0.7.1.tar.gz
664  tar zxvf mysql-proxy-0.7.1.tar.gz
665  cd mysql-proxy-0.7.1
./configure --prefix=/usr/local/mysql-proxy --with-mysql=/usr/local/mysql --with-lua

 

     结果提示glib2版本不对

772  cp /usr/local/glib2/lib/pkgconfig/glib-2.0.pc /usr/lib/pkgconfig/

     然后提示lua不对,于是我下了一个lua.pc

# vars from install Makefile

# grep '^V=' ../Makefile
V= 5.1
# grep '^R=' ../Makefile
R= 5.1.1

# grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/'
prefix= /usr/local/lua
INSTALL_BIN= ${prefix}/bin
INSTALL_INC= ${prefix}/include
INSTALL_LIB= ${prefix}/lib
INSTALL_MAN= ${prefix}/man/man1
INSTALL_LMOD= ${prefix}/share/lua/${V}
INSTALL_CMOD= ${prefix}/lib/lua/${V}

# canonical vars
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: Lua
Description: An Extensible Extension Language
Version: ${R}
Requires:
Libs: -L${libdir} -llua -lm
Cflags: -I${includedir}

    接着提示libevent错误 研究了半天 直接把安装路径放到/usr/下面

648  cd ~/libevent-1.4.12-stable
853  ./configure --prefix=/usr/ && make && make install
868  cd ..
869  cd mysql-proxy-0.7.1
856  ./configure --prefix=/usr/local/mysql-proxy/ --with-mysql=/usr/local/mysql/ --with-lua --with-libevent=/usr/

    这次总算./configure 通过了

        接着make,结果又出错~~提示找不到什么.h的文件
        到make里面去看,原来是编译的时候需要几个库文件,安装路径里面没有~
        这个做的真不好。。

875  cp ../lua-5.1.4/src/lua*.h .
876  cp ../lua-5.1.4/src/lauxlib.h .

    总算make && make install通过了

892  /usr/local/mysql-proxy/sbin/mysql-proxy –V

    测试一把,又出错了。。。

894  chcon -t texrel_shlib_t /usr/local/mysql-proxy/lib/libmysql-chassis.so.0

    原来是selinux作怪,改了。

896  /usr/local/mysql-proxy/sbin/mysql-proxy –V

    总算OK了。

 

 

 

接着来配服务。

      把 rw-splitting.lua 放到/usr/local/mysql-proxy/share/mysql-proxy/下面

 

rw-splitting.lua:

--[[ $%BEGINLICENSE%$
Copyright (C) 2007-2008 MySQL AB, 2008 Sun Microsystems, Inc

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

$%ENDLICENSE%$ --]]

---
-- a flexible statement based load balancer with connection pooling
--
-- * build a connection pool of min_idle_connections for each backend and maintain
--   its size
-- *
--
--

local commands    = require("proxy.commands")
local tokenizer   = require("proxy.tokenizer")
local lb          = require("proxy.balance")
local auto_config = require("proxy.auto-config")

--- config
--
-- connection pool
if not proxy.global.config.rwsplit then
    proxy.global.config.rwsplit = {
        min_idle_connections = 1,
        max_idle_connections = 1,

        is_debug = false
    }
end

---
-- read/write splitting sends all non-transactional SELECTs to the slaves
--
-- is_in_transaction tracks the state of the transactions
local is_in_transaction       = false

-- if this was a SELECT SQL_CALC_FOUND_ROWS ... stay on the same connections
local is_in_select_calc_found_rows = false

---
-- get a connection to a backend
--
-- as long as we don't have enough connections in the pool, create new connections
--
function connect_server()
    local is_debug = proxy.global.config.rwsplit.is_debug
    -- make sure that we connect to each backend at least ones to
    -- keep the connections to the servers alive
    --
    -- on read_query we can switch the backends again to another backend

    if is_debug then
        print()
                print("[connect_server] " .. proxy.connection.client.dst.name)
    end

    local rw_ndx = 0

    -- init all backends
    for i = 1, #proxy.global.backends do
        local s        = proxy.global.backends[i]
        local pool     = s.pool -- we don't have a username yet, try to find a connections which is idling
        local cur_idle = pool.users[""].cur_idle_connections

        pool.min_idle_connections = proxy.global.config.rwsplit.min_idle_connections
        pool.max_idle_connections = proxy.global.config.rwsplit.max_idle_connections
        if is_debug then
            print("  [".. i .."].connected_clients = " .. s.connected_clients)
            print("  [".. i .."].pool.cur_idle     = " .. cur_idle)
            print("  [".. i .."].pool.max_idle     = " .. pool.max_idle_connections)
            print("  [".. i .."].pool.min_idle     = " .. pool.min_idle_connections)
            print("  [".. i .."].type = " .. s.type)
            print("  [".. i .."].state = " .. s.state)
        end

        -- prefer connections to the master
        if s.type == proxy.BACKEND_TYPE_RW and
           s.state ~= proxy.BACKEND_STATE_DOWN and
           cur_idle < pool.min_idle_connections then
            proxy.connection.backend_ndx = i
            break
        elseif s.type == proxy.BACKEND_TYPE_RO and
               s.state ~= proxy.BACKEND_STATE_DOWN and
               cur_idle < pool.min_idle_connections then
            proxy.connection.backend_ndx = i
            break
        elseif s.type == proxy.BACKEND_TYPE_RW and
               s.state ~= proxy.BACKEND_STATE_DOWN and
               rw_ndx == 0 then
            rw_ndx = i
        end
    end

    if proxy.connection.backend_ndx == 0 then
        if is_debug then
            print("  [" .. rw_ndx .. "] taking master as default")
        end
        proxy.connection.backend_ndx = rw_ndx
    end

    -- pick a random backend
    --
    -- we someone have to skip DOWN backends

    -- ok, did we got a backend ?

    if proxy.connection.server then
        if is_debug then
            print("  using pooled connection from: " .. proxy.connection.backend_ndx)
        end

        -- stay with it
        return proxy.PROXY_IGNORE_RESULT
    end

    if is_debug then
        print("  [" .. proxy.connection.backend_ndx .. "] idle-conns below min-idle")
    end

    -- open a new connection
end

---
-- put the successfully authed connection into the connection pool
--
-- @param auth the context information for the auth
--
-- auth.packet is the packet
function read_auth_result( auth )
    if is_debug then
        print("[read_auth_result] " .. proxy.connection.client.dst.name)
    end
    if auth.packet:byte() == proxy.MYSQLD_PACKET_OK then
        -- auth was fine, disconnect from the server
        proxy.connection.backend_ndx = 0
    elseif auth.packet:byte() == proxy.MYSQLD_PACKET_EOF then
        -- we received either a
        --
        -- * MYSQLD_PACKET_ERR and the auth failed or
        -- * MYSQLD_PACKET_EOF which means a OLD PASSWORD (4.0) was sent
        print("(read_auth_result) ... not ok yet");
    elseif auth.packet:byte() == proxy.MYSQLD_PACKET_ERR then
        -- auth failed
    end
end

---
-- read/write splitting
function read_query( packet )
    local is_debug = proxy.global.config.rwsplit.is_debug
    local cmd      = commands.parse(packet)
    local c        = proxy.connection.client

    local r = auto_config.handle(cmd)
    if r then return r end

    local tokens
    local norm_query

    -- looks like we have to forward this statement to a backend
    if is_debug then
        print("[read_query] " .. proxy.connection.client.dst.name)
        print("  current backend   = " .. proxy.connection.backend_ndx)
        print("  client default db = " .. c.default_db)
        print("  client username   = " .. c.username)
        if cmd.type == proxy.COM_QUERY then
            print("  query             = "        .. cmd.query)
        end
    end

    if cmd.type == proxy.COM_QUIT then
        -- don't send COM_QUIT to the backend. We manage the connection
        -- in all aspects.
        proxy.response = {
            type = proxy.MYSQLD_PACKET_OK,
        }
        if is_debug then
            print("  (QUIT) current backend   = " .. proxy.connection.backend_ndx)
        end

        return proxy.PROXY_SEND_RESULT
    end

    proxy.queries:append(1, packet, {resultset_is_needed = true})
    -- read/write splitting
    --
    -- send all non-transactional SELECTs to a slave
    if not is_in_transaction and
       cmd.type == proxy.COM_QUERY then
        tokens     = tokens or assert(tokenizer.tokenize(cmd.query))

        local stmt = tokenizer.first_stmt_token(tokens)

        if stmt.token_name == "TK_SQL_SELECT" then
            is_in_select_calc_found_rows = false
            local is_insert_id = false

            for i = 1, #tokens do
                local token = tokens[i]
                -- SQL_CALC_FOUND_ROWS + FOUND_ROWS() have to be executed
                -- on the same connection
                -- print("token: " .. token.token_name)
                -- print("  val: " .. token.text)
                if not is_in_select_calc_found_rows and token.token_name == "TK_SQL_SQL_CALC_FOUND_ROWS" then
                    is_in_select_calc_found_rows = true
                elseif not is_insert_id and token.token_name == "TK_LITERAL" then
                    local utext = token.text:upper()

                    if utext == "LAST_INSERT_ID" or
                       utext == "@@INSERT_ID" then
                        is_insert_id = true
                    end
                end

                -- we found the two special token, we can't find more
                if is_insert_id and is_in_select_calc_found_rows then
                    break
                end
            end

            -- if we ask for the last-insert-id we have to ask it on the original
            -- connection
            if not is_insert_id then
                local backend_ndx = lb.idle_ro()

                if backend_ndx > 0 then
                    proxy.connection.backend_ndx = backend_ndx
                end
            else
                print("   found a SELECT LAST_INSERT_ID(), staying on the same backend")
            end
        end
    end

    -- no backend selected yet, pick a master
    if proxy.connection.backend_ndx == 0 then
        -- we don't have a backend right now
        --
        -- let's pick a master as a good default
        --
        proxy.connection.backend_ndx = lb.idle_failsafe_rw()
    end

    -- by now we should have a backend
    --
    -- in case the master is down, we have to close the client connections
    -- otherwise we can go on
    if proxy.connection.backend_ndx == 0 then
        return proxy.PROXY_SEND_QUERY
    end

    local s = proxy.connection.server

    -- if client and server db don't match, adjust the server-side
    --
    -- skip it if we send a INIT_DB anyway
    if cmd.type ~= proxy.COM_INIT_DB and
       c.default_db and c.default_db ~= s.default_db then
        print("    server default db: " .. s.default_db)
        print("    client default db: " .. c.default_db)
        print("    syncronizing")
        proxy.queries:prepend(2, string.char(proxy.COM_INIT_DB) .. c.default_db)
    end

    -- send to master
    if is_debug then
        if proxy.connection.backend_ndx > 0 then
            local b = proxy.global.backends[proxy.connection.backend_ndx]
            print("  sending to backend : " .. b.dst.name);
            print("    is_slave         : " .. tostring(b.type == proxy.BACKEND_TYPE_RO));
            print("    server default db: " .. s.default_db)
            print("    server username  : " .. s.username)
        end
        print("    in_trans        : " .. tostring(is_in_transaction))
        print("    in_calc_found   : " .. tostring(is_in_select_calc_found_rows))
        print("    COM_QUERY       : " .. tostring(cmd.type == proxy.COM_QUERY))
    end

    return proxy.PROXY_SEND_QUERY
end

---
-- as long as we are in a transaction keep the connection
-- otherwise release it so another client can use it
function read_query_result( inj )
    local is_debug = proxy.global.config.rwsplit.is_debug
    local res      = assert(inj.resultset)
      local flags    = res.flags

    -- if inj.id ~= 1 then  -- this was causing some misleading errors
        -- ignore the result of the USE <default_db>
        -- the DB might not exist on the backend, what do do ?
        --
        if inj.id == 2 then
            -- the injected INIT_DB failed as the slave doesn't have this DB
            -- or doesn't have permissions to read from it
            if res.query_status == proxy.MYSQLD_PACKET_ERR then
                proxy.queries:reset()

                proxy.response = {
                    type = proxy.MYSQLD_PACKET_ERR,
                    errmsg = "can't change DB ".. proxy.connection.client.default_db ..
                        " to on slave " .. proxy.global.backends[proxy.connection.backend_ndx].dst.name
                }

                return proxy.PROXY_SEND_RESULT
            end
        end
    --    return proxy.PROXY_IGNORE_RESULT
    -- end

    is_in_transaction = flags.in_trans
    local have_last_insert_id = (res.insert_id and (res.insert_id > 0))

    if not is_in_transaction and
       not is_in_select_calc_found_rows and
       not have_last_insert_id then
        -- release the backend
        proxy.connection.backend_ndx = 0
    elseif is_debug then
        print("(read_query_result) staying on the same backend")
        print("    in_trans        : " .. tostring(is_in_transaction))
        print("    in_calc_found   : " .. tostring(is_in_select_calc_found_rows))
        print("    have_insert_id  : " .. tostring(have_last_insert_id))
    end
end

---
-- close the connections if we have enough connections in the pool
--
-- @return nil - close connection
--         IGNORE_RESULT - store connection in the pool
function disconnect_client()
    local is_debug = proxy.global.config.rwsplit.is_debug
    if is_debug then
        print("[disconnect_client] " .. proxy.connection.client.dst.name)
    end

    -- make sure we are disconnection from the connection
    -- to move the connection into the pool
    proxy.connection.backend_ndx = 0
end

 

    启动mysql-proxy代理

963 touch /var/log/mysql-proxy/mysql-proxy.log

965 /usr/local/mysql-proxy/sbin/mysql-proxy --proxy-read-only-backend-addresses=192.168.1.7:3306 --proxy-backend-addresses=192.168.1.9:3306 --proxy-lua-script=share/mysql-proxy/rw-splitting.lua > /var/log/mysql-proxy/mysql-proxy.log &

968 netstat –antp | grep 4040                              #看看有没有起来

969 ps –aux | grep mysql                                      #看看进程里面有没有 一些配置的路径里面都可以看到

985  /usr/local/mysql/bin/mysql -u root -p -P4040 –hlocalhost

                                                                        #登陆一下看看,

  

读写分离测试

    登陆3306端口,在从服务器testtb上增加几条记录

    客户端做多个连接到mysql-proxy的端口4040。

    insert一条记录,可以看到主服务器也有增加了记录。从服务器是同步过来的数据

    select * from testtb;在一个客户端连接的时候,显示的是主服务器的表内容

                                 而有多个客户端连接之后,就会显示从服务器的testtb表内容

 

 

 

    最后,他是同步所有database的,如果只需要备份指定的数据库,请一定要在my.cnf中加上

     replicate-do-db=dbname 

    不然,他找不到其他数据库,正常的数据库也不会更新了。

 

 

生成一个/usr/local/bin/mysql-proxy.sh

#! /bin/bash
/usr/local/mysql-proxy/sbin/mysql-proxy --proxy-read-only-backend-addresses=192.168.1.7:3306 --proxy-backend-addresses=192.168.1.9:3306 --proxy-lua-script=share/mysql-proxy/rw-splitting.lua > /var/log/mysql-proxy/mysql-proxy.log &

 

在/etc/rc.local 文档中加入一条

       /usr/local/bin/mysql-proxy.sh &

 

参考资料:

http://sery.blog.ccidnet.com/blog-htm-do-showone-uid-3587-itemid-472099-type-blog.html  

                                                                                      MySQL 主从复制读写分离实现

http://www.yayu.org/look.php?id=136                                   MySQL 主从同步关键句

http://butian.org/knowledge/develop/DB/20090520/1124.html    MySQL 主从服务器的一些技巧

http://www.3389hack.com/xueyuan/fuwuqi/MySQL/22601.html  MySQL配置文件my.cnf 例子的最详细翻译

05 noviembre

Oracle数据库的灾难恢复(转)


     随着办公自动化和电子商务的飞速发展,企业对信息系统的依赖性越来越高,数据库作为信息系统的核心担当着重要的角色。尤其在一些对数据可靠性要求很高的行业如银行、证券、电信等,如果发生意外停机或数据丢失其损失会十分惨重。为此数据库管理员应针对具体的业务要求制定详细的数据库备份与灾难恢复策略,并通过模拟故障对每种可能的情况进行严格测试,只有这样才能保证数据的高可用性。数据库的备份是一个长期的过程,而恢复只在发生事故后进行,恢复可以看作是备份的逆过程,恢复的程度的好坏很大程度上依赖于备份的情况。此外,数据库管理员在恢复时采取的步骤正确与否也直接影响最终的恢复结果,本文主要针对 Oracle数据库可能遇到的各种故障提供了相应的恢复的方法,仅供大家参考。

 
     要对Oracle数据库备份与恢复有清晰的认识,首先有必要对数据库的几种运行状态有充分的了解。Oracle数据库的运行状态主要分为3种,他们依次为:


l Nomount(非安装)Oracle只是读取ini文件中的配置信息,并初始化SGA区。
l Mount(安装)Oracle除了需要读取ini文件还要读取控制文件,并从中获取有关数据库的物理结构等信息。
l Open(打开)数据库要检查所有文件处于同一时间点,对错误进行恢复对未完成事务回滚,并最终可以允许用户访问。


     数据库的备份主要分为三种类型:冷备份;热备份;逻辑备份;
     数据库的备份不是本文讨论的重点,在这里只作一个概要的介绍,Oracle数据库备份主要有:

 
l Cold Backup(冷备份) 主要指在关闭数据库的状态下进行的数据库完全备份,备份内容包括所有数据文件、控制文件、联机日志文件、ini文件。
l Hot Backup(热备份) 指在数据库处于运行状态下,对数据文件和控制文件进行备份,要使用热备份必须将数据库运行在(Archive Log)归档方式下。
l Export(逻辑备份)这是最简单的备份方法,可按数据库中某个表、某个用户或整个数据库来导出,并且支持全部、累计、增量三种方式。使用这种方法,数据库必须处于打开状态,而且如果数据库不是在restrict状态将不能保证导出数据的一致性。


     数据库的恢复可分为两大类:完全恢复;不完全恢复;


完全恢复指将数据库恢复到发生故障的时间点,不丢失任何数据。

不完全恢复指将数据库恢复到发生故障前的某一个时间点,此时间点以后的所有改动将会丢失。如果没有特殊需求,我们建议应尽量使用完全恢复。


     Oracle 数据库的恢复过程分两步进行,首先将把存放在重做日志文件中的所有重做运用到数据文件,之后对重做中所有未提交的事务进行回滚,这样所有数据就恢复到发生灾难那一时刻了。数据库的恢复只能在发生故障之前的数据文件上运用重做,将其恢复到故障时刻,而不能将数据文件反向回滚到之前的某一个时刻。举个例子,我们有一个2001/1/1的数据库备份,当2001/5/1使我们发现数据库中数据发生混乱,希望将数据库恢复到2001/4/30时的状态,我们只能先恢复2001/1/1的数据库备份然后在其上运用重做记录使其前滚到2001/4/30时的状态,而不能将2001/5/1的数据库向后回滚到2001 /4/30。


     为了系统的设计数据库的恢复方案,我们先对可能遇到的错误进行分类,Oracle数据库错误主要分为5大类:


l SQL语句失败
l 线程失败
l 实例失败
l 用户操作失败
l 存储设备失败


     如果发生前三种失败,不需要我们人为干涉,Oracle系统会自动进行恢复。对于用户操作型的失败(如误删除数据),我们采取的补救措施主要有导入最新的逻辑备份或进行到某一时间点的不完全恢复。从Oracle 8之后的新版本中引入了基于表空间的时间点恢复(TSPITR),可以单独将包含错误操作的表空间恢复到指定时间,而不必对整个数据库进行不完全恢复。当错误操作发现比较及时而且数据量不大的情况下也可以考虑使用logminer生成反向SQL。

 
     针对存储设备的失败的情况比较复杂也是本文讨论的重点,存储设备的失败必然会使放置在其上的文件变为不可用,我们先将Oracle数据库所涉及到的文件进行一个划分,主要可分为:


l Oracle的系统文件,指Oracle的运行文件,各种应用程序
l 数据库控制文件
l 数据库联机重做日志文件
l 数据文件
l 归档日志文件


     避免第一种文件失败主要依赖系统管理员进行操作系统级的备份,当发生事故后只能依靠操作系统备份将其恢复。
     控制文件中记录着整个数据库的结构、每个数据文件的状况、系统SCN、检查点计数器等重要信息,在创建数据库时会让用户指定三个位置来存放控制文件,他们之间互为镜像,当其中任何一个发生故障,只需将其从ini文件中注释掉故障数据文件就可重新将数据启动。当所有控制全部失效时,可以在Nomount模式下执行create controlfile来重新生成控制文件,但必须提供redo log,data file,文件名和地址以及MAXLOGFILES,MAXDATAFILES,MAXINSTANCES等信息。如果失败之前运行过alter database backup controlfile to trace或alter database backup controlfile to ‘xxx’对控制文件作备份,恢复时可使用生成的脚本来重建或用备份文件覆盖,如果使用了旧的控制文件在恢复时要使用recover xxx using backup controlfile选项来进行恢复,并使用resetlogs选项来打开数据库。

 

 


     如果丢失的是联机日志文件,分两种情况处理1、丢失的是非活动的日志文件;2、丢失的是当前激活的日志文件。


     如果是第一种情况,而发生故障的日志文件组又具有多个成员,可以先将数据库shutdown,然后用操作系统命令将损坏日志文件组中好的日志成员文件把损坏的成员文件覆盖(在同一个日志成员组中的所有日志文件的各为镜象的),如果其物理位置不可用可将其拷贝到新的驱动器上,使用alter database rename file ‘xxxx’ to ‘xxxx’改变文件位置,之后启动数据库,如果正常马上进行一个冷备份。如果损坏的日志组中只有一个日志成员,先mount上数据库,将其转换为 noarchivelog模式,执行alter database add logfile member ‘xxx’ to group ‘x’给相关组增加一个成员,再执行alter database drop logfile member ‘bad_file’将损坏的日志文件删除,由于数据库的结构发生变动需要备份控制文件,之后将数据库改回archivelog模式,做一个冷备份。

 


     如果丢失的是当前激活的日志文件,数据库又没有镜像而且当前日志组中所有成员均变为不可用。

     首先将数据库shutdown abort,从最近的一次全备份中恢复所有的数据文件,将数据库启动到mount状态。如果原来的日志文件物理位置不可用,使用alter database rename file ‘xxx’ to ‘xxx’改变文件的存放位置。然后,使用recover database until cancel命令来恢复数据库,直到提示最后一个归档日志运用完之后,输入cancel。之后用alter database open resetlogs打开数据库,如果没有问题,立即进行一个冷备份。注意!所有包含在损坏的redo log中的信息将会丢失,也就是说数据库崩溃前已经提交的数据有可能会丢失。这对于某些要求很高的应用将会损失惨重,因此应尽量使每个日志组具有多个日志成员,并且放置在不同的驱动器上一防止发生介质故障。

 


     数据文件发生故障的情况也分为多种情况,

1、丢失包含在SYSTEM表空间的数据文件;
2、丢失没有回滚段的非SYSTEM数据文件;
3、丢失有回滚段的非SYSTEM数据文件。


     如果损坏的是系统表空间的数据文件。唯一的办法是从上一次备份中恢复受损的数据文件,(如果原位置不可用使用alter database rename命令改变新文件的位置),之后在数据库mount的状态下执行recover database/datafile对数据库进行回复,才能将数据库打开。注意:当SYSTEM表空间或其中的数据文件脱机,数据库是无法被打开的,因此必须在mount状态下将所有的恢复工作完成。


     当丢失的数据文件不属于系统表空间而且也不包含回滚段时,有可选择在数据库的两种状态下进行恢复---在数据库open的状态或者在数据库mount的状态。如果用户急于访问数据库中未受损部分的数据或对损坏的数据文件进行恢复需要很长时间,可以先使受损的数据文件脱机,将数据库打开给用户访问,再恢复受损的数据文件最后将其联机。步骤如下:先在数据库mount时,将相关的数据文件或表空间进行脱机alter database datafile xxx offline,然后将数据库open,这样就能使数据库未受损的部分先供用户访问,之后再进行recover datafile/tablespace,完成后用alter database datafile/tablespace ‘xxx’ online使其恢复联机就可被访问了。 当然用户也可以选择在数据库mount状态下,用recover database/datafile将所有的恢复工作做完,将所有数据文件一起打开供用户访问。


     如果丢失的数据文件是最后一种情况,即包含有回滚段的非系统表空间数据文件。也可以选择是在数据库先open的状态还是在mount状态下恢复。不过与上一种情况不同的是当包含回滚段的数据文件损坏时,如果使其先offline将数据库打开,那么所有数据库崩溃前未提交的事务涉及到的表将无法访问,也就是说在回滚段恢复前其中涉及的对象都不允许被访问。而且当所有包含回滚段的数据文件都在offline状态时,数据库无法进行任何DML操作,因此在数据库open状态恢复包含回滚段的数据文件时,可以先创建几个临时回滚段供数据使用create rollback segment temp1 tablespace system; alter rollback segment temp1 online;,当数据文件恢复后再将他们删除alter rollback segment temp1 offline; drop rollback segment temp1;。注意:当用这种方法使恢复的数据文件online之后,所有的原有回滚段将处于offline状态,必须手工使用alter rollback segment RBSxx online;使他们恢复联机状态,这样才能被数据库正常使用。如果在数据库mount状态下完成所有恢复,则不需要上述步骤。


     如果丢失数据文件后,用户发现没有故障前的数据文件的备份,而且自从丢失的数据文件最早建立之后一直没有使用过resetlogs选项打开过数据库。也就是说用户的控制文件是在损坏的数据文件建立前创建的,归档日志中包括对损坏数据文件的所有重做记录。用户就还有一种恢复方法,用户可以先将损坏的数据文件或表空间脱机 alter database datafile / tablespace xxx offline,之后执行alter database create datafile ‘new/xxx.dbf’ as ‘old/xxx.dbf’,数据库会根据保存在控制文件中的信息重建一个空的数据文件,之后再执行recover tablespace / datafile将所有重做记录运用到数据文件,使其完全恢复到当前状态,之后便可再将其恢复联机。

 


     如果丢失的是最后一种文件---归档文件或归档文件所处的物理位置不可用,首先shutdown数据库,立即作一个冷备份。然后修改ini文件中的归档日志文件目的路径,重新启动数据库。以后再发生灾难只需从最新的备份中将相关文件恢复,数据库作recover时就不需要备份之前丢失的归档文件了。在Oracle 8之后的新版本中提供了log_archive_duplex_dest和log_archive_dest_1...5等参数允许保留多份归档文件到不同位置,甚至到远端服务器从而保证归档文件的可靠性。

 


最后再说几点数据库恢复时的注意事项:


1.本文讨论所有情况的默认前提是数据库运行在归档(ARCHIVELOG)方式下,并只涉及到一般常见的情况和最基本的恢复方法。使用Oracle提供的恢复管理器RMAN也能完成上述任务,如果运行环境比较复杂建议使用RMAN来做备份和恢复。


2.一旦数据库发生灾难,最好在进行恢复之前做一次完全的冷备份,以便在进行恢复时产生差错还可以进行补救。很大一部分数据丢失是由于不正确的恢复操作所引起的。


3. 当数据库完成恢复之后,尤其是使用resetlogs选项打开数据库之后,要马上关闭数据库进行一次完全的冷备份。因为,为防止放弃的重做日志被下次恢复时再次运用,resetlogs选项会重新创建redo log文件并将其的计数清零,这将使之前做的所有备份将变为不可用(一般情况下)。


4.要特别注意当进行数据库完全恢复,从发生故障的时间点前的备份中恢复损坏文件时,一定不要使备份中的redo log文件覆盖了当前的redo log文件,否则就只能进行不完全恢复并且要丢失一部分数据了。


原作者:吴悦

03 noviembre

对不起。

本来想写影评的,明天再写吧

 

实在是有些受不了。

   一个28岁的人 还要寄人于篱下 被迫离开自己最亲的人,去受人照顾

   怎么也接受不了。我宁愿一个人漂泊流离 也要靠自己的能力来换取生活

    总是想不依靠别人的力量 总是想独立 而且更应该去帮助身边的人

     可是似乎很失败 28岁的自己 才刚能勉强让自己一个人生活起来 更别提拿出精力来为别人付出

 

    可是 即使如此 我也不愿意再无端受人照顾了  这是耻辱。

 

 

    谢谢你们。其实我也知道你们是好意。非常对不起。

02 noviembre

It’s love

We shall always save a place for ourselves, only for ourselves. And then begin to love.

Have no idea of what it is, who he is, how to love or how long it will be. Just wait for one love.

Maybe no one will come out, but this kind of waiting is the love itself. 

 

刚才在朋友的blog里看到的一句话,突然觉得很有feeling。也许这样子的爱情才是真正的爱情, 态度

   可是 等待 似乎又不是一个 最好的途径

谢国忠:有效市场是个神话

 

  最好的办法,是限制货币增长与名义GDP增长率间的偏差

  货币需求是有效的吗?这个问题的答案关系到怎样的货币政策称得上最好。随着金融机构杠杆率的提高,对货币需求不断增大,这个问题就相当于在问金融体系是否有效。我认为,答案是否定的。货币当局或中央银行有责任考虑到这一点。最好的办法,是限制货币增长与名义GDP增长率间的偏差。特别是,当经济基本面可能在短期受损时,持续的偏差仍应予以纠正。

神话破灭

  这是一个严肃的学术课题。我为什么要在这里和普通读者讨论这个问题?

  首先,这与每个人都息息相关。中国的散户投资者主导着资产市场。他们做出投资或投机决定时,大多认为“政府不会让资产价格下跌”。政府支出一旦有了限制,那这种期望还有几分可信?关于对货币扩张限制的讨论,能够帮助中国投资者评估投资决策的风险。

  其次,从世界范围来看,货币供应量增速都远远高于名义GDP的增速。也就是说,货币增长被用来支撑高杠杆率,这在金融部门尤其明显。当然,原因是央行通过降低利率来应对金融危机,有时甚至是强行增加银行的流动性,以期他们能够增加贷款,刺激经济。不过,这些钱却流入了资产市场,导致资产市场繁荣兴旺。活跃的资产价格稳定了全球经济。尽管大多数分析家认为,活跃的资产市场反映了他们对全球经济蓬勃发展的正确预期。但是,我认为这不是事实。像过去的十年一样,资产市场的繁荣支持了经济增长,而不是倒过来——由于强大的经济增长导致资产市场繁荣——因此,一切只不过是个泡沫。

  尽管全球经济正温和复苏,整体经济形势仍困难重重。经合组织国家的失业率都处于历史高位。资产市场的繁荣与真实的经济困难之间的对比,在近代可谓绝无仅有。尽管工人和企业都在努力挣扎,资产玩家却重新收获了账面利润。资产繁荣的背后,是央行的货币政策。我们不禁要问,政策实现了其帮助实体经济的目标了吗?还是说,政策帮助的只是那些投机者,希望他们能给实体经济留点残羹冷炙?

  金融机构从中央银行获取大量货币,但当前的金融危机暴露了货币运行存在的严重低效。对那些引发了危机的人提供如此多的钱,理由恰恰是因为他们引发了危机,这是什么道理?好比说,当房子着火了,你必须扑灭大火并找到罪魁祸首。可问题是,纵火者被要求去救火。那么,如何可以肯定,他们不会引起另一场大火?

  大部分人认为改革金融体制,而非限制货币供应,是解决这一问题的办法。一旦如此,未来对货币的需求将是有效的。到目前为止,金融危机中发现的问题仍没有得到纠正。过去十年,全球金融体系已变得相当庞大,将中央银行、立法者和政府困在其中。行将推进的改革,不会触碰到那些引发当前危机的主要因素。即使最好的改革能够实行,核心问题仍然难以解决:金融从业人员用别人的钱来赌博,当下对注的时候,他们将得到巨大的回报;下错注,他们也不会赔偿。这个激励问题表明,现行的全球金融体系,鼓励了风险冒进的偏好,有效市场并非如此。中央银行限制货币供给,是解决这一问题的惟一办法。过去十年的资产价格通胀,以及破灭后的灾难,都证明了这一论点是可信的。

  上世纪70年代的滞胀,促使经济学家研究为何货币刺激并没有增加需求,却直接转为通胀。这一研究促进了理性预期理论的发展,解释了大众对货币政策的反应。它的结论显而易见,即决策者可以反复愚弄普通人。多人因此获得诺贝尔奖。米尔顿·弗里德曼主张将以货币供给增长为目标,作为中央银行的指导原则。这一做法将使中央银行以货币增长为目标,“自动驾驶”,并让市场决定利率。

  理性预期理论被进一步用来解释投资者的行为,并引出了有效市场理论:在一定条件下,理智的投资者将带来有效的资产价格,这种价格能够正确反映未来预期。用学术术语来说,有效资产价格,就是包含了所有有关未来的有用信息的价格。这为拆除那些源自“大萧条”时期得到的教训而建立起来的监管架构,奠定了基础。

  上世纪70年代的滞胀,使得中央银行疲于应付短期通胀。依据有效市场理论,中央银行决定完全满足金融机构的货币需求,以支持他们的杠杆率。这种组合为过去十年间出现的巨大泡沫奠定了基础。由于全球化通胀保持在较低水平,华尔街可以无限量地从中央银行获得流动性,制造泡沫。

  在西方金融市场中,机构投资者占主导地位,散户或个人投资者则主导了东方金融市场。多数机构投资者是以季度市场指数为基准,同时,他们持有的现金量还有限制。这些制约因素使他们处于不利地位,很难跑赢大盘。这就是为什么大多数机构投资者都是指数追随者。额外的管理成本,使得大多数机构投资者表现比指数差,这并不会增加市场的效率。

改革的困境

  过去十年,金融市场最显著的发展是绝对表现基金(Absolute performance funds)和对冲基金的增加。但是,他们只是放大了市场的波动性,并未提高市场效率。由于对冲基金经理的薪酬是旱涝保收,因此,他们自然乐于见到长期波动。这是一个委婉的“正面算我赢,反面算你输”的掷硬币游戏。对冲基金业让其管理人员,而不是投资人收益颇丰。

  无论怎样尝试去改善机构投资者的激励结构,“管理别人的钱”带来的激励扭曲难以改变。制度化一度被誉为提高市场效率的一大进步,已被证明使无效状况更甚。面临着变幻莫测市场的发展中国家,一直寻求以制度化来稳定市场。他们应该三思。制度化或能减少短期波动,但会变成大崩溃。

  散户或者个人投资者经常错误地将短时期波动当做趋势。“羊群行为”产生了自我实现的趋势,而这大都只是暂时的。但是,这种羊群行为有时也会持续很长一段时间,引发巨大的泡沫。这种泡沫会导致资源配置严重失当。

  为了尽量减少今后出现金融危机的可能,人们可以改革金融体系,以减少出现危机的倾向;或者在制定货币政策时,同时考虑资产价格以及消费物价。一年前,危机爆发时,世界各地的决策者发誓要改革金融体系,消除腐败和过度杠杆化。在政府花费数万亿美元救助金融机构之后,改革的动力已经减弱。美国国会改革法案已经淡化,因此,他们并无力阻止另一次重大危机。

  资本充足率要求以及透明度,是有效的金融改革的关键。例如,场外交易的衍生品的名义价值达到数万亿美元。它们在一个不透明的环境中蓬勃发展。做市商可以通过欺骗买家和监管机构获取高额利润:向他们收取超高费用,但他们并未为提供这种高风险产品投入大量资金。如果市场是透明的,而且资本要求合理,那么这项业务也不会开展得这样大。在理论上,衍生工具能够帮助买家降低风险;而在实践中,由于复杂的结构可以隐藏杠杆率,衍生工具会带来更大的风险。除非能够看到旨在针对衍生产品市场的问题的改革,否则,所谓的金融改革很难称之为“有效”。

谁又将声名扫地?

  天下没有不散的宴席,现在也是如此。有两个情形预示着另一场危机的爆发。首先,每个交易者借入美元购买东西。华尔街多数交易商是美国人、英国人,还有澳大利亚人。他们都很了解美国。美联储维持着零利率政策,美国政府也支持弱势美元,以刺激美国的出口。除非是傻瓜,人人都能看出,美国政府正在“ 帮助”你借美元去投机。但是,这些交易员对其他国家并不熟悉,特别是新兴经济体。他们一年也就去那里一两次,即使这一两次,还是和美国的投行一起去的:这些投行可是很想要卖东西给他们的。他们愿意相信任何事,除了美元会升值。当然,华尔街的银行也会这么告诉他们。由于这些人为数众多,他们的行动在短期内会自我实现。举例来说,澳元从底部算起,已经升值了35%。现在,这些家伙坐在巨大的账面利润上,感觉自己是如此聪明。当然,华尔街的交易商们在付给投资人之前,已经先喂饱了自己。

  一旦交易规模过大,就像现在这样,只需要一个小冲击就能引发飓风,而你永远不知道这个冲击会是什么。一旦有事发生,所有这些交易商就会迅速退出,这可能会导致另一场危机。

  石油价格的飙升,可能是宴会中另一个不速之客。它可能引发通胀预期回升,并引发债券市场大崩溃。由此产生的极高债券收益率可能迫使央行提高利率,以减少对通货膨胀的担心。另一轮资产价格大下滑,将再度激起对于全球主要金融机构资产负债表的恐惧,再次造成混乱。

  石油是制造泡沫的完美材料:石油供应不能及时回应油价上涨,它需要很长的时间来扩大生产能力,而且由于生活方式和生产方式的粘性,石油需求也不能迅速减少。无论是需求还是供应方面,石油的价格敏感度都较低,很适合用来制造泡沫。当流动性既便宜又易得的时候,石油投机者随处可见。

  石油投机商不再只是那些偷偷摸摸的对冲基金。普通百姓也可以通过购买交易所交易基金拥有石油或其他任何东西。而且,没有道理不去这么做。中央银行已明确表示,将保持尽可能充足的货币供给,使纸币贬值,帮助债务人。如果你赌得很大,当你下错注的时候,政府会帮你摆脱困境,并且降低利率以使你能够下更大的赌注。所以,在这个世界上,最好做个投机者,当权者永远与你同在。

  对于那些想成为投机分子的人,我有一言相劝:一旦债券市场大幅下跌,尽快逃命去吧。石油泡沫来得容易,去得也快,因为它会刺破其他泡沫。一旦这些泡沫破灭,供石油泡沫生存的氧气也就消失了。

  2010年出现二次探底的情况已经很明显。目前的经济复苏得益于企业补充库存以及财政刺激。明年,西方消费者在囊中羞涩之后迅速恢复的几率微乎其微。高失业率将使他们的收入难以支撑其消费。他们不太可能再去借钱消费。

  许多分析家都认为,只要失业率依旧居高不下,那么,就应当不断采取刺激政策。正如我刚才所说,供求不匹配——而不是需求疲软本身——是高失业率的主要原因。更多的刺激只会引发通货膨胀和金融不稳定。

  上世纪70年代的滞胀,让一批认为可以“用一点通胀换得经济大幅增长”的银行家声名狼藉。当前的这场危机,将会使那些忽略资产价格通胀,甚至创造通胀去刺激经济增长的这一代中央银行家们声名扫地。玩火者,必自焚。■