2009年12月25日星期五

emacs distel devel 配置问题

环境
emacs=23.0.0.1
os = xp sp3
.emacs 配置抄用 http://bc.tech.coop/blog/070528.html
—————————–
实际状况
emacs:
error “Can’t handle event closed in state derl-recv-challenge-ack
emacs erlang:
Connection attempt from disallowed node ‘distel_3844@LIWOOOOD-3FD36A’ **

问题:
通常两种问题 1. cookie 不匹配 2. node name 不匹配

排查问题:
首先排查第一个问题:
查看在emacs 中和erlang中是否调用同一个cookie配置文件. 默认情况下是检查
home 目录下的 .erlang.cookie.
1. elrang 中通过 init:get_argument(home). 找到位置 “c:/Document …/Admini..”,
2 emacs 中cookie 可通过变量 derl-cookie 查看. 结果:
Its value is nil
但有这么一句
When NIL, we read ~/.erlang.cookie.

mmd 我想知道问题了,
C:\>env | grep HOME
HOME=d:\emacs
HOMEDRIVE=C:
HOMEPATH=\Documents and Settings\Administrator

问题总结:
在windows下 emacs 调用的home目录是 HOME. 而在erlang所依赖的home 目录是HOMEPATH. 两个调用的 .erlang.cookie 位置不一样

解决:
1. cp “c:/Documents and …/Administ../.erlang.cookie” d:/emacs
2. 在erlang 端 -setcookie cookie ,
在emacs中(setq derl-cookie “cookie”)

参考:
http://osdir.com/ml/lang.erlang.distel.devel/2003-02/msg00001.html

2009年12月22日星期二

erl 命令

1. erl -pa 后边尽可能跟 绝对路径. 这是个很容易出错的点

2009年12月15日星期二

转:Erlang开发建议(杂记版)

http://www.javaeye.com/topic/374167
作者:litaocheng


以下是在erlang项目开发中的一些记录,即包含很多通俗易懂的原则,也包含一些似是而非的建议,比较混乱,还没有积累到一个可以分门别类的地步,各位就将就看吧..
:)

* 确保没有任何编译警告

* Erlang中String采用list实现,32位系统中,其1个字符用8个字节的空间(4个保存value, 4个保存指针)。因此string速度较慢,空间占用较大

* 在Server中,总是尽力书写尾递归(tail-recursive)的函数

* 使用'++'时,left list会被拷贝,然后添加到right list的头部,因此最好把length较短的list放在左侧

* 避免使用regexp,如果需要正则表达式,请使用re

* timer模块的大部分函数实现,依赖于一个process,如果过多使用timer,会导致这个process负载过大,影响效率。
推荐使用erlang:send_after/3及erlang:start_timer/3

* 避免使用list_to_atom/1,因为erlang中atom数量最大为1048576, 且不进行GC控制。因此如果持续性的调用list_to_atom/1
可能很容易达到系统上限,从而导致emulator terminate。请使用list_to_existing_atom/1。

* list内部实现为一个列表,因此length(List), 需要遍历整个list比较耗时

* 对于不同的数据类型,使用不同的size函数:tuple_size/1, byte_size/1, bit_size/1

* 使用binary match来进行binary的分割,而不使用split_binary/2

* 如果两个list都拥有很多数据,那么请不要使用'--',而是将数据转化到ordsets,然后调用ordsets:substract/2.

* 对于binary相关操作可以进行binary优化(bin_opt_info编译选项)代码框架:

* f(<>,...) ->
... % Rest is not used here
f(Rest,...);
f(<>,...) ->
... % Rest is not used here
f(Rest,...);
...
f(<<>>, ...) ->
ReturnValue.

* 调用lists:flatten/1可以将list扁平化,这个操作代价很大,比'++'还要昂贵。下面这些时候我们可以避免:
将数据发送给port时
调用list_bo_binary/1和iolist_to_binary前

* 小的函数可以让您方便的找出错误的函数和代码

* 不要在同一行出现相同的符号
20 some_fun() ->
21 L = [{key1, v1}, {key2, [some_record#v21, v22]}],
22 ...
编译时,会提示line 21 '[' 语法错误, 因为21行有多个 '[' ,所以这个bug不能准确定位,你需要花时间去排查代码。
好的做法是:
20 some_fun() ->
21 L = [{key1, v1},
22 {key2, [some_record#v21, v22]}
23 ],
...
这样,编译其会提示你 line 22 '[' 语法错误,你很开就知道是那个地方错了。

* 使用 CTRL + \ 或 init:stop(), 可以退出Erlang, 使用CTRL + G 及 CTRL + C 弹出菜单选项,可以选择是否退出Erlang。
其中CTRL + G可以用来连接其他的shell, CTRL + C可以查看其他一些系统信息
Ctrl + C abort 是野蛮的退出方式

* use "open_port({fd,0,2}, [out])" make erlang program write standard error to unix system

* If you don't run experiments before you start designing a new system, your entire system will be an experiment!

* standard data structure desc:

Module Description
sets sets, i.e. a collection of unique elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative arrays
ets hash tables and ordered sets (trees)
dets on-disk hash tables

Suggestion:
elments count: 0 - 100 | 100 - 10000 | 10000 -
our select : list | ets | gb_tree

* 通过code:clash/0 检测代码中是否有module冲突现象(sticky)

* epmd -d -d 启动 epmd 可以查看erlang node之间的通讯

* 将正常的逻辑代码和错误处理代码分离,发生错误时,尽管错误。由另一个错误处理模块进行处理

* 类似于操作系统,我们的程序也可以分为kernel 和 user 两层, 对于kernel绝对不能出现错误, 对于user可以出现错误,进行恢复

* process顶层loop涉及的代码及函数,最好在一个module中实现

* process 的register name和module名称一致, 便于寻找代码

* 每个process具有一个单一的角色,比如:supervisor 用来进行错误恢复, work 工作者,可以出现错误, trusted worker 不会出现错误

* 通过函数调用可以实现的功能,就不要使用sever实现(如gen_server, 及类似的loop 实现)

* 给消息加一个tag,在发生错误的时候,可以定位到消息,同时也有利于程序的稳健

* 在消息循环中,对于unknown的消息,请调用lib:flush_receive/0 将其清除,减轻process msg queue的长度

* server中总是书写尾递归的循环

* 尽量使用record, 而不是原始的tuple来表现数据结构, 在使用record时,使用select match:
#person{name = Name, age = Age} = Person

* 对于返回值,最好也添加一个tag,用来说明返回值类型,或者执行成功与否

* 尽可能少的使用catch和try,在erlang程序中,不推荐主动捕获异常。只有当我们的逻辑特别复杂,我们可以使用throw来返回数据,使用catch来获取返回值。

* 当然程序与外界交互,外界数据不可靠时,需要使用catch和try

* 慎重使用process dictory, 当你使用get/1, put/1时,你的应用会具有很大的slide effect。可以通过加入一个新的参数来保存原本需要存储到process dictory中数据

* 如果不想使自己糊涂,请不要使用import

* 使用export时,将功能类似的接口组合在一起,并添加合理的注视,这样你的接口更清晰,别人使用起来更方便

* 不要书写嵌套太深的代码

* 不要书写太长的module

* 不要书写太长的函数

* 每行代码不能太长

* 避免使用 "_" 匿名变量,请为每个变量选择有意义的名称,如够某个变量暂时不使用,请以下划线 "_" 开始

* {error, enfile} enfile error in socket 是以为内linux系统中 ulimit 限制, 在root下修改:ulimit -n 25000

* {error, enotconn} 表示socket已经关闭

* 在erlang开发时,慎重使用macro,因为erlang的single assign的缘故,同时调用某个marco,而macro又定义了某个变量,可能导致badmatch错误。
比如:
-define(ADDLINEINFO1(F),
(
begin
Str1 = lists:concat(["[Mod:", ?MODULE, " Line:", ?LINE, "]"]),
Str1 ++ F
end
)).
-define(WARN(Log, F, D), log4erl:warn(Log, ?ADDLINEINFO(F), D)).
如果连续使用 WARN, 会出现此错误

* erlang中可以定义很多环境变量:
ERL_MAX_ETS_TABLES 设置最大的ets数目 默认1400
ERL_MAX_PORTS erlang最大的port数目 默认1024

* .app文件中的start_phases, 选项既可以用来作为include applications之间的同步启动,也可以用来对单个application进行分布启动。
顺序如下
包含included app:

application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
=> incl_app_cb:start_phase(go, normal, [])
ok

无included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
ok

* 任何时候,都要重视函数的返回值,通过match确保您的预期,如果发生错误,那么就大胆的表达出来。

2009年7月13日星期一

org mode

org mode
http://doc.norang.ca/org-mode.html

org publish
http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.php

org remember
http://www.gnu.org/software/emacs/manual/html_node/org/Remember-templates.html
http://mwolson.org/static/doc/remember/

2009年6月25日星期四

ubuntu 网卡安装

机器类型 hp u6012cn, ubuntu9.04自带的r8169 网卡驱动太新,跑不起来.
1. 找到主板型号945GCT-HM
2. 通过1 找到网卡型号 板载网卡 集成 10/100 Mps Realtek RTL8101E 网卡
3. 到 realtek 官网http://152.104.125.41/ 搜索得到对应的驱动下载页
4. uname -a linux kernel 2.6.28.11-generic
5. 找到对应的linux 驱动
6. 通过驱动自带redme 进行安装
7. 搞定 可乐一杯

2009年6月13日星期六

emacs cedet+ecb+cscope+gdb-ui

http://www.360doc.com/content/080321/14/7821_1133699.html
cedet: collection of emacs development environment tools
ecb : Emacs Code Browser

配上 php python 调试, 便于开发

http://www.linuxjournal.com/article/7876 emacs+gdb

---------------------
http://downloads.sourceforge.net/mingw/gdb-6.8-mingw-3.tar.bz2?modtime=1208982015&big_mirror=1

解压里面的bin/gdb.exe放到mingw/bin里面,然后就可以用了。

这个是mingw的下载主页,上面的链接就是在这个里面的。
http://sourceforge.net/project/showfiles.php?group_id=2435

2009年6月9日星期二

Repository moved permanently to xxxx please relocate

可以在http://subversion.tigris.org/faq.html#301-error 找到答案

之前的配置为



DAV svn
SVNParentPath /data/svn/

AuthType Basic
AuthName "Authorization Realm"
AuthUserFile /etc/svnpwdfile
Require valid-user
# SVNListParentPath on

DocumentRoot /data/svn/
ServerName svn.example.cn


貌似正确,可在浏览器里正常 svn checkout时的时候就报Repository moved permanently to xxxx please relocate 错误

原因在faq里明显 就是apache 迷惑了, 可是不设DocumentRoot 就会报错. 解决办法也简单乱设一个有效的路径.... 妈的 居然这样就过了

mysql create database指定字符集

解决乱码,很基础的问题. 但如果不留意会犯
create database redmine character set utf8;

2009年6月8日星期一

批量svn lock

目的:想要svn批量lock一些文件
1.第一次实现
用php实现,原理是应用svn list ,根据传进来的地址进行递归. 将文件lock/unlock
缺点: 不够灵活,每次都要改代码
2.第二次实现
在之前的基础上加入 enable disable filter 参数
优点:相对方便,不用每次都改代码
缺点:无法满足特殊需求, 还是无法避免动代码
3.第三次实现
php脚本只用来通过svn遍历指定目录下的所有文件, 其他的依靠命令来处理就好了
例如:php listsvn.php file:///data/svn/shop/working/b2b1.2/ | grep -e "/ctl\..*\.php" -i | xargs -I % svn unlock %
优点: 足够灵活,足够强大
缺点: 呵呵 每行命令有点长,
总结: 优点远大于缺点

http协议状态码

服务器返回给客户端的状态码。这个信息非常有价值,因为它指示了请求的结果,或者是被成功响应了(以2开头),或者被重定向了(以3开头),或者出错了(以4开头),或者产生了服务器端错误(以5开头)。完整的状态码列表参见HTTP规范(RFC2616第10章)。

http://www.w3.org/Protocols/rfc2616/rfc2616.txt

解决vista系统部分CHM打不开,“无法正常显示”的问题

转:http://www.cnblogs.com/lqb/archive/2009/01/24/1380639.html
解决vista系统部分CHM打不开,“无法正常显示”的问题
症状:显示左侧目录树,右侧内容提示为“无法显示网页”。
原因:Microsoft系统安全性升级导致。
解法:属性页->解除锁定即可。
不只vista有这个问题,只要是NTFS分区都有这个问题

apache+fcgid+redmine安装心得

freebsd 70 apache22 fcgid redmine

如果是还未安装配置,请先看文尾处的参考资料 进行配置.勿阅读本文 免得造成疑惑

安装过程 一波三折,断断续续花了一周时间
1.装fastcgi
2.redmine 安装
首先是在安装ruby上折腾颇多
如果是在freebsd下ruby的包尽量用,可以省力不少.通过 pkg_info | grep ruby 时刻关注所装的包,因为ruby的包之间互为依存. 一定要留意.在调试中出现问题 google 找到原因,大多情况是因为缺包或者包版本不对造成的

关键节点
Test the installation by running WEBrick web server:
ruby script/server webrick -e production
Once WEBrick has started, point your browser to http://localhost:3000/.
You should now see the application welcome page.
如果测试通过表示基本安装已经完成,

3. 整合apache
这时我犯了个致命错误导致文件,用apache fastcgid 模式可以跑起来但是 css js 全部无法加载
解决:
1. 首先还是同过 . redmine/dispatch.fcgi 来测试包是否有问题. 包依赖我是通过这种方式解决掉的, 可当此步骤通过后 依然无法加载css js
2. 排除了ruby的问题,当然怀疑到 httpd.conf 配置问题, 查看/var/log/httpd-error.log经过反复排查 无误, 告失败
3. 这时候想到了.htaccess 的问题,找到 redmine/public/.htaccess 进行调试 不得要领
4. 有些抓狂, 再找到redmine/log/production.log
看到错误
ActionController::RoutingError (No route matches "/stylesheets/jstoolbar.css"
google之 无果,但是想到了 .htaccess 是通过rewrite 将访问转到 dispatch.fcgi上的想到问题应该是出在了rewrite上
打开rewrite log
RewriteLog "/var/log/rewrite.log"
RewriteLogLevel 3

5. 查看结果 rewriteCond %{REQUEST_FILENAME} !-f 失效 js css都通过 dispatch.fcgi 在解析,这当然找不到
可为什么会出现这个问题?依然是个问号 继续google之. 没有答案 为了调试,我把.htaccess 进行了删减 来排查问题
之前的疑问全部浮出水面

RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]


RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]


RewriteRule ^(.*)$ dispatch.cgi [QSA,L]

当我把 mod_fastcgi.c IfModule mod_cgi.c 两段去掉时.一切正常了. 头绪来了 mod_fastcgi mod_fcgid mod_cgi 其中至少跑了两个. 那么问题出在我在配置fcgid 的时候没有将mod_cgi 去掉所导致的问题. 我靠.
把 LoadModule cgi_module libexec/apache22/mod_cgi.so 注释掉,干掉 .htaccess 重新 svn update 重启apache 一切ok!

6.总结
当出现问题时 一定要查看log(各种log 服务的 软件的),通过log问题一块块排查 不能慌乱. 注意思考 依靠网络 但不依赖网络

参考:
1.安装fastcgid
http://www.cyberciti.biz/faq/freebsd-apache22-fastcgi-php-configuration/
(如安此文章出现问题请查看我的另一篇文章 http://leafghost.blogspot.com/2009/06/apache2fastcgi.html )
2.redmine 安装
http://www.redmine.org/wiki/redmine/RedmineInstall
3.整合 apache
http://www.redmine.org/wiki/1/HowTo_configure_Apache_to_run_Redmine

2009年6月1日星期一

apache2配置fastcgi

参考:http://www.cyberciti.biz/faq/freebsd-apache22-fastcgi-php-configuration/

遇到一个问题
[notice] mod_fcgid: process /usr/local/www/phpPgAdmin/images/themes/default/title.png(2905) exit(communication error), terminated by calling exit(), return code: 255
除了php都无法加载
解决办法, 把 SetHandler fcgid-script 注释掉 换上 AddHandler fcgid-script .php就成了

疑问:
1.FCGIWrapper /usr/local/bin/php-cgi .php 是做什么的
2.[notice] mod_fcgid: call /data/www/shop/shopadmin/index.php with wrapper /usr/local/bin/php-cgi 怎么解决?

没测过, 但是直观感觉是网站快了.. 呵呵

unix jobs

假设你发现前台运行的一个程序需要很长的时间,但是需要干其他的事情,你就可以用 Ctrl-Z ,终止这个程序,然后可以看到系统提示:
[1]+ Stopped /root/bin/rsync.sh
然后我们可以把程序调度到后台执行:(bg 后面的数字为作业号)
#bg 1
[1]+ /root/bin/rsync.sh &
用 jobs 命令查看正在运行的任务:
#jobs
[1]+ Running /root/bin/rsync.sh &
如果想把它调回到前台运行,可以用
#fg 1
/root/bin/rsync.sh
这样,你在控制台上就只能等待这个任务完成了。

& 将指令丢到后台中去执行
[ctrl]+z 將前台任务丟到后台中暂停
jobs 查看后台的工作状态
fg %jobnumber 将后台的任务拿到前台来处理
bg %jobnumber 将任务放到后台中去处理
kill 管理后台的任务

chrome about:

转:http://www.chromefans.org/chrome-tutorial/full-list-of-google-chrome-abount-command.htm
Like most other browsers, Google Chrome can be fine-tuned by typing "about:command" to show information about version number, memory usage, cached files, plug-ins and more details. Here's the full list:

1. about:cache - A list of all the web pages cached by Google Chrome
2. about:dns - Prefetching DNS records produced benefits
3. about:histograms - A list of histograms for Google Chrome's internal metrics
4. about:internets - Google Chrome's humorous Easter egg
5. about:memory - Measuring memory usage in a multi-process browser
6. about:network - Used for I/O tracking
7. about:plugins - The list of plug-ins that are available in Google Chrome
8. about:stats - A list of internal counters and timers
9. about:version - Shows the version number the browser, WebKit and JavaScript V8 engine
10. view-cache:[URL] - Shows you some under-the-hood cache details
11. view-source:[URL] - Shows the source code.

ports更新方式(cvsup portsnap)

1. cvsup -L 2 /root/ports-supfile
cp /usr/share/examples/cvsup/ports-supfile /root/
修改 ports-supfile 依据位置使用 cvsup1 ~ cvsup13.tw.freebsd.org服务器
也可通过 -h 来指定更新服务器

ports-supfile文件中ports-all 表示我们要更新 /usr/ports 目录下的所有档案。您也可以只更新其中的部份目录,只要将 ports-all 以井字号 "#" 标示起来,并将档案中 ports-base 那一行的 # 移除,接着您就可以依您所要更新的目录来要移除其它的 # 字号。例如,我们只要更新 /usr/ports/www 这个目录,将 ports-all 以 # 标示起来之后,我们还要移除 ports-base 及 ports-www 开头的 #。

2. portsnap fetch update
Portsnap 是一套用以安全地分发 FreeBSD 的系统。 每隔大约一个小时, 就会生成一份 ports 的最新 “快照”, 它会被打包并进行数字签名。 这些文件接下来将通过 HTTP 来分发。

下载压缩的 Ports 套件快照到 /var/db/portsnap。您可以根据需要在这之后关闭 Internet 连接。
# portsnap fetch
假如您是首次运行 Portsnap, 则需要将快照释放到 /usr/ports:
# portsnap extract
如果您已经有装好的 /usr/ports 而您只想更新,则应执行下面的命令:
# portsnap update

因为是下载压缩包,所以速度要比cvs 一个个拉要快很多,
————————————————————-----------------

使用方法:
/etc/portsnap.conf 里面更改
SERVERNAME=portsnap.hshh.org
portsnap简介:
portsnap从freebsd6.0开始引进系统,给与用户方便的更新系统ports
portsnap的命令比较少
fetch 获取数据
extract 释放全部ports
update 更新ports
第一次使用可以 portsnap fetch extract
以后使用可以 portsnap fetch update
如果写在cron可以用 portsnap cron update

3.总结
如果很急只想更新部分ports 可以用cvsup.如果想一劳永逸还是portsnap 更舒适
http://www.twbsd.org/chs/book/index.php?ch=10

参考:http://freebsd.chinaunix.net/doc/2007/01/17/1123592.shtml

大量小文件的实时同步方案

转:http://blog.daviesliu.net/2008/04/24/sync/

大量小文件的实时同步方案

davies 发表于 2008 年 04 月 24 日

传统的文件同步方案有rsync(单向) 和 unison(双向)等,它们需要扫描所有文件后进行比对,差量传输。如果文件数量达到了百万甚至千万量级,扫描所有文件将非常耗时。而且正在发生变化的往往是其中很少的一部分,这是非常低效的方式。

之前看了Amazon的Dynamo的设计文档,它们每个节点的数据是通过Hash Tree来实现同步,既有通过日志来同步的软实时特点(msyql, bdb等),也可以保证最终数据的一致性(rsync, unison等)。Hash Tree的大体思路是将所有数据存储成树状结构,每个节点的Hash是其所有子节点的Hash的Hash,叶子节点的Hash是其内容的Hash。这样一旦某个节点发生变化,其Hash的变化会迅速传播到根节点。需要同步的系统只需要不断查询跟节点的hash,一旦有变化,顺着树状结构就能够在logN级别的时间找到发生变化的内容,马上同步。

文件系统天然的是树状结构,尽管不是平衡的数。如果文件的修改时间是可靠的,可以表征文件的变化,那就可以用它作为文件的Hash值。另一方面,文件的修改通常是按顺序执行的,后修改的文件比早修改的文件具有更大的修改时间,这样就可以把一个目录内的最大修改时间作为它的修改时间,以实现Hash Tree。这样,一旦某个文件被修改,修改时间的信息就会迅速传播到根目录。

一般的文件系统都不是这样做的,目录的修改时间表示的是目录结构最后发生变化的时间,不包括子目录,否则会不堪重负。因为我们需要自己实现这个功能,利用Linux 2.6内核的新特性inotify获得某个目录内文件发生变化的信息,并把其修改时间传播到它的上级目录(以及再上级目录)。Python 有 pyinotify,watch.py的代码如下:

  1. #!/usr/bin/python
  2. from pyinotify import *
  3. import os, os.path
  4. flags = IN_CLOSE_WRITE|IN_CREATE|IN_Q_OVERFLOW
  5. dirs = {}
  6. base = '/log/lighttpd/cache/images/icon/u241'
  7. base = 'tmp'
  8. class UpdateParentDir(ProcessEvent):
  9. def process_IN_CLOSE_WRITE(self, event):
  10. print 'modify', event.pathname
  11. mtime = os.path.getmtime(event.pathname)
  12. p = event.path
  13. while p.startswith(base):
  14. m = os.path.getmtime(p)
  15. if m <>
  16. print 'update', p
  17. os.utime(p, (mtime,mtime))
  18. elif m > mtime:
  19. mtime = m
  20. p = os.path.dirname(p)
  21. process_IN_MODIFY = process_IN_CLOSE_WRITE
  22. def process_IN_Q_OVERFLOW(self, event):
  23. print 'over flow'
  24. max_queued_events.value *= 2
  25. def process_default(self, event):
  26. pass
  27. wm = WatchManager()
  28. notifier = Notifier(wm, UpdateParentDir())
  29. dirs.update(wm.add_watch(base, flags, rec=True, auto_add=True))
  30. notifier.loop()

在已经有Hash Tree的时候,同步就比较简单了,不停地获取根目录的修改时间并顺着目录结构往下找即可。需要注意的是,在更新完文件后,需要设置修改时间为原文件的修改时间,目录也是,保证Hash Tree的一致性,否则没法同步。mirror.py的代码如下

  1. #!/usr/bin/python
  2. import sys,time,re,urllib
  3. import os,os.path
  4. from os.path import exists, isdir, getmtime
  5. src = sys.argv[1]
  6. dst = sys.argv[2]
  7. def local_mirror(src, dst):
  8. if exists(dst) and mtime == getmtime(dst):
  9. return
  10. if not isdir(src):
  11. print 'update:', dst
  12. open(dst,'wb').write(open(src).read())
  13. else:
  14. if not exists(dst):
  15. os.makedirs(dst)
  16. for filename in os.listdir(src):
  17. local_mirror(os.path.join(src,filename), os.path.join(dst,filename))
  18. os.utime(dst, (mtime,mtime))
  19. def get_info(path):
  20. f = urllib.urlopen(path)
  21. mtime = f.headers.get('Last-Modified')
  22. if mtime:
  23. mtime = time.mktime(time.strptime(mtime, '%a, %d %b %Y %H:%M:%S %Z'))
  24. content = f.read()
  25. f.close()
  26. return int(mtime), content
  27. p = re.compile(r'([\d.]+?) +([\w/]+)')
  28. def remote_mirror(src, dst):
  29. mtime, content = get_info(src)
  30. if exists(dst) and mtime == int(getmtime(dst)):
  31. return
  32. print 'update:', dst, src
  33. if not src.endswith('/'):
  34. open(dst,'wb').write(content)
  35. else:
  36. if not exists(dst):
  37. os.makedirs(dst)
  38. for mt,filename in p.findall(content):
  39. mt = int(float(mt))
  40. lpath = dst+filename
  41. if not exists(lpath) or int(getmtime(lpath)) != mt:
  42. remote_mirror(src+filename, lpath)
  43. os.utime(dst, (mtime,mtime))
  44. if src.startswith('http://'):
  45. mirror = remote_mirror
  46. else:
  47. mirror = local_mirror
  48. while True:
  49. mirror(src, dst)
  50. time.sleep(1)

如果源文件不在同一台机器上,可以通过NFS等共享过来。或者可以通过支持列目录的HTTP服务器来访问远程目录,mirror.py 已经支持这种访问方式。server.py 是用webpy做的一个简单的只是列目录的文件服务器。由于瓶颈在IO上,它的性能不是关键。server.py的代码如下:

  1. #!/usr/bin/python
  2. import os,os.path
  3. import web
  4. import time
  5. root = 'tmp'
  6. HTTP_HEADER_TIME = '%a, %d %b %Y %H:%M:%S %Z'
  7. class FileServer:
  8. def GET(self, path):
  9. path = root + path
  10. if not os.path.exists(path):
  11. return 404
  12. mtime = time.localtime(os.path.getmtime(path))
  13. web.header('Last-Modified', time.strftime(HTTP_HEADER_TIME, mtime))
  14. if os.path.isdir(path):
  15. for file in os.listdir(path):
  16. if file.startswith('.'): continue
  17. p = os.path.join(path,file)
  18. m = os.path.getmtime(p)
  19. if os.path.isdir(p):
  20. file += '/'
  21. print m, file
  22. else:
  23. print open(path,'rb').read()
  24. urls = (
  25. "(/.*)", "FileServer",
  26. )
  27. if __name__ == '__main__':
  28. web.run(urls, globals())

为了获得更好性能,以达到更好的实时性,Hash Tree最好是平衡的,比如BTree。如果一个文件发生变化,同步它需要进行的IO操作为N*M,其中N为数的层数,M为每层的文件数目。现在我们N为2,M最大为10000,适当减少它可以获得更好的性能,比如N为4,M为100。在以后创建目录结构时,最好能够考虑这方面的因素。

之前hongqn推荐过一个利用inotify的文件同步方案,同步方式类似于mysql和bdb等,由于过于复杂导致不可靠而没有采用。上面这个方案只用了一百多行Python代码就基本解决问题了,是不是很帅?:-)


2009年5月30日星期六

FreeBSD笔记┊Ports部署apache2+php5+mysql5+ZendOptimizer(转)

转:http://www.coos.cn/article.asp?id=194

FreeBSD笔记┊Ports部署apache2+php5+mysql5+ZendOptimizer

其实咱学习freebsd的最终目的,也就是LAMP应用。但是我一直不赞成直接就去学习AMP的学习,而是先把L,也就是操作系统先玩懂,在去整服务,就明朗的多了。
所以现在接触freebsd半个月,我开始是潜心学习freebsd的相关系统管理,现在基本上算是弄懂了。所以可以开始来学习服务配置了,昨天星期天,花了一天的时间在家里研究,最后忙到另成2点左右,才终于配置成功。其实配置成功后,在回头看看其实原来这么简单。

一、系统准备
什么叫系统准备,前面不是已经学习怎么安装系统了吗?
但是专业的服务器是不需要安装那么多东西的,我们安装的时候就选择minimal安装,然后使用sysinstall安装scr内核,以及ports。
然后编译内核,去掉一些没用的东西。这个我还没学,稍晚一点再学习。
然后升级portstree,可以用portsnap或者cvsup,推荐使用portsnap,这个已经学习过了,可以看前面的笔记。

二、安装apache2.0
升 级ports目录树后,最新版的apache是2.2.9_5。本来我是想安装最新版的,但是公司用的是2.0,为了能够和公司同步,我在这里也安装 apache2.0。但其实2.2和2.0相差不大,而2.2安装的时候会启动make config,也就是一个类图形界面,可以手动选择需要的模块,这样更直观一点;apache 2.0却没有,如果需要设置模块,就要用参数来指定了。

现在来安装apache 2.0:
[root@bsd01 ~] cd /usr/ports/www/apache20
[root@bsd01 apache20] make install clean


但是安装完之后,竟然无法正常启动,虽然用
httpd -k start
apachectl start
/usr/local/etc/rc.d/apache2 start
这些命令启动的时候,都没有报错,但是
[root@bsd01 ~]# apachectl stop
httpd (no pid file) not running
竟然提示httpd没有运行。

我们来看看错误在那里:
[root@bsd01 ~]# cat /var/log/httpd-error.log | tail -f
[Mon Nov 17 13:28:07 2008] [error] [client 10.1.1.20] File does not exist: /usr/local/www/data/favicon.ico
[Mon Nov 17 13:28:08 2008] [error] [client 10.1.1.20] File does not exist: /usr/local/www/data/favicon.ico
[Mon Nov 17 13:28:09 2008] [error] [client 10.1.1.20] File does not exist: /usr/local/www/data/favicon.ico
[Mon Nov 17 13:28:29 2008] [notice] caught SIGTERM, shutting down
[Mon Nov 17 13:28:32 2008] [notice] Apache/2.0.63 (FreeBSD) configured -- resuming normal operations
[Mon Nov 17 13:28:44 2008] [notice] caught SIGTERM, shutting down
[Mon Nov 17 13:28:45 2008] [alert] (EAI 8)hostname nor servname provided, or not known: mod_unique_id: unable to find IPv4 address of "bsd01"
Configuration Failed
[Mon Nov 17 13:28:59 2008] [alert] (EAI 8)hostname nor servname provided, or not known: mod_unique_id: unable to find IPv4 address of "bsd01"
Configuration Failed


貌似是找不到hostname,所以我们编辑/etc/hosts文件:
[root@bsd01 ~]# vi /etc/hosts
127.0.0.1 localhost localhost.my.domain
改成下面(也就是后面加上本机计算机名):
127.0.0.1 localhost localhost.my.domain bsd01

现在来启动测试,发现启动成功了:
[root@bsd01 ~]# apachectl start
[root@bsd01 ~]# fetch http://127.0.0.1
127.0.0.1 100% of 1517 B 161 kBps


三、安装php5
[1]. 先来安装php5:
[root@bsd01 ~]# cd /usr/ports/lang/php5
[root@bsd01 php5]# make install clean

然后会出现“make config”的界面,选择你需要的组件就可以,一般如下面所示:
Options for php5 5.2.6_2
───────────────────────────────────────
[X] CLI Build CLI version
[X] CGI Build CGI version
[X] APACHE Build Apache module
[ ] DEBUG Enable debug
[X] SUHOSIN Enable Suhosin protection system (not for jails)
[X] MULTIBYTE Enable zend multibyte support
[ ] IPV6 Enable ipv6 support
[ ] MAILHEAD Enable mail header patch
[ ] REDIRECT Enable force-cgi-redirect support (CGI only)
[ ] DISCARD Enable discard-path support (CGI only)
[X] FASTCGI Enable fastcgi support (CGI only)
[X] PATHINFO Enable path-info-check support (CGI only)


然后OK开始安装。

[2]. 配置apache以支持php:
[root@bsd01 ~]# vi /usr/local/etc/apache2/httpd.conf
加入如下2行:
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps

另外看有没有下面这行,没有的话也加上:
LoadModule php5_module libexec/apache2/libphp5.so

然后找到下面这行,在后面加上index.php:
DirectoryIndex index.html index.html.var index.php


[3]. 安装php5扩展
[root@bsd01 ~]# cd /usr/ports/lang/php5-extensions
[root@bsd01 php5-extensions]# make install clean

然后会出现“make config”的配置界面,选择需要的组件就可以了,一般如下所示:
Options for php5-extensions 1.1
───────────────────────────────────────
[X] BCMATH bc style precision math functions
[X] BZ2 bzip2 library support
[X] CALENDAR calendar conversion support
[X] CTYPE ctype functions
[X] CURL CURL support
[ ] DBA dba support
[ ] DBASE dBase library support
[X] DOM DOM support
[X] EXIF EXIF support
[X] FILEINFO fileinfo support
[X] FILTER input filter support
[ ] FRIBIDI FriBidi support
[X] FTP FTP support
[X] GD GD library support
[X] GETTEXT gettext library support
[ ] GMP GNU MP support
[X] HASH HASH Message Digest Framework
[X] ICONV iconv support
[X] IMAP IMAP support
[ ] INTERBASE Interbase 6 database support (Firebird)
[X] JSON JavaScript Object Serialization support
[X] LDAP OpenLDAP support
[X] MBSTRING multibyte string support
[X] MCRYPT Encryption support
[X] MHASH Crypto-hashing support
[ ] MING ming shockwave flash support
[ ] MSSQL MS-SQL database support
[X] MYSQL MySQL database support
[ ] MYSQLI MySQLi database support
[ ] NCURSES ncurses support (CLI only)
[ ] ODBC unixODBC support
[X] OPENSSL OpenSSL support
[ ] PCNTL pcntl support (CLI only)
[X] PCRE Perl Compatible Regular Expression support
[X] PDF PDFlib support (implies GD)
[X] PDO PHP Data Objects Interface (PDO)
[X] PDO_SQLITE PDO sqlite driver
[ ] PGSQL PostgreSQL database support
[X] POSIX POSIX-like functions
[ ] PSPELL pspell support
[ ] READLINE readline support (CLI only)
[ ] RECODE recode support
[X] SESSION session support
[ ] SHMOP shmop support
[X] SIMPLEXML simplexml support
[X] SNMP SNMP support
[ ] SOAP SOAP support
[X] SOCKETS sockets support
[X] SPL Standard PHP Library
[X] SQLITE sqlite support
[ ] SYBASE_CT Sybase database support
[ ] SYSVMSG System V message support
[ ] SYSVSEM System V semaphore support
[ ] SYSVSHM System V shared memory support
[ ] TIDY TIDY support
[X] TOKENIZER tokenizer support
[ ] WDDX WDDX support (implies XML)
[X] XML XML support
[X] XMLREADER XMLReader support
[ ] XMLRPC XMLRPC-EPI support
[X] XMLWRITER XMLWriter support
[X] XSL XSL support (Implies DOM)
[ ] YAZ YAZ support (ANSI/NISO Z39.50)
[X] ZIP ZIP support
[X] ZLIB ZLIB support


这个安装过程比较长,需要耐心等待。
至此,apache+php基本上算是配置成功了。“apachectl restart”重启一下。然后去下载个php探针去测试一下。


四、安装mysql5
[1]. mysql5的安装
安装过程很简单,因为前面我们安装php组件的时候,它自动给我们安装了mysql-client5.0,所以我们server也安装5.0好了:
[root@bsd01 ~]# pkg_info | grep mysql
mysql-client-5.0.67_1 Multithreaded SQL database (client)
php5-mysql-5.2.6_2 The mysql shared extension for php
[root@bsd01 ~]# cd /usr/ports/databases/mysql50-server
[root@bsd01 mysql50-server]# make install clean

* 不过这样安装的mysql不支持gb2312,gbk等编码,查询会出错。可以使用“make WITH_XCHARSET=all install clean” 的安装命令来释放其他的编码支持。如果使用“make WITH_CHARSET=gb2312 WITH_XCHARSET=all install clean”这样的安装命令,则表示把释放所有编码支持并设置gb2312为mysql的默认编码,一般来说是不可取的,除非你真的决定想这么做!

[2]. mysql5配置过程
不要以为上面的安装完之后,mysql-server就可以使用了,其实会出故障的:
[root@bsd01 ~]# mysql -u root
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

我就是被这个问题搞了我2天都没解决,现在开始配置:
[root@bsd01 ~]# cp /usr/local/share/mysql/my-large.cnf /etc/my.cnf
[root@bsd01 ~]# /usr/local/bin/mysql_install_db --user=mysql
[root@bsd01 ~]# /usr/local/bin/mysqld_safe --user=mysql &
[1] 74754
[root@bsd01 ~]# mysqladmin -u root pqssword '123456'

[root@bsd01 ~]# ps -ef | grep mysqld
ps: Process environment requires procfs(5)
74754 p5 I 0:00.08 /bin/sh /usr/local/bin/mysqld_safe --user=mysql
74780 p5 S+ 0:00.02 grep mysqld
[root@bsd01 ~]# kill -9 74754
[1]+ Killed: 9 /usr/local/bin/mysqld_safe --user=mysql
[root@bsd01 ~]# /usr/local/etc/rc.d/mysql-server start
[root@bsd01 ~]# pgrep mysqld
74775
[root@bsd01 ~]# mysql -u root -p
Enter password:123456
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.0.67-log FreeBSD port: mysql-server-5.0.67_1

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>


五、为php配置ZendOptimizer
ZendOptimizer可以为php的解析加速,听说可以提高40%-100%的执行速度。所以一般php都会加载这个,现在我们来配置:
[root@bsd01 /]# cd /usr/ports
[root@bsd01 ports]# make search key=^Zend
Port: ZendOptimizer-3.3.0.a
Path: /usr/ports/devel/ZendOptimizer
Info: An optimizer for PHP code

[root@bsd01 ports]# cd /usr/ports/devel/ZendOptimizer
[root@bsd01 ZendOptimizer]# make install clean


这样就可以安装完成了,然后会有提示,在php.ini加入如下文字:
[root@bsd01 ~]# vi /usr/local/etc/php.ini
在最后加入如下文字:

[Zend]
zend_optimizer.optimization_level=15
zend_extension_manager.optimizer="/usr/local/lib/php/20060613/Optimizer"
zend_extension_manager.optimizer_ts="/usr/local/lib/php/20060613/Optimizer_TS"
zend_extension="/usr/local/lib/php/20060613/ZendExtensionManager.so"
zend_extension_ts="/usr/local/lib/php/20060613/ZendExtensionManager_TS.so"

然后重启apache服务:
[root@bsd01 ~]# apachectl stop
[root@bsd01 ~]# apachectl start


六、让freebsd自动启动apache+mysql服务
至此,apache+php+mysql已经配置成功了,现在我们配置让freebsd能够在开机的时候自动运行这些服务。
[root@bsd01 ~]# vi /etc/rc.conf
加入如下2行:
apache2_enable="YES"
mysql_enable="YES"

另如果你在手动启动apache的时候,经常提示:
[Wed Nov 26 22:05:59 2008] [warn] (2)No such file or directory: Failed to enable the 'httpready' Accept Filter

那是因为apache无法开始Accept Filter机制。
则可以在/boot/loader.conf加入“accf_http_load="YES"”即可:
[root@bsd01 ~]# echo 'accf_http_load="YES"' >> /boot/loader.conf


结语:
至此,freebsd7.0下的apache2+php5+mysql5+ZendOptimizer3就已经完满成功了,这里花了我2天多时间的研究。网上很多的教程都是比较不切实际,所以最重要的还是自己实践。
其中最麻烦的就是mysql数据库了,稍微不注意就出现那个/tmp/mysql/sock的错误,很烦,而且网上也找不到具体的解决办法。根据经验,一般是mysql数据库没有启动起来,可以使用“pgrep mysqld”来看看进程有没有启动。
如果没有,可尝试先用“mysql_install_db --user=mysql”,然后再用“mysqld_safe &”来启动,然后重启电脑。

还就是比较烦freebsd的就是我发现如果用“apachectl、mysql-server”这些服务命令执行start|restart命令的时候,经常是服务没启动,但是也不报错,有时候想骂人。所以最好把mysql加在/etc/rc.conf里让它自己启动。
apache 重启的时候,也最好不要用“apachectl restart”,还是依次用“apachectl stop”;"apachectl start"来使用,最后别忘了用“pgrep httpd”来看一下有没有正常启动。没办法,好像freebsd下的apache+mysql有点不保险,所以我们要处处留意。