Linode VPS with Nginx的进一步优化

  • 清理系统服务

    可以关闭不必要的系统服务,linux下常用chkconfig,在ubuntu系统上最常用sysv-rc-conf,界面更友好使用更方便,直接通过源安装即可运行。

    sudo apt-get install sysv-rc-conf
    sudo sysv-rc-conf
    

    通过软件可以发现,Linode提供的系统已经关闭了很多不必要的服务,但是系统自带了apache,直接取消选择关闭即可。

  • nginx过期设置

    在nginx中,可以对部分类型资源配置过期时间,以利用客户端缓存,降低服务器端负载,某些媒体资源可以禁用log。

    在对应的nginx配置文件youdomain.com中添加

    location ~* ^.+\.(gif|jpg|jpeg|png|bmp|ico|swf)$ {
        root /home/myname/wwwroot/yourdomain.com;
        access_log off;
        expires 7d;
    }
    location ~* ^.+\.(js|css)$ {
        root /home/myname/wwwroot/yourdomain.com;
        expires 24h;
    }
    
  • wordpress静态化

    cos-html-cache是WP的静态化插件,他可以将WP通过UrlRewrite优化过的Url链接彻底静态化。你只需要在WP后台设置固定链接为某种静态文件类似的形式(例如/archives/%post_id%.html),你就可以使用该插件生成对应的静态文件,从此用户将直接访问此静态文件,而不必再通过php解释,极大提高运行效率。

    具体操作上面链接描述很详细,无需赘述。

    不过我在启用此插件后,发现能正常生成网站根目录下index.html,但无法生成/archives/%post_id%.html。我写了一个php脚本放在网站根目录下测试,也无法在/archives目录下生成文件,提示找不到该目录。在cos-html-cache源文件中可以找到,生成html文件的脚本,路径信息是通过$_SERVER[“DOCUMENT_ROOT”]获取的,但是尝试打印该值发现无值。最后我发现必须在Nginx站点配置文件中在php-fast-cgi的配置项里增加网站的root路径如下

    location / {
        root   /home/myname/wwwroot/yourdomain.com;
        index  index.html index.htm index.php;
        if (-f $request_filename) {
            break;
        }
        if (-d $request_filename) {
            break;
        }
        rewrite ^(.+)$ /index.php?q=$1 last;
    }
    location ~ \.php$ {
        #必须定义root -----------------------------------------
        root   /home/myname/wwwroot/yourdomain.com;
        #------------------------------------------------------
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_index   index.php;
        fastcgi_param   SCRIPT_FILENAME  /home/myname/wwwroot/yourdomain.com$fastcgi_script_name;
        include     /usr/local/nginx/conf/fastcgi_params;
    }
    
    

    如果不添加该root信息,在php中则无法正确获取$_SERVER[“DOCUMENT_ROOT”]参数,会导致路径定位错误。不过按照一般逻辑,这个应该是继承前面的root设置,不必重复定义。也许是因为fastcgi是从nginx转向到另一个新的进程的缘故,所以需要具体定义参数传递。不过nginx应该自动获取该值,避免重复手工操作。

Setup on Linode.com with ubuntu+nginx+php+fastcgi+mysql 续

嗯嗯,继续。

  • nginx和fastcgi启动配置

    2个配置文件,放于/etc/init.d下面。

    cd /etc/init.d
    touch fast-cgi
    touch nginx
    sudo chmod +x /etc/init.d/nginx /etc/init.d/fast-cgi

    nginx

    #! /bin/sh
    
    ### BEGIN INIT INFO
    # Provides:          nginx
    # Required-Start:    $all
    # Required-Stop:     $all
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: starts the nginx web server
    # Description:       starts nginx using start-stop-daemon
    ### END INIT INFO
    
    PATH=/usr/local/nginx/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    DAEMON=/usr/local/nginx/sbin/nginx
    NAME=nginx
    DESC=nginx
    
    test -x $DAEMON || exit 0
    
    # Include nginx defaults if available
    if [ -f /etc/default/nginx ] ; then
    	. /etc/default/nginx
    fi
    
    set -e
    
    . /lib/lsb/init-functions
    
    test_nginx_config() {
      if nginx -t
      then
        return 0
      else
        return $?
      fi
    }
    
    case "$1" in
      start)
    	echo -n "Starting $DESC: "
            test_nginx_config
    	start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
    		--exec $DAEMON -- $DAEMON_OPTS || true
    	echo "$NAME."
    	;;
      stop)
    	echo -n "Stopping $DESC: "
    	start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
    		--exec $DAEMON || true
    	echo "$NAME."
    	;;
      restart|force-reload)
    	echo -n "Restarting $DESC: "
    	start-stop-daemon --stop --quiet --pidfile \
    		/var/run/$NAME.pid --exec $DAEMON || true
    	sleep 1
            test_nginx_config
    	start-stop-daemon --start --quiet --pidfile \
    		/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
    	echo "$NAME."
    	;;
      reload)
            echo -n "Reloading $DESC configuration: "
            test_nginx_config
            start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \
                --exec $DAEMON || true
            echo "$NAME."
            ;;
      configtest)
            echo -n "Testing $DESC configuration: "
            if test_nginx_config
            then
              echo "$NAME."
            else
              exit $?
            fi
            ;;
      status)
    	status_of_proc -p /var/run/$NAME.pid "$DAEMON" nginx && exit 0 || exit $?
    	;;
      *)
    	echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2
    	exit 1
    	;;
    esac
    
    exit 0

    fast-cgi

    #! /bin/sh
    
    ### BEGIN INIT INFO
    # Provides:          fast-cgi
    # Required-Start:    $all
    # Required-Stop:     $all
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: starts the fast-cgi web server
    # Description:       starts fastcgi using start-stop-daemon
    ### END INIT INFO
    
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    
    NAME=spawn-fcgi
    DESC=spawn-fcgi
    DAEMON=/usr/local/bin/spawn-fcgi
    
    DAEMON_OPTS="-u www-data -g www-data -C 8 -a 127.0.0.1 -p 9000 -P /var/run/$NAME.pid -- /usr/bin/php5-cgi"
    
    test -x $DAEMON || exit 0
    
    set -e
    
    case "$1" in
      start)
    	echo -n "Starting $DESC: "
    	start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
    	echo "$NAME."
    	;;
      stop)
    	echo -n "Stopping $DESC: "
    	start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid --exec $DAEMON || true
    	echo "$NAME."
    	;;
      restart|force-reload)
    	echo -n "Restarting $DESC: "
    	start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid --exec $DAEMON || true
    	sleep 1
    	start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
    	echo "$NAME."
    	;;
      reload)
          echo -n "Reloading $DESC configuration: "
          start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid --exec $DAEMON || true
          echo "$NAME."
          ;;
      *)
    	N=/etc/init.d/$NAME
    	echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
    	exit 1
    	;;
    esac
    exit 0

    这两个脚本需要注意的是目录的定位,如果在编译阶段加入了目录设置的参数,那么你同时需要在这里修改定义。另外fast-cgi需要注意DAEMON_OPTS的参数设置。

    这2个脚本都有一个同样的问题,就是无法正常停止服务。我虽然不太了解shell程序,但是根据我其他编程经验,两个脚本都是通过start-stop-daemon命令来开启和停止服务。但我使用的情况是可以正常开启,但无法正常关闭。所以我不得不写了一个简单的关闭并重启nginx服务的脚本,是通过直接kill进程来实现的。

    cd ~
    mkdir tools
    cd tools
    touch reset_nginx
    chmod +x reset_nginx

    reset_nginx内容

    sudo kill `cat /usr/local/nginx/logs/nginx.pid`
    sudo /etc/init.d/nginx start

    但是fast-cgi的服务即使我kill进程并删除pid文件也无济于事,fast-cgi仍然照常运行……这有点不合逻辑,也许我操作错误,或者是权限问题。不过fast-cgi开启后一般也没有必要进行重启或其他操作,这个问题留待以后解决吧。或者有哪位同学知道的,请不吝赐教!

    最后这2个脚本需要注册为系统服务,需要安装rcconf。

    sudo apt-get install rcconf
    sudo rcconf

    嗯,很怀旧的DOS操作界面……呵呵,大家选择2个脚本,再ok退出即可。

  • nginx站点配置

    由于dreamhost的习惯,并且这个虚拟机还要放callaly的blog(http://callaly.net),所以nginx的站点我放到用户目录下去了。

    cd ~
    mkdir wwwroot
    cd wwwroot
    mkdir yourdomain.com

    编辑/usr/local/nginx/conf/nginx.conf

    user www-data;
    worker_processes 2;
    
    events {
    	worker_connections  1024;
    	use epoll;
    }
    
    http {
    	include       mime.types;
    	default_type  application/octet-stream;
    
    	sendfile       on;
    	tcp_nopush     on;
    	tcp_nodelay    on;
    
    	keepalive_timeout  65;
    
    	gzip  on;
    
    	#设置默认站点,禁止所有IP访问
    	server {
    		listen 80 default;
    		return 403;
    	}
    
    	#包含其他站点配置
    	include /usr/local/nginx/sites-enabled/*;
    
    }

    创建站点文件

    cd /usr/local/nginx
    sudo mkdir sites-available
    sudo mkdir sites-enabled
    sudo touch sites-available/yourdomain.com
    sudo ln -s sites-available/yourdomain.com sites-enabled/yourdomain.com
    	

    编辑sites-available/yourdomain.com

    server {
    	listen       80;
    	server_name  www.yourdomain.com yourdomain.com;
    
    	access_log	/home/myname/wwwroot/log/yourdomain.com.access.log;
       	error_log	/home/myname/wwwroot/log/yourdomain.com.error.log;
    
    	location / {
    		root   /home/myname/wwwroot/yourdomain.com;
    		index  index.html index.htm index.php;
    
    		# WordPress URL优化
    		if (-f $request_filename) {
    			break;
    		}
    		if (-d $request_filename) {
    			break;
    		}
    
    		# WordPress URL重写,如果你的wp目录不在根目录,请修改路径
    		rewrite ^(.+)$ /index.php?q=$1 last;
    	}
    
    	location ~ \.php$ {
    		fastcgi_pass	127.0.0.1:9000;
    		fastcgi_index	index.php;
    		fastcgi_param	SCRIPT_FILENAME /home/myname/wwwroot/yourdomain.com$fastcgi_script_name;
    		include		/usr/local/nginx/conf/fastcgi_params;
    	}
    
    	#如果前面编译nginx时添加了with-http_stub_status_module参数
    	#就可以通过此设置访问yourdomain.com/status(名称自定)查看站点状态
    	location /status {
    		stub_status on;
    		access_log off;
    	}
    }

    nginx的站点配置基本ok

  • wordpress备份和恢复

    需要把dreamhost主机上的内容迁移过来,可操作方法很多,最好在服务器端直接操作,速度更快。文件操作很简单不赘述,关于数据库的备份和恢复简单说下。

    #导出 - 在原服务器
    mysqldump -h old_host -p old_dbname -u old_dbuser >wp_bak.sql
    
    #登录mysql
    mysql -h new_host -u new_dbuser
    
    #创建新数据库,注意编码
    create database 'new_dbname' default character set utf8 collate utf8_general_ci;
    
    #导入 - 确保备份sql文件在当前目录
    use new_dbname;
    source wp_bak.sql;

    至此整个站点配置已经基本完成,可以敲域名访问了。

这篇文章大部分内容来自于网上,我东拼西凑来的,特在此列出供大家参考。

some conception in java

  • JNDI: (Java Naming and Directory Interface) 这是在javaEE体系内部的一个“域名”系统,你可以通过配置指定某种资源的命名,然后通过该命名来引用资源,以达到程序代码和资源之间解耦的目的。这里的资源最常见的是jdbc数据源,通常还会有某种环境实体、EJB组件或者其他资源引用。
  • RMI: (Remote Method Invocation) RMI内置于java语言核心,是java最高效的远程对象访问和调用技术。实现类似功能的技术每个平台都有,.NET平台下有.net remoting,不过到3.0以后都整合为WCF了。RMI是基于TCP/IP的,效率很高,是EJB的实现基础,但是不能穿越防火墙。要能穿越防火墙当然得走http,最常见的就是web service得soap了,不过公认soap的效率是非常低的。我google了一下,java常用的技术还有Hessian/Burlap/Httpinvoker,这些都是基于http协议的,可以穿越防火墙。其中Hessian基于二进制代码,协议公开,在.net/php/python等各个语言都有相应实现。Burlap是基于xml,效率相对低些。Httpinvoker内置于Spring,据说效率和RMI差不多,但是应用不多不太成熟。目前除了EJB基于RMI以外,其他情况下最常用的是Hessian。
  • JMS: (Java Message Service) 共享空间和消息传递是软件系统中最常用的数据传播方式,jms就是java提供的消息传递服务,一般也叫做消息中间件,基本来说这也是每个技术平台必备构成,例如.net或者说ms的消息队列(MQ)组件。如何控制消息的传递?点对点?分发订阅?异步传输?这些特性都由jms提供,不需要程序员自己再从头开发了。特别的,javaEE提供了一种特殊的消息驱动bean(message-driven bean,MDB),他将ejb和jms联系起来,利用jms消息来调用bean。
  • JAXP: (Java API for XML Processing) 这个东东名字叫api,但是严格来说不算是api,而是一个xml操作的抽象层。java中解析xml的方法很多(例如DOM和SAX),使用这些api去解析xml时需要编写的代码完全不同,因此可以认为业务代码和xml解析耦合非常紧密。为了消除这种耦合产生了jaxp,通过jaxp你可以采用相同的业务代码用不同的解析器操作xml——当然事实上由于两种解析器的理念不同,代码还是会有一定的差别。

    老实说,我有点没搞懂,既然仍然无法完全避免业务代码的差别,那又何必一定要这样搞呢?也许这不是我这儿纸上谈兵能理解的,需要具体的问题来实践。

  • JAXR: (Java API for XML Registries) 这也是一种解耦或者说抽象机制,registries是指目前互联网上分布的基于xml的注册服务,例如ebXML和UDDI。而jaxr使你能通过统一的接口访问这些不同的xml注册服务。

java体系的概念太多了,这只是最近看的很少一部分。

thinking of java web develop learning

看了几天java web开发的东东,简单梳理一下。

  • 容器

    这是java web开发过程中非常强调的一个概念。顾名思义,在它的内部存放着某些东西,各种java对象,包括所谓的bean等等。java的容器也可以称其为一个应用服务,或一个框架,用户通过配置指定代码或者说对象、构件存放的路径,以及对象之间的关系、对象和容器直接的关系。这通常有一套标准,例如javaEE本身的servlet/jsp的规范,或容器本身特定的某些标准,你的配置和代码必须符合这种标准,才能被容器调用使用。标准有很多形式,xml的配置、java接口的实现、对象的继承、java的标注等等,他们决定了对象如何被容器调用、对象之间的关系、以及对象在容器中的运行状态。

    目前作为java web开发最常用的servlet/jsp容器是tomcat,企业应用服务器是jboss。spring框架虽然没有服务器的概念,但是从其包含、组织、调用java组件的特征来看,也可以说是容器了。

    回忆.net,虽然没有特别强调容器的概念,但是从程序的流程和组织架构来说,iis就是.net web程序运行的容器了。

  • web生命周期

    在任何技术平台的web开发中,web的生命周期都是一个核心概念。由于web应用都是基于http协议和b/s模式,所以不论采用何种技术,其生命周期都是类似的。

    • 请求与响应:

      客户端请求-服务器端运算服务-响应,request->service->response,这个标准的http访问流程存在于任何一种web开发平台中。流程对应的对象引用和方法也都相似,HttpServletRequest封装http的请求,可以通过该对象获取请求相关的各种参数,HttpServletResponse封装对客户端的响应,通过该对象可以设置http流的各种响应数据,HttpServlet.service(HttpServletRequest req, HttpServletResponse res)则实现服务的计算内容,获取请求,再根据程序逻辑设置响应。

    • scope:

      web程序有其自有的运行环境和上下文,在java web开发中一般称其为scope(page|request|session|application)。

      • page 是最小运行环境,一个jsp page即一个servlet类实例,但是page scope并非指这个servlet实例的变量,它的有效范围是该servlet对象和某次http请求的交集,只能在当前请求当前页面有效。
      • request 是某次请求范围内有效,即使该请求在服务器端通过forward跨越多个servlet。
      • session(HttpSession) 是指某个用户会话的全过程,这是为了弥补无状态的http会话缺陷,通过cookie识别客户端并在服务器端添加状态的机制。
      • application(ServletContext) 是指在整个应用(context)范围内有效的程序环境。

      在这些scope中,request|session|application都可以通过setAttribute/getAttribute在有效范围内设置获取变量。这是一种常见的代码数据共享方式,不过存在线程安全问题,需要注意考虑并发情况。

    • 对象各自的生命周期:

      所有的对象都有其各自的生命周期,初始化-运行时-销毁。通常初始化和销毁是由容器控制,运行时会运行程序代码实现逻辑。同时,servlet还提供监听(listener)和过滤(filter)的机制,使程序能控制对象生命周期更广的范围。当然这些都必须实现指定的接口,并通过xml或标注等容器认可的方式配置编码,使容器能访问调用。

  • jsp标签

    标签是web页面的表现中非常常见的技术,最原始的标签就是html模板内的变量替换,估计做web的人人都写过。java web的标签有jsp的标准标签、el、自定义标签,JSTL应该也属于自定义标签,只是后来作为标准发布了。

    • 繁杂的标签:

      jsp标准的标签实现,我个的感觉有些繁杂。java平台一向以自由著称,但是作为一种技术的标准,内容和实现应该尽量简洁,提供一种标准的实现方式即可,是否采用其它第三方库完全可以由用户自己选择。

      jsp的标准标签提供了jsp页面实现的基本功能,它包括基本的页面定义、servlet类程序定义、表达式、包含、异常等等,其他程序逻辑则通过代码片段来实现。继此之后,大家觉得在一个xml文档里面,java代码片段到处飞,看上去不太美观,因此jstl出来了。通过自定义标签,他试图把所有标准标签实现不了必须依靠代码片段实现的东西转换为标签,从而在jsp模板里消灭java代码片段。因此他实现了环境变量的设置和引用,异常,程序流转逻辑等等,甚至通过sql库实现数据库操作。我考虑了很久,除非那种没有任何性能要求,简单到只有1、2个的页面的应用,否则是不太可能采用这种方式来实现数据库操作的。而xml形式的程序逻辑标签(if|else|choose|when…)也过于繁琐,远不如代码片段简洁。

      I18N库倒是很简单实用,但是它的本地化文件数据格式太简单,只适合某些很简单的单词单句的本地化,如果有比较复杂的内容,估计这么简单的数据格式是无法满足要求的。不知道有没有接口可以对底层进行重写,否则实用价值有限。

    • el库:

      el是非常简洁漂亮的,基本上可以把他当作是某种脚本变量的引用,据说javaEE5以后官方也大力提倡使用。但是我觉得也挺逗,这不就和当初试图消灭jsp模板里面非xml风格元素的目标相冲突吗?el可完全不是xml风格,虽然他比java代码对文档的破坏性小,但他也仅仅是表达式,无法实现其他逻辑功能。

    • 自定义标签:

      通过tag api,或者通过简单的标签文件,用户可以创建自定义标签,这和asp.net中的自定义控件和用户控件如出一辙。在我以往的经验中,除了基于学习的目的,从来没有自己开发过控件,用户控件一般也只用于进行简单的包含,方便做缓存或部分逻辑控制。

      我感觉自定义标签和asp.net自定义控件的情况类似,多用于某些企业系统的开发,或者是某些商业库的实现。而在一般网站系统中去开发和自定义一套标签库是非常困难的,代价成本非常高。实现本身比较复杂,增加了开发人员学习成本,库的维护和发展得不到保障,增大了程序复杂度增大了运算资源的消耗。上面这些问题对于需求变化快、应用访问量非常高的网站应用来说是致命的,而对于一般的企业系统来讲影响比较小。

    • 代码和界面分离的传说:

      我相信所有做web的人——无论前端后端——都听过这么一个论述,如果web页面模板能够和后端程序完全分离,那么前端和后端能完全相互无干扰的工作,将大大提高工作效率。从理论上来说,如果能做到这一点确实能大大提高工作效率,然而能做到吗?所谓界面本身就是程序的一部分,他和程序逻辑是息息相关的。除非某个界面和程序完全没有关系,否则他必然存在某种形式的程序逻辑控制代码,不管这种代码是代码片段、xml还是简单表达式,又或者未来发明个别的什么东西。这是应用的需求和软件开发工作的实质决定的。

      又有某种说法,认为将程序控制实现为html格式类似的标签,可以帮助前端人员更容易识别和修改html模板,这个说法更不可信。我长期和设计师及前端人员合作,事实上除极个别极端情况,大多数人都很容易理解简单的程序语法,如变量或对象声明、简单的程序逻辑控制等。甚至很多设计师为了页面控制方便,自己写一些简单控制逻辑。这个学习成本很低,而且基本上所有的流行程序语言语法都类似。而仅jsp的标签库就有多少种?其表达形式何其花样百出?很多时候还存在需要设计师理解标签库设置界面外观等等情况,对设计师来说复杂度远远高于去了解一门程序语言的简单语法。

    对标签这种形式,我的态度是实现方式越简单,表现形式越简洁越好,不必完全拒绝程序代码,不要过于苛求xml文档化,过犹不及。对于jsp标签的现状,我觉得可以参考asp.net,通过继承或者实现分部类,把jsp的大部分代码逻辑放到后端java程序中去,分离代码和模板。或者强化el,有限制的实现某种jsp中的脚本语言,甚至嫁接一个别的脚本语言进来。嗯,都不错。

  • bean就是组件

    在我未接触java之前,就总是听说javaBean和ejb,我不知道为什么要取名为bean,那应该只是源于java的某种趣味的称呼吧。bean就是对象,没有什么不同,只是他需要符合某些标准,以方便jsp或其他调用。看了这些标准,bean和.net中的组件是一个概念,没有什么区别。在jsp中访问bean很简单,就是一些现成的标签,设置一下bean的scope。我仍然觉得这种标签访问方式感觉很恶劣……

    关于ejb,我看的这本书简单讲了一个例子,如何创建并访问。ejb我感觉和bean的差别在2个方面,一是ejb是分布式组件,除业务逻辑类本身外,还需要按标准创建相关的接口、配置、部署,最后提供远程调用的能力。二是ejb的服务器应该会提供强大的管理功能,组件之间的关系、结构组合、性能优化、事务等等,这一部分我看的书没有提。书还是ejb2的例子,ejb3据说已经大大简化了,嗯,待学习了。

  • jdbc:

    总的来说,jdbc和其他技术的数据接口没有太大差别,这种趋同是由数据库支持的底层机制所决定的,不会因上层平台技术改变。比较有趣的是,jdbc实现事务是把先取消自动提交事务,然后执行sql,再commit,失败则通过异常处理rollback。

  • 有趣的java

    搞java也一个多星期了,感觉java确实很繁杂,不论语法还是平台框架,很多东西不如.net平台简洁有效。但是java更加自由,整个开源世界存在很多框架、技术可供你自由选择——当然这种选择是需要成本的,有时候这也是一种痛苦。另外,对于软件构架,java更趋向于从技术和程序的角度,而.net趋向于从用户的角度,对于技术人员来讲,java的这种视角更加可贵。