自动监测和重启 FastCGI 服务

昨天有个服务器出了点小问题,PHP FastCGI 进程无缘无故就死在那里了,造成 Nginx 不能和 FastCGI 通信,不能解析 PHP 页面,只能看到 Nginx 的 默认 HTML 页面。登录到服务器检查日志也没有找到原因,重启 FastCGI 后恢复正常。服务器上装了 monit,如果服务关闭的话会自动重启,但是这里 FastCGI 服务并没有关闭,只不过由于某种原因不能和 Nginx 通信,所以 monit 误认为 FastCGI 运行正常没有执行重启 FastCGI 的命令。

今天写了一个 Python 脚本用来后台监测 nginx 的日志,如果在日志里发现 111: Connection refused 或者 104: Connection reset by peer 等错误就 kill 掉所有 php-cgi 进程后重启服务。程序有几个地方需要说明:

1、如果不先 kill 直接运行 /etc/init.d/php-cgi restart 重启服务有时候不管用,因为这时候 php-cgi 只是驻留在内存里的死进程而而已不能执行任何命令,所以需要 kill 全部 php-cgi 进程后再启动;
2、读 nginx 的 log 文件的时候要小心,log 文件通常很大,如果用 python 的普通读文件函数会把整个文件读出来后再处理,速度很慢,也会占用大量内存,所以最好用 tail 截取文件,我们只需要分析最后部分(也是最近)的记录即可;
3、程序通过 /var/run/php_cgi.pid 来判断 PHP FastCGI 是否正在运行,通过 /var/log/nginx/error.log 来判断 Nginx/FastCGI 是否工作正常,每600秒检查一次,如果工作不正常 sleep 2秒后重启 php-cgi;
4、本程序可扩展到重启其他服务,比如通过 /var/run/lighttpd.pid 来判断 lighttpd 是否需要重启;
5、程序中 daemonize 函数来自 Python Cookbook(O’Reilly ) 一书。

程序使用

拷贝下面代码做一定修改以后保存为 checkphpcgi,增加文件可执行权限后用 root 运行程序:

# chmod +x checkphpcgi

# ./checkphpcgi
usage: ./checkphpcgi start|stop|restart

# ./checkphpcgi start

如果想要停止程序:

继续阅读 »

在 Python 中使用 difflib 比较字符串

用 Shell 写程序还是不方便,今天用 Python 把昨天写的 Bash 脚本重写了,遇到两个关于字符串的个小问题:

1、做个类似 diff 工具的效果,大致指出两个字符串的不同之处,这个可以用 difflib 模块解决。

!/usr/bin/python
import difflib

text1 = """http://www.vpsee.com is a website which is dedicated for 
building scalable websites on cloud platforms. The keywords are: Linux, Mac,
Cloud Computing, C, Python, MySQL, Nginx, VPS, Performance, Scalability,
Architecture, ..., etc. Have fun!"""
text1_lines = text1.splitlines()

text2 = """http://VPSee.com is a website which is dedicated for 
building scalable websites on cloud platforms. The keywords are: Linux, Mac,
Cloud Computing, C, Python, MySQL, Nginx, VPS, Performance, Scalability,
Programming, Optimisation, Architecture, ... , etc. Have fun !"""
text2_lines = text2.splitlines()

d = difflib.Differ()
diff = d.compare(text1_lines, text2_lines)
print '\n'.join(list(diff))

程序运行结果如下:

- http://www.vpsee.com is a website which is dedicated for 
?        ^^^^^^^

+ http://VPSee.com is a website which is dedicated for 
?        ^^^

  building scalable websites on cloud platforms. The keywords are: Linux, Mac,
  Cloud Computing, C, Python, MySQL, Nginx, VPS, Performance, Scalability,
- Architecture, ..., etc. Have fun!
+ Programming, Optimisation, Architecture, ... , etc. Have fun !

2、如何比较两个字符串,并且忽略大小写、空白字符、TAB 制表符、换行等。这个很容易解决,把字符串转换成小写后 split,然后以空格为分隔符 join 在一起。

继续阅读 »

用 Shell 脚本访问 MySQL 数据库

下午写了一个简单的 bash 脚本,用来测试程序,输入一个测试用例文件,输出没有通过测试的用例和结果,然后把结果保存到数据库里。如何在 bash 脚本里直接访问数据库呢?既然在 shell 里可以直接用 mysql 命令操作数据库,那么在 shell script 里也应该可以通过调用 mysql 来操作数据库。比如用下面的 bash shell 脚本查询数据库:

Bash

#!/bin/bash

mysql -uvpsee -ppassword test << EOFMYSQL
select * from test_mark;
EOFMYSQL

如果需要复杂的数据库操作的话不建议用 shell 脚本,用 Perl/Python/PHP 操作数据库很方便,分别通过 Perl DBI/Python MySQLdb/PHP MySQL Module 接口来操作数据库。这里再给出这三种不同语言连接、查询数据库的简单例子(为了简单和减少篇幅删除一些不必要的代码):

Perl

#!/usr/bin/perl
use DBI;

$db = DBI->connect('dbi:mysql:test', 'vpsee', 'password');
$query = "select * from test_mark";
$cursor = $db->prepare($query);
$cursor->execute;
while (@row = $cursor->fetchrow_array) {
        print "@row\n";
}

Python


继续阅读 »

修正 Django Step by Step 的一些例子

周末看了 limodouDjango Step by Step 入门教程,写得很棒,通俗易懂,谢谢先。Django 发展太快,现在已是 1.0.2 版本,可惜 Django Step by Step 上面的例子还是 0.9x 版本,所以编译运行上面的例子时会出现一些问题,主要是一些兼容问题,列出来以供参考:

第六讲

3、编辑 wiki/models.py


pagename = models.CharField(maxlength=20, unique=True)

在 Django 1.0.2 中,上面的 maxlength 应改为:

max_length

6、修改 wiki/views.py


c = Context({‘pagename’:page.pagename, ‘content’:content})

上面代码输出 content 时会把 “< >” 等字符转义输出成 “< &gt”,这个时候需要关闭自动转义,以便 content 输出 HTML 代码。改成如下:

c = Context({'pagename':page.pagename,'content':content},autoescape=False)

还有一种方法就是在 wiki/page.html 里改成:

{% autoescape off %}

{{ content }}

{% endautoescape %}

第七讲

3、修改 address/models.py


gender = models.CharField(‘性别’, choices=((‘M’, ‘男’), (‘F’, ‘女’)),
maxlength=1, radio_admin=True)

注意上面的 radio_admin=True 已经在 Django 1.0.2 中不适用了,不能写在 field 里,admin 和 model分离了,把 models.py 的全部内容用以下代码替换:

from django.db import models

# Create your models here.
class Address(models.Model):
        name = models.CharField('Name', max_length=6, unique=True)
        gender = models.CharField('Sex', choices=(('M', 'Male'), ('F', 'Female')), max_length=1)
        telphone = models.CharField('Telphone', max_length=20)
        mobile = models.CharField('Cellphone', max_length=11)
        room = models.CharField('Room', max_length=10)

from django.contrib import admin

class AddressAdmin(admin.ModelAdmin):
        model=Address
        radio_fields = {'gender':admin.VERTICAL}

admin.site.register(Address, AddressAdmin)

6、修改 urls.py

from django.conf.urls.defaults import *

urlpatterns = patterns(”,

# Uncomment this for admin:
(r’^admin/’, include(‘django.contrib.admin.urls’)),
)

新的变化已经在 Django 1.0.2 生成的默认 url.py 里了,只需要把 urls.py 里面的 comment 前面的 # 去掉就可以了。

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

# Uncomment the next line to enable the admin:
     (r'^admin/(.*)', admin.site.root),

7、增加超级用户

manage.py shell
>>> from django.contrib.auth.create_superuser import createsuperuser
>>> createsuperuser()

只需要改成下面一条命令:

./manage.py createsuperuser

以上修正在 Django 1.0.2 + Python 2.5.1 + Mac OS X 10.5.7 上调试通过。