python在生产环境可选的memcached lib

May 15th, 2009 Sparkle 5 comments

memcached对动态语言帮助很大,因为动态语言的模式和实际的部署模型,python/php/ruby等不可能像Java那样在JVM内存中开辟一块内存来缓冲数据(而实际上Java这样做也会遇到容量不够,GC,集群等问题)。不过在实际使用中,我发现python memcached lib并没有想象中那么成熟、完整,经过一番研究之后,目前至少能勉强在生产环境中使用。

从memcached官方wiki中可以看到,python还是有不少可以使用的lib的,但是经过测试和比较之后,发现选择的方案也不多。我们还是从比较出名的web框架入手吧,毫无疑问,Django是目前python最好的框架之一,在生产环境使用它的人也比较多,而且它的文档很详细,有一节就是专门提到cache的部分 。Django推荐使用cmemcache,在不能使用cmemcache的情况(例如windows机器),就使用python-memcached。经过我的实际测试,这个或许不是性能最好,版本最新,功能最多的选择,但是是一个很稳靠的选择。

cmemcache封装的是libmemcache,这个类库很久没有更新了,目前libmemcached比较活跃,功能也比较全面。这里值得一提的是Python libmemcached是来自豆瓣贡献的类库,不过因为使用的人不多,所以最终我没有选择。另外还有一个pylibmc也是对libmemcached的封装,这是cmemcache_hash的作者写的类库(稍后会提到cmemcache_hash),很可惜我一直没有编译成功。

但是实际使用cmemcache/python-memcached的组合也是要进行一些封装的,首先有cmemcache不是线程安全的问题 ,另外就是Python libmemcached的hash算法有问题。什么?你从来不用超过1个的memcached服务器?我还是建议你至少用2个memcached服务器吧,至少有backup。

而cmemcache和Python libmemcached的hash算法不一样。这里我们还需要cmemcache_hash,名字可能有少少误导,它的作用是领到Python libmemcached的hash跟cmemcache一致

于是我们的封装代码大概是这样

try:
    import cmemcache as memcache
    logger.warn('load cmemcache')
    # although cmemcache might be thread safe
    # but we still make it thread local
    # also it can use separate socket connect in each thread for more performance 
    from threading import local
except ImportError, e:
    logger.warn('cmemcache error: %s', e)
    import memcache
    import cmemcache_hash
    logger.warn('load python-memcache with cmemcache_hash')
    # python-memcache is already using thread local
    class local():
        pass
 
class Memcache(local):
    def __init__(self, servers):
        self._current = memcache.Client(servers)
    def current(self):
        return self._current
Categories: Uncategorized Tags: ,

python cmemcache是不是线程安全的

February 14th, 2009 Sparkle 6 comments

答案是,我不确定,但是我更倾向于认为它是线程不安全的

原因在于
1、网上任何讨论,都从未提及过cmemcache所用的libmemcache是线程安全的,也没有提及过cmemcache实现了线程安全,而libmemcached从一开始就强调自己是线程安全的
2、我个人不太熟悉C代码,所以看libmemcache的代码也没有办法判断出来,但是我看到cmemcache的c接口代码在针对socket操作的代码前后使用了Py_BEGIN_ALLOW_THREADS;Py_END_ALLOW_THREADS;进行包围,而这两个宏的作用,是解除GIL,让多线程可以进入相应的代码。天啊,本来我们还期望对socket操作进行加锁,现在竟然还竟然解除GIL。本来因为GIL的存在,可能还有些希望,现在cmemcache为了让socket操作不要阻塞,反而令到自己是线程不安全的。(如有理解错误请指正)
3、python一直习惯的部署模型是单线程多进程,所以线程安全对很多类库来说,并不重要也不考虑。但是现在越来越多的python程序部署使用了多线程的模型(又或者多线程多进程),线程安全问题也凸显出来

综上所属,我的结论是,我不确定是否线程安全的,呵呵,但是我认为要进行线程安全的修正,至少没有坏处

修正方法很简单,直接套用python-memcached的做法(至于这种做法的优劣也在那篇文章有提及到)

import cmemcache as memcache
from threading import local
class Memcache(local):
    def __init__(self, servers):
        self._current = memcache.Client(servers)
    def current(self):
        return self._current
Categories: Uncategorized Tags: ,

python-memcached是不是线程安全的

January 22nd, 2009 Sparkle No comments

答案是肯定的,前提你在使用Python 2.4+和python-memcached 1.36+
为什么我们需要线程安全的memcached client,因为我们的实际应用一般是多线程的模型,例如cherrypy、twisted,如果python-memcached不是线程安全的话,引起的问题不仅仅是并发修改共享变量这么简单,是外部socket链接的数据流的混乱
python-memcached怎么实现线程安全的呢?查看源代码看到

try:
    # Only exists in Python 2.4+
    from threading import local
except ImportError:
    # TODO:  add the pure-python local implementation
    class local(object):
        pass
 
 
class Client(local):

很取巧的让Client类继承threading.local,也就是Client里面的每一个属性都是跟当前线程绑定的。实现虽然不太优雅,但是很实在
但是别以为这样就可以随便在线程里面用python-memcached了,因为这种thread local的做法,你的应用必须要使用thread pool的模式,而不能不停创建销毁thread,因为每一个新线程的创建,对于就会使用一个全新的Client,也就是一个全新的socket链接,如果不停打开创建销毁thread的话,就会导致不停的创建销毁socket链接,导致性能大量下降。幸好,无论是cherrypy还是twisted,都是使用了thread pool的模式

参考资料:
http://code.djangoproject.com/ticket/3701
http://lists.danga.com/pipermail/memcached/2007-June/004482.html

Categories: Uncategorized Tags: , ,

Mercurial和Git的主要区别

August 17th, 2008 Sparkle 5 comments

1、Mercurial用Python开发,Git用C开发,相对来说,Git比较快,但是Mercurial的性能也不差
2、Mercurial对windows平台支持比较好,而且有一个开发中的TortoiseHg,而且NetBeans内置支持,Git主要还是用命令行,而且对windows不太友好
3、Mercurial核心指令只有10个左右,Git核心指令几十个,全部指令更多了,Mercurial比较简单,也容易上手
4、Mercurial一个目录树就是一个分支,需要使用分支就必须clone一份完整的目录树,这样比较浪费空间,而且使用IDE的时候要为新分支开一个新项目,Git支持本地分支,在一个目录树里面开无限个分支,切换非常方便迅速。这个功能也是我慢慢迁移到Git上的主要原因
5、Git内置对SVN的支持,现在也很多人在SVN repo上使用Git,方便自己的分支开发,当然跟别人合作还是会受到SVN本身的限制,Mercurial有一个第三方的hgsvn,最初的版本还有编码问题,现在已经修正了,但是它只能从SVN导入数据到Mercurial,不能把在Mercurial做的提交导入SVN,作者说未来会制作这个功能,这样就限制了hgsvn的使用,只能作为类似备份的性质

Categories: Uncategorized Tags: ,

在Squid后面的Nginx如何记录客户端IP

July 17th, 2008 Sparkle 4 comments

(这是我在去年12月的时候查到的资料,不知道现在nginx的文档有没有更完善)
通常我们会在web server前面部署squid,这个时候web server的所有请求都是来自squid,那我们的web server的日志记录到的所有请求都是squid服务器的IP。这个时候,我们会让squid发出一个X-Forwarded-For的header包含真正客户端的IP,我们需要修改web server的日志记录字段用header X-Forwarded-For代替remote_ip,apache的修改方法很简单,这里就不说了。
这里要说的是nginx的修改方法,其实原理很简单,但是nginx的文档里面完全没有提及怎么拿某个header,ft。最后还是在maillist找到答案的
http://thread.gmane.org/gmane.comp.web.nginx.english/944/focus=946

All client headers are available as $http_… variables.
For example, “X-Strange-Header” as $http_x_strange_header.

剩下的就很简单了

Categories: 互联网 Tags: ,

mercurial的现状

June 23rd, 2008 Sparkle No comments

最初是从cyfdecyf的文章认识mercurial的,后来用netbeans开发rails,当时netbeans 6.0还没正式发布,我在用netbeans 6.0测试版,发现竟然有mercurial插件,而且更新相当频繁,于是也对mercurial颇有好感,到后来mercurial插件纳入netbeans正式发布包里面,之后netbeans宣布从cvs转到mercurial,这一切都很自然发生了.mercurial 1.0正式发布,而且有netbeans插件,还有TortoiseHg这个类似TortoiseSVN的windows工具,再加上指令并不多(十条指令左右,相比git的几十条指令),而且你还可以在dreamhost上搭建你的中央源,mercurail始终是新手和小项目的首选

Categories: Uncategorized Tags:

mercurial&git的远程模式

June 23rd, 2008 Sparkle No comments

mercurail和git是一个很自由的版本管理软件,我们随时可以在自己的机器上任意一个目录启用版本管理,不需要任何服务器.但是,当我们需要跟别人协作的时候,应该怎么处理呢.我们可以N个人之间互相乱pull来push去,但是这样的网状结构并不方便管理,非常容易混乱,一般来说,我们会指定一个中央源,大家都把代码push到中央源.我认为它们的远程模式有如下几种:

1.U盘

最常见的情况就是我在家和公司都要使用同一份源代码,于是我就会把中央源定在U盘上,而家里和公司的电脑各有一份本地副本,代码提交到本地,然后push到U盘上.例如我会在U盘上建立一个sparkle_repo的目录,放少量代码和一些文档用git管理.也有不少人是这样用SVN的,不过经常会遇到盘符变化的问题.

优点是完全不需要网络,缺点也很明显,如果要跟朋友协作的话将会相当麻烦

2.网上邻居共享文件夹

很简单,在本地网络随便找一台机器共享一个完全读写的文件夹,然后把中央源放在上面,适合公司内部的简单使用.

优点是简单,缺点是,别人都能完全读写文件夹,干什么事情都可以了,包括删除整个目录.你当然可以进行权限认证,但是认证通过之后,一样可以做任何事情

3.ssh

功能丰富的ssh对于传送文件当然不在话下(我工作的时候都是用ssh而不是ftp传送文件),最适合有个人ssh主机的情况,例如拥有一个dreamhost的空间,你只要在ssh帐户下随便开一个目录就能作为中央源,但是如果你要跟朋友协作的话,你还是得告诉他你的ssh帐号,又或者你对机器有足够的控制权可以让两个ssh帐号访问到同一个目录.另外,ssh比网络邻居要好的地方是你可以控制能够通过ssh的指令,这样可以只允许mercurial/git的指令通过,防止有意或无意的删除目录

以上三种模式其实原理是一样的,就是通过一个大家都可以读写的目录进行协作

4.私有协议

mercurial&git都可以启动一个daemon server进行使用,mercurial启动的port是8000,其实是使用http协议的,而经常见到的git://xxxxx就是git的私有协议.由于要启动额外的daemon,你必须对机器有一定的控制权才行,例如你不能在dreamhost这样使用.

5.http模式

git只能通过http进行查看和pull,不能进行push操作,有点像viewcvs那样.这点来说,mercurial就比较厉害了,官方包里面提供了一个hgweb.cgi文件,通过配置这个cgi文件,我们可以在一个apache环境中提供push功能,也就是说我们可以在dreamhost上这样使用mercurial,非常棒(下一篇文章我将介绍怎么在dreamhost使用mercurial)

6.Don’t push to me, I will pull from you

是不是有点像IOC(Don’t call me, I will call you).我阅读到相关资料的时候,看见这样一种模式,简直有如脑袋哐当一声.我们太以中央式版本管理的思路来想分布式版本管理了,认为一定要有一个中央源,然后大家都push数据到中央,而且还要认证什么的.git提出的这种模式,就是没有中央源,但是有中央人,并不是大家push到中央,而是中央从大家那里pull,其他人只要用某种形式,例如共享文件夹,或者http等方法公开你的副本,然后发email什么的通知中央人到你的副本中pull.
例如我sparkle负责整个项目,然后我只从各个模块的主管的源那里pull数据,而各个模块的主管从他的手下coder pull数据(事实上使用git的大型项目都是分成多个级别的),我熟悉模块主管,所以我知道他们是可信的,至于他们的数据从哪里来的我不关心,而他们也对他们的手下coder信任,从他们那里pull数据,如此一级一级下去.这种处理模式,一来不需要认证的部分,二来中央的数据是可控的,就是我负责,而不是多个人push的模式那样,并不一定能确定是否正确,第三点,可以分级.

Categories: Uncategorized Tags: ,

一份未使用的rails ppt

June 23rd, 2008 Sparkle 1 comment

去年受朋友所托,准备了一份在广州BEA user group演讲的rails ppt
可惜后来user group搁浅…

点击下面的链接下载

  rails.pdf (1.8 MiB, 638 hits)

ppt是去年11月准备的,并未完全完成

Categories: Ruby Tags: , ,

Mercurial之权限问题

June 9th, 2008 Sparkle 3 comments

我多次跟朋友讨论分布式版本管理软件的时候,都提到一个固有的缺陷,就是权限认证问题.传统的中央式版本管理软件,例如SVN,可以很简单地在服务器上做登录验证,可以阻止非法用户获取文件,当然,你可以使用一些外部手段来进行读取限制,例如http basic认证,iptables等手段,但是这样只能针对整个Mercurial库进行控制,不能像SVN那样对某一个目录树进行限制,你可以把不同的模块使用独立的Mercurial库来保存,但是那会增加管理的复杂性,而且你很难实现权限组的概念.不过,分布式版本管理最常用的地方是开源领域,也因此SVN比较适合公司内部使用,一般情况你也不希望员工能方便地把源代码带回家.

上面提到的是权限问题,另外一个比较大的就是认证问题.回想一下我们使用SVN的流程,我用sparkle&password登录SVN,然后提交修改,别人就能在SVN上看到这次的修改是我提交的,因为只有我才拥有sparkle这个帐号的密码,别人就没有办法冒认我.而使用Mercurial的时候,我们根本不用登录(当然有些远程模式可以配置需要登录,但是并没有认证效果,我在迟点专门写一篇远程模式的文章),使用Mercurial的时候,我们一般会先设置我们的名字,例如Sparkle,但是,别人一样可以取这个名字,你根本没有办法证明/阻止别人冒认你.又比如说我一个朋友Nomad的提交让我一起commit到center,我先把Nomad的修改pull到我这里,然后我再push到一个大家认为的公共库center,也就是说我同时把写着是我的修改和Nomad的修改提交,我随时可以假冒Nomad.

当然,你也可以认为大家都是守法的,比如说团队成员是可控的,但是这始终是个问题.因为没有了中心,也就没有了认证的可能性.其实有一个办法可以解决,就是使用证书签名,在我的提交里面,我附带一份使用我的私钥对此修改的签名,大家就可以通过公钥去验证这的确是我签发的,就能证明我的身份.不过目前大家还是比较少用这种模式,因为使用成本也挺高的.

Categories: Uncategorized Tags:

我为什么放弃使用cacti

May 7th, 2008 Sparkle 5 comments

本来想趁着把cacti从我的生产服务器中移除之前,把我之前的安装配置写成一篇文章,结果发现我已经无法理解cacti是怎么配置的,这也是我放弃使用它的其中一个原因。

在这里,我先说说cacti和mrtg、rrdtool之间的关系,或许还有一些朋友不是很了解。mrtg和rrdtool都是Tobi Oetiker的作品,rrdtool是一个循环式数据库工具,它只负责存储数据,而mrtg是一个采集和画图工具。经常我们能看到cacti和mrtg的对比,那是因为他们两者的功能是一致的,都是采集画图,其实cacti也是是用rrdtool来存储数据,甚至更多其他的网管软件,都是使用rrdtool来存储,我只想说,rrdtool是一个神物。绝大部分人都认为cacti比mrtg好,的确,mrtg比较久远了,功能也比较欠缺,cacti通过php和mysql的辅助提供更多的功能,也提供更直观的界面

但是,cacti太复杂了。需要php(还好),需要mysql(我真的没有的话怎的),还有那个烂鬼snmp协议(当然,mrtg也是通过snmp采集协议的)。我真的不明白,snmp是一个怎样的简单网络管理协议,我觉得一点也不简单,也不直观。或许可能是因为我没有受过正统的网管培训的缘故?说实在话,我真的不知道当初我是怎么把linux下面的snmpd的配置调出来的,基本上完全不明白每一个参数是什么意思,参数又是怎么跟网络流量,硬盘空间挂上关系。当然,如果你的对象是一些cisco设备就不一样,一般情况下他们都是预配置好暴露什么数据。但是如果你的设备是一台linux服务器,那使用snmp协议就变得很麻烦。

我需要一种agent模式的网管软件,而不是一个什么简单通用的网络协议,agent跟它的采集器之间跑什么协议我不关心,当然如果可以简单地做二次开发就更好了。其实,在linux下使用snmp来采集数据,某种程度都可以说是一种agent模式,因为我需要在linux机器上安装snmpd这个agent,只是这个agent很难配置。反正我都要在linux上面安装软件的,何不选择一个很直观的agent模式的软件呢,而且是可以直接调用shell之类的实现监控script的功能,说实在话,怎么通过snmpd然后调用script或许我需要的数据,我真的不知道。

于是,我选择了nagios,很简单明了的使用方法,和plugins编写方法,我甚至还用ruby写了一个script来监视某个进程是否还在运行的plugin。可惜nagios并不支持数据采集,它仅仅是一个监控,监视某些状态值是否正确,而没有把数据值的历史记录下来,nagios并不使用rrdtool。其实,nagios并不是跟cacti/mrtg等同的工具,我还需要一个采集画图的工具。再搜索nagios资料的时候,我发现twitter也是是用nagios的,另外他们还是用了munin。munin正是我也需要的东西,agent模式,不需要mysql,方便的插件编写。我只花了半天时间就把它使用起来了,迟点还打算写一些munin的插件。

我是没有打算把cacti的安装配置使用写下来了,迟点我把nagios和munin的一些心得写下来吧。

Categories: 互联网 Tags: , ,