So Tired !_! 逆水行舟, 不进则退!

23Aug/11

python datetime 操作相关

Posted by Nick Xu

网上COPY的。里面有问题请自便。

我只是用了一个方法,用来取昨天的日期,并且格式为yyyy-mm-dd
yesterday = (datetime.date.today() + datetime.timedelta(days=-1)).isoformat()

import time
import datetime

# 2007-11-25 15:36:35

#使用datetime模块可以很方便的解决这个问题,举例如下:

d1 = datetime.datetime(2005, 2, 16)
d2 = datetime.datetime(2004, 12, 31)

# 结果:47
print (d1 - d2).days

#上例演示了计算两个日期相差天数的计算。

starttime = datetime.datetime.now()

endtime = datetime.datetime.now()
print (endtime - starttime).seconds

#上例演示了计算运行时间的例子,以秒进行显示。

d1 = datetime.datetime.now()
d3 = d1 + datetime.timedelta(days =10)

print str(d3)
print d3.ctime()

# 上例演示了计算当前时间向后10天的时间。
# 如果是小时 days 换成 hours

# 其本上常用的类有:datetime和timedelta两个。它们之间可以相互加减。
# 每个类都有一些方法和属性可以查看具体的值,如datetime可以查看:天数(day),小时数(hour),星期几(weekday())等;
# timedelta可以查看:天数(days),秒数(seconds) 等。

#
# time , datetime , string 类型互相转换
#
# string -> time
# time.strptime(publishDate,"%Y-%m-%d %H:%M:%S")
#
# time -> string
# time.strftime("%y-%m-%d",t)

date = '2007-01-01'

print type(date)

date = time.strptime(date,"%Y-%m-%d")

print type(date)

print date[0]

d4 = datetime.datetime(date[0], date[1],date[2])

print d4
print type(d4)

#将日期时间对象转成字符串则要用

date = time.strftime("%y-%m-%d",date)
print type(date)

#其中d为日期时间对象

开发需要 搜到了这个程序 因要求前一天的日期 就该了下

根据上面的原理 很容易就可以写出取得前一天日期的程序

d1 = datetime.datetime.now()
d3 = d1 + datetime.timedelta(days = -1)

print datetime.date.today() + datetime.timedelta(days=-1)

print datetime.date.today() - datetime.timedelta(days=1)

Tagged as: No Comments
23Aug/11

ASP.NET 4.0 安裝在 IIS6 最常遇到的四個問題

Posted by Nick Xu

昨天同事將一個 ASP.NET 4.0 的網站安裝到客戶的 IIS6 主機上 (測試環境),結果過程非常不順利,他們曾經一度覺得客戶的主機不知道經過幾隻手蹂躪過了(因為有好多人在共用 Administrator 帳號)進而產生排斥安裝在客戶主機以及 “為什麼我們要用 ASP.NET 4” 的感覺,不過在一群人的努力之下最後還是克服了困難,我特別因此寫下筆記,相信這些問題有其他人也可能會遇到。

要執行 ASP.NET 4.0 網站必須先安裝 Microsoft .NET Framework 4

安裝前必須先確定你的作業系統版本是在支援的範圍內:

  • Windows XP SP3
  • Windows Server 2003 SP2
  • Windows Vista SP1 (含) 以後版本
  • Windows Server 2008 (伺服器核心角色不支援)
  • Windows 7
  • Windows Server 2008 R2 (伺服器核心角色不支援)

常見問題1:設定網站站台ASP.NET 頁籤時找不到 ASP.NET 4.0 的選項

設定網站站台的 ASP.NET 頁籤時找不到 ASP.NET 4.0 的選項

注意:如果你只有安裝 .NET Framework Client Profile是不支援 ASP.NET 的,必須下載 Microsoft .NET Framework 4 (獨立安裝程式) 來安裝才會完整。

.NET Framework Client Profile

正常來說,只要 Windows Server 2003 已經先安裝好 IIS 再安裝 Microsoft .NET Framework 4 就可以在 IIS 6.0 網站站台ASP.NET 頁籤找到 ASP.NET 4.0 的選項:

只要 Windows Server 2003 已經先安裝好 IIS 再安裝 Microsoft .NET Framework 4 就可以在 IIS 6.0 網站站台的 ASP.NET 頁籤找到 ASP.NET 4.0 的選項

常見問題2:安裝好 .NET 4 後還是找不到設定網站站台ASP.NET 頁籤的 ASP.NET 4.0 的選項

這問題通常出在先安裝 Microsoft .NET Framework 4 才安裝 IIS6,這時必須輸入以下指令將 ASP.NET 4.0 註冊進 IIS6 即可:

C:WINDOWSMicrosoft.NETFrameworkv4.0.30319aspnet_regiis.exe -ir -enable

C:WINDOWSMicrosoft.NETFrameworkv4.0.30319aspnet_regiis.exe -ir -enable

常見問題3:安裝好 .NET 4 也設定好網站站台的 ASP.NET 4.0 的選項依然無法執行網站

這裡的「無法執行網站」其實所有執行的頁面都會出現 找不到這個頁面 (HTTP 錯誤 404 - 找不到檔案或目錄) 的回應,不管你怎麼設定目錄安全性或任何執行權限都無法執行任何 ASP.NET 程式,而且可能只有靜態頁面可以讀取而已,像是如下圖示這麼一般性的錯誤訊息真的很容易讓 IT 人員不知如何是好:

找不到這個頁面 (HTTP 錯誤 404 - 找不到檔案或目錄)

如果你因為安裝 ASP.NET MVC 而有設定「萬用字元應用程式對應」的話,則會發現網站所有頁面包括靜態檔案讀去都會回應 找不到這個頁面 的錯誤!

應用程式設定 - 萬用字元應用程式對應

此問題發生的原因是 IIS6 阻擋了 c:windowsmicrosoft.netframeworkv4.0.30319aspnet_isapi.dll 程式的執行,由於所有會被導向到此 ISAPI Handler 的要求全部都會失敗,所以才會導致你所有 HTTP 要求都會得到 HTTP 404 Not Found 的結果。

解決方式很簡單,只要到 [網頁服務延伸] 的地方將 ASP.NET v4.0.30319 設定 [允許] 即可,如下圖示:

到 [網頁服務延伸] 的地方將 ASP.NET v4.0.30319 設定 [允許] 即可

常見問題4:ASP.NET 4.0 的網站站台已經設定好也可以正常執行了,但執行一段時間會自己掛掉!

如果你在同一個應用程式集區設定了兩個不同版本的 ASP.NET 就會造成這個問題,例如你原本有個 ASP.NET 2.0 的站台,並且設定的應用程式集區為 DefaultAppPool,然而你之後又新增了一個 ASP.NET 4.0 的站台,而預設的應用程式集區也是在 DefaultAppPool 的話就會發生衝突了,這時就會看是哪個站台先被執行起來,先跑起來的那個站台才會搶到所有權,後面執行的那個就會發生 Server Application Unavailable伺服器應用程式無法使用 的錯誤:

伺服器應用程式無法使用

解決的方法有二:

  • 將共用應用程式集區的 網站站台 網站應用程式(虛擬目錄) 都設定到 ASP.NET v4.0.30319
  • 區分兩個不同的應用程式集區

常見問題5:在站点属性里找不到asp.net选项

到服务器上运行:cscript %SYSTEMDRIVE%inetpubadminscriptsadsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1

如果还不行再运行这个:cscript %SYSTEMDRIVE%inetpubadminscriptsadsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 0

还不行再运行:%SYSTEMROOT%Microsoft.NETFrameworkv1.1.4322aspnet_regiis.exe -i

最后还不行就没办法咯。。。。

Filed under: 点NET No Comments
9Aug/11

django学习笔记——进阶——模型

Posted by Nick Xu

新建应用程序

在开始之前需要新建一个应用程序。在这之前我们已经创建了 project , 那么 project 和 app 之间到底有什么不同呢? 它们的区别就是一个是配置另一个是代码。也就是说一个app是一套Django功能的集合,通常包括模型和视图,按Python的包结构的方式存在。

在“ mysite“ 项目文件下输入下面的命令来创建“ books“ app
python manage.py startapp books
这个命令在mysite目录下新建了一个book的app应用程序

模型

模型创建的流程
1:在settings.py中配置数据库信息
2:在app中models.py文件里定义模型

from django.db import models

class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()

class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()

class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()

每个模型相当于单个数据库表,每个属性也是这个表中的一个字段

3:模型安装
编辑 settings.py 文件, 找到 INSTALLED_APPS 设置,INSTALLED_APPS 告诉 Django 项目哪些 app 处于激活状态.

INSTALLED_APPS = (
# 'django.contrib.auth',
# 'django.contrib.contenttypes',
# 'django.contrib.sessions',
# 'django.contrib.sites',
'mysite.books',
)

首先,用下面的命令对校验模型的有效性:
python manage.py validate
没问题之后运行下面的命令来生成 CREATE TABLE 语句:
python manage.py sqlall books
然后通过下列命令执行SQL
python manage.py syncdb
syncdb 命令是同步你的模型到数据库的一个简单方法。 它会根据 INSTALLED_APPS 里设置的app来检查数据库, 如果表不存在,它就会创建它。 需要注意的是, syncdb 并 不能 同步模型的修改到数据库。 (本章的最后将详细讨论修改数据库的架构)

基本数据访问

from books.models import Publisher
p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',
city='Berkeley', state_province='CA', country='U.S.A.',
website='http://www.apress.com/')
p1.save()
publisher_list = Publisher.objects.all()

首先,导入Publisher模型类, 通过这个类我们可以与包含 出版社 的数据表进行交互。
接着,创建一个“ Publisher“ 类的实例并设置了字段“ name, address“ 等的值。
调用该对象的 save() 方法,将对象保存到数据库中。 Django 会在后台执行一条 INSERT 语句。
最后,使用“ Publisher.objects“ 属性从数据库取出出版商的信息,这个属性可以认为是包含出版商的记录集。 这个属性有许多方法,这里先介绍调用“ Publisher.objects.all()“ 方法获取数据库中“ Publisher“ 类的所有对象。这个操作的幕后,Django执行了一条SQL “ SELECT“ 语句。

注意:当你使用Django modle API创建对象时Django并未将对象保存至数据库内,除非你调用“ save()“ 方法
如果需要一步完成对象的创建与存储至数据库,就使用“ objects.create()“ 方法

p1 = Publisher.objects.create(name='Apress',
address='2855 Telegraph Avenue',
city='Berkeley', state_province='CA', country='U.S.A.',
website='http://www.apress.com/')

查询数据
Publisher.objects.all() 查询出表的所有数据
数据过滤
Publisher.objects.filter(name=’Apress’) 查询出name为apress值的记录
Publisher.objects.filter(country=”U.S.A.”, state_province=”CA”)
包含性查找
Publisher.objects.filter(name__contains=”press”) 查找出name中包含press的记录。在 name 和 contains 之间有双下划线。其他的一些查找类型有: icontains (大小写无关的 LIKE ), startswith 和 endswith , 还有 range
获取耽搁数据
Publisher.objects.get(name=”Apress”) 如果结果是多个对象,会导致抛出异常:如果查询没有返回结果也会抛出异常

排序

Publisher.objects.order_by(“state_province”, “address”)
逆向排序
Publisher.objects.order_by(“-name”)
连锁
Publisher.objects.filter(country=”U.S.A.”).order_by(“-name”)

限制返回数量
Publisher.objects.order_by(‘name’)[0] 返回第一个
相当于
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 1;
取出特定子集
Publisher.objects.order_by(‘name’)[0:2]
类似于
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 0,2;

更新数据
更新单个字段
Publisher.objects.filter(id=52).update(name=’Apress Publishing’)
类似于
UPDATE books_publisher
SET name = ‘Apress Publishing’
WHERE id = 52;

更新多个字段
p = Publisher.objects.get(name=’Apress’)
p.name = ‘Apress Publishing’
p.save()
类似于
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = ‘Apress’;

UPDATE books_publisher SET
name = ‘Apress Publishing’,
address = ‘2855 Telegraph Ave.’,
city = ‘Berkeley’,
state_province = ‘CA’,
country = ‘U.S.A.’,
website = ‘http://www.apress.com’
WHERE id = 52;
在这个例子里我们可以看到Django的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的

删除数据
p = Publisher.objects.get(name=”O’Reilly”)
p.delete()
删除多条记录
Publisher.objects.filter(country=’USA’).delete()

指定模型的缺省排序方式

class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()

def __unicode__(self):
return self.name

class Meta:
ordering = ['name']

class Meta,内嵌于 Publisher 这个类的定义中(如果 class Publisher 是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统 )。你可以在任意一个 模型 类中使用 Meta 类,来设置一些与特定模型相关的选项

Tagged as: , No Comments
7Aug/11

用monit监控系统关键进程

Posted by Nick Xu

monit是一款功能强大的系统状态、进程、文件、目录和设备的监控软件,用于*nix平台, 它可以自动重启那些已经挂掉的程序,非常适合监控系统关键的进程和资源,如:nginx、apache、mysql和cpu占有率等。而监控管理Python进程,常用的是supervisor,后续会另外撰文介绍。

下面分别介绍monit的安装、配置和启动。

安装

在debian或ubuntu上安装monit非常方便,通过下面的命令

sudo apt-get install monit

即可,其它*nix上也很简单,下载源码走一遍安装三步就OK了。

./configure
make
make install

安装后,默认的配置文件为/etc/monit/monitrc。

配置

添加需要监控的进程等信息至monit的配置文件,monit的配置详见下面的示例文件,为了便于理解,关键的配置我都给出了中文的注释。

##
## 飞龙日志 示例monit配置文件,说明:
## 1. 域名以example.com为例。
## 2. 后面带xxx的均是举例用的名字,需要根据自己的需要修改。
##
###############################################################################
## Monit control file
###############################################################################
#
# 检查周期,默认为2分钟,对于网站来说有点长,可以根据需要自行调节,这改成30秒。
set daemon  30

# 日志文件
set logfile /var/log/monit.log

#
# 邮件通知服务器
#
#set mailserver mail.example.com
set mailserver localhost           

#
# 通知邮件的格式设置,下面是默认格式供参考
#
## Monit by default uses the following alert mail format:
##
## --8<--
## From: monit@$HOST                         # sender
## Subject: monit alert --  $EVENT $SERVICE  # subject
##
## $EVENT Service $SERVICE                   #
##                                           #
## 	Date:        $DATE                   #
## 	Action:      $ACTION                 #
## 	Host:        $HOST                   # body
## 	Description: $DESCRIPTION            #
##                                           #
## Your faithful employee,                   #
## monit                                     #
## --8<--
##
## You can override the alert message format or its parts such as subject
## or sender using the MAIL-FORMAT statement. Macros such as $DATE, etc.
## are expanded on runtime. For example to override the sender:
#
# 简单的,这只改了一下发送人,有需要可以自己修改其它内容。
set mail-format { from: webmaster@example.com }

# 设置邮件通知接收者。建议发到gmail,方便邮件过滤。
set alert userxxx@gmail.com

set httpd port 2812 and            # 设置http监控页面的端口
     use address www.example.com   # http监控页面的IP或域名
     allow localhost               # 允许本地访问
     allow 58.68.78.0/24           # 允许此IP段访问
     ##allow 0.0.0.0/0.0.0.0       # 允许任何IP段,不建议这样干
     allow userxxx:passwordxxx     # 访问用户名密码

###############################################################################
## Services
###############################################################################
#
# 系统整体运行状况监控,默认的就可以,可以自己去微调
#
# 系统名称,可以是IP或域名
check system www.example.com
    if loadavg (1min) > 4 then alert
    if loadavg (5min) > 2 then alert
    if memory usage > 75% then alert
    if cpu usage (user) > 70% then alert
    if cpu usage (system) > 30% then alert
    if cpu usage (wait) > 20% then alert

#
# 监控nginx
#
# 需要提供进程pid文件信息
check process nginx with pidfile /var/run/nginx.pid
    # 进程启动命令行,注:必须是命令全路径
    start program = "/etc/init.d/nginx start"
    # 进程关闭命令行
    stop program  = "/etc/init.d/nginx stop"
    # nginx进程状态测试,监测到nginx连不上了,则自动重启
    if failed host www.example.com port 80 protocol http then restart
    # 多次重启失败将不再尝试重启,这种就是系统出现严重错误的情况
    if 3 restarts within 5 cycles then timeout
    # 可选,设置分组信息
    group server

#   可选的ssl端口的监控,如果有的话
#    if failed port 443 type tcpssl protocol http
#       with timeout 15 seconds
#       then restart

#
# 监控apache
#
check process apache with pidfile /var/run/apache2.pid
    start program = "/etc/init.d/apache2 start"
    stop program  = "/etc/init.d/apache2 stop"
    # apache吃cpu和内存比较厉害,额外添加一些关于这方面的监控设置
    if cpu > 50% for 2 cycles then alert
    if cpu > 70% for 5 cycles then restart
    if totalmem > 1500 MB for 10 cycles then restart
    if children > 250 then restart
    if loadavg(5min) greater than 10 for 20 cycles then stop
    if failed host www.example.com port 8080 protocol http then restart
    if 3 restarts within 5 cycles then timeout
    group server
    # 可选,依赖于nginx
    depends on nginx

#
# 监控spawn-fcgi进程(其实就是fast-cgi进程)
#
check process spawn-fcgi with pidfile /var/run/spawn-fcgi.pid
    # spawn-fcgi一定要带-P参数才会生成pid文件,默认是没有的
    start program = "/usr/bin/spawn-fcgi -a 127.0.0.1 -p 8081 -C 10 -u userxxx -g groupxxx -P /var/run/spawn-fcgi.pid -f /usr/bin/php-cgi"
    stop program = "/usr/bin/killall /usr/bin/php-cgi"
    # fast-cgi走的不是http协议,monit的protocol参数也没有cgi对应的设置,这里去掉protocol http即可。
    if failed host 127.0.0.1 port 8081 then restart
    if 3 restarts within 5 cycles then timeout
    group server
    depends on nginx

虽然在注释里有详细说明,但是我还是要再强调说明几点:

  1. start和stop的program参数里的命令必须是全路径,否则monit不能正常启动,比如killall应该是/usr/bin/killall。
  2. 对于spawn-fcgi,很多人会用它来管理PHP的fast-cgi进程,但spawn-fcgi本身也是有可能挂掉的,所以还是需要用 monit来监控spawn-fcgi。spawn-fcgi必须带-P参数才会有pid文件,而且fast-cgi走的不是http协议,monit的 protocol参数也没有cgi对应的设置,一定要去掉protocol http这项设置才管用。
  3. 进程多次重启失败monit将不再尝试重启,收到这样的通知邮件表明系统出现了严重的问题,要引起足够的重视,需要赶紧人工处理。

当然monit除了管理进程之外,还可以监控文件、目录、设备等,本文不做讨论,具体配置方式可以去参考monit的官方文档

启动、停止、重启

标准的start、stop、restart

sudo /etc/init.d/monit start
sudo /etc/init.d/monit stop
sudo /etc/init.d/monit restart

看到正确的提示信息即可,若遇到问题可以去查看配置里指定的日志文件,如/var/log/monit.log。

从我的服务器这几年的运行情况(monit发了的通知邮件)来看,nginx挂掉的事几乎没有,但apache或fast-cgi出问题的情况还是比较多见,赶快用上monit来管理你的服务器以提高服务器稳定性,跟502 Bad Gateway之类错误说拜拜吧。

附件:monit示例配置文件 (注:下载后请去掉.txt文件后缀)

Tagged as: , No Comments
6Aug/11

linux下安装ZendOptimizer支持

Posted by Nick Xu

wget http://nick.txtcc.com/nickfiles/ZendOptimizer-3.3.9-linux-glibc23-i386.tar.gz

解压后复制到/usr/lib/php5/ZendOptimizer.so

修改php.ini 加入下面的内容

zend_extension=/usr/lib/php5/ZendOptimizer.so

 

 

 

 

 

 

wget http://pecl.php.net/get/vld

wget http://www.php.net/get/php-5.2.17.tar.gz/from/cn.php.net/mirror

mv mirror php.tar.gz

 

sudo apt-get install autoconf

wget http://nick.txtcc.com/nickfiles/libxml2-2.7.2.tar.gz
tar -xzvf libxml2-2.7.2.tar.gz
cd libxml2-2.7.2
sudo ./configure
sudo make install

sudo apt-get install libmysqlclient-dev

 

 

#tar -xzf vld-0.8.0.tgz //解压
#mv vld-0.8.0 vld //重命名
#cd -R vld ../php-4.3.8/ext //拷贝vld目录到php的解压目录下的ext中
#cd php-4.3.8
#rm configure //删除configure,因为下面的buildconf会重新生成新的configure
#./buildconf //如果出现错误,就按提示加上相应的参数.
#./configure –with-mysql –with-apxs2=/usr/www/bin/apxs –enable-vld 重新检查php
#make 编译
#make install 安装

服务器必须先安装ZendOptimizer
运行Zend后的文件,查看源代码就可以看到了.

3Aug/11

Nginx CommandLine Starting, Stopping, and Restarting

Posted by Nick Xu

Starting Nginx

Nginx is invoked from the command line, usually from /usr/bin/nginx.

Basic Example of Starting Nginx

/usr/bin/nginx

Advanced Example of Starting Nginx

/usr/bin/nginx -t -c ~/mynginx.conf -g "pid /var/run/nginx.pid; worker_processes 2;"

 

Options

Nginx has only a few command-line parameters. Unlike many other software systems, the configuration is done entirely via the configuration file (imagine that).

-c </path/to/config> Specify which configuration file Nginx should use instead of the default.

-g Set global directives. (version >=0.7.4)

-t Don't run, just test the configuration file. nginx checks configuration for correct syntax and then try to open files referred in configuration.

-s signal Send signal to a master process: stop, quit, reopen, reload. (version >= 0.7.53)

-v Print version.

-V Print nginx version, compiler version and configure parameters.

-p prefix Set prefix path (default: /usr/local/nginx/). (version >= 0.7.53)

-h,-? Print help.

Stopping or Restarting Nginx

There are two ways to control Nginx once it's already running. The first is to call Nginx again with the -s command line parameter. For example,

 /usr/bin/nginx -s stop

will stop the Nginx server. (other '-s' options are given in the previous section)

The second way to control Nginx is to send a signal to the Nginx master process.. By default nginx writes its master process id to /usr/local/nginx/logs/nginx.pid. You can change this by passing parameter with ./configure at compile-time or by using pid directive in the configuration file. Here's how to send the 'QUIT' (Graceful Shutdown) signal to the Nginx master process:

 kill -QUIT $( cat /usr/local/nginx/logs/nginx.pid )

The master process can handle the following signals:

TERM, INT Quick shutdown
QUIT Graceful shutdown
KILL Halts a stubborn process
HUP Configuration reload
Start the new worker processes with a new configuration
Gracefully shutdown the old worker processes
USR1 Reopen the log files
USR2 Upgrade Executable on the fly
WINCH Gracefully shutdown the worker processes

There's no need to control the worker processes yourself. However, they support some signals, too:

TERM, INT Quick shutdown
QUIT Graceful shutdown
USR1 Reopen the log files

Loading a New Configuration Using Signals

Nginx supports a few signals that you can use to control it's operation while it's running.

The most common of these is 15, which just stops the running process:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      2213  0.0  0.0   6784  2036 ?        Ss   03:01   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf

The more interesting option however, is being able to change the nginx configuration on the fly (notice that we test the configuration prior to reloading it):

2006/09/16 13:07:10 [info]  15686#0: the configuration file /etc/nginx/nginx.conf syntax is ok
2006/09/16 13:07:10 [info]  15686#0: the configuration file /etc/nginx/nginx.conf was tested successfully
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      2213  0.0  0.0   6784  2036 ?        Ss   03:01   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf

What happens is that when nginx receives the HUP signal, it tries to parse the configuration file (the specified one, if present, otherwise the default), and if successful, tries to apply a new configuration (i.e. re-open the log files and listen sockets). If successful, nginx runs new worker processes and signals graceful shutdown to old workers. Notified workers close listen sockets but continue to serve current clients. After serving all clients old workers shutdown. If nginx couldn't successfully apply the new configuration, it continues to work with an old configuration.

RequestForReviewCategory -- (Request For Review: Just What Happens With The Worker Processes at a HUP? -Olle)

Upgrading To a New Binary On The Fly

If you need to replace nginx binary with a new one (when upgrading to a new version or adding/removing server modules), you can do it without any service downtime - no incoming requests will be lost.

First, replace old binary with a new one, then send USR2 signal to the master process. It renames its .pid file to .oldbin (e.g. /usr/local/nginx/logs/nginx.pid.oldbin), then executes a new binary, which in turn starts a new master process and the new worker processes:

: PID  PPID USER    %CPU   VSZ WCHAN  COMMAND
33126     1 root     0.0  1164 pause  nginx: master process /usr/local/nginx/sbin/nginx
33134 33126 nobody   0.0  1368 kqread nginx: worker process (nginx)
33135 33126 nobody   0.0  1380 kqread nginx: worker process (nginx)
33136 33126 nobody   0.0  1368 kqread nginx: worker process (nginx)
36264 33126 root     0.0  1148 pause  nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36266 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36267 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)

At this point, two instances of nginx are running, handling the incoming requests together. To phase the old instance out, you have to send WINCH signal to the old master process, and its worker processes will start to gracefully shut down:

: PID  PPID USER    %CPU   VSZ WCHAN  COMMAND
33126     1 root     0.0  1164 pause  nginx: master process /usr/local/nginx/sbin/nginx
33135 33126 nobody   0.0  1380 kqread nginx: worker process is shutting down (nginx)
36264 33126 root     0.0  1148 pause  nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36266 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36267 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)

After some time, old worker processes all quit and only new worker processes are handling the incoming requests:

: PID  PPID USER    %CPU   VSZ WCHAN  COMMAND
33126     1 root     0.0  1164 pause  nginx: master process /usr/local/nginx/sbin/nginx
36264 33126 root     0.0  1148 pause  nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36266 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36267 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)

At this point you can still revert to the old server because it hasn't closed its listen sockets yet, by following these steps:

  • Send HUP signal to the old master process - it will start the worker processes without reloading a configuration file
  • Send QUIT signal to the new master process to gracefully shut down its worker processes
  • Send TERM signal to the new master process to force it quit
  • If for some reason new worker processes do not quit, send KILL signal to them

After new master process quits, the old master process removes .oldbin suffix from its .pid file, and everything is exactly as before the upgrade attempt.

If an update is successful and you want to keep the new server, send QUIT signal to the old master process to leave only new server running:

: PID  PPID USER    %CPU   VSZ WCHAN  COMMAND
: 36264     1 root     0.0  1148 pause  nginx: master process /usr/local/nginx/sbin/nginx
: 36265 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
: 36266 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
: 36267 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)

   
site
site