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
答案是,我不确定,但是我更倾向于认为它是线程不安全的
原因在于
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
答案是肯定的,前提你在使用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
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的使用,只能作为类似备份的性质
(这是我在去年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.
剩下的就很简单了
去年受朋友所托,准备了一份在广州BEA user group演讲的rails ppt
可惜后来user group搁浅…
点击下面的链接下载
[download id="1"]
ppt是去年11月准备的,并未完全完成
本来想趁着把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的一些心得写下来吧。
http://www.javaeye.com/post/498557
copy on write array list
ConcurrentHashMap
ReentrantLock
ReentrantReadWriteLock
CAS
我都有在用,JDK内置
一直都想写一些关于它们的文章,不过始终太松散,而且我是知道原理然后直接用API而已
我随便说一些
楼主的copy on write模式是可取的,JDK很早就引入copy on write array list来处理Listener部分,在写入非常非常少的情况下,copy on write其实是很好的。至于楼主的实现好不好就不知道了
ConcurrentHashMap用了多个锁来处理,里面有一个一个的bucket来隔离锁,默认就是16个bucket&锁。但是它也有缺点,就是不能保证数据绝对准确,例如他的size就是不准确的。但是它肯定是线程安全的
ReentrantLock是可以代替synchronized的东西,除了写起来比synchronized难稍稍。默认是non-fair模式,比synchronized快很多,如果改成fair就会下降到跟synchronized差不多
ReadWriteLock很简单,read不互斥,write互斥
CAS就是AtomicInteger之类的了,使用了CPU的交换指令,理论上比锁快,但是在高并发的环境一样会下降
你们还是看一下JDK源代码和JavaDoc好过了,你们的讨论本来就有答案的
上次谈到一些Mercurial的事情,后来因为忙别的事情没有继续写下去。中途跟cyfdecyf通过几次email讨论Mercurial。总体来说,我对Mercurial和分布式版本管理的理解还是比较松散的,比较难形成文章,但还是很希望把我所知道的写出来。
我对分布式版本管理的理解很简单。首先这里假设你有一般版本管理软件的概念(CVS或者SVN)。假设你在家里装了一个SVN服务器,你在家里编写的代码都提交上去。在公司也装了一个SVN,你在公司编写的代码也都提交上去。这里就有两个完全独立的SVN服务器了。分布式版本管理,就是这两个SVN服务器之间可以互相提交,其操作就像你提交上其中一台SVN那样,SVN之间互相提交就会将多个changeset同时提交。而且这两个SVN服务器没有主次之分,这样处理是很容易混乱的,实际上,我们会架设另一个SVN服务器,作为两个SVN的父,两个SVN向父提交changeset。这个行为仅仅是方便我们管理的一个比较好的参考做法,并没有强制。另外,当然SVN服务器是不支持互相提交的,于是我们需要一个分布式版本管理软件。
个人觉得,一台SVN就好像一台MySQL,我们只有一个数据库。而分布式版本管理就好像Master-Master MySQL集群。有经验的朋友就会知道,在集群中使用自增字段是不可取的,就像SVN的changeset id是自增的不能适应分布一样。做MySQL集群很经常会用UUID作为主键,分布式版本管理也使用了类似的机制来保证多个库之间的changeset有唯一的ID不会冲突。这个已经是比较细节的处理问题。这里暂时不打算细节研究具体的机制或者使用方法,先有一个大概的概念,看软件的refrence很快会上手的。
再待续
预告:
权限问题
Mercurial目前的情况
远程模式
在Dreamhost上使用Mercurial
Mercurial基本使用
购买的虚拟主机没有备份服务(另外收费),但是很好地有SSH权限和Cron权限,于是写了一个简单的shell脚本备份打包mysql的数据,然后email到我的邮箱。但是Linux的mail命令并不能发送附件,于是自己写了一个小程序来发送附件。由于我比较熟悉Ruby,于是就用Ruby来实现,当然你也可以用Python或者Perl来实现
to_mail = ARGV[0]
backup_name = ARGV[1]
backup_attach = ARGV[2]
require 'net/smtp'
require 'rubygems'
require 'mailfactory'
mail = MailFactory.new
mail.to = to_mail
mail.from = "backup@weavesky.com"
mail.subject = "#{backup_name} backup"
mail.text = "no content"
mail.attach backup_attach
Net::SMTP.start("localhost") do |smtp|
smtp.send_message mail.to_s, mail.from, mail.to
end
后来我找到一些更简单的做法
uuencode file.txt file.txt | mail email@address.com
不过这种做法是不会产生附件的,仅仅将文件内容编码之后当content发送
如果你的机器上有装mutt的话,就更简单了
echo "no content" | mutt -s "subject" -a file.txt email@address.com
我现在就是用这种做法
Recent Comments