2010年9月 归档
Subversion 镜像写代理的配置注意事项
9月25日
可以用 Subversion 镜像的方式实现容灾,一般无需配置复杂的写代理(Write-through proxy)
- 在镜像端提供相同授权的访问
- 禁止除了同步管理员帐号之外的写权限,通过 ReadonlySvnMirror 设定即可
但是分布式团队,需要同时在一个版本库工作:
- 为了提高读取速度,通过镜像实现各个异地团队拥有相同的本地读取速度
- 但只能在一个版本库写,因此只有有一个团队用本地的速度写版本库
实际上因为提交后还要进行异地版本库同步,因此写本地版本库速度也会有延迟。延迟出现在提交后的远程同步。 - 另外的团队要设置写代理,这样使用读取本地镜像时相同的 URL 实现版本库的写操作
但是版本库写代理的设置还是相当复杂,而且需要管理员大量的手工操作才能完成。注意事项有:
要为 HTTPS 虚拟机打开 SSLProxyEngine
如果要使用 https 协议代理提交,就需要打开 https 协议的 Apache 虚拟主机配置,启用 SSLProxyEngine 设置。
SSLEngine on SSLProxyEngine on
Subversion写代理的配置不能使用 SVNParentPath
SVNParentPath 是管理员最喜欢用的指令,只要设定为版本库的根,不必在为新建版本库设置 <Location> 配置小节。
但是对于 Subversion 写代理,必须使用 SVNPath 来版本库的实际部署路径,这是因为:
- 写代理需要配置 SVNMasterURI,但是 SVNMasterURI 只能设置一个 URL
- 即 SVNMasterURI 要可 SVNPath 配对使用,而不能和 SVNParentPath 一起使用。
- 因此需要为需要进行写代理的版本库逐一进行设置。
TODO:修改 mod_dav_svn 的代码,使得 SVNMasterURL 可以和 SVNParentPath 一起用,即 SVNMasterURI 是一个指向版本库根的 URL
基于 SVNParentPath 的版本库和单独配置的写代理版本库不能在有重叠的 location 中混搭
考虑是否可以使用如下有重叠的Location中进行混搭,既方便本地主版本库的维护,又方便同样域名和路径前缀的写代理版本库?
<Location /svn/> DAV svn SVNParentPath /opt/svn/svnroot ... </Location> <Location /svn/myrepos> SVNPath /opt/svn/svnroot/myrepos SVNMasterURI https://svn2.sun.moon.ossxp.com/svn/myrepos ... </Location>
不幸的是,上面的配置无法正确运行。虽然 Location 可以重叠,但是重叠的 Location 的配置会传递和覆盖。
上一个的 SVNParentPath 传递的下面不允许配置 SVNParentPath 的写代理的配置中,破坏了写代理的正确运行。反之亦然。
Subversion的镜像版本库要提供两套 URL!
如果镜像版本库只有一个 URL,那么向该 URL 写的时候,代理提交到主版本库。但是主版本库到镜像版本库同步时,又该如何呢?
因此需要提供两个 URL:
- 一个可以直接写(通过 ReadonlySvnMirror 钩子可以限制只有特定同步管理员可写)
- 另外一个不能直接写,而是通过代理。即用 SVNMasterURI 指令设置真正要写到的版本库地址
Subversion写代理的 URL 的路径部分必须和主版本库的路径相同!
即如果主版本库的 URL 是 https://svn.moon.ossxp.com/svn/myrepos 。镜像版本库的写代理的 URL 地址的主机名可以不同,但是路径必须相同,例如 https://svn2.sun.ossxp.com/svn/myrepos 。看到了么,一个是月亮 moon,一个是太阳 sun。
对于版本库同步用的 URL 地址则没有限制。

Subversion 管理后台升级
9月25日
Subversion 管理后台最近版本升级解决两个主要问题:Subversion版本库同步的同步锁清除,以及 IE8兼容性问题。
Subversion 版本库同步时同步锁的清除
Subversion版本库容灾备份,主版本库提交时,会临时在镜像版本库的 rev0 的版本属性中添加 svn:sync-lock 和 svn:sync-currently-copying 两个临时属性作为同步锁,避免针对一个版本库同时有多个同步进程。这么设计是因为 SVN 镜像可以是远程调用。
在特定情况下,会造成死锁:
- 同步开始后,突然的网络中断,导致同步失败,而同步的目标版本库(镜像版本库)的 rev0的锁尚未删除。
- 再次同步时,由于 rev0 的版本属性中的锁的存在,导致同步失败。
- Subversion 的主从备份失效。
死锁发生后,客户端的感受
- 客户端提交会发现速度很慢,会被阻塞10秒钟以上
- 实际上,提交已经完成,在进行主从同步时被阻塞
- Subversion的同步一旦发现被同步锁阻塞时,会持续尝试10次,每次间隔1秒钟
最新的同步机制,能够自动判断锁的有效性,避免主从同步失效
- 在同步发起时,会记录同步进程的 PID 到一个临时文件
- 当发现镜像中存在锁的时候,会检测本地锁文件,以及是否有对应的同步进程
- 如果发现锁是僵尸锁,则删除镜像版本库rev0 中的僵尸锁,继续执行版本库同步
- 如果同步过程有错误发生时,会通过钩子脚本(post-commit 或 post-revprop-change)将同步的错误会直接通过用户提交通知界面进行显示。
- 管理员也可以设置 debug 诊断标志,当 debug 打开,同步成功的信息也会以“错误通知”的方式显示在提交后的通知界面中。(同步成功的消息显示为控制台错误,这是 Subversion 的 post-commit 等脚本的设计机制决定的)

同时,还为 subversion 钩子提供手工版本库同步的接口:
(其中 /opt/svn/svnroot 是版本库的根目录)
- 显示版本库的状态:
$ sudo python /etc/subversion/hooks/scripts/svn_mirror.py /opt/svn/svnroot/
- 手工对配置了容灾的版本库进行同步:
$ sudo python /etc/subversion/hooks/scripts/svn_mirror.py sync /opt/svn/svnroot/
IE8 兼容性问题
部分界面在 IE8 不能正常显示。当打开 IE8 浏览器的“兼容视图”,则能够正常显示。
最终定位到是元素显隐,IE8的支持和以前不同。原来的实现是通过设置 element.style.visibility 为 ‘hidden’ 或者 ‘visible’ 实现 DIV 的消隐。当对 div 重复进行隐藏后,再设置显示时, DIV 中的表单域却不能显示出来!
通过 google 查询了半天,也对子元素的 style.visibility 设置为 inherit 也没有什么改观,对IE 恨的牙痒痒的。IE 的调试工具也很匮乏,FireBug lite 让 Firebug 可以在 IE 里运行,但毕竟是 CSS 的问题,也帮不了大忙。
忽的灵机一动,既然框架中已经用了 prototype, 为什么不采用 prototype 本身已经封装好的元素消隐呢,于是利用 Prototype 重写 Javascript,解决这个棘手的问题。
主要的 Javascript 修改,类似于:
- $('path_list_box').style.visibility = 'hidden';
- $('path_list_box').style.position = 'absolute';
+ $('path_list_box').hide();
- $('path_input_box').style.visibility = 'visible';
- $('path_input_box').style.position = 'relative';
+ $('path_input_box').show();

Redmine 邮件发送问题的诊断
9月17日
鉴于部分 redmine 爱好者因邮件发送问题很纠结,不知道为何他/她的 redmien 邮件时灵时不灵,回帖的地方太小,因此专门辟此博文。
(说明:下文中出现的 redmine 配置文件路径是 群英汇 Redmine 部署的标准路径,个人配置的 redmine 请勿对号入座 :-D )
Redmine Email 配置
配置文件为 /opt/redmine/web/config/email.yml 。我们内网的 redmine 的 email.yml 配置为:
production:
delivery_method: :smtp
smtp_settings:
address: localhost
port: 25
domain: bj.ossxp.com
# authentication: :login
# user_name: "redmine@example.net"
# password: "redmine"可以看出:
- 我们 redmine 服务器本身架设了一个 SMTP 服务器
这样就避免了使用其他 SMTP,由于授权、网络联通性、邮件发送频率限制、内容过滤等各种原因造成的邮件发送失败的问题 - domain 实际上是 SMTP 连接时 HELO 命令的参数。
一般情况,无所谓。但有的 SMTP 会作 DNS 查询,若 SMTP 客户端 IP 和该域名解析的不一致,可能会倒在这里 O:-) - 后面的三条认证相关语句注释掉,因 localhost 自身允许 open relay,故此没有必要设置认证
实际上,Redmine 的邮件发送框架采用 Rails 自身的 actionmailer,还有一些重量级配置
- logger: 是否对邮件处理产生日志?
Redmine 缺省 production(生产平台)的 environment 设置中, logger 被设置为 nil,不产生和邮件有关的日志 - raise_delivery_errors: 是否因为邮件发送错误,抛出异常?
如果设置为 true,则遇到邮件发送失败,页面显示异常,同时在 log 中也记录异常详细信息
直接在管理员界面测试邮件配置
看到“发送测试邮件”的链接了么?
Redmine 的日志文件
日志文件的位置在 /opt/redmine/log 目录下。对于生产平台,日志文件是 /opt/redmine/log/production.log。
一个 Linux 下跟踪显示 log 文件的小窍门:
$ tail -f /opt/redmine/log/production.log
产生更多的邮件相关日志
对于运行在 production 模式的 Redmine,日志很少,是因为配置文件 /opt/redmine/web/config/environments/production.rb 中关闭了 email 相关 log 等。
配置文件 /opt/redmine/web/config/environments/production.rb 和日志相关设置有:
- config.log_level = :error
日志级别。如果设置为 :info,则有更多日志。如果设置为 :debug,你会看到海量的日志。 - config.action_mailer.raise_delivery_errors = false
是否因为邮件发送错误抛出异常。设置为 true,你不会错过任何邮件发送失败了,不过副作用么… ;-) - config.action_mailer.logger = nil
不记录邮件相关的日志。注释掉这一行,就可以在日志文件中看到更多邮件相关日志了。
修改日志别忘了重启 Apache。注意:日志级别调整,会影响 redmine 的性能,在诊断结束后请复原。
用 Gitolite 搭建 Git 服务器
9月15日
上次给客户作 git 培训,PPT文档中关于用 gitolite 搭建服务器搭建有点语焉不详。
这次写了一个文档补上。 对 gitolite 的改进也已经 PUSH 到 github 上,可以公开下载了。
参见: 《Git 服务器构建》
关于 pySvnManager 的回复
9月15日
最近有网友问 pySvnManager 的问题,我把解答放到了这里
关于软件安装
问:
看到你开发的这个pysvnmanager很不错,比较适合于svn的 账户 权限管理,我的操作系统是centos,用easy_install安装的是0.4版本,不知道 哪里 有0.5版本下载呢?
答:
直接从 sourceforge.net 上下载源代码安装吧
安装出错
问:
我下载了源码,按照README中 的指导进行安装
$ cd config $ make $ python setup.py compile_catalog $ paster serve --reload develogment.ini 运行却报错如下: /usr/lib/python2.4/site-packages/PasteScript-1.7.3-py2.4.egg/paste/script/pluginlib.py:81: UserWarning: Unbuilt egg for pySvnManager [unknown version] (/usr/local/pysvnmanager) pkg_resources.require(plugin) Traceback (most recent call last): File "/usr/bin/paster", line 7, in ? .....
答复:
应该是依赖的 pylons 框 架未安装。
其实有源代码,你可以编译出 egg 包哇。
$ python setup.py bdist_egg
然后,就可以安装 dist 目录 下的 egg 包,安装 egg 包会自动安装依赖的 pylons 框架。
你看到 Readme 并执行的指 令是直接运行源码,为调试而用的。
关于认证
问:
还有一个问题想请交一下,我想从LDAP服务器同步帐号来做认证。现在单独从本地密码文件,或者单独LDAP服务登录都可以。但是两个一起用,好像不行。因为看到localconfig.py文件里面说可以二者都用。因为我想把root管理帐号认证放在本地,其他帐号放在LDAP服务器,不知道这样可不可以?谢谢!
答复:
同时用两种认证,就需要在 auth 数组同时加入两种认证方式,如下:
from pysvnmanager.model.auth.http import htpasswd_login
import ldap
from pysvnmanager.model.auth.ldap_login import ldap_login
auth = [htpasswd_login, ldap_login]
## LDAP login parameters
ldap_uri = 'ldap://localhost'
ldap_binddn = 'cn=ldapreader,dc=foo,dc=bar'
ldap_bindpw = 'guess'
ldap_base = 'dc=foo,dc=bar'关于 LDAP 用户组授权
问:
我还有一个问题关于LDAP账户同步的问题。我先在LDAP服务器上建立了一个svnusers用户组,把有权限使用svn的用户都加到这个组里面来;然后在apache里面读取svnusers组里面的memberUid来实现svn对特定组的账户读取。所以我就想问不知道能否在pysvnmanager里面实现这样的功能,也就是读取属于某一个组的用户帐号?
答复:
我的 LDAP 授权模型和你的不同,不是通过用户组而是为用户设置名为 authorizedService 多值属性进行授权。可以通过设置 ldap_filter 加以判断:
ldap_filter = '(&(uid=%(username)s)(authorizedService=svn)(ossxpConfirmed=TRUE))'
我的方案要新增 LDAP schema,可以配合我们公司的统一管理平台进行图形化的用户授权。
你的方案也很好,不过在认证过程增加了一次查询(用户组匹配),会影响执行效率。
我给中央领导留言
9月13日
今天下午从客户现场回公司,看到了新闻:中央媒体开设网上留言板 可给胡锦涛留言,为难得的话语权的到来而感激涕零。
上午在客户现场还顺便交流了翻墙技术,听到了客户对网络审核的抱怨。没有迟疑,马上就想利用难得的话语权,去给中央领导留言,也顾不上留言是第几百万条了,也不管有没有可能被关注。
下面就是我一直在思考的,想说的话…
UNetbootin 让Linux安装更简单
9月9日
一般 Linux 的安装采用光盘的安装方式,上周在客户部署就遇到服务器没有光驱的情形,临时四处去借,好狼狈。
光盘安装还可能遇到一个问题就是:由于硬件太新而光盘内核太旧导致无法识别硬件,安装失败。
用网络安装是个好方法,但一个是部署麻烦,还有引入DHCP服务器可能会和用户网络中已有的DHCP冲突。
UNetbootin 提供了另一种解决方案:U盘启动。
U盘启动不是什么新鲜话题,但偶然发现的 UNetbootin 项目,让 U 盘启动 Linux 安装如此简单。
- 提供图形化界面,点点鼠标就搞定 Linux 启动 U 盘
- 虽然本身不提供多启动U盘制作,但可以很容易手工编辑启动菜单,实现多启动U盘
- Debian和Ubuntu的启动支持网络启动,还支持从U盘中的 ISO 镜像执行安装
如果U盘太小,不能放下太多的ISO镜像,那么就用网络安装。如果能架设一个 Debian/Ubuntu 的软件包缓存服务器,网络安装的效率可以达到或超过光盘安装。




最新评论