• 25 十一 2009 /  互联网技术

    昨天花了一下午的时间测试一个程序的执行效率,该程序是一个后台日志分析的程序,犯懒用php写的,毕竟php对文本处理效率很高(编写&执行),一开始担心php的数组按照键值查询效率低,所以使用memcache作为内存缓存来用。

    程序编写好后执行正常,当处理数据量上来以后,发现执行很慢。其它的项目中我也发现在压力测试时memcache会是瓶颈并导致很高的cpu占用,因此怀疑是否自己编译的php+memcached有问题,或者是其它问题。于是做了下面的测试。

    Trace for /logprocess/process_sessiontime_memcached.php
    Total Elapsed Time = 767.74
    Total System Time = 19.15
    Total User Time = 742.67

    Real User System secs/ cumm
    %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name
    --------------------------------------------------------------------------------------
    69.2 531.12 531.12 520.74 520.74 6.94 6.94 92646 0.0057 0.0057 0 Memcached->set
    21.4 164.18 164.18 157.25 157.25 4.85 4.85 92646 0.0018 0.0018 0 Memcached->get

    从上面的数据能看出,这个程序php执行的瓶颈在memcache,而set操作更加有问题,接近70%的时间都在做set操作,难道真是使用的模块有问题嘛?我查过php的memcached模块,代码基本上就是一个连接,实质使用的还是libmemcached这个库的内容,所以如果要是有问题的话也肯定在libmemcached这个上面。但网上搜索后,无果,没有人说它有问题。

    后来细想,按照上面的数据折算,读写平均的话122.22次/秒,读单独是564.30次/秒,写单独是174.47次/秒,数据表现也算不错了。写慢是memcache以及被测试的程序逻辑有矛盾,我了解了一下,memcache会使用item(key+value)的长度做前期的定位,试想如果程序使得value长度不断变化,是否set会不断移动item所在的slab位置呢(将旧的变成过期,再按照新写入数据的流程写入新的item)?没有深度考究,但觉得值得怀疑;如果写操作所占用的cpu释放出来的话,读的效率应该可以更高,回头可以测试一下,估计能超过1千次/秒。

    总结上述,memcache使用要被仔细的规划,取长补短,如果随意使用的话未必能有好的效果。上面的程序其实就不应该用memcache,频繁的写不是memcache的强项,而分布式、多点频繁读取才是强项。

    说道缓存,所以我顺便又测试了Alternative PHP Cache(APC)的模式,还是刚才的程序,出来的结果是读写平均392.57次/秒,比memcache快3倍多,我没有出读写分离的数据,估计如果单读的话,应该还能再快一些,毕竟APC是本地缓存。因此,如果你的应用不需要分布式的话,APC是一个很好的选择,它能帮你在一台机器的情况下,保持并缓存每次php请求之间的数据。其次,它还是一个类似eAccelerator的代码opcode缓存模块,可以提高php代码执行速度。

    最后,回到我一开始没有考虑的解决方案,因为我不需要跟其它进程或者服务器共享我的数据,所以直接用php的数组,处理速度是多少呢?15,441次/秒!当然啦,内部就是一堆指针指来指去而已,我没有想到的是数组在很多无序的key中找value还是很快的,所以以后大家可以放心这么使用,只是注意配置文件中允许的php运行时占用的内存再调大点就好了。

    总结,任何设计要根据具体的应用需求来选择解决方案,选择时要考虑所选技术本身的特性,取其优点避其缺点。Memcache不适合做数据频繁变化的内存共享,一次写入多次读取的模式会更适合一些。Tokyo Tyrant / Tokyo Cabinet / Redis也许能用于频繁读写的情况,我还没有时间去评测;BTW,以前还使用Mysql内存表做这类事情多一点,希望能构建一个数据写入缓存机制,但是实际使用时还是有一些问题,所以有空再找找新的解决方案吧。

    最后说一句,就一句:在Memcache盛行的当今,Memcache不可滥用。

    Tags: , ,

  • 23 十一 2009 /  互联网技术

    脑子不好使,只能记录下来以后备用

    首先python有几个版本,我现在选择的是2.5版,版本越低,可选择的第三方支持包就越多,当然也要平衡,低版本也会有性能问题,或者小bug。2.6是3.0的过度版本,有很多新的特性但又兼容老的版本(3.0有些老版本的语法、特性就不支持了),所以权衡选择了2.5版。

    python自身的安装比较简单,在linux下就是通过源码编译就可以了,需要注意的是,python在linux系统下作为很底层的语言支持,通常系统会有一个版本默认已经安装了,如果你觉得那个版本够用就直接用,如果安装新的版本,最好不要改动或者覆盖那个版本。我一般都在/usr/local/python2.5目录下安装一个新的,然后ln -s /usr/local/python2.5/bin/python2.5 /usr/bin/python2.5,这样原有的版本和新的版本互不干扰。

    python的扩展包很多,一般分成两类,两种方法来安装
    1、扩展包是直接的源码包
    通常这种包解开后会有一个setup.py的文件,使用你希望安装这个扩展包的python版本来运行python setup.py install就可以完成安装,当然你也可以先python setup.py make再install,意思和linux下编译源代码的流程是类似的。

    2、.egg文件
    这种类似jar的代码包是一个叫easy_install的项目产生的,首先你可以下载并安装easy_install;如果你的easy_install是.egg结尾的,可以使用sh easy_install.egg来安装。如果是普通源码包就参考上面第一种方法安装。
    安装后会在 /bin/目录下多出来一个叫easy_install的脚本。你下载的.egg包就可以运行./easy_install xxx.egg来安装了。
    当然还有一个更简单的方法,就是./easy_install module_name,这样它就会在网上找到适当的模块进行自动安装并且保持模块之间的关联。
    easy_install除了网上查询包自动下载,后续的工作就是在 /lib/python2.5/site-packages/目录下的easy_install.pth文件中加入了.egg文件的关联而已,并且将.egg文件拷入上述这个目录,这样python在寻找软件包的时候就能找到并自动装载。

    BTW:有关Python MySQLdb模块
    上述安装方法很自然就可以将这个模块安装好,但是我的习惯不喜欢将mysql客户端的库放在默认的位置,导致实际python导入模块的时候会报错,这时候只需要将你的库文件路径加入/etc/ld.so.conf中,并且执行ldconfg -v就可以了。

    Tags:

  • 19 十一 2009 /  杂项

    over-working

    最近又听说有人因为工作劳累而驾鹤西游了,某公司危机公关忙得不亦乐乎,顿时觉得有点悲哀。

    记得Joel Spolsky在他的The Best Software Writing I这本书里面收录过一篇文章叫EA: The Human Story,主要内容是描述EA内部过渡加班的问题,并且用数字说明加班也许并不能提高工作效率,反而会降低工作效率,引发员工很多心理问题导致最后人员流失。

    个人认为公司不能将加班当做正常的一种工作手段,如果你在估算工作计划的时候就把加班考虑进去了,那你就丧失了所有缓冲时间;试想加班是计划的一部分的话,如果不能按照计划完成,你还有什么选择?

    人是有周期性的,长期在高度紧张的状态容易效率低下以及疲惫不堪,情绪会非常波动,整天只有身躯在办公室里坐着而思想不知道跑到那里去了,这样的表现公司是不愿意看到的,但老板通常会想念大家,希望7X24小时在公司能看到大家忙碌。停下来想一想,这样的效果好嘛?磨洋工对项目有意义嘛?

    在不能改变别人的情况下,你就需要自己注意,如果觉得累或者情绪不好,就干脆什么都停下来,休息,睡个觉,做点别的无关的事情,也许做着做着你就有新的工作思路以及冲动了。

    希望传闻的悲剧能被合理的解决,并且大家尽量避免悲剧的再度发生。