| Subcribe via RSS

postfix 发信邮件服务器设置

11月 6th, 2008 | 2 Comments | Posted in Linux, Postfix < by Martian Guo >

以下设置针对需要大量外发邮件的服务器,如果你的邮件服务器是专门用来发垃圾邮件的,那么下面这些设置恐怕也没有太多作用,下面的这些设置也仅仅是让我们发出的邮件更符合发送规则,当然了,如果滥发,不管你设置怎么样的策略,一旦超过了邮件运营商的限制,封你还是没商量的。

安装djbdns
djbdns 是一個由Qmail 的作者所设计的一个轻量级DNS server,我们使用它提供的dnscache服务作为本地邮件发送的DNS查询缓存,用于加快邮件的转发速度。
ucspi-tcp软件包由一组工具组成。它们用来简单的建立客户机-服务器tcp后台程序。TcpServer是一个比inetd安全性更好的选择。它内建有基于规则的连接控制,能完善地在达到预定义的最大系统负载时将连接推迟

shell>wget http://www.qmailtoaster.org/download/develop/ucspi-tcp-toaster-0.88-1.3.5.src.rpm
shell>wget http://www.qmailtoaster.org/download/develop/daemontools-toaster-0.76-1.3.3.src.rpm
shell>wget http://www.qmailtoaster.org/download/develop/djbdns-1.05-1.0.5.src.rpm
Shell >yum -y install rpm-build
shell>rpm -vih daemontools-toaster-0.76-1.3.3.src.rpm
shell>rpm -ivh ucspi-tcp-toaster-0.88-1.3.5.src.rpm
shell>rpm -ivh djbdns-1.05-1.0.5.src.rpm
shell>cd  /usr/src/redhat/SPECS
shell>rpmbuild --bb daemontools-toaster.spec
shell>rpmbuild --bb ucspi-tcp-toaster.spec
shell>rpmbuild --bb djbdns.spec
shell>cd  /usr/src/redhat/RPMS/i386
shell>rpm --ivh daemontools-toaster-0.76-1.3.3.i386.rpm  ucspi-tcp-toaster-0.88-1.3.5.i386.rpm
shell>rpm --ivh djbdns-1.05-1.0.5.i386.rpm djbdns-localcache-1.05-1.0.5.i386.rpm
shell>rm {/var/djbdns/,/}service/{axfrdns,tinydns}               // 我们只需要dnscache 服务
shell>echo -n 10000000 >/var/djbdns/dnscache/env/CACHESIZE  // 修改DNS内存cache大小10M
shell>echo -n 30000000 >/var/djbdns/dnscache/env/DATALIMIT
shell>echo nameserver 127.0.0.1 >/etc/resolv.conf
shell>/etc/init.d/djbdns start

安装domainkey
雅虎的这项技术被称之为“DNS端的电子签名(DomainKeys)”,专门对付各种各样经过改头换面的垃圾邮件。垃圾邮件经常通过改动电子邮件的发送着对用户进行欺骗,用户往往会误以为这不是垃圾邮

件,因而打开查看的可能性加大。雅虎的“DomainKeys”允许接受电子邮件的系统对邮件进行检查,以确定邮件发送者的身份是不是假的。“DomainKeys”通过使用加密技术完成电子邮件发送者身份的
验证。外发的邮件通过私人密码进行数字签名,而接受电子邮件的系统则使用公共密码对签名进行核实。

shell>wget http://nchc.dl.sourceforge.net/sourceforge/dk-milter/dk-milter-1.0.1.tar.gz
shell>yum -y install sendmail-devel                       // dk-milter编译需要
shell>yum -y install csh
shell>tar -zxvf dk-milter-1.0.1.tar.gz
shell>cd dk-milter-1.0.1
shell>sh Build -c
shell>sh Buld install
shell>cd dk-filter
shell>chmod +x  gentxt.csh
shell>./gentxt.sh  default  hiadmin.com                     // 保存输出的文字
shell>cp default.private  /etc/postfix/hiadmin.com.key.pem   // 拷贝私钥到/etc/postfix
shell>chmod 600  /etc/postfix/hiadmin.com.key.pem
shell>/usr/bin/dk-filter  -A  -l  -p inet:8891@localhost  -d  hiadmin.com  \  // 启动dk-filter签名服务
                     -s  /etc/postfix/hiadmin.com.key.pem  -S  default

dk-filter 命令说明:

-a peerlist   # 那些 host 不做 DKIM check
-A               # dk-filter 死掉時自動重啟
-b modes         # s (singer) / v (verify) 預設為 sv
-c canon         # 預設是 simple (表頭不改變),
                 # 另外為 relaxed (表頭可能修正,去除空白,不換行等等)
-C config        # 設定檔,詳見下述
-d domlist       # 要 sign 的 domain 列表,以逗號區隔
-D               # 一併 sign -d 之下 domain 的 sub-domain
-f               # 前台執行
-h               # 會在 Mail Header 中加入 X-DomainKeys 資訊
-H               # DomainKey-Signature 中說明 sign 的 header 資訊
-i ilist         # 只做 sign, 不做 verify,預設為 127.0.0.1
-I elist         # 透過此主機轉信之來源做 sign,不做 verify
-l               # log 必要訊息到 maillog
-m mtalist       # MTA 名字,也就是 DaemonPortOptions 中的 Name,預設是全部
-M macrolist     # MTA macros which enable signing
-o hdrlist       # 哪些 Header 不 sign,Ex: -o to,subject,date , From 一定要 sign
-P pidfile       # pid file 路徑
-s keyfile       # private key
-S selector      # selector,會以 selector._domainkey.Domain 進行 type=TXT 查詢
-u userid        # 以什麼身份執行
-V               # 版本資訊

将以下公匙记录到DNS Server 上
例:

default._domainkey   IN  TXT "k=rsa; t=y; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALxzF8xb/uXCnC58p/kCLtxW5tm/xrR905O6X0C6Ydohw574EsimbCaeqsCtqm+3IKyrnBj3JeShbEGBJN5HEF0CAwEAAQ==" ;

----- DomainKey default for hiadmin.com

分别建立记录 :

default._domainkey.hiadmin.com
  _domainkey.hiadmin.com

设置一条txt记录 :

k=rsa; t=y; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALxzF8xb/uXCnC58p/kCLtxW5tm/xrR905O6X0C6Ydohw574EsimbCaeqsCtqm+3IKyrnBj3JeShbEGBJN5HEF0CAwEAAQ==

设置 SPF
Sender Policy Framework。SPF可以防止别人伪造你来发邮件,是一个反伪造性邮件的解决方案。当你定义了你的domain name的SPF记录之后,接收邮件方会根据你的SPF记录来确定连接过来的IP地址是

否被包含在SPF记录里面,如果在,则认为是一封正确的邮件,否则则认为是一封伪造的邮件。
例:

hiadmin.com.    466    IN    TXT     "v=spf1 ip4:61.xx.xx.xx ip4:61.xx.xx.xx mx ~all"

61.152.246.24-25 和 MX 记录中设置的主机为信任邮件发送服务器,其他全部不信任
修改 /etc/postfix/main.cf
增加

smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

测试
发一封信到google 检查邮件头是否包含了 DomainKey-Signature
如下所示

Received-SPF: pass (google.com: domain of public@hiadmin.com designates 61.xxx.xxx.xx as permitted sender) client-ip=61.xxx.xxx.xxx;
DomainKey-Status: good (test mode)
Authentication-Results: mx.google.com; spf=pass (google.com: domain of public@hiadmin.com designates 61.xxx.xxx.xxx as permitted sender) smtp.mail=public@hiadmin.com;

domainkeys=pass (test mode) header.From=public@hiadmin.com
Received: from pc00497 (unknown [211.xxx.xxx.xxx])
by hiadmin.com (Postfix) with ESMTPA id 980912580D1
for <martian2008@gmail.com>; Mon, 27 Oct 2008 17:46:09 +0800 (CST)
DomainKey-Signature: a=rsa-sha1; s=default; d=hiadmin.com; c=simple; q=dns;
b=Q/1un1hpfsZP7zs+0rPsVzb3DFtpIaaGkPL2aSEjmQL7cx9Fhn8EtYLz1J8p7xKLt
lItLJN609cDDER5kjCJKg==

设置milter-limit 控制postfix 发送频率
milter-limit 是Sendmail 的一个filter,用于限制用户发邮件的数量,以防止邮件服务器
被非法用于发送垃圾邮件,它可以实现对指定的客户端IP、收件人、发件人进行限制。该
filter可以不做任何修改即可用于Postfix中
到www.snertsoft.com 下载 (需要注册)
http://www.snertsoft.com/download/milter-limit-0.13.tar.gz
http://www.snertsoft.com/download/libsnert-current.tar.gz

shell>yum install db-devel
shell> tar -zxvf libsnert-current.tar.gz
shell> tar -zxvf milter-limit-0.13.tar.gz
shell>cd com/snert/src/lib
shell> ./configure --with-db=/usr            # 检查是否有Berkeley DB 支持
shell> make build
shell> cd ../milter-limit
shell> ./configure --enable-run-user=postfix --enable-run-group=postfix
shell> make build
shell> make install

修改 /etc/postfix/main.cf

smtpd_milters = unix:/var/run/milter/milter-limit.socket  # 如果有多个milter 用逗号分隔

过滤规则:
milter-limit 的规则文件写在/etc/mail/access 中,然后用makemap 来生成
makemap hash /etc/mail/access.db < /etc/mail/acces
# 请注意access.db权限不能为可执行,并且可以让postfix 用户能够读取
/etc/mail/access 文件的规则包括

milter-limit-Connect:       # 客户端连接IP
milter-limit-From:          # 发件人地址
milter-limit-To:             # 收件人地址
milter-limit-Auth:          # 通过SMTP认证的发件人

支持以下匹配规则
[network/cidr]limit        无类域间路由
!pattern!limit              简单文本匹配
/regex/limit               POSIX正则表达式

limit:时间单位可以是秒(s)、分钟(m)、小时(h)、天(d)、星期(w)
格式: messages ‘/’ time [unit]

过滤规则例子:

milter-limit-Connect:80.94              [80.94.96.0/20]-1/1   500/3d          # 冒号之间不能有空格

# 80.94开头的网段:从地址80.94.96.0/20 (80.94.96.0- 80.94.111.255) 不受限制,其他地址限制在 3天内最多发送500封邮件

milter-limit-To:163.com                                        100/1h

# 发往163.com域限制在1小时发送100封邮件
策略:
启动参数: policy=reject

none            什么都不做
tag              给邮件标题打标签   启动参数:subject-tag=[SPAM]
quarantine     将邮件送入隔离队列(不发送,需要通过命令激活).
later            不接收邮件,提示发送端发送延迟消息,邮件仍旧在发送端的队列中,稍候重试
reject           拒绝邮件(默认值)
discard         直接丢弃

启动命令

/usr/local/sbin/milter-limit  verbose=all policy=later -start

如果需要调试使用 verbose=all 在/var/log/maillog 中查看日志
其他参数用 -help 参数查看
postfix 基本参数设置

smtp_skip_4xx_greeting = yes
smtp_skip_5xx_greeting = yes
default_destination_concurrency_limit = 2 #同一IP并发连接
initial_destination_concurrency = 2
smtp_helo_name = mail.hiadmin.com        # 本机对外真实域名
smtpd_milters = inet:localhost:8891,unix:/var/run/milter/milter-limit.socket   
#使用sendmail 的milter-limit 插件来实现对指定的客户端IP、收件人、发件人进行限制
阅读内文 Tags: , , , , ,

lighttpd 配置reload问题

10月 28th, 2008 | 3 Comments | Posted in LightHttpd < by Michael Field >

lighttpd1.4.x
默认情况下无法使用reload功能,即kill -HUP “PID OF LIGHTTPD” ?
在网上搜索了一番,结果发现可以使用lighttpd的sbin目录下的lighttpd-angel来实现这个reload功能;

方法如下:

/pathtolighttpd/sbin/lighttpd-angel -D -f /pathtolighttpd/conf/lighttpd.conf

-D 表示不在后台执行;(默认是在后台执行的)
而这个reload功能一定是要-D参数才能获得支持;

这样新问题就出现;一般管理服务器都是远程登录的ssh中执行&指令的话会导致退出登录ssh后无响应;
可以通过调整延时时间来设定,但毕竟使用起来有点麻烦;

最后执行在前面增加一个nohup工具,总算问题解决了,但毕竟还不完美;

nohup /pathtolighttpd/sbin/lighttpd-angel -D -f /pathtolighttpd/conf/lighttpd.conf &

然后再修改lighttpd的service脚本如下:

...
prog="lighttpd"
lighttpd="/pathtolighttpd/sbin/lighttpd-angel" #多增加一个lighttpd-angel的变量
lighttpd1="/pathtolighttpd/sbin/lighttpd"
RETVAL=0

start() {
        echo -n $"Starting $prog: "
        #以lighttpd-angel启动,去掉daemon函数,不然会启动失败,无法和nohup一起使用;
        /usr/bin/nohup $lighttpd -D -f $LIGHTTPD_CONF_PATH 2 >/dev/null &
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
        return $RETVAL
}

stop() {
        echo -n $"Stopping $prog: "
        killproc $lighttpd1 #杀进程的依旧是lighttpd
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
        return $RETVAL
}

reload() {
        echo -n $"Reloading $prog: "
        killproc $lighttpd -HUP
        RETVAL=$?
        echo
        return $RETVAL
}
....

这样修改完发现每次start的时候不能正常显示[OK];lighttpd-angel开启的时候会调用lighttpd主程序;这样就是lighttpd和lighttpd-angel一起运行,这个也是执行reload必须的;

如果有更好的办法,请留言讨论!
貌似lighttpd1.5.x会解决这个问题。

阅读内文 Tags: , ,

SQUID动态URL日志不完整的问题

10月 17th, 2008 | 2 Comments | Posted in Squid < by ready >

SQUID 2.6.STABLE6

logformat combined %>a %ui %un [%tl] "%rm %ru  HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh %tr
access_log /home/squid/log/access.log combined

问题:
当访问的URL为:http://www.hiadmin.com/xxx.php?codetin=pig时:
日志为:

222.68.179.90 - - [18/Oct/2008:00:52:00 +0800] "GET http://www.hiadmin.com/xxx.php?  HTTP/1.1" 304 299 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)" TCP_IMS_HIT:NONE 0

URL后面的:codetin=pig 丢失了。

解决方法:
在squid.conf中添加:

strip_query_terms off

重新reload squid,日志正常。

strip_query_terms
默认为开启。是为了保护用户的隐私,而不在日志中记录“?”后面的参数。

阅读内文

虚拟机硬盘大小调整

10月 15th, 2008 | No Comments | Posted in Xen < by Johnny Woo >

1.情况说明
使用xen虚拟机时创建的虚拟机磁盘是2G大小
在运行一段时间之后,发现磁盘空间接近满
需要对已有的磁盘空间进行扩容
2.遇见问题
一开始我想使用dd直接将原始文件dump到一个更大的文件中
dd if=/xen/centos/centos.img of=/xen/centos/centos2.img bs=1M count=4096
但是导出之后centos2.img仍旧只有2G大小.
然后我先建立一个4G的空文件.再将原始文件导入
dd if=/dev/zero of=/xen/centos/centos2.img bs=1M count=4096
查看文件大小.centos2.img已经是4G了.接着倒入原始文件
dd if=/xen/centos/centos.img of=/xen/centos/centos2.img bs=1M count=4096
执行后centos2.img仍旧变回了2G.

3.解决方法
使用seek参数,从原有的centos.img文件的末尾bs*seek处(2048*1M)开始.写入空内容,共写入count*bs大小(2048*1M)
dd if=/dev/zero of=/xen/centos/centos.img bs=1M count=2048 seek=2048
查看centos.img.发现文件变为4G
重新打开虚拟机,登录系统后查看文件系统
df -h
返回的分区大小仍旧是2G.说明文件系统还没有变大
重新设定设备文件分区大小为4G
resize2fs /dev/sda1 4096M

阅读内文 Tags:

lighttpd控制fastcgi进程数

9月 26th, 2008 | 2 Comments | Posted in LightHttpd < by Johnny Woo >

lighttpd默认的fastcgi产生数是8
如果要增加或者减少fastcgi进程数
就需要修改配置文件,进行定制

fastcgi.server             = ( ".php" =>
                               ( "localhost" =>
                                 (
                                   "socket" => "/var/run/lighttpd/php-fastcgi.socket",
                                   "bin-path" => "/usr/local/php/bin/php-cgi",
                                    "min-procs" => 1,
                                    "max-procs" => 1,
                                    "bin-environment" => (
                                        "PHP_FCGI_CHILDREN" => "3",
                                    ),
                                     "bin-copy-environment" => (
                                        "PATH", "SHELL", "USER"
                                   ),

                                    "idle-timeout" => 20
                                 )
                               )
                            )

就是PHP_FCGI_CHILDREN参数.控制fastcgi进程的产生数
有一点要注意
如果使用ea,xcache或者APC等等OPCODE加速器
一定要将max-procs设置为1
否则可能会产生问题.

阅读内文

PHP与Perl操作Memcached速度差异比较

9月 26th, 2008 | 4 Comments | Posted in PHP, Perl, memcached < by Johnny Woo >

由于最近在进行memcached方面的工作
在性能测试中
使用了php以及perl对memcached进行操作
结果发现php与perl对memcached操作的性能
差异大约在40~50%之间
以下是测试脚本
所作的操作一样.使用1k的数据重复512000次.
总共插入memcached 500M的数据

php操作脚本

<?php
ini_set("memcache.hash_function","crc32");
$memcache = new Memcache;
$memcache->addServer('localhost', 30001);
$memcache->flush();
for($i=0;$i<512000;$i++){
        
$memcache->set($i,
"共1k的填充数据",0,1000);
}
?>

接着是perl脚本

#!/usr/bin/perl
use Cache::Memcached();
$memcache=new Cache::Memcached{'servers'=>["localhost:30001"]};
$memcache->flush_all();
for($i=0;$i<512000;$i++){
    
$memcache->set($i,
"共1k的填充数据");
}
$memcache->disconnect_all();

从代码行数上来看.两者也几近一致
但是测试结果却是大相径庭
我们在linux下使用time对执行进行计时
3次执行结果如下

[root@lenovo5 ~]# time ./test1k.pl
real    1m2.265s
user    0m36.427s
sys     0m17.114s
[root@lenovo5 ~]# time ./test1k.pl
real    1m2.814s
user    0m36.380s
sys     0m17.463s
[root@lenovo5 ~]# time ./test1k.pl
real    1m13.684s
user    0m44.603s
sys     0m18.366s
[root@lenovo5 ~]# time php ./test1k.php
real    0m38.055s
user    0m11.768s
sys     0m13.891s
[root@lenovo5 ~]# time php ./test1k.php
real    0m38.892s
user    0m12.416s
sys     0m14.044s
[root@lenovo5 ~]# time php ./test1k.php
real    0m38.955s
user    0m12.430s
sys     0m13.088s

差异很明显.perl执行需要1分左右而php只需要40秒不到
就是php的执行比perl的大约快40%
分析之后有几个因素的可能
1.perl的字串处理速度较慢.我们看到perl版本的set中不需要加入长度参数.这样每次插入可能都会需要set函数去判断传入的字串长度.这样可能较慢.但是随后我们发现php的set虽然有长度参数.但是这个参数并非是强制性的.比如我参数写了1000,实际字串有1200.结果将会是插入1200长度的字串,而并没有截断.所以这一点不是非常站得住脚
2.perl的扩展与php扩展实现方式不同.php的memcache客户端是PECL.也就是C扩展,而perl的扩展实现很有可能还是perl.所以会有性能差异.

阅读内文

使用memcached分布式保存PHP session

9月 19th, 2008 | 1 Comment | Posted in PHP, memcached < by Johnny Woo >

安装完memcached之后
参考安装memcached客户端
在php.ini中
将session.save_handler 修改为memcache,并修改save_path指向memcached的地址和端口即可
session.save_handler = memcache
session.save_path = tcp://127.0.0.1:10001

Memcache的PECL这个扩展非常强大
可以支持failover以及分布存储
使用方法很讲但.
只需要在session.save_path的参数列表中
使用逗号分隔各个memcached服务器
则保存的session会经过hash之后保存到各个mc服务器中
而hash的算法.memcache支持两种,crc32以及fnv
memcache.hash_function= {crc32,fnv}
文档中很少有提到fnv算法的,据说其散列要比crc32更好
但是我通过以下小小的程序实验之后,发现仍旧是crc32的散列算法分布的更加平均.

<?php
ini_set("memcache.hash_function","crc32");
$memcache = new Memcache;
$memcache1 = new Memcache;
$memcache2 = new Memcache;
$memcache->addServer('localhost', 11211);
$memcache->addServer('localhost', 11212);
$memcache->flush();
$memcache1->connect('localhost',11211);
$memcache2->connect('localhost',11212);
$fp1 = fopen("mem1.txt","w");
$fp2 = fopen("mem2.txt","w");
for($i=0;$i<1000;$i++){
        
$memcache->set($i,$i,0,1000);
        
fwrite($fp1,$memcache1->get($i)." ");
        
fwrite($fp2,$memcache2->get($i)." ");
}
fclose($fp1);
fclose($fp2);
?>

接着我就session的保存进行了测试
我开了3个memcached进程进行测试

<?php
ini_set("memcache.hash_function","fnv");
ini_set("error_reporting","E_CORE_ERROR");
$memcache1 = new Memcache;
$memcache1->connect('localhost',11211);
$memcache1->flush();
 
$memcache2 = new Memcache;
$memcache2->connect('localhost',11212);
$memcache2->flush();
 
$memcache3 = new Memcache;
$memcache3->connect('localhost',11213);
$memcache3->flush();
$fp1 = fopen("mem1.txt","w");
$fp2 = fopen("mem2.txt","w");
$fp3 = fopen("mem3.txt","w");
for($i=0;$i<1000;$i++){
        
session_start();
        
$ssid=session_id();
        
echo $ssid;
        
session_register("id");
        
$_SESSION["id"]=$ssid;
        
session_write_close();
        
fwrite($fp1,$memcache1->get($ssid)." ");
        
fwrite($fp2,$memcache2->get($ssid)." ");
        
fwrite($fp3,$memcache3->get($ssid)." ");
        
//session_destroy();
}
fclose($fp1);
fclose($fp2);
fclose($fp3);
?>

比较奇怪的是.memcached2一般都会不被选中
而1,3的内容是一致的.可能是为了failover
而当我把1,3关闭一台后.2中将会出现内容,说明memcached2是正常工作的
而不论我的散列算法使用crc32还是fnv
这种现象都存在
最后我发现.这个测试程序存在问题
因为在session_write_close之后.整个程序的session都是唯一的了.
也就是虽然循环了这么多次.里面包含了session_destroy调用.但是返回的session id都是同样的
这就导致了两个文件中的内容一致而另一个文件中没有内容
基于此点
我只能分次调用脚本,脚本修改如下

<?php
ini_set("memcache.hash_strategy","consistent");
ini_set("memcache.hash_function","crc32");
ini_set("error_reporting","E_CORE_ERROR");
ini_set("memcache.allow_failover","0");
$memcache1 = new Memcache;
$memcache1->connect('localhost',10001);
$memcache1->flush();
 
$memcache2 = new Memcache;
$memcache2->connect('localhost',10002);
$memcache2->flush();
 
$memcache3 = new Memcache;
$memcache3->connect('localhost',10003);
$memcache3->flush();
$fp1 = fopen("mem1.txt","a+");
$fp2 = fopen("mem2.txt","a+");
$fp3 = fopen("mem3.txt","a+");
    
session_start();
    
$ssid=session_id();
    
echo $ssid."\n";
    
session_register("id");
    
$_SESSION["id"]=$ssid;
    
//session_destroy();
    
session_write_close();
    
fwrite($fp1,$memcache1->get($ssid)." ");
    
fwrite($fp2,$memcache2->get($ssid)." ");
    
fwrite($fp3,$memcache3->get($ssid)." ");
    
session_destroy();
fclose($fp1);
fclose($fp2);
fclose($fp3);
?>

然后再shell中重复运行多次.返回的ID不同了
再打开mem*.txt文件查看
发现3个文件中,每个session会保存在其中两个文件.然后分布不同
这证明了使用memcache来保存session.一个是做到了failover.第二会按照session id来做hash分布保存

阅读内文 Tags: , , ,

lighttpd防盗链技术的一个变形

9月 18th, 2008 | No Comments | Posted in LightHttpd < by Tommy >

lighttpd 中的mod_secure_download.c模块中的防盗链技术大家已经很清楚了,但是这个模块要求会改写一些url的地址,形如:

The generated URL has to have the format:

<uri-prefix>/<token>/<timestamp-in-hex>/<rel-path> which looks like "yourserver.com/bf32df9cdb54894b22e09d0ed87326fc/435cc8cc/secure.tar.gz"

<token> is an MD5 of

   1. a secret string (user supplied)
   2. (rel-path)(starts with /)
   3. (timestamp-in-hex)

具体参考:http://trac.lighttpd.net/trac/wiki/Docs%3AModSecDownload

如果有这样的需求,要求不改变原来的下载url,而做到对某些资源进行防盗链呢?
最后我们可以这样做,增加get方法,即是把加密额的部分通过get方法传递给lighttpd的mod_secure_download.c模块
例如,
原来的url: yourserver.com/secure/secure.tar.gz
新的url:yourserver.com/secure/secure.tar.gz?credentials=fhsfhskfaskfhsakfsk2343askfskfsk

这样,我们就做到在不改变原来url的情况下又可以用到mod_secure_download.c模块的防盗链功能

下面要修改mod_secure_download.c模块的源代码,其实很简单,只要熟悉lighttpd的一些常见插件就可以在几分钟内搞定这个功能

/*
* if there is a key = md5,
* otherwise sent 403
* */
if (NULL != (get_param = (data_string *)array_get_element(p->get_params, "key"))) {
    /* too short */
    if (get_param->value->used < 2) {
con->http_status = 403;
return HANDLER_FINISHED;
    }

    md5_str = get_param->value->ptr;

    /* check if it is a md5 string */
    if ( strlen(md5_str) != 40 || !is_hex_len(md5_str, 40) ) {
con->http_status = 403;
log_error_write(srv, __FILE__, __LINE__, "ss", "key-md5 invalid:", md5_str);

return HANDLER_FINISHED;
    }
}
else{
    con->http_status = 403;

    return HANDLER_FINISHED;   
}

上面的代码就是通过get方法获得加密的字符串,然后下面的代码就是原来lighttpd中的防盗链出来流程

lighttpd的这个加密模块,我个人认为还是有点需要改进的地方
大家也看出来了,对于防盗链,这里采用的是md5单向加密的技术,但是client端向服务器发送的请求加密串是包含时间的(也正是这个时间才是我们用于判断这个url的有效时间,从而达到防盗链的目的),个人觉得可以对明文传输的时间进行一下简单的加密(当然要是可以双向的加密)

还有一点需要注意的地方,就是这个防盗链模块在lighttpd的配置文件中的lighttpd.conf加载顺序是很重要的,
一定要将这个防盗链模块放在mod_flv_streaming.c/mod_h264_streaming.c模块加载之前加载

server.modules = ( ..., "mod_secdownload",
“mod_flv_streaming”,
"mod_h264_streaming",
 ... )

不然,防盗链模块会不起作用的,因为flv/h264这些模块里面会有

con->file_finished = 1;
return HANDLER_FINISHED;
阅读内文

lighttpd支持wordpress伪静态地址

9月 12th, 2008 | 3 Comments | Posted in LightHttpd < by Johnny Woo >

以前发过nginx支持伪静态的配置
这次换了VPS之后
由于内存比较小.直接用lighttpd来做web service
当中rewrite的配置又有不同
而这次配置.让我也产生了研究rewrite以及redirect差异以及基本原理的想法
下面先给出配置

url.rewrite = (
"^/(wp-.+).*/?" => "$0",
"^/(sitemap.xml)" => "$0",
"^/(xmlrpc.php)" => "$0",
"^/(.+)/?$" => "/index.php/$1"
)

会正则的应该能看出什么意思
但是怎样生效.我觉得rewrite和redirect有相当大的差别

阅读内文

Apache 防盗链

9月 12th, 2008 | 1 Comment | Posted in Apache < by ready >

临时要求在apache中加防盗链。网上搜集了一些资料整理一下发在这里,方便以后翻阅。
关于mod_authz_host模块参看:http://doc.linuxpk.com/doc/apache/mod/mod_authz_host.html
1。通过User-Agent浏览器类型限制

SetEnvIf User-Agent ^blueapple go_out
<Directory /home/domain>
Order Allow,Deny
Allow  from all
Deny from env=go_out
</Directory>

2。通过Referer限制

SetEnvIf Referfer ^$ go_out
SetEnvIf Referfer ^http:\/\/baidu.com(\/|$)”  go_out
<Directory /home/domain>
Order Allow,Deny
Allow  from all
Deny from env=go_out
</Directory>

referer为空禁止访问。
referer为http://baidu.com限制访问。

阅读内文

lighttpd 1.5.0 测试版使用笔记

9月 9th, 2008 | 5 Comments | Posted in LightHttpd < by ready >

下载地址:http://www.lighttpd.net/download/lighttpd-1.5.0-r1992.tar.gz

lighttpd 1.5.0和lighttpd 1.4.19最大的区别在于1.5.0 增加了异步IO(AIO)的支持。在lighttpd的blog上面有一篇测试文章可以很清楚的看到在磁盘IO方面1.4.19和1.5.0的巨大差别。文章地址:http://blog.lighttpd.net/articles/2006/11/12/lighty-1-5-0-and-linux-aio

经过我们实地使用得到的数据和blog上介绍的数据是相匹配的。不过在实地使用中,当磁盘IO在进行大量读操作的同时又进行大量写操作的时候,服务器会出现死机现象。我这里只有在空白的cache节点开始提供cdn服务的前一两天才会碰到。随着缓存的文件越来越多发生的概率也越来越小。一般缓存两天以后再也没有发生过死机现象。我想这也是为什么cdn服务商会极力推荐你使用预缓存的原因吧。

对于上面提到的死机问题的解决办法是:在提供cache的开始几天里使用lighttpd 1.4.19。等缓存数据基本完成的时候再换成lighttpd 1.5.0。1.4.19由于它的io慢,死机的可能性会大大降低。我们采取这个方法后,开始缓存的几天里没有服务器死机。

软硬件环境:
服务器:dell 1950
操作系统:CentOS 5
磁盘:raid1 sata 1TB*2

跟上面lighttpd blog在磁盘方面情况类似。

阅读内文

lighttpd plugin.h代码阅读笔记

9月 9th, 2008 | No Comments | Posted in LightHttpd < by ready >

这篇文章是从别人的网站上面保存下来的,忘记那个网站了。对于原作者说声抱歉。
该文件中定义了lighttpd的模块插件结构体。此结构体大量使用了函数指针,对进一步深入了解函数指针很有现在。现在的工作是,解释结构体中每个字段的含义,用处,使用方法。搞清楚插件中几个函数的调用序列,插件中几个函数的返回值对lighttpd有什么影响。

#ifndef _PLUGIN_H_

#define _PLUGIN_H_

#include “base.h”

#include “buffer.h”

//此宏定义服务器函数的通用格式,参数为 server 类型指针,一个 指向模块定义的数据结构的void 类型指针

#define SERVER_FUNC(x) \

static handler_t x(server *srv, void *p_d)

#define CONNECTION_FUNC(x) \

static handler_t x(server *srv, connection *con, void *p_d)

#define INIT_FUNC(x) \

static void *x()

//下面四个是服务器级别的函数

#define FREE_FUNC SERVER_FUNC

#define TRIGGER_FUNC SERVER_FUNC

#define SETDEFAULTS_FUNC SERVER_FUNC

#define SIGHUP_FUNC SERVER_FUNC

//下面五个是连接级别的函数

#define SUBREQUEST_FUNC CONNECTION_FUNC

#define JOBLIST_FUNC CONNECTION_FUNC

#define PHYSICALPATH_FUNC CONNECTION_FUNC

#define REQUESTDONE_FUNC CONNECTION_FUNC

#define URIHANDLER_FUNC CONNECTION_FUNC

#define PLUGIN_DATA size_t id //这个定义的是所有模块插件的内部数据都必须有一个公共字段,这个字段的值由lighttpd统一管理,类似于一个序列值,给每个模块都定义一个ID号。

//模块插件结构体,包含的信息相当的丰富。

typedef struct {

size_t version; //一般写为 : LIGHTTPD_VERSION_ID 什么时候不一样呢。

buffer *name; /* name of the plugin */ //一般写为模块的名字 , 如 mod_skeleton

//下面这些函数指针指向的函数是要编写模块的开发人员实现的,当然,有些是可选的,有些是必须实现的。

void *(* init) (); //在加载当前模块的时候调用,但不是第一个要调用的函数。在此之前会调用 *_plugin_init 函数初始化当前模块。它是第一个实际调用的插件函数。此函数用于初始化模块内部数据结构,此内部数据结构被赋给*plugin_init中设定的data字段了。
handler_t (* set_defaults) (server *srv, void *p_d); //实际调用的第二个插件函数。此函数是配置文件解析入口。它应该传递一个选项参数列表给config_insert_values函数,并且还要检查参数是否有效,如果是无效参数,则需要给该选项参数设置默认值,或者返回错误。
handler_t (* cleanup) (server *srv, void *p_d); //最后一个调用的模块插件函数。用于清理当前模块使用的内存。它在当前模块被卸载的前一该被lighttpd调用。
/* is called … */
handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */ //每一秒都会调用的插件函数,模块如果不需要此定时器,可以忽略它。
handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */ //如果lighttpd收到SIGHUP信号,则它会调用插件中的这个函数,通知插件做相应处理。lighttpd收到这个信号时并不会退出,因而对模块来说可以忽略这个信号。这个函数的调用顺序不定,在模块被加载之后,被卸载之前的任何时刻都可能调用此函数,这依赖于用户行为,用户可能手工向lighttpd发送SIGHUP信号。

handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */ //在lighttpd 设置了 uri_raw之后被调用。uri_raw是在什么时候设置的呢?
handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */ //在lighttpd设置了uri.path 之后被调用。uri.path是在什么时候设置的呢?
handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */ //当 lighttpd 需要docroot的时候此函数被调用。 不太明白这个docroot的意思,lighttpd为什么会不定时的需要 docroot 呢?
handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path */ // 在lighttpd设置了physical.path之后被调用。
handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */ //在请求结束的时候被调用,这个时候是否已经处理了请求并将数据发送到了客户端了呢?
handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */ //在连接终止的时候被调用。这时候请求的响应数据肯定已经发送到了客户。
handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */ // 当此次请求的连接状态发生变化时此函数被调用。连接状态类型定义: connection_state_t

handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d); //在设置了physical.path之后被调用。这和 handle_physical函数有什么区别呢。

/* when a handler for the request
* has to be found
*/
handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */ //?????
handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */ //在每次请求的最后调用。这和 handle_request_close ,handle_request_done 有什么关系,好象是在这两 个调用中间某个时刻调用的???
void *data; //这个是指向模块内部数据结构的指针。

/* dlopen handle */
void *lib; //dlopen 当前模块时返回的指向此模块动态库的指针变量。用于 dlclose, dlsym , dlerror 函数调用。
} plugin;

int plugins_load(server *srv);
void plugins_free(server *srv);

//与结构体中的函数指针对应的函数调用,一一对应。其实模块插件中的函数指针是在下面这些函数中被调用的。
handler_t plugins_call_handle_uri_raw(server *srv, connection *con);
handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
handler_t plugins_call_handle_subrequest(server *srv, connection *con);
handler_t plugins_call_handle_request_done(server *srv, connection *con);
handler_t plugins_call_handle_docroot(server *srv, connection *con);
handler_t plugins_call_handle_physical(server *srv, connection *con);
handler_t plugins_call_handle_connection_close(server *srv, connection *con);
handler_t plugins_call_handle_joblist(server *srv, connection *con);
handler_t plugins_call_connection_reset(server *srv, connection *con);

handler_t plugins_call_handle_trigger(server *srv);
handler_t plugins_call_handle_sighup(server *srv);

handler_t plugins_call_init(server *srv);
handler_t plugins_call_set_defaults(server *srv);
handler_t plugins_call_cleanup(server *srv);

int config_insert_values_global(server *srv, array *ca, const config_values_t *cv);
int config_insert_values_internal(server *srv, array *ca, const config_values_t *cv);
int config_setup_connection(server *srv, connection *con);
int config_patch_connection(server *srv, connection *con, comp_key_t comp);
int config_check_cond(server *srv, connection *con, data_config *dc);
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);

#endif

阅读内文

CentOS 5 lvs+piranha实现隧道模式负载均衡

9月 9th, 2008 | 3 Comments | Posted in LVS < by ready >

一。需要的软件包
1. ipvsadm-1.24-8.1.i386.rpm
2. modcluster-0.8-27.el5.i386.rpm
3. piranha-0.8.4-7.el5.i386.rpm
4. system-config-cluster-1.0.39-1.0.noarch.rpm
5. php-5.1.6-5.el5.i386.rpm
6. php-cli-5.1.6-5.el5.i386.rpm
7. php-common-5.1.6-5.el5.i386.rpm
8. http*

或者选择系统自带的 Cluster 套件可以直接安装。

二。系统架构。

Virtual IP :192.168.1.20(VIP 对外提供服务器的ip地址,也就是域名解析到的地址。)
Load Balance : 192.168.1.16(LB12)
Real Server:192.168.1.14(r14)、192.168.1.15(r15)
二.LVS Server的安装设置(LB12):
1。安装
# rpm -ivh *
安装完包以后,会生成最主要的几个文件分别是:/etc/sysconfig/ha/lvs.cf,/etc/init.d/piranha-gui,/etc/init.d/pulse
2。设置piranha管理密码
# piranha-passwd
按照提示输入管理密码
3。启动 web 服务和piranha
# service httpd start
# service piranha-gui start
4。配置lvs
配置lvs主要通过piranha提供的http方式完成。
4.1。访问http://192.168.1.16:3636/
4.2。点击“Login”,再弹出的登陆框输入用户名:piranha,密码是前面通过piranha-passwd设置的密码,“确定”。
具体的配置可以参考http://www.dvdshop.com.cn/manual/redhat_AS_3.0_CS/index.html 第12章。
注意:控制面板-〉VIRTUAL SERVERS ->Virtual IP Address: 设置VIP地址。
4.3。启用数据转发
# vi /etc/sysctl.conf

net.ipv4.ip_forward = 0
改为
net.ipv4.ip_forward = 1
注意:重新启动系统一个此设置才会生效。

传统文档的lvs节点配置现在都由piranha图形工具来完成,因此不需要使用命令行来配置。

5。ipvsadm启动
# service ipvsadm start
如果在重新启动的时候,提示说/etc/sysconfig/ipvsadm不存在。那么
# touch /etc/sysconfig/ipvsadm

三.Real Server的设置(r14、r15):
1。创建IP Tunnel
# ifconfig tunl0 192.168.1.20 netmask 255.255.255.255 broadcast 192.168.1.20 up
2。将tunl0加入路由表(routing table)
# route add -host 192.168.1.20 dev tunl0
这四句目的是为了关闭ARP广播响应
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/tunl0/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/tunl0/arp_announce
注意:上面的语句只是临时关闭。服务器重新启动以后设置就自动消失了。
如果需要让设置长时间有效那么,进行如下操作:
# vi /etc/sysctl.conf
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.tunl0.arp_ignore = 1
net.ipv4.conf.tunl0.arp_announce = 2
下面的语句恢复原始设置。
echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/tunl0/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/tunl0/arp_announce
注意:上面的语句只是临时恢复。服务器重新启动以后设置就自动消失了。
如果需要让设置长时间有效那么,进行如下操作:
# vi /etc/sysctl.conf
net.ipv4.conf.all.arp_ignore = 0
net.ipv4.conf.all.arp_announce = 0
net.ipv4.conf.tunl0.arp_ignore = 0
net.ipv4.conf.tunl0.arp_announce = 0

阅读内文 Tags: , ,

Squid日志拆分shell

9月 9th, 2008 | 4 Comments | Posted in Linux, Squid, shell < by ready >

vi split_log.sh

#!/bin/sh
count=$#
if [ $count -le 0 ]
then
echo “please input date”
exit
fi
filename=”access.log”

cd ~weblog/

if [ ! -d ./$1 ]
then
mkdir ./$1
fi

cd ./$1

rm * -f

zcat ../$filename.$1.gz | gawk -F ‘[ /]‘ ‘ {dom=$11;print $0 >> dom}’

for file in ./*
do
if [ -s $file ]
then
gzip $file
else
rm $file -f
fi
done

参数使用的是长格式日期
例如:
./split_log.sh 20080909

在产生的日志中会出现一些莫名其妙的域名日志,这是由于有人非法使用squid做代理造成的。这样的情况在配置禁止非法代理也一样会发生。

阅读内文

一次网上面试经历

9月 7th, 2008 | 16 Comments | Posted in Squid, 生活随笔 < by Martian Guo >

应朋友介绍,有幸在网上接受了一家国内比较著名的网络公司的面试,其实这家公司之前已经接触过两次,对于这次面试,和上两次一样,至少自己是不满意的,感觉自己仍旧欠缺很多东西,先把这次面试的问题说一下

  • 你认为组成web站点体系有哪些元素?
  • 这样的配置,在apache起来后会有几个子进程? (别把这个问题想的简单化)
    <IfModule mpm_prefork_module>
    StartServers 5
    MinSpareServers 50
    MaxSpareServers 100
    MaxClients 150
    MaxRequestsPerChild 0
    </IfModule>
  • 在apache的worker MPM中,为什么ServerLimit要放到配置段最前面?
  • 千兆网卡的极限pps是多少?是如何算出来的?
  • 为什么lighttpd,nginx的并发性能比apache要高?
  • top命令里running的值表示什么意思?这个值和CPU数有什么关系?
  • 在http header头里看到的:Last-Modified,Expires,max-age,etag这四者有什么关系?
  • 一个web站点,如何计算所需要的带宽?公式是什么?
  • 如何看http的并发连接数的?
  • FIN_WAIT2是在什么状态?
    iostat看到的:
    wsec/s = 600
    那么wKB/s = ?
  • 当打开apache的mod_status后,可以通过http://ip/server-status看到相关的状态值,那么Srv, Acc, M,SS,Req各表示什么含义?
  • 如何计算客户端到服务器段的带宽?

对于上面这些问题,也说不上有多难,很多问题google上都能够找到,而且对于系统运维人员来说这些内容是必须了解的,但是你说仅仅是了解,恐怕也不够,其实很多东西不是说没接触过,而是都做过和接触过,但没有深入的去研究过,只知其然 而不知其所以然,感觉做我们这行的,需要掌握的知识面是相当广泛的,大到网络应用架构到,小到一个命令的参数,一个脚本编写,你都要知道,知识是需要积累的,但也需要你怎么运用他,我们很多时候所做的仅仅是如何用,而没有去考虑为什么要这样用,比如说技术文档,有多少人会仔细的查看MAN帮助,有多少人去研究过RFC文档?再比如说简单的iptables应用,一般很少会过多的去考虑当使用了iptables 后会对tcp连接产生多大的影响,可能在等到出现 “ip_conntrack: table full, dropping packet.”的情况下才会去检查问题的所在,很多人会觉得这些东西都是需要经验的,你碰到过这个问题就知道,没有碰到过就不知道,就如上面的问题,假如你的服务器每天就几千连接,恐怕你是一辈子都不会碰到这个问题的。道理是这样,但我们是不是也应该多了解一下这么做合理性,可能会出现什么问题。一个架构的实施一个软件的应用,不是简单的把它部署运行起来,我们应该考虑更多的问题。像我们blog的Johnny Woo同学,他考虑的问题就比我要深入的多,比如说他经常会做一些测试,各种WEB服务器,缓存服务器的性能测试,一些架构技术的研究,我想知识的积累就是如此,不是等待问题的出现,而是自己去找出可能会出现问题,GOOGLE提供给了我们一个非常巨大的知识库,我们如何把别人共享的知识转化成我们自己掌握的知识,关键还是在于实践,在于自己去找问题。还有一点,环境因素,就如上面说的,如果你的环境是每天只有几千人的访问量,你可能不会太多的去关注性能方面的问题,而即使关注,也仅仅是靠自己做一些实验测试而不能真正在生产环境下检验,这也是其中的一个问题,但关键一点还是在于自己,一个问题,一个技术是否是想继续深入的去了解呢,还是仅仅满足现在的要求而不考虑其他方面了。我想,我现在所欠缺的应该就是这些了。

另外再讨论一个问题:我们每天接触的最多的是自由软件,在感叹全世界那么多无私的开发者贡献出那么多完美的软件的同时,对于我们能做的难道仅仅是使用这些软件吗?我是相当佩服国内外一些做系统运维的牛人,他们是相当优秀的系统架构师,另外同时也是相当优秀的软件工程师。使用者最了解自己需要什么样的软件,那么对于系统运维,有谁比我们更了解我们需要什么吗?一个好的环境,再加上一份激情,你会有很多事情要做。

以上内容只是我个人的一些感受,希望经常关注我们blog的朋友能提供一些建议,非常感谢。

阅读内文

xen虚拟机开启过多后用完loop设备问题解决

9月 4th, 2008 | No Comments | Posted in Xen < by Johnny Woo >

xen虚拟机开设超过4个后
会用完loop device
处理方法为
修改
/etc/modprobe.conf:
增加
options loop max_loop=64
执行
/sbin/rmmod loop
/sbin/modprobe loop
执行
ls -l /dev/loop* | wc -l
应该返回64

阅读内文 Tags: ,

samba 服务无法访问

9月 2nd, 2008 | No Comments | Posted in samba < by Johnny Woo >

日志显示 does not exist or permission denied when connecting [...]
原因是SELINUX阻止了samba去访问设置好的共享目录

阅读内文 Tags:

memcached 入门到理解

8月 28th, 2008 | No Comments | Posted in memcached < by Michael Field >

这是由 mixi 株式会社 开发部系统运营组的两位工程师所写,日常负责程序的运营。本文将针对最近在Web应用的可扩展性领域的热门话题memcached,说明其内部结构和使用。

文章分为5个章节、案例讲解,推荐大家阅读学习,中文版PDF文档下载地址见最下!

  • 第1章 memcached的基础
    • 1.1 memcached是什么?
      1.2 memcached的特征
      1.3 安装memcached
      1.4 用客户端连接
      1.5 使用Cache::Memcached
      1.6 总结
  • 第2章 理解memcached的内存存储
    • 2.1 Slab Allocation机制:整理内存以便重复使用
      2.2 在Slab中缓存记录的原理
      2.3 Slab Allocator的缺点
      2.4 使用Growth Factor进行调优
      2.5 查看memcached的内部状态
      2.6 查看slabs的使用状况
      2.7 总结
  • 第3章 memcached的删除机制和发展方向
    • 3.1 memcached在数据删除方面有效利用资源
      3.2 LRU:从缓存中有效删除数据的原理
      3.3 memcached的最新发展方向
      3.4 外部引擎支持
      3.5 总结
  • 第4章 memcached的分布式算法
    • 4.1 memcached的分布式
      4.2 Cache::Memcached的分布式方法
      4.3 Consistent Hashing
      4.4 总结
  • 第5章 memcached的应用和兼容程序
    • 5.1 mixi案例研究
      5.2 memcached应用经验
      5.3 兼容应用程序
      5.4 总结
      如今,越来越多的Web应用程序开始使用memcached这个高速的缓存服务器软件。然而,memcached的基础知识远远未能像其他Web技术那样普及,memcached在国内的大规模应用也鲜为人知。而日本的mixi(http://mixi.jp)则在这方面走在了前面,不仅大规模使用memcached作为缓存来加速Web应用,而且自行开发了Tokyo Cabinit、Tokyo Tyrant等一系列相关的软件。

      最近,日本的技术评论社的网站上刊登了mixi的两名工程师长野雅广、前坂徹撰写的一篇连载《memcachedを知り尽くす》。这篇连载语言简洁、通俗易懂,非常适合memcached入门的人阅读。

    PDF档下载地址

    阅读内文 Tags: , , , ,

    Cacti实现短信报警

    8月 25th, 2008 | 6 Comments | Posted in Cacti < by John.Lv >

    一、 软件环境:cacti(需Threshold插件),飞信机器人(fetion)
    二、 安装过程:
    Cacti的Threshold插件下载及安装配置参见:Cacti配置e-mail报警
    飞信机器人(fetion)下载及安装配置参见:系统监控:linux命令行-飞信客户端发送免费报警短信
    三、 配置过程:
    1.按照Cacti配置e-mail报警配置并启用thold
    2.编辑cacti/plugins/thold/thold-functions.php
    在thold–functions.php查找thold_mail($global_alert_address, ”, $subject, $msg, $file_array);行在此行下面加入:

    exec("echo $subject >>/var/www/html/cacti/plugins/thold/alter.log");
    exec("/var/www/html/cacti/plugins/thold/sendsms.sh");

    查找 thold_mail($item["notify_extra"], ”, $subject,
    $msg, $file_array);行在此行下面加入:

    exec("echo $subject >>/var/www/html/cacti/plugins/thold/alter.log"); #将报警信息记录到alter.log
    exec("/var/www/html/cacti/plugins/thold/sendsms.sh"); #执行sendsms.sh

    备注:本人的thold安装在/var/www/html/cacti/plugins/thold/目录中,如果注释掉thold_mail,只通过短信发送报警。不注释掉thold_mail,会通过email和短信同时发送报警

    thold-functions.php生成的alter.log范例如下:

    192.168.1.207 - Used Space - G: Label: [hdd_percent] is still above threshold of 85 with 99

    编写脚本sendsms.sh自动调用飞信机器人发送报警

    #!/bin/sh
    #send sms by fetion
    #Write by John.Lv
    if [ ! -e "/var/www/html/cacti/plugins/thold/alert.log" ];then #判断alter.log是否存在
    echo "Usage:alert.log does not exist"
    exit
    fi
    if [ -n "`cat /var/www/html/cacti/plugins/thold/alert.log`" ]; then #判断alter.log是否有报警信息
    admin="135xxxxxxxx"  #短信接收人,需在你飞信的好友列表中
    echo "sms $admin "`cat /var/www/html/cacti/plugins/thold/alert.log` >>/var/www/html/cacti/plugins/thold/sms.txt #发送alter.log中的报警信息给admin
    echo "exit" >> /var/www/html/cacti/plugins/thold/sms.txt #退出飞信
    else
    echo "Usage:no alert"
    exit
    fi
    if [ -n "`cat /var/www/html/cacti/plugins/thold/sms.txt`" ] ; then
    /var/www/html/cacti/plugins/thold/install/fetion -u 13512345678 -p "123456" -b /var/www/html/cacti/plugins/thold/sms.txt  -EN
    #调用fetion发送短信,命令格式和参数说明参见:系统监控:linux命令行-飞信客户端发送免费报警短信
    rm -f /var/www/html/cacti/plugins/thold/sms.txt 1>/dev/null 2>&1
    rm -f /var/www/html/cacti/plugins/thold/alert.log 1>/dev/null 2>&1
    else
    echo "Usgae:no message to send"
    exit
    fi

    ok,配置完成了,现在就可以通过短信接收报警信息了

    阅读内文 Tags:

    Cacti实现MSN报警

    8月 22nd, 2008 | 6 Comments | Posted in Cacti < by John.Lv >

    一、 软件环境:cacti(需Threshold插件),MSN机器人(SendMsg)
    二、 安装过程:
    Cacti的Threshold插件参见:Cacti配置e-mail报警
    MSN机器人(SendMsg)参见:系统监控:msn在线机器人实时报警
    三、 配置过程:
    1.按照Cacti配置e-mail报警配置并启用thold
    2.编辑cacti/plugins/thold/thold-functions.php
    在thold–functions.php查找thold_mail($global_alert_address, ”, $subject, $msg, $file_array);行在此行下面加入:

    exec("echo $subject >>/var/www/html/cacti/plugins/thold/alter.log");
    exec("sh /var/www/html/cacti/plugins/thold/sendmessage.sh");

    查找 thold_mail($item["notify_extra"], ”, $subject,
    $msg, $file_array);行在此行下面加入:

    exec("echo $subject >>/var/www/html/cacti/plugins/thold/alter.log");
    exec("sh /var/www/html/cacti/plugins/thold/sendmessage.sh");

    备注:本人的thold安装在/var/www/html/cacti/plugins/thold/目录中,如果注释掉thold_mail,只通过MSN发送报警。不注释掉thold_mail,会通过email和MSN同时发送报警

    thold-functions.php生成的alter.log范例如下:

    192.168.1.207 - Used Space - G: Label: [hdd_percent] is still above threshold of 85 with 99

    编写脚本sendmessage.sh自动调用SendMsg发送报警

    #!/bin/sh
    echo `echo -n "date:"&&date +%Y-%m-%d-%H:%M` >> /var/www/html/sendMsg/msn.txt.1
    #得到当前的日期+时间
    cat /var/www/html/cacti/plugins/thold/alter.log >>/var/www/html/sendMsg/msn.txt.1
    #读取alter.log的报警信息
    now=`date +%Y-%m-%d-%H:%M`
    SA=(disk)
    msnaddr=(lvming104@hotmail.com) #报警接收人msn
    sendMsg()
    {
    num=0
    while [ $num -lt 1 ];
    do
    wget --post-data "sender=test@live.cn&password=12346&recipient=${1}&message=${2}" http://127.0.0.1/sendMsg/index.php -O /var/www/html/sendMsg/index.php.1 >/dev/null 2>&1
    #sender:发送人msn,password:密码。/var/www/html/sendMsg为sendMsn安装目录
    if [ -f /var/www/html/sendMsg/index.php.1 ]; then
    if cat /var/www/html/sendMsg/index.php.1 |grep -i successfully >/dev/null 2>&1;then
    num=1 #判断信息发送成功
    elif cat /var/www/html/sendMsg/index.php.1 |grep -i "The user appears to be offline" >/dev/null 2>&1;then
    num=1 #判断msn接受人为是否在线状态
    echo "The user is offline."
    exit 0
    elif cat /var/www/html/sendMsg/index.php.1 |grep -i "Something went wrong trying to connect to the server" >/dev/null 2>&1;then
    num=1 #判断msn 服务器存在连接问题
    echo "MSN server is wrong."
    exit 0
    else
    num=0 #除了以上三种情况退出循环外,其他情况重试。
    fi
    rm -f /var/www/html/sendMsg/index.php.1
    else
    num=0
    fi
    done
    }
     
    mv /var/www/html/sendMsg/msn.txt /var/www/html/sendMsg/bak/msn$now.txt -f 1>/dev/null 2>&1
    mv /var/www/html/sendMsg/msn.txt.1 /var/www/html/sendMsg/msn.txt -f 1>/dev/null 2>&1
    rm /var/www/html/cacti/plugins/thold/alter.log -f 1>/dev/null 2>&1

    for i in 0
    do
    if cat /var/www/html/sendMsg/msn.txt ; then
    messages=`cat /var/www/html/sendMsg/msn.txt ` #读取要发送的信息
    sendMsg "${msnaddr[$i]}" "$messages" #发送报警信息
    else
    continue
    fi
    done

    ok,配置完成了,现在就可以通过MSN接收报警信息了:如下所示

    下次更新Cacti实现短信报警,敬请期待

    阅读内文 Tags: