不应该是家,窝更适合一点

发布新日志

  • nginx集群[配置参考贴]

    2012-02-06 10:27:34

        今天搭建了个集群,基于nginx服务,下面吧参考帖子转载,以备后后用:
    nginx集群

    http://hi.baidu.com/dianhui/blog/item/2f5e6ecb26f5e619bf09e62a.html

    Nginx 简介

    Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,它已经在该站点运行超过两年半了。 Igor 将源代码以类 BSD 许可证的形式发布。尽管还是测试版,但是,Nginx 已经因为它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名了。

    根据最新一期(08 年 6 月份)的 NetCraft 调查报告显示,已经有超过两百万的主机使用了 Nginx,这个数字超过了另外一个轻量级的 HTTP 服务器 lighttpd, 排名第四,并且发展迅速。下面是这份报告的前几名的报表:

    产品网站数
    Apache84,309,103
    IIS60,987,087
    Google GFE10,465,178
    Unknown4,903,174
    nginx2,125,160
    Oversee1,953,848
    lighttpd1,532,952

    关于这期调查报告的更详细信息请看下面链接:

    http://survey.netcraft.com/Reports/200806/

    下图是最近几个月使用 Nginx 和 lighttpd 的网站数比较


    图 1. 最近几个月使用 Nginx 和 lighttpd 的网站数比较
    图 1. 最近几个月使用 Nginx 和 lighttpd 的网站数比较

    使用 Nginx 前必须了解的事项

    1. 目前官方 Nginx 并不支持 Windows,您只能在包括 Linux、UNIX、BSD 系统下安装和使用;
    2. Nginx 本身只是一个 HTTP 和反向代理服务器,它无法像 Apache 一样通过安装各种模块来支持不同的页面脚本,例如 PHP、CGI 等;
    3. Nginx 支持简单的负载均衡和容错;
    4. 支持作为基本 HTTP 服务器的功能,例如日志、压缩、Byte ranges、Chunked responses、SSL、虚拟主机等等,应有尽有。

    在 Linux 下安装 Nginx

    为了确保能在 Nginx 中使用正则表达式进行更灵活的配置,安装之前需要确定系统是否安装有 PCRE(Perl Compatible Regular Expressions)包。您可以到 ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ 下载最新的 PCRE 源码包,使用下面命令下载编译和安装 PCRE 包:

    # wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.7.tar.gz
    # tar zxvf pcre-7.7.tar.gz
    # cd pcre-7.7
    # ./configure
    # make
    # make install

    接下来安装 Nginx,Nginx 一般有两个版本,分别是稳定版和开发版,您可以根据您的目的来选择这两个版本的其中一个,下面是把 Nginx 安装到 /opt/nginx 目录下的详细步骤:

    # wget http://sysoev.ru/nginx/nginx-0.6.31.tar.gz
    # tar zxvf nginx-0.6.31.tar.gz
    # cd nginx-0.6.31
    # ./configure --with-http_stub_status_module –prefix=/opt/nginx
    # make
    # make install

    其中参数 --with-http_stub_status_module 是为了启用 nginx 的 NginxStatus 功能,用来监控 Nginx 的当前状态。

    安装成功后 /opt/nginx 目录下有四个子目录分别是:conf、html、logs、sbin 。其中 Nginx 的配置文件存放于 conf/nginx.conf,Nginx 只有一个程序文件位于 sbin 目录下的 nginx 文件。确保系统的 80 端口没被其他程序占用,运行 sbin/nginx 命令来启动 Nginx,打开浏览器访问此机器的 IP,如果浏览器出现 Welcome to nginx! 则表示 Nginx 已经安装并运行成功。

    常用的 Nginx 参数和控制

    程序运行参数

    Nginx 安装后只有一个程序文件,本身并不提供各种管理程序,它是使用参数和系统信号机制对 Nginx 进程本身进行控制的。 Nginx 的参数包括有如下几个:

    -c <path_to_config>:使用指定的配置文件而不是 conf 目录下的 nginx.conf 。

    -t:测试配置文件是否正确,在运行时需要重新加载配置的时候,此命令非常重要,用来检测所修改的配置文件是否有语法错误。

    -v:显示 nginx 版本号。

    -V:显示 nginx 的版本号以及编译环境信息以及编译时的参数。

    例如我们要测试某个配置文件是否书写正确,我们可以使用以下命令

    sbin/nginx – t – c conf/nginx2.conf

    通过信号对 Nginx 进行控制

    Nginx 支持下表中的信号:

    信号名作用描述
    TERM, INT快速关闭程序,中止当前正在处理的请求
    QUIT处理完当前请求后,关闭程序
    HUP重新加载配置,并开启新的工作进程,关闭就的进程,此操作不会中断请求
    USR1重新打开日志文件,用于切换日志,例如每天生成一个新的日志文件
    USR2平滑升级可执行程序
    WINCH从容关闭工作进程

    有两种方式来通过这些信号去控制 Nginx,第一是通过 logs 目录下的 nginx.pid 查看当前运行的 Nginx 的进程 ID,通过 kill – XXX <pid> 来控制 Nginx,其中 XXX 就是上表中列出的信号名。如果您的系统中只有一个 Nginx 进程,那您也可以通过 killall 命令来完成,例如运行 killall – s HUP nginx 来让 Nginx 重新加载配置。

    配置 Nginx

    先来看一个实际的配置文件:

    user  nobody;# 工作进程的属主
     worker_processes  4;# 工作进程数,一般与 CPU 核数等同
    
     #error_log  logs/error.log; 
     #error_log  logs/error.log  notice; 
     #error_log  logs/error.log  info; 
    
     #pid        logs/nginx.pid; 
    
     events { 
        use epoll;#Linux 下性能最好的 event 模式
        worker_connections  2048;# 每个工作进程允许最大的同时连接数
     } 
    
     http { 
        include       mime.types; 
        default_type  application/octet-stream; 
    
        #log_format  main  '$remote_addr - $remote_user [$time_local] $request ' 
        #                  '"$status" $body_bytes_sent "$http_referer" ' 
        #                  '"$http_user_agent" "$http_x_forwarded_for"'; 
    
        #access_log  off; 
        access_log  logs/access.log;# 日志文件名
    
        sendfile        on; 
        #tcp_nopush     on; 
        tcp_nodelay     on; 
    
        keepalive_timeout  65; 
    
        include   gzip.conf; 
        
        # 集群中的所有后台服务器的配置信息
        upstream tomcats { 
      server 192.168.0.11:8080 weight=10; 
      server 192.168.0.11:8081 weight=10; 
      server 192.168.0.12:8080 weight=10; 
      server 192.168.0.12:8081 weight=10; 
      server 192.168.0.13:8080 weight=10; 
      server 192.168.0.13:8081 weight=10; 
        } 
    
        server { 
            listen       80;#HTTP 的端口
            server_name  localhost; 
    
            charset utf-8; 
    
            #access_log  logs/host.access.log  main; 
    
      location ~ ^/NginxStatus/ { 
         stub_status on; #Nginx 状态监控配置
         access_log off; 
      } 
    
      location ~ ^/(WEB-INF)/ { 
         deny all; 
      } 
     
    
      location ~ \.(htm|html|asp|php|gif|jpg|jpeg|png|bmp|ico|rar|css|js|
      zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma)$ { 
                 root /opt/webapp; 
         expires 24h; 
            } 
    
            location / { 
         proxy_pass http://tomcats;# 反向代理
         include proxy.conf; 
            } 
    
            error_page 404 /html/404.html; 
    
            # redirect server error pages to the static page /50x.html 
            # 
      error_page 502 503 /html/502.html; 
            error_page 500 504 /50x.html; 
            location = /50x.html { 
                root   html; 
            } 
        } 
     }

    Nginx 监控

    上面是一个实际网站的配置实例,其中灰色文字为配置说明。上述配置中,首先我们定义了一个 location ~ ^/NginxStatus/,这样通过 http://localhost/NginxStatus/ 就可以监控到 Nginx 的运行信息,显示的内容如下:

    Active connections: 70 
    server accepts handled requests
     14553819 14553819 19239266 
    Reading: 0 Writing: 3 Waiting: 67

    NginxStatus 显示的内容意思如下:

    • active connections – 当前 Nginx 正处理的活动连接数。
    • server accepts handled requests -- 总共处理了 14553819 个连接 , 成功创建 14553819 次握手 ( 证明中间没有失败的 ), 总共处理了 19239266 个请求 ( 平均每次握手处理了 1.3 个数据请求 )。
    • reading -- nginx 读取到客户端的 Header 信息数。
    • writing -- nginx 返回给客户端的 Header 信息数。
    • waiting -- 开启 keep-alive 的情况下,这个值等于 active - (reading + writing),意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接。

    静态文件处理

    通过正则表达式,我们可让 Nginx 识别出各种静态文件,例如 images 路径下的所有请求可以写为:

    location ~ ^/images/ {
        root /opt/webapp/images;
    }

    而下面的配置则定义了几种文件类型的请求处理方式。

    location ~ \.(htm|html|gif|jpg|jpeg|png|bmp|ico|css|js|txt)$ {
        root /opt/webapp;
        expires 24h;
    }

    对于例如图片、静态 HTML 文件、js 脚本文件和 css 样式文件等,我们希望 Nginx 直接处理并返回给浏览器,这样可以大大的加快网页浏览时的速度。因此对于这类文件我们需要通过 root 指令来指定文件的存放路径,同时因为这类文件并不常修改,通过 expires 指令来控制其在浏览器的缓存,以减少不必要的请求。 expires 指令可以控制 HTTP 应答中的“ Expires ”和“ Cache-Control ”的头标(起到控制页面缓存的作用)。您可以使用例如以下的格式来书写 Expires:

    expires 1 January, 1970, 00:00:01 GMT;
    expires 60s;
    expires 30m;
    expires 24h;
    expires 1d;
    expires max;
    expires off;

    动态页面请求处理

    Nginx 本身并不支持现在流行的 JSP、ASP、PHP、PERL 等动态页面,但是它可以通过反向代理将请求发送到后端的服务器,例如 Tomcat、Apache、IIS 等来完成动态页面的请求处理。前面的配置示例中,我们首先定义了由 Nginx 直接处理的一些静态文件请求后,其他所有的请求通过 proxy_pass 指令传送给后端的服务器(在上述例子中是 Tomcat)。最简单的 proxy_pass 用法如下:

    location / {
        proxy_pass        http://localhost:8080;
        proxy_set_header  X-Real-IP  $remote_addr;
    }

    这里我们没有使用到集群,而是将请求直接送到运行在 8080 端口的 Tomcat 服务上来完成类似 JSP 和 Servlet 的请求处理。

    当页面的访问量非常大的时候,往往需要多个应用服务器来共同承担动态页面的执行操作,这时我们就需要使用集群的架构。 Nginx 通过 upstream 指令来定义一个服务器的集群,最前面那个完整的例子中我们定义了一个名为 tomcats 的集群,这个集群中包括了三台服务器共 6 个 Tomcat 服务。而 proxy_pass 指令的写法变成了:

    location / {
        proxy_pass        http://tomcats;
        proxy_set_header  X-Real-IP  $remote_addr;
    }

    在 Nginx 的集群配置中,Nginx 使用最简单的平均分配规则给集群中的每个节点分配请求。一旦某个节点失效时,或者重新起效时,Nginx 都会非常及时的处理状态的变化,以保证不会影响到用户的访问。

    总结

    尽管整个程序包只有五百多 K,但麻雀虽小、五脏俱全。 Nginx 官方提供的各种功能模块应有尽有,结合这些模块可以完整各种各样的配置要求,例如:压缩、防盗链、集群、FastCGI、流媒体服务器、Memcached 支持、URL 重写等等,更关键的是 Nginx 拥有 Apache 和其他 HTTP 服务器无法比拟的高性能。您甚至可以在不改变原有网站的架构上,通过在前端引入 Nginx 来提升网站的访问速度。

    本文只是简单介绍了 Nginx 的安装以及常见的基本的配置和使用,更多关于 Nginx 的信息请阅读文章后面的参考资源。在这里要非常感谢我的朋友——陈磊(chanix@msn.com),他一直在做 Nginx 的中文 WIKI(http://wiki.codemongers.com/NginxChs),同时也是他介绍给我这么好的一款软件。

    如果您的网站是运行在 Linux 下,如果您并没有使用一些非常复杂的而且确定 Nginx 无法完成的功能,那您应该试试 Nginx 。

  • 运用系统思考,走上改善之路

    2011-08-29 10:06:23

    为什么敏捷实施,或是任何一点的过程改进都步履维艰?即使是十几人的团队中,也会出现“写自动化测试”──“不写自动化测试”──“写自动化测试”──“不写自动化测试”这种循环往复的过程?

    除了人们常常总结的“敏捷实施模式”,或是“敏捷失败经验分享”这样的具体话题之外,是不是还有一些存在于思维模式中的更加根本性的因素,阻碍了我们对系统全景的认知,从而导致改革先行者的黯然退场?

    本文将通过两个案例来讲述如何使用系统思考,从全局掌握我们所处的复杂环境,做到既见树木,又见森林。

    案例1:舍本逐末

    有一个测试团队的负责人找到我们说,我觉得现在的自动化测试问题很大,执行时间长,也不稳定,有的时候是测试写错了,也要花很长时间修。我打算组织一批人,重新设计一下测试代码的架构,把常用的底层功能封装成设计良好的API

    我的同事说,好啊,你们打算怎么做呢?

    他说,我也还没想好,所以想过来商量一下。我希望这个东西做成以后,能够让不会写程序的QA们都能用它来写自动化测试脚本了,他们现在就是这样,又要做测试,又要学着写程序,我觉得太辛苦了。能让他们不用学编程就能写测试脚本就好了。

    ……要不我们先看一下现在的代码,了解一下都有什么问题,然后再讨论?我们内心有点小小的纠结。

    好吧,我来给你们开通访问权限,找人给你们讲代码。他很爽快的答应了。

    打开代码之后我们就忍不住风中凌乱了,满屏都是重复的代码片段,让人一阵阵的眩晕。两天之内,我们仅仅用了提取方法这一个重构手法,就删掉了 1200行代码。期间还发现,不知道谁在调试的时候把一处代码从等待3秒改成了等待10秒忘了改回来,于是其他人再复制粘贴的时候,就全变成了等待10 秒。

    于是事情就明朗化了。

    依赖于一小拨人重新设计代码结构,提炼API,确实会在短期内使问题得到缓解。但使用这些API的人依然是那些不懂得如何编程的QA,他们依然会使 用复制粘贴来解决问题。再好的架构、再优秀的设计,最终还是会淹没在大量重复的代码中,犹如黄金深埋浮沙之下。而且如果问题表象得到暂时解决,人们就会缺 少动力从根本上提升QA的编码能力,随着设计一点一点腐化,就又需要精兵强将充当救火队员。如此不断反复,直到有一天又回到重新设计乃至重写的老路上来。

    这是个典型的舍本逐末的模型。

    分析

    在上面的场景中,对于测试代码质量低劣这个问题有两种解决方案,一种是精兵强将解决,另一种是测试人员自己解决,每一种方案都会削弱代码质量不断下滑的趋势,从而让系统处于一种平衡状态。如下图所示:

    图中的“S”表示同向连接,即箭头起点所示变量的增长会导致另一方变量的增长;“O”表示反向连接,即箭头起点变量的增长会导致另一方的减少。天平表示调节环路,该回路会趋于平衡稳定。

    但是,由精兵强将出马可以让问题症状迅速得到缓解,提升测试人员的编码能力则需要长期的辅导训练,不可能一蹴而就,所以图中下方的调节环路实际上是有时间滞延存在的:

    与此同时,由精兵强将解决问题会减少测试人员锻炼的机会,从而削弱测试人员的编码能力,进一步使人们不倾向于让测试人员自己解决问题,又转过头来增强了对于精兵强将的依赖。所以还要在图中增加另外一条回路:

    滚雪球表示增强环路,该回路会使得回路上的所有节点持续增强

    这幅图的全貌便构成了舍本逐末的模型。彼得·圣吉在《第五项修炼》中对此解释到:

    上面的环路代表快速见效的症状解,它迅速解决问题症状,但只是暂时的。下面的环路包含了时间延滞,它代表较根本的解决方案,但其效果要较长的时间才 会显现出来。然而它可能是惟一持久见效的方式。有时候舍本逐末的结构中,会多出一个由症状解所带来的副作用所形成的增强环路。发生这样的情形时,副作用常 使问题更难以解决。

    人们或者是因为没有找到问题的根源,或者是因为时间延滞的存在,倾向于采取一种简单易行又可以立竿见影的方案,这便是症状解了。但是症状消除以后, 问题就不再令人重视,从而丧失了从根本上解决问题的能力。而问题依然深藏,等到它有一天再度浮上水面时,症状就会更重,更难解决。

    这是一条不断衰减的增强环路。在回路上每走一步,情况就会更恶劣一分。

    面对舍本逐末,通常的解决方案有两条:

    必须要认识到症状解只是短期止痛的手段,切不能形成依赖;

    在症状得到缓解之后,要继续加强对根本解的重视。

    但见招拆招总是相对容易一些的,更关键的地方是,如何才能识别出舍本逐末这样的模型?当我们采取某些理所当然的对策却得到了不合理的结果,有什么办法可以帮助我们分析问题根源,找到解决方案?

    要认清问题的本质,就必须要认识到,我们所处的是各个因素之间紧密连接相互影响的复杂系统,当前采取的行动,会从多方面对这个系统产生影响,而这些影响之间或推波助澜,或相互牵制,从而导致相同的行动在长期和短期来看具有不同的结果。

    比如,当代码中发现bug的时候,很多人的常见反应都是调试──定位──解决这样的思路。从眼前来看,发现bug立即修复是可以最快见效的手 段,但却丧失了将测试进行完善的机会,相当于是安全网上明明出现了漏洞却听之任之。等到以后因为需求变更等原因影响了这块代码的时候,就再也无法通过执行 测试来得到快速而完整的反馈了。

    丹尼斯·舍伍德在《系统思考》中说,

    如果你希望了解一个系统,并进而能够预测它的行为,那么,就非常有必要将系统作为一个整体来研究。将系统各部分割裂开来研究,很可能破坏系统内部的连接,从而破坏系统本身。

    如果你希望影响或控制系统的行为,你必须将系统作为一个整体来采取行动。在某些地方采取行动并希望其他地方不受影响的想法注定要失败──这也就是连接的意义所在。

    为了帮助人们更好的从整体上研究复杂系统的行为,丹尼斯在书中提供了一套完整的工具──系统循环图。

    系统循环图中共有三个基本要素:

    增强环路。在增强环路中共有偶数个O型连接,增强环路上的各个节点会呈现指数增长或指数衰退。

    调节环路。在调节环路上共有奇数个O型连接,调节环路上的各个节点会趋于平衡状态。它会消化掉外界的影响力,使改变难以发生。

    时间滞延。时间滞延是一个不容忽视的影响力,由于滞延的存在,人们常常会发现某个行为在短期内没有产生预想的结果,从而加大投入力度,当行为的后果出现在眼前时,却已经矫枉过正。

    下面我将通过另一个真实的案例来讲述系统循环图的应用。

    案例2:历史不断重演

    一天中午,我忽然听到有人说,我们又开始讨论要不要放弃自动化功能测试了。

    咦?你为什么要说又呢?我忍不住问道。

    因为我们半年前已经讨论过一次,当时得出的结论是不再写自动化测试了。后来不记得是什么原因了,又用Cucumber来写,最近发现每次上线还是要做大量的手工测试,这些自动化测试又要浪费很多时间来修,所以我们准备讨论一下到底还要不要继续写。

    当天下午,我参加了这个团队的讨论,终于弄清楚了事情的来龙去脉:

    大概是一年前,为了减少手工测试的成本,团队决定一步步把上线时需要手工回归的测试用例转换成自动化,同时决定每个story做完以后都要加入自动化测试。研究了几天webdriver以后,就开始了自动化测试的尝试。

    但麻烦很快就出现了。第一,开发人员用Java代码写的测试,QA不好理解,也不是很清楚哪些场景被测试覆盖到,哪些没有,所以无法信赖测试结果; 第二,测试跟开发共用一套数据库,数据总是受到污染,因此造成测试失败,浪费大量定位和修复的时间。而数据库是由国外的客户控制的,催促了很长时间也没能 给测试分离出一套专用的数据库来。

    测试红啊红,修啊修,后来一算时间,在自动化测试上投入了120多人天,却依然得不到一套稳定执行的测试用例,不但没办法保证交付质量,还让每个人心力交瘁。于是毅然决然的停掉了。

    过了两三个月,客户终于准备好了一套专门用来跑功能测试的数据库,开发团队也对行为驱动开发有了一定的认识。于是又开始写自动化测试,这次用了CucumberQA写场景,Dev写实现。

    写了大概有100多个场景的测试,又有人开始质疑这一切:第一,整套系统实在是太庞大复杂了,写到现在为止,连1/4都没覆盖到,所以上线还是手工 回归。我们到底要花多大的精力才能把所有的场景都自动化起来,这些投入是不是值得?第二,测试环境还是不稳定,比如本地数据跟CI用的数据不一致,比如 Tomcat里面部署的应用常常启动不起来,等等。每个问题都要消耗大量的人力。这些浪费能不能平衡自动化测试到最后能够带来的收益?

    但团队中还有其他人对自动化测试持有乐观态度,认为问题总是可以解决的,只要坚持不懈就能够看到长期的回报。于是就有了这次讨论。

    分析

    绘制系统循环图的第二条法则是:从有趣的地方开始。在这个案例的场景下,开发团队最关心的是该不该写自动化测试,它对交付能力会带来什么影响,于是我们选择自动化测试的数量作为起始点。

    接下来是第三条法则──“询问它将驱动什么,以及它的驱动力是什么’”

    我们首先可以想到的是,自动化测试的数量增加,会缩短发现Bug的周期,但是这个作用是需要测试数量积累到一定程度才会发挥出来的。它同时还会增加测试的开发和维护成本,增加测试执行时间,缩短手工测试周期。见下图:

    手工测试周期的缩短会带来交付周期的缩短,提升产品收益,从而使人们更倾向于编写自动化测试。于是在图中就出现了一个增强环路:

    而测试的开发维护成本增加,会导致开发进度放缓,从而削弱收益,于是在图的下方出现了调节环路,这条调节环路的存在,会阻碍人们在自动化测试上的投入。

    与此类推,我们同样在图中可以发现其他的增强环路与调节环路:

    而在这四条回路之外,还会有其他因素对这个结构造成影响:

    画出系统循环图以后,就可以结合团队的状况进行整体分析:

    首先回到质疑的声音上来,有人说,整套系统实在是太庞大复杂了,写到现在为止,连1/4都没覆盖到,所以上线还是手工回归,这里反映出的正是从 自动化测试数量手工测试时间这条线上的时间滞延的效果。在前文中提到过,时间滞延在反馈环路中会造成矫枉过正,这里是它的第二个作用──给人带 来挫败感。它会导致某个行为在短期内看不到任何效果,当滞延的时间过长时,会令人失望乃至放弃努力。消除时间滞延可以对系统起到卓有成效的改善。在这个案 例中,我们可以通过推动手动测试用例向自动化测试的转化来缩短滞延。

    然而,当时间滞延的作用被削弱以后,还有另外的问题等着去解决。下面再来看看这支团队从写自动化测试不写自动化测试的变化过程中发生了什么。

    在刚开始写自动化测试的时候,团队主要的感受是QA少了手工测试的时间,质量多了保障,所以增强环路发挥了作用,每个story完成以后,开发人员 都会为所对应的场景写几个测试。但当测试数量增加到一定程度,调节环路的反馈力量开始占据主导地位──测试时间变长、维护成本增加。而且测试数量越多,带 来的问题就越大,最后便有了第一次的选择:放弃自动化测试。

    这正是《第五项修炼》中描述的成长上限模型:

    增强环路导致成长。成长总会碰到各种限制与瓶颈,然而大多数的成长之所以停止,却不是因为达到了真正的极限。这是由于,增强环路固然产生快速的成长。却常在不知不觉中,触动一个抑制成长的调节环路开始运作,而使成长减缓、停顿,甚或下滑。

    ……

    当改善的速度慢下来,你会更加努力地去改善。但渐渐的,你愈是用力推动你所熟悉的做法,调节环路的反作用愈是强烈,使你的努力愈是徒劳无功。到了最后,最常有的反应是放弃他们原来的目标。

    所以,当我们观察到有增强环路与调节环路遭遇的情况出现时,更为有效的解决方案应该到调节环路上寻找。在上面的系统循环图中,测试环境稳定性、 开发人员技能可以限制测试的开发维护成本硬件数量与质量可以限制测试运行时间,我们可以通过控制这些在调节环路之外起作用的因素,削弱 调节环路的影响,让增强环路的成长继续开始。

    小结

    结构决定行为。增强环路总是产生指数级的上升或衰减;调节环路总是倾向于使整个环路趋于平衡状态;各种环路的相互影响,就会产生舍本逐末成长上限或是饮鸩止渴等基本模型。

    然而不幸的是,参与系统的各个部分,常常见树不见林,只能针对眼中见到的局部信息,做出局部的最佳决策。但每个人的局部最佳决策,并不能构成整个系统的全局最佳决策。因为系统中有反馈、有延迟,因和果在时空上并不紧紧相连,显而易见的解往往无效。

    在纷乱芜杂的因果关系中,使用系统思考可以帮助我们理清问题的脉络,认识系统全貌,从而进一步寻找有效的杠杆解──比如案例2中的限制调节环路;而不是固囿于局部优化,把环状的因果关系割裂成线段,看不到当前采取的行动会在未来反作用于自身,因此导致各种系统问题的出现。

    系统循环图是一个很强大的工具,但一个人的视野总是有限的,用头脑风暴的方式往往可以得到更全面的认知。案例2的图形就是小组讨论的结果。只是这种方式需要引导者时时注意控制讨论的边界,不要偏离重心。

    本文通过两个实际案例对系统思考的基本概念进行了描述,并讲解了如何使用系统循环图对一个复杂系统进行分析,对这方面知识感兴趣的读者可以通过《系统思考》和《第五项修炼》这两本书进行深入研究,学会用这套工具来指导持续改进的步伐。


  • Web服务器和应用程序服务器有什么区别

    2009-06-16 16:06:16

     

       通俗的讲,Web服务器传送(serves)页面使浏览器可以浏览,然而应用程序服务器提供的是客户端应用程序可以调用(call)的方法(methods)。确切一点,你可以说:Web服务器专门处理HTTP请求(request),但是应用程序服务器是通过很多协议来为应用程序提供(serves)商业逻辑(business logic)。

    下面让我们来细细道来:

    Web服务器(Web Server)
    Web服务器可以解析(handles)HTTP协议。当Web服务器接收到一个HTTP请求(request),会返回一个HTTP响应(response),例如送回一个HTML页面。为了处理一个请求(request),Web服务器可以响应(response)一个静态页面或图片,进行页面跳转(redirect),或者把动态响应(dynamic response)的产生委托(delegate)给一些其它的程序例如CGI脚本,JSP(JavaServer Pages)脚本,servlets,ASP(Active Server Pages)脚本,服务器端(server-side)JavaScript,或者一些其它的服务器端(server-side)技术。无论它们(译者注:脚本)的目的如何,这些服务器端(server-side)的程序通常产生一个HTML的响应(response)来让浏览器可以浏览。

    要知道,Web服务器的代理模型(delegation model)非常简单。当一个请求(request)被送到Web服务器里来时,它只单纯的把请求(request)传递给可以很好的处理请求(request)的程序(译者注:服务器端脚本)。Web服务器仅仅提供一个可以执行服务器端(server-side)程序和返回(程序所产生的)响应(response)的环境,而不会超出职能范围。服务器端(server-side)程序通常具有事务处理(transaction processing),数据库连接(database connectivity)和消息(messaging)等功能。

    虽然Web服务器不支持事务处理或数据库连接池,但它可以配置(employ)各种策略(strategies)来实现容错性(fault tolerance)和可扩展性(scalability),例如负载平衡(load balancing),缓冲(caching)。集群特征(clustering—features)经常被误认为仅仅是应用程序服务器专有的特征。

    应用程序服务器(The Application Server)
    根据我们的定义,作为应用程序服务器,它通过各种协议,可以包括HTTP,把商业逻辑暴露给(expose)客户端应用程序。Web服务器主要是处理向浏览器发送HTML以供浏览,而应用程序服务器提供访问商业逻辑的途径以供客户端应用程序使用。应用程序使用此商业逻辑就象你调用对象的一个方法(或过程语言中的一个函数)一样。

    应用程序服务器的客户端(包含有图形用户界面(GUI)的)可能会运行在一台PC、一个Web服务器或者甚至是其它的应用程序服务器上。在应用程序服务器与其客户端之间来回穿梭(traveling)的信息不仅仅局限于简单的显示标记。相反,这种信息就是程序逻辑(program logic)。 正是由于这种逻辑取得了(takes)数据和方法调用(calls)的形式而不是静态HTML,所以客户端才可以随心所欲的使用这种被暴露的商业逻辑。

    在大多数情形下,应用程序服务器是通过组件(component)的应用程序接口(API)把商业逻辑暴露(expose)(给客户端应用程序)的,例如基于J2EE(Java 2 Platform, Enterprise Edition)应用程序服务器的EJB(Enterprise JavaBean)组件模型。此外,应用程序服务器可以管理自己的资源,例如看大门的工作(gate-keeping duties)包括安全(security),事务处理(transaction processing),资源池(resource pooling), 和消息(messaging)。就象Web服务器一样,应用程序服务器配置了多种可扩展(scalability)和容错(fault tolerance)技术。

    一个例子
    例如,设想一个在线商店(网站)提供实时定价(real-time pricing)和有效性(availability)信息。这个站点(site)很可能会提供一个表单(form)让你来选择产品。当你提交查询(query)后,网站会进行查找(lookup)并把结果内嵌在HTML页面中返回。网站可以有很多种方式来实现这种功能。我要介绍一个不使用应用程序服务器的情景和一个使用应用程序服务器的情景。观察一下这两中情景的不同会有助于你了解应用程序服务器的功能。

    情景1:不带应用程序服务器的Web服务器

    在此种情景下,一个Web服务器独立提供在线商店的功能。Web服务器获得你的请求(request),然后发送给服务器端(server-side)可以处理请求(request)的程序。此程序从数据库或文本文件(flat file,译者注:flat file是指没有特殊格式的非二进制的文件,如properties和XML文件等)中查找定价信息。一旦找到,服务器端(server-side)程序把结果信息表示成(formulate)HTML形式,最后Web服务器把会它发送到你的Web浏览器。

    简而言之,Web服务器只是简单的通过响应(response)HTML页面来处理HTTP请求(request)。

    情景2:带应用程序服务器的Web服务器

    情景2和情景1相同的是Web服务器还是把响应(response)的产生委托(delegates)给脚本(译者注:服务器端(server-side)程序)。然而,你可以把查找定价的商业逻辑(business logic)放到应用程序服务器上。由于这种变化,此脚本只是简单的调用应用程序服务器的查找服务(lookup service),而不是已经知道如何查找数据然后表示为(formulate)一个响应(response)。 这时当该脚本程序产生HTML响应(response)时就可以使用该服务的返回结果了。

    在此情景中,应用程序服务器提供(serves)了用于查询产品的定价信息的商业逻辑。(服务器的)这种功能(functionality)没有指出有关显示和客户端如何使用此信息的细节,相反客户端和应用程序服务器只是来回传送数据。当有客户端调用应用程序服务器的查找服务(lookup service)时,此服务只是简单的查找并返回结果给客户端。

    通过从响应产生(response-generating)HTML的代码中分离出来,在应用程序之中该定价(查找)逻辑的可重用性更强了。其他的客户端,例如收款机,也可以调用同样的服务(service)来作为一个店员给客户结帐。相反,在情景1中的定价查找服务是不可重用的因为信息内嵌在HTML页中了。

    总而言之,在情景2的模型中,在Web服务器通过回应HTML页面来处理HTTP请求(request),而应用程序服务器则是通过处理定价和有效性(availability)请求(request)来提供应用程序逻辑的。

    警告(Caveats)
    现在,XML Web Services已经使应用程序服务器和Web服务器的界线混淆了。通过传送一个XML有效载荷(payload)给服务器,Web服务器现在可以处理数据和响应(response)的能力与以前的应用程序服务器同样多了。

    另外,现在大多数应用程序服务器也包含了Web服务器,这就意味着可以把Web服务器当作是应用程序服务器的一个子集(subset)。虽然应用程序服务器包含了Web服务器的功能,但是开发者很少把应用程序服务器部署(deploy)成这种功能(capacity)(译者注:这种功能是指既有应用程序服务器的功能又有Web服务器的功能)。相反,如果需要,他们通常会把Web服务器独立配置,和应用程序服务器一前一后。这种功能的分离有助于提高性能(简单的Web请求(request)就不会影响应用程序服务器了),分开配置(专门的Web服务器,集群(clustering)等等),而且给最佳产品的选取留有余地。

Open Toolbar