Archive

Archive for April, 2010

程序员提高工作效率的方法

April 29th, 2010 西坪 No comments

最近一段时间以来,效率相当地高。 纵观前些年的工作效率中,少有这么利落快速而且不加班的。 回顾这几年,我工作效率的提高主要有下面的几个方面。

一、集中目标

专注目标。凡是工作效率高的时间段里,工作目标都很明确。每天一上班,心里就想明白了今天要干什么,每天下班时,想想今天都实现了什么,有什么目标还没有实现。尽管每天早上来了先看看股票新闻,中午饭后看看股票新闻,偶尔下午还打个盹什么的,但工作的时候确实格外专注,丝毫也不会走神。

分离与当前无关的任务/问题。
专注目标不是那么容易做到的。印象中以前工作中经常会碰到的问题是工作中遇到的问题。一方面可能得益于基本功的增强,最近虽然也遇到了一些问题,但是都能够通过简单阅读或查找文档,或浏览问题相关的库的源码解决; 另一方面,遇到的问题我总是避繁就简,首先倾向于寻找简单可用可靠的方案,并将心中的疑虑记录下来,集中成一个列表,工作之外翻翻书,系统思考和学习,而不会因为这个问题而叉开思路对相关的内容研究一番。总之,专注当前的任务,把新问题记录下来,回头再专心攻克。

例如我第一次用ibatis,遇到了一些表可以用集合和映射来加强Pojo的OO功能,但是我并不熟悉ibatis的这些特性,并且使用简单的方案也是可行的,于是就直接使用简便方案(在我看来,ibatis主要是将SQL集中起来管理、简化SQL操纵,对OO不感冒)。

工作列表。不论是开发还是设计,一个文本格式的位于源代码存储系统下的待办工作列表与IDE中的TODO项一起构成了专注目标的重要工具。工作目标分解是基本工作步骤,记录工作中产生的新的问题(任务),这样,子问题越来越多,项目中要干的事情越来越丰富。经常性地调整当前工作任务列表,根据重要性对这些任务进行划分。每天都干掉一些问题,经常想着那些最重要的问题。

简单但有迹可寻的设计材料。在思考和工作的过程中,一方面,项目的过程通常比较长,另一方面经验相对丰富的人手头总是有多个事情在并行进行。当时间太长记不清出了或者是切换任务时,经常要查看此前的代码和设计,易于修改以及有历史记录的设计材料对于保持设计思路的完整十分有意义。(设计材料还应该包括重要的图)

正式准确可以依靠的需求文档。这一条无论怎么说都不过分,遇到需求不确定的地方,就去查需求文档。如果没有,就请能够回答的人来回答,委托给他,先去做别的。细想在上一家公司,经常要承担多种角色,甚至连需求也经常没人给一个最终决策,设计开发的时候在模棱两可的需求之间做决定,很烦心。对于一个设计/开发人员而言,需求人员在需求问题方面就是绝对的权威。如果有些建议,可以建议,但一切均以需求/产品人员为准。

单元测试。另一有助于集中精力编码的就是单元测试。单元测试让我集中精力实现当前的功能,需要依赖的其他功能,我总是先生成一个接口,让当前的功能通过测试后再专心去实现该接口。一天下来,一个一个的测试点亮了绿色,一个一个的接口被实现,整天都是十分惬意的。单元测试的另外一个收益就是放心地去重构吧,放心地去做新的特性吧。

二、简化问题的能力

无论是在广义的工作方法/工作态度上,还是在针对具体问题的设计/实现上,我认为最重要的个人能力就是化繁为简了。化繁为简是所有工作方法/软件设计的核心。将那些可以砍掉的工作砍掉(最多做个记录),做到尽可能地经济,尽可能地简单。

从工作方法和态度上来讲,真正需要去做的工作才值得去做,大力砍掉那些不应该在当前工作中处理的事情。例如不必要的优化,不必要的扩展性,不必要的性能,不必要的功能,可以不要的技术,不必要的流程,不必要的文档,统统砍掉,一切可以没有的全都不能有

工作中也可能遇到非关键的难题,通常绕过它们,使用更简单的方案就是了。纠缠于这些不重要的难题,最容易浪费时间。例如,eclipse忽然坏掉了,最好的方法是重装一个; 又如以前我经常自己建一个持续集成服务器,现在我直接养成每次写完代码手工跑一遍的习惯(前提是够用)。简化你的工作!简化!

从设计/实现来讲,最好的方案就是最简单直接、一眼就能看懂的方案。记得刚到一个新的环境,有一个统计任务,既要用到数据库也要用缓存,我做了精细的设计来保证最终一致性,状态流程都很完整,并且使用线程池来并发运行分批处理,最后再合并。虽然控制得很完美很精细,但是流程和结构都很复杂。上头根据此前的项目经验给出了一个更简单的例子,直接将各个任务划分为多个线程,分开存储,到了该统计的时候,冻结数据在所有的分区上做统计。状态砍掉一半,流程缩减一半。

事实上,作为简单直接的一个附带效应,最简单直接的方式,通常性能也最好。

简化问题的能力,是一个人的核心能力。

三、基本功

基本功的内容十分复杂。首先,对整个计算机体系的理解,对操作系统/虚拟机/数据库本质的理解,对语言基础类和库的理解,我觉得是核心基本功

第二项基本功,就是学习能力。 通过快速阅读核心文档理解核心思想,然后其他的东西总是能从文档中查到就行。细枝末节的东西,即学即用,学过就忘可也。

第三项基本功,就是文档、资料的搜索和收集

要想在工作中如行云流水,另外一个方面就是避开暂时还不熟悉的技术和工具,不熟悉的东西很难用好,更难用顺畅。尤其是那些纠结复杂、华而不实的技术,不要去碰。这属于简化能力的范畴。

四、工具

选择工具的核心标准,就是简单朴素可信赖

文本格式的设计,加上易于修改的图。 我喜欢用一个简单的文本格式来记录设计,随时修改,随时查阅。而附上几幅简单直接的图,经常能够更简单直接地表达更多的内容。

简单的可信赖的工具。我曾经将很长的时间用来构建Maven的环境上,用Maven管理依赖,尤其是跟Eclipse协作时,经常出现诡异。现在我用ant,或者只用Maven,maven不与eclipse纠缠在一起。如果一个工具出几次诡异现象,那就干脆丢掉它。

版本管理工具。 不仅仅源码要由版本管理,整个项目过程的所有知识,全部用版本管理系统管理起来,集中存放。现在我用subversion和git。

虚拟机中Host与Guest文件共享

April 13th, 2010 西坪 1 comment

最近很多工作在Linux下做,但是因为整个公司的环境是Windows,很多事情也经常要在Windows下处理。于是在Windows XP上用VMware搭建了OpenSUSE,同时使用这两种系统。经过这段时间的使用,觉得OpenSUSE的桌面支持确实是做得不错的,似乎比Ubuntu更加方便简单。但是Ubuntu更流行,很多简单的设置问题,网络上随处可见Ubuntu的解决方案,而SUSE的方案却难觅踪影。

例如,我经常使用VMWare的共享文件夹特性来在Host与Guest之间交换数据,共享文件。 但是在OpenSUSE下,却没有找到合适的方法。最终,不得不求助于Samba。 Samba在OpenSUSE上的安装是很方便的,基本上遵照 How To Samba With openSuse 10.3 And Windows XP 的指导,三两步就完成了。 完毕以后,在Windows XP 下映射一个盘符到 \\GUEST_HOSTNAME\users 就完成了。我完全关闭了Guest上的防火墙,有防火墙反而可能招致麻烦。

而在OpenSUSE上访问Windows XP也很简单,基本上遵照 SDB:Access to Windows Shares 的 Manual Procedure 部分,将Windows XP共享目录加入到 /etc/fstab 中:

  1 /dev/sda1            swap                 swap       defaults              0 0
  2 /dev/sda2            /                    ext4       acl,user_xattr        1 1
  3 /dev/sda3            /home                ext4       acl,user_xattr        1 2
  4 proc                 /proc                proc       defaults              0 0
  5 sysfs                /sys                 sysfs      noauto                0 0
  6 debugfs              /sys/kernel/debug    debugfs    noauto                0 0
  7 usbfs                /proc/bus/usb        usbfs      noauto                0 0
  8 devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
  9 //x.x.x.x/work   /mnt/windows    cifs  auto,uid=liuz,gid=users,umask=0002,iocharset=utf8,credentials=/etc/winpasswd 0 0

别忘了保护你的密码文件:

chmod 600 /etc/winpassword

特殊之处,是指定了一个 uid=liuz, 将文件的所有者指定为liuz这个用户,方便增删改等操作。有关 uid,gid,umask等的解释如下: (来源)

uid与gid
uid即user identifer,gid即group identifer。设置所有文件的所有者和群组。gid=64,即权限为所有者可读、写,不能执行,群组用户可读、不能写、执行。
umask
umask即user mask,即用户屏蔽。umask=007,即所有文件的权限中,屏蔽其它使用者的读、写、执行权限。

总结

总结一下我使用的这三种方法:

  • 1) 使用VMware提供的共享文件夹功能。
  • 2) 使用Samba为Windows Host OS 共享Linux Guest OS文件系统。
  • 3) 在Linux Guest OS中mount Host OS (Windows系统)的共享文件夹。
Categories: server & system Tags: , ,

导出Memcached中的全部数据

April 5th, 2010 西坪 4 comments

Update(Mar 18th, 2011) 最近,我们针对数十个Memcached集群(数据从几G到几十G)进行了数据转换工作,虽是不得已而为之,但是整个过程还算顺利。编写导出脚本需注意的是cachedump得到的很多key其实已经过期了,这部分过期的key要通过get()操作,将之从Memcached中清除,使之不再出现在下次的cachedump中。
================================================================

因为特别的原因,需要从Memcached中导出所有的数据。因为Memcached对数据的遍历是明确不支持的,所以必须想歪门邪道的方法。

现在网络上主要有两种思路,一种是通过Memcached提供的stats cachedump命令导出,例如下面这些网址:

以上文章都利用这个命令导出了部分数据。但事实上,cachedump的输出会限制在 2*1024*1024=2M 字节的长度内(Memecahed source: items.c, func: do_item_cachedump),其导出的格式如下所示:

ITEM key990017 [1 b; 1270394155 s]
ITEM key990016 [1 b; 1270394155 s]
ITEM key990015 [1 b; 1270394155 s]
ITEM key990014 [1 b; 1270394155 s]

即使不计算key的长度,每一条数据至少要占掉近三十个字节,2M最多到几万项数据。对于Item数量很大的情况下,这种方法并不能导出全部数据。

下面的地址佐证了这些观点。

第二种思路来自 Twitter infrastructure team 的 Evan Weaverpeeping into memcached , 利用 linux 的 ptrace 系统调用导出memcached进程中数据,分析这些数据得到memcached的所有Key。

但是这种方式有其限制的,一方面,编译Memcached时必须编译入调试信息 (参见link); 另一方面,在分析时对内存消耗太大。我们对一个只使用了64M内存、含有76万左右数据项的Memcached进程进行分析,在完成23万左右数据项时,分析进程占用内存的达到1040M,导致虚拟机内存用满,关闭了该进程。

因为我们现在运行的memcached是不带编译符号的,所以放弃了第二种方式。 第一种方式,则只能考虑怎么将slabs中的数据分批导出来。 Memcached 支持一个可选的 slabs reassign 命令,可以将一个slab内的数据项移动到其他slab。但这个命令必须在编译 memcached 时加入该特性。

最后,还是利用了第一种方法,每一次导出一批数据以后就从memcached中删除这一批数据,直到全部导出为止。 虽然这种办法很土,但是还是能够应付一次性数据迁移。 当然这是不得以而为之,明智的做法还是在一开始就不要将需要持久化的数据持久化到其他服务中,而不是只存放于memcached中。