2011年8月17日星期三

除虫故事(三)

    第三个bug是刚出的,贝壳刚刚从现场回来,提交了bug系统关闭申请。
    问题是这样的,我们有一套系统,为客户提供从web访问某台windows的能力,作为管理系统使用。这个系统的后台使用了三四个不同的程序,通过管道通讯。目标设备上有一个组件,要适应2000/2003/2008的32位和64位环境,非常复杂。最近,贝壳将这套系统的目标设备的组件进行了重编译,提供了64位版本。然后测试发现,32位系统不工作了,64位系统正常。
    第一反应是什么?一定是组件有问题?贝壳在服务器上,直接使用连接程序去连接,结果是成功的。这个表明组件应当是正常的,或者部分正常。问题就在web页面到连接程序的过程中某处。
    负责web界面到连接程序的工程师同事接手了下一步排查,他也是一头雾水。系统看来一切正常,连接程序明明可以工作,为什么从web页面调用就会失败呢?而且只有32位会失败。web页面对CPU字长(而且是目标设备的CPU字长)并不敏感阿,这个听起来不合理。
    测试过程中,测试部门的同事偶然的看了一下日志系统,发现了问题。我们的连接程序会写出日志,默认情况下这个日志的属主应当是web.web的,而当时的日志是root.root的,而且权限是644。所以当连接程序被直接调用,当前id是root,就可以连接成功。而连接程序被web调用,当前id是apache,日志写出就会失败,程序就挂了,目标设备会失去反应。
    出现这个错误的原因也很直观,在某次调试后,有人删除了原始的日志,并且直接执行了连接程序。但奇怪的是,同样是连接程序挂掉,为什么64位就可以继续执行呢?我们讨论不出为什么,只有基本猜测,64位设备是2008,rdp服务版本比较高,所以相对健壮。
    所以,实际的错误是两个。一个是日志权限导致的连接程序不工作。另一个是64位下不正常的连接程序依旧可以工作。
    好吧,总结一下这个奇怪的问题中的教训。
1.隔离最小差异。要验证是否是组件升级导致问题,一定要进行旧组件测试,然后再测试新组件。万不可假定旧组件可以正常运行,直接测试新组件,从而将非组件问题带入排查。
2.单元测试隔离。每个部分都要做单元测试,如果测试通过却无法连接,那就是环境问题。再查不出,再检查通讯/调用记录。
3.通讯系统关联错误。当两个程序通过通讯工作,其中一个程序死亡时。另一个程序应当能够检测并且报错退出,而不是出现各种异常反应。
4.日志底线设计。程序一定要写日志,如果日志写不出,就写系统日志,再写不出,设法报全局错误。

2011年8月15日星期一

ACC lead to no core temp reading?

    I bought a Phenom II X4 955 CPU month ago, recently I find that HWMonitor can't read core temp, just motherboard temp. I googled it and find this article. This article said that ACC is a tech will make AMD X3 work like X4 by unlock cores in BIOS. But CPU core temp sensors will not work, even use a real four cores CPU.
    贝壳一个月前买了一块羿龙II X4 955(黑盒),但是最近发现HWMonitor读不出核心温度,只有主板温度。放狗搜了一下,找到这篇文章。根据这篇文章说,ACC是一种能够让AMD三核CPU像四核一样工作的技术,只要在BIOS中打开unlock cores选项就好。但是这个会使得CPU的核心温度传感器不工作,即使你真的有四个核,而不是仿冒四核。

2011年8月14日星期日

linux下的文件系统选型

    贝壳原来一直认为文件系统可以随便选,结果最近吃了两次苦头。一个是btrfs对虚拟机支持不良,另一个是特定情况下xfs性能比ext3高20倍。痛定思痛,打算列一下文件系统选型的方法和依据,欢迎拍砖。
    下面我列一下纳入参考的文件系统,当然,ntfs就不要出来搞基了,玩嵌入式/光盘live之类的朋友也不要来凑热闹了阿。btrfs(简介), ext3ext4(简介), jfs(简介), reiserfsxfs,基本涵盖常用文件系统。最下面加入ntfs和zfs对比,实际上不参与选型。以下进制换算为1024,大小依次为KB,MB,GB,TB,PB,EB,ZB。
文件系统 btrfs ext3 ext4 jfs reiserfs reiser4 xfs ntfs zfs
最大卷容量 16 EB 32 TB 1 EB (16TB) 32 PB 16 TB ?? 16 EB 256 TB 16 EB
最大文件容量 16 EB 2 TB 16 TB 4 PB 8TB 8TB 8 EB 16 TB 16 EB
目录结构 B tree list/tree list/Htree B tree B+ tree dancing B* tree B+ tree B+ tree hash table
文件分配 extents bitmap/table bitmap/extents bitmap/extents bitmap ?? extents bitmap ??
ACLS Yes Yes Yes Yes No No Yes ACLS only Yes
checksum Yes No journal No No No No No Yes
透明压缩 Yes No No No No Plugin No Yes Yes
透明加密 No No No No No Plugin No Yes Yes
online defrag Yes No Yes Yes No Yes Yes Yes Yes
shrink Yes Yes Yes No Offline resize Offline No Yes No
特性 SSD





Stream
    首先,文件系统选择上要考虑现实性和支持情况。如果你希望得到广泛的支持,在移动硬盘上被多个系统挂载,应用于老内核,或者不使用/boot分区,那么可选项目基本只有ext3。作为老牌文件系统,ext3的支持是最广泛的,工具组也相对全面。无论其他文件系统拥有多大的优势,在现实情况考虑下往往会败给ext3,基本就是因为广泛的使用和支持。另外,btrfs我所知还没有fsck工具,出了问题全看RP,而且在上面使用虚拟机速度特别慢。reiser4作者目前在监狱中,出了问题能否获得支持全靠RP。jfs用的人相对xfs少一些,也比较不活跃。这些虽然并不出现在数据上,但是最好特别注意。
    其次,文件系统的选择要考虑必要特性。例如如果你希望使用SSD支持,你可选的项目就只有btrfs。如果需要透明加密,那只有reiser4。当然,在决定必要特性前,请仔细考虑,自己是否真的必须使用这些特性。为了一个不必须的特性选用一个不合适的文件系统会付出极大代价。linux下文件系统还是比较单调和弱小了点,基本不支持透明压缩,全部不支持透明加密,ext两兄弟更是没有完全实现Btree目录结构(ext4其实有用Htree,一种改过的Btree,不过为了兼容ext3,好像升级来的目录不使用)。不过好佳在,大部分都支持online defrag/growing,否则不如一头撞死算了。ext3/4, btrfs是支持shrink的,但是jfs, xfs只支持growing,reiser4必须offline shrink。xfs的growing在1T(一说2T)以上有点问题,非64位内核在1T以上可能无法创建inode。本来是会在1T内创建inode,使用高位空间。但是growing的时候可能地位空间已经满了,会报没有空间的错误。解决方案是将老文件移出再移回,或者看看用inode64参数是否解决。如果你确定需要shrink,最佳选项是使用ext4。另外补充一点,ntfs的online shrink也不是完美无缺,他只能shrink到未被使用的地方。也就是说,如果有不可移动文件,有可能就无法shrink到以下内容。
   第三个要确定的问题,是你的系统服务的数据大小。即使是表里面最小的ext3,一次也可以使用2T的卷。贝壳全部数据加起来大概2T多一点,家用绝对不成问题。然而作为商业用途,动辄数百T的数据正常到不能再正常,ext3就可以直接出局了,同理reiser4也直接出局。jfs是唯一没有达到EB级别的文件系统,不过32PB也可堪一用,大部分商业系统都到不了这个量级。在管理大型卷的时候,bitmap比extents会消耗更大的空间进行管理。因此不支持bitmap的文件系统可以少考虑,ext3/4虽说支持extents,但是ext3中默认不开启,必须手工指定挂载参数。ext4中一旦启用extents,就无法兼容于ext3。
    最后是性能考量。在贝壳在公司的测试中,xfs会性能高于ext3达20倍。因为根据这篇文章,xfs的随机写性能比ext兄弟差很多,但是顺序写的性能比ext要强上无数倍。我们的业务大部分情况下是顺序写,因此差异非常明显。所以,当你的特性要求差不多的时候,性能和稳定性是另一个考量因素。
文件系统 btrfs ext3 ext4 jfs reiserfs xfs
全填充速率 1m22.083s 1m34.821s 1m15.495s 1m5.819s 1m34.310s 1m38.953s
全填充利用率 0.8945 0.9065 0.9047 0.9959 0.9927 0.9918
大文件效率 14.676 17.435 10.7255 13.7493 14.319 12.7093
大文件删除 2.693 5.262 2.422 0.037 1.802 0.296
小文件效率 9.949 5.131 2.7866 40.949 13.605 8.978
小文件删除 6.737 10.7227 1.39 16.116 2.756 5.653
循环列文件 0.124 0.089 0.002 0.094 0.19 0.099
大文件read 2046206 1931451 1946598 2003912 1537752 1970242
大文件write 1279625 565960 926461 962617 446841 812466
大文件rndread 2012771 1926287 1934420 1985273 1490199 1976056
大文件rndwrite 1380404 1187010 1294689 1446011 1308210 1384804
小文件read 2375893 2934815 3019732 2708437 2559371 2236197
小文件write 926602 526469 681710 844237 395810 939536
小文件rndread 3324647 3544566 2702282 3737551 4045575 2666753
小文件rndwrite 910277 1525970 1244240 1910756 1790393 1311261
    以上数据,在公司的debian testing上测定。机器型号Dell Inspiron 560s,CPU Dual-Core E5700,4G内存,硬盘WDC WD3200AAKS-75L9A0。系统是debian testing,内核2.6.39-2-amd64。全填充是用time dd if=/dev/zero of=abc来测试填满一个分区的速度和容量。大文件是四个ISO文件,共1.3G,从tmpfs上复制到目标设备上的时间平均值,三次平均。小文件是pypy/python2.7/linux kernel2.6.39所有源码,总计49242个文件,629M。从tmpfs上复制到目标设备的时间平均值,三次平均。循环列文件是通过time find .测试效率。下面测试单位为bytes/sec,是iozone测试结果。
    首先是文件利用率,btrfs/ext3/ext4会消耗10%左右的空间作为系统消耗。如果你需要比较高的磁盘利用率,请不要考虑这三种系统。也许你会认为,放文件又不会放满,必须空出部分来才能减少文件碎片。实际上,被消耗掉的空间也并不是白白消耗,你的所有数据,都会增加10%的系统消耗空间。因此ntfs的防碎片阀值(为了防止碎片化,磁盘使用率不应当高于)大约是85%,而ext3就只有75%-80%。
    其次是大文件效率,除了ext3不予考虑外,其余系统都过的去。btrfs/ext4在删除大文件的时候耗时略多,大概是和管理特性有关。
    第三是小文件效率。如果你需要用小文件,千万不要考虑jfs,慢到我无法相信。ext4比btrfs和xfs快了四倍左右,非常适合操作大量小文件。例如源码编译,有blog说ext4比xfs快数倍。
    最后是循环列文件效率,同样,ext4一枝独秀,其余水准相去不远。

    综合以上几个考量,linux中比较推荐的文件系统是ext4, xfs两种。大量文件存储用xfs,小规模文件密集使用用ext4。在特定情况下,可以使用btrfs(它的特性非常全)或者jfs(小文件操作慢,但是随机读写快)。兼容考量下,可以用ext3。不推荐使用reiser4。

参考:
  1. Linux filesystems benchmarked: EXT3 vs EXT4 vs XFS vs BTRFS - Bonnie++ random seeks and file handling
  2. Ext4 ReiserFS Btrfs 等7种文件系统性能比拼
  3. Filesystems (ext3, reiser, xfs, jfs) comparison on Debian Etch
  4. XFS, Reiser, JFS & ext3 performance on Suse 9 Enterprise
  5. Filesystems (jfs, xfs, ext3) comparison on Debian

2011年8月10日星期三

硬盘底座入手

    贝壳买的新硬盘底座入手了,质感不错,很沉,只是在插入硬盘的时候对准不是很方便,总是要对一下才能对准。而且硬盘插上去有点摇晃,如果长时间使用还是会伤硬盘的。不过针对短时间使用,底座正是一个好解决方案。
    硬盘底座,就是将硬盘插上去,然后接入电脑的器件。现在大部分硬盘底座都是sata接口的,以前有IDE接口的,贝壳试过,不稳。IDE本身就不支持热插拔,硬做上去当然好不到哪里去。通常而言,硬盘底座/移动硬盘/sata热插拔是三种相关又各有特点的解决方案。底座的目标是使得硬盘可以更换,使用底座的人,多数希望在一台电脑上更换使用一个接一个的硬盘,对硬盘没有特殊要求。移动硬盘,基本就是把底座的硬件和硬盘捆绑到一起。使用移动硬盘的人,是希望一个硬盘在一台台的电脑上使用,对电脑没有特殊要求。而sata热插拔是强调热,即可以不关机接入设备,对台式机用处不大。通常是现场空间不足了,不能关机增加存储设备造成的需求,对插拔次数支持并不好。有资料说,普通sata接口大概能承受50次的插拔。普通硬盘安装而言,50次是一个非常足够的数目了,但是移动硬盘使用的话,几天就用光了。
    底座支持两种接口,usb2.0和esata。前者的速率是480bps,后者速率是3.0Gbps,合前者最高60M/s,后者最高375M/s。一块民用硬盘的突发速率往往高达150M/s,usb对于普通台式机而言显然是远远不足了。而且esata直接挂入硬盘控制设备下面,而USB则是挂入USB控制器链,效率上说差了一点不说,而且esata是作为普通硬盘对等管理的。
    贝壳本次的方案,是通过一根sata 2 esata接线,将mini-itx主板上的一路未使用的sata引出机箱,连接到底座上。但是linux下要支持esata,必须在BIOS中将SATA设备模式改为AHCI,而后重启进入系统,可以看到设备变了。当然,这个改变对于windows系统来说是个灾难,但是linux系统完全不在乎这个事情。
debox:~# lspci | grep -i sata
00:1f.2 SATA controller: Intel Corporation N10/ICH7 Family SATA AHCI Controller (rev 01)
debox:~# lsmod | grep ahci
ahci                   25089  2 
libahci                22767  1 ahci
libata                149043  2 ahci,libahci
    这次更改造成的一个额外效果就是,机器上的普通sata硬盘速度也上升了。从原来的71M/s到了115M/s,提升相当惊人。

2011年8月9日星期二

读一读我的blog用户

    好吧,应该是viewer,姑且称为user。谢谢你们的关注,这个blog才撑的下去。坚持写blog,尤其是技术blog,是个很辛苦的事情。查证技术很花时间,也没什么回报,一不留神还会成了各大互联网公司的免费写手。不过看看每个月的ip和pv,好吧,还是值得的。
    说是读一读,当然,我不会有你们的名单。我做的是审计,可不代表我会审查来的每个人。但是我的blog里面安装了统计系统,google还有个webmaster。我们来看看数据报表。
    首先是,大概1/3的我的读者是geek,或者足够geek,其余是麻瓜。各种windows系统占了2/3,我觉得普通blog不会出现这个比例...
    然后,firefox家族占了一半不到一点的流量,chrome占1/4,一点的safari,其余的IE。感谢党,感谢国家,感谢CCAV,这样的比例让我在抛弃IE的时候决定不会太艰难。
    来源,google不计,第一是baidu,其次twitter,然后豆瓣。google不计是因为通过google过来的人都算不出来....
    爬虫上说,google占了一半,其次是sogou(这个混帐爬虫占了1/3的流量却没带来几个ip/pv)。然后是Yahoo和baidu,两个没差多少。
    google reader订阅数是180,平均每周更新3.3篇,我还算努力吧?
    最后是很丢脸的ip/pv,上个月ip2700/pv8900,本月预期ip3300/pv8600。

linux下多种文件系统在小规模追加写下的性能

    因为公司需要,所以贝壳最近做了一个比较。多种文件系统,在小规模写下的性能。
    首先要说明的一点是,贝壳的blog为了保持便于传播,因此惯例是不贴图。这次的图,全部在blog同空间的相册上,通过引用方式放原始连接,可以保持原味查看。我知道中国不少站长复制粘帖大法厉害,不过大家手下留情,可以的话自己找个图床,贝壳可以提供所有原始图片。万一相册过载,blog也会跟着挂掉,谢谢谢谢。
    这次的内容,对于有些类型的应用很有价值,具体哪些——懂行的自然了解,就不多嘴了。测试的目标,是测试在同样的环境下,不同文件系统对于散碎的写文件的支撑能力。测试方法如下。
    首先,贝壳写了一个程序,可以开N个子进程。每个进程打开4个文件,分别写出16, 32, 64, 256字节大小的块。间隔m秒写一次。当磁盘吞吐耗尽的时候,大量的线程会排队在iowait上,因此造成iowait和loadavg快速上升。当loadavg明显超过CPU数时,宣告文件系统压力达到极限。具体测试方法,使用自己设计的压力系统对磁盘造成压力,然后通过压力读取系统读取系统参数,输出到文件。通过一个filter重新组织文件,计算移动平均数等。最后通过gnuplot输出图像。由于具体有些涉及公司业务,贝壳避嫌,就不贴出源码了。draw.plot的代码在最后。
    这个业务情况的核心问题是,对同一个文件,在一段时间内会写多次。正常情况下,这些数据会堆积在系统的Dirty区域,直到dirty_ratio的限制到了,或者dirty_expire_centisecs的限制到了,系统才会开始强制写出。否则每隔dirty_writeback_centisecs的时间,系统会写出部分数据。虽然理论上说,一个磁盘的IOPS应当在每秒600-700次上下,但是实际上并不是只能支撑150个并发的。然而设计的好的文件系统,支撑并发数会比设计的差的文件系统明显高。
    这个测试环境和实际的另一个差异,在于读写平衡上。这个业务和大部分的日志系统是很类似的(其实我们系统的业务就是日志)。但是商业用日志系统的特点是在高散碎文件写的情况下还有高随机读。这点在测试中并没有涉及,测试是单纯的大量文件追加写,请读者自行注意。
    首先是400进程,间隔1秒写出,测试对象是ext3, ext4, ntfs, jfs, xfs, btrfs,基本涵盖常见的linux文件系统。ntfs不属于常见的linux文件系统,本轮只做对比测试。首先可以看到的是ext3糟糕到吐血的表现,磁盘写io只有500上下,400个进程最多有280多个在排队。这货不是坑爹呢么。ext4的结果就正常很多,io在100上下,开始的高开是因为前一个测试的静默时间不足。jfs的结果很搞笑,队列load倒是不高,可是Dirty缓存一路上涨,让人不禁怀疑到底有没有写出。xfs的表现中规中矩,半分钟一次写出,和贝壳机器上的dirty_expire_centisecs相吻合,Dirty也不高。btrfs和jfs的情况类似。
    上一轮中,筛掉ntfs和ext3,其余进行1000进程,间隔1秒写出测试。测试对象是,ext4, jfs, xfs, btrfs。这次ext4也表现出了坑爹的一面,Dirty最高250M多,load也明显超过了2,写io大约在700上下,就此出局。btrfs这次的Dirty控制还不错,在25-40M徘徊,写出也不多。看似情况略好,实际上暴露出btrfs一个非常大的弱点,突发响应能力差,服务不稳定。一次集中写出,就能让排队数飞速上涨。jfs虽然曲线类似,但是队列可从没有超过1。综合考虑,后期平均load也明显超过了2,一样出局。xfs还是一样中规中矩的写出,非常低的io和Dirty。jfs依然是高速上涨的Dirty和超级低的io。
    测试到这里,只剩下了jfs和xfs。jfs的特点是大量使用Dirty,平均io很低。xfs的特点是Dirty使用比较低,io输出比较平均。不过我们的服务器内核对xfs的支持比jfs要好一点,所以使用xfs已成定局,下面就是测试两者的极限性能而已。
    第三轮的参数是2000个进程,0.75秒间隔。jfsxfs表现非常相似,让贝壳差点怀疑自己是测试错了东西。核查之后,确实没有。所以就下狠手,测试了一把高压力的。
    第四轮的参数是3200个进程,0.5秒间隔。从绝对量上,大概是基础测试的16倍。在jfs测试开始后的三分钟内,load上升到了60,宣告出局,因此贝壳这里没有jfs的图像。但是xfs还是完美的顶住了压力。Dirty已经上涨到了80-120M,平均io也到了300。然而平均load只有1左右,最高load也只有1.4。
    最终测试的参数是4000个进程,0.5秒间隔,基础测试的20倍。xfs的表现万分惊艳,平均io300-400,Dirty100-160M,平均load大约是1,最高也只有2。也就是说,到最后贝壳还是没有测试出xfs的最高压力。
    另外,贝壳也通过iozone对两者进行了测试,结论是,xfs在读写性能上比ext3高一些,但是在随机读写上大幅低于ext3。无论哪个数据,都无法出现这种20倍以上差距的现象。因此贝壳又对文件系统选择发生了兴趣,具体写在下一篇blog上。
    从最终结论上说,我们确定了xfs比ext3的巨大提升(20倍以上),并准备对xfs进行可用性测试。如果您有什么经验,欢迎和我联系。
-------------draw.plot-------------
set terminal png size 1920,1080
set output "out.png"
set xdata time
set timefmt "%H:%M:%S"
set y2tics
set origin 0,0
set size 1,1
set multiplot
set origin 0,0.5
set size 1,0.5
plot 'out.dat' using 1:2 with lines title 'Buffer',\
     'out.dat' using 1:3 with lines title 'Cached',\
     'out.dat' using 1:4 with points title 'Dirty' axes x1y2
set origin 0,0
set size 1,0.5
plot 'out.dat' using 1:5 with points title 'wio',\
     'out.dat' using 1:6 with lines title 'sma_wio',\
     'out.dat' using 1:7 with lines title 'loadavg' axes x1y2
unset multiplot
-------------draw.plot-------------

2011年8月7日星期日

从C++的一个特性到设计原则再到哲学

    最近在看C++的设计和演化,里面讲到算符重载。关于这个,Effactive C++里面明确说明,不要试图重载&&和||算符。因为这个重载造成的结果和默认不符(Not same with the default)。
    &&和||有什么特殊?熟悉C的朋友考虑这么一个问题。if(i && ++i)的作用是什么?基本来说,这个语句是判断i是否为0或者-1的,并且有个额外效果就是对i进行自增。但是,如果i == 0,则不进行自增,这就是&&的短路求值原则。这个原则产生了一系列写法,例如sh中常见的 [ -z "$ABC" ] && { ... }。
    不过当重载了&&或者||后,就破坏了短路求值原则。因为C系列语言是应用序语言,参数先求值。所以后参数*一定*会被求值,无论前参数的值是多少。
    更加悲崔的是,这个破坏了最小惊讶原则,或者叫做知识内隐原则。当你使用一个知识的时候,你会根据自己的经验对这个知识做内隐的预期。例如,虽然螺丝有左螺纹也有右螺纹,然而你在拧螺丝的时候,多数预期是顺时针拧紧。不论其理由,这个已经成为常态。同样,有下压把手的门是扇页门,画着杯子的店家是咖啡店和茶馆,画着裙子的厕所是女厕,这些都是你对知识内隐的预期。破坏这个预期,相当于把螺丝改为反向,下压把手的门改成移门,画着杯子的店家是古董店,男厕画裙子一样,会让人感到不知所措。大家会莫名其妙的绕出去,确认门上画的确实是裙子,走进去再看到男厕,感到世界莫名其妙。
    同样的道理,如果一个对象使用了&&重载,程序员唯一能够快速发现的机会就是在调试时单步了&&的语句。如果他运气不好,可能在数个小时内都找不到理由,直到反汇编目标代码为止。
    那C++为什么设计算符重载?那是设计给需要的算符用的。其实C++一直是一个矛盾的设计,一方面他认为,程序员是不可信的,所以C++里面有隔离保护系统,例如私有成员函数和变量。另一方面,他又认为程序员应当对自己的行为负责,因此他设计了复杂的算符重载,复杂的继承系统,并期待程序员能够按照正确的方法使用。这是一个奇妙的,矛盾的设计思路,反映设计者自身的冲突(例如多人设计),或者C++设计者的实用主义倾向(选择最实用的设计)。python语言的思路相对统一,他认为程序员应当为自己的行为负责,所以python的隔离系统都是伪系统。而java的思路也相对统一,他认为程序员是不可信的,所以java才会搞出复杂的架构哲学。

2011年8月4日星期四

估算(一)

    出租车价又涨了,贝壳好奇出租车上面水到底多深,就找几个师傅了解了一下行情,大家看看吧。
    首先是油价,目前是7块多,不到8块,按照7.5算。出租车都不太新,每百公里油耗不小,按照8-10算不过分。一般出租,只要在市区跑着,平均速度大约是40公里/小时。司机都是24小时轮班制的,做一休一。平均做一天,大概上缴330-380不等的出租车管理费。以上就是大致的原始数据。
    一天24小时,大约要跑960公里。乘上油耗,大约是86.4升的油。折合价格,大概是650上下。这是工作一天的油价。
    师傅做一休一,一个月只能做15天。按照税前4500的工资算,一天要赚300才能做平。对于老驾驶员,还做一休一来说,这个价格不算太高。去掉三金和税,还剩下3650。
    一天管理费350,一个月师傅这里能缴5250的管理费。但是三金就要缴掉2000,还剩下大概2000是真正的管理费。
    我们综合来算,一天的成本是1300。
    平均里程费用的问题,其实有点复杂。不考虑夜程,大概可以用3.5算。大概原理是这样的。
    3公里以内,14元。就算正好3公里,费用还是4元多。不足3公里平均费用更高。
    3-10公里,一公里2.4。最低值平均费用4.6,最高值平均费用3.1,最终得到的平均费用都介于两者之间,里程越长,平均费用越低。
    10公里以上,一公里3.6元。总平均费用会从3.1逐步上升到3.5左右的样子。
    从区间函数变化可以发现,出租车费用最低的区段大约在9-11公里之间。6公里以内的费用最高,12公里以上的费用就平均了。注意,以上计算都是时间-距离折算计算,即时间延误被乘以系数加到距离上了。实际出租车计价表也是采用的这种算法。
    中途插播一句,如果是多人短途,例如三四个人2公里多。或者8-10公里的地理距离,价格在28-35上下,都是比较合算的坐法。出租替代公交的成本不高。
    1300的成本,除以3.5的公里费用,得到371公里。加上各种余量考虑,出租车司机一天最高驾驶1000公里,实际400公里有客就可以收回成本,即空载率不应低于40%,否则就亏本了。
    我们观察成本,发现一半多的大头多来自油价。难怪每次油价变化出租车师傅都一脸郁闷。
    对抗油价变化的方法也很简单,就是等车,减少空乘移动。从上面数据可以看出,每公里载客可以赚入2.8元,一天的除油费成本650。如果每次载客结束都是当场熄火等待乘客,只要232公里就可以收回成本。所以我们经常可以看到机场或者各个地方的司机师傅,排长队等车。而且油价越高,师傅移动拉客的成本越高,越趋向于等车。
    一个师傅每个月缴2000的管理费,上海大约是5万到10万辆出租,一辆出租两位师傅轮流开。一个月给各个出租公司上缴的管理费大约是2亿到4亿。
    出租公司要负责车辆管理,叫车电话服务,人力资源,还有无线电调度,是有一定开销的。车辆管理的费用浮动,不大好算,然而普通人的车辆,一次养护成本大约是1200,一年一次。我们假定出租公司成本翻倍,一辆一个月200,全上海的车辆维护大约是1000-2000万。叫车电话,调度管理按照1:100的管理比例,需要500人持续管理。按照合三金工资4000(对于无技术的接线员来说,会比需要技术,连班转的出租师傅工资低)计算,大约是200W一个月。无线电调度不是很清楚,应该没有特别高的成本——除了牌照一类的问题外。
    满打满算,各家公司的总开销,加上正常盈利,一个月5000万已经足够。那么2-4亿中的其余部分到哪里去了呢?是成为了出租公司盈余,还是成为政府管理拍照费用,这就不得而知了。
    以上数据,都是2011年5-7月间,和各个出租师傅聊天时提到的。大部分数据都是经过一位以上师傅的口中说出,有一定准确性。然而由于仅听取了同一利益倾向的所有当事人,所以数据可能有一定误差。

2011年8月2日星期二

如果你的python项目一定要源码保密,你一定用错语言了

    python的特征在于快速编写代码,快速运行得到结果。通常而言,就是高开发速度。
    如果你的项目需要源码保密,那通常不会是高速开发的项目。因为能够高速开发的,就能够高速复制。别人在看到你的概念和基本逻辑后,可以非常快的抄一份出来。代码什么的根本是浮云。

除虫故事(二)

    第二个故事,是一次oracle数据库的紧急损坏抢修问题。
    当时客户紧急保修,系统无法继续工作,重启后无效。我们就找了DBA赶快飞去客户那里。客户有两台应用服务器和两台数据库,应用服务器组成热备的态势,数据库组成RAC。数据保存在一个SAN盘阵上,LogFile放本地,ArchivedLog使用备份脚本复制到备份服务器后删除。听起来是挺靠谱的方案,没想到就坏了。
    去了后,客户说暂时恢复了运作。然而我们还是要出具详细的报告,因此赶快去了机房。贝壳第一眼看的东西,就是/var/log。里面的报告是err9,也就是文件读写错误。oracle一切正常,应用发布服务器一切正常。
    这下有点抓瞎了,难不成要出具一份报告说SAN盘阵损坏?可是损坏也得有厂商来维修,说坏得有真凭实据阿。现在SAN一切正常,这个报告怎么写呢?
    说来算巧合,贝壳检查磁盘的时候,顺手打了一句df -h进去,看到磁盘空间已经用掉了80%以上,顺口问了句DBA,如果空间耗尽会如何。DBA说会挂起,和目前状况一致。贝壳顿觉狐疑,是不是空间耗尽呢?是的话,为什么会神秘的恢复呢?
    Oralce的运作非常精巧,也非常复杂。当一条SQL语句执行的时候,先写LOG,然后操作数据,最后再将结果写入LOG。当出现问题需要复原的时候,根据某个时间点的数据备份,和整个运作过程中的所有Log,就可以复原。但是LOG写出的时候量非常大,没有无限的空间给他写阿。所以LogFile的设计是文件循环,当写满一个文件,切换下一个文件。一个文件写满后,就会有一个服务,趁着磁盘空闲,将Log压缩备份为ArchivedLog,然后再将这个文件的状态变为Empty。
    我们的设计,是通过脚本备份ArchivedLog,除去最后一个文件外,复制到备份服务器上,然后删除。但是我们对ArchivedLog的量估计不足,一天清理一次,分配空间只有20G出头。系统开始的时候压力不高,因此绰绰有余。后来压力逐渐升高,这天的操作比较多,ArchivedLog量大了点,导致空间写满。当ArchivedLog空间满之后,备份进程就会报告错误,这就是/var/log下面err9的来历,因此LogFile无法备份出来。当所有的LogFile被循环写满后,SQL执行前试图写入LogFile失败,执行就会失败,然后挂起在那里。这导致了所有应用发布服务器的失效。
    备份脚本的设计是定时和开机结合的,在客户第一次重启设备的时候,已经执行了备份脚本。然而备份动作需要执行相当久,中间客户又重启了几次,导致备份工作进展缓慢。直到半个小时后,第一份ArchivedLog才备份出去。然后清理文件,开始LogFile的备份,大约执行了一个小时多。此时服务就突然恢复了,因为空间问题已经暂时解决。而后是不断的ArchivedLog备份和LogFile的备份的平衡,直到我们到的时候,LogFile已经全部空了,ArchivedLog还没有完成备份。因此我们才能抓到最后的尾巴。
    反过去检查备份脚本的执行记录,基本验证了这个想法,客户也接受了我们的报告,不过还是要责令修改系统——这是后话不提了。
    这个故事里面,至少有几个教训。
  1.     对于所有编程时无关紧要的假定值,在开发时可以胡给一个差不多就行,但是上线的时候必须重新分配合理的值。因此必须将这些假定值记录出来,否则从程序中找出假定值来本身就是一个非常困难的事情。
  2.     确实运作一下,搞清楚运作方方面面的问题,不要想当然,觉得没问题。就算运作了没问题,在时间的考验前都没人敢保证没事。
  3.     一套系统,尤其是大型复杂系统,必须有懂得运维的人员接手管理。检查磁盘IO,CPU压力,内存和磁盘用量,数据量,网络响应速度等等问题。
  4.     废物Log不要乱出,太多的Log和没有无异。如果早关注备份脚本的执行记录,就能早找到问题。可是由于量太大,我都是过滤掉了看的。