If you want to start git the new version control system, take a look at this page http://rogerdudler.github.com/git-guide/ which is really good for beginning.
I made some notes for myself:
- Create a git repository:
mkdir git_repo
cd git_repo
git init
This will create an empty repository in folder git_repo
- Clone a git repository to local
git clone /path_to_repo (such as /data/git_repo)
This will clone the whole repository to local
- Work on local computer and commit into local repository
After do some modifications, add the modifications into local index, and then commit to local heads. See the tutorial file for the differences between them.
git add --all
git commit -m "Some comments"
- Push modifications to master repository
git push origin master
This will push all your local modifications into the master repository which will be seen by other people.
- Update files
git pull == git fetch && git merge
"fetch" only update the heads, you need to "merge" the new files. "pull" command will do them together automatically.
- Fix conflicts
When there are any conflict happen, git will put the modifications together into the conflict files and give you errors. Use "git diff source_branch target_branch " to see the differences and change them in the conflict file by yourself. Then add them into your local repository as merged.
git add --all
- Branch
Create a new branch with specified name
git checkout -b branch_name (if use master instead of branch_name, you get the trunck
And then commit to a branch
git push origin
Delete a branch
git branch -d branch_name
Just make a list to remember
- Develop language: Java
- Develop frameworks: Felix, maven-pax-plugin , ipojo
- Source code version control: svn, git
- Build tool: Maven
- Continuous integration tool: Hudson
- Mysql DRM ide: mysql work bench (here are more alternatives for power designer : http://alternativeto.net/software/sybase-power-designer/)
- UI flow axrue: http://www.axure.com/
TO BE COMTINUE…
JvmTI (Jvm Tools Interface) 作为一个强大的jvm工具接口,提供很多很强大有用的功能。最近尝试下使用,简单记录下。
中文参考的是Ken Wu的博客,太具体的细节我就不累述了,这里直接解释我的hello world的过程吧。
Read more…
作为一个unix/linux小白,今天折腾了下ssh登录,使用rsa,不再需要输入密码了,具体步骤如下:
- 在本机(客户端)生成rsa密钥
ssh-keygen -t rsa
这个命令会要提示三次输入:
1、第一次是存储rsa密钥的文件名称,默认的是id_rsa,可以直接回车使用默认的,也可以自己定义新的名称,最好还是放到.ssh目录下就可以了;
2、第二次是输入密码,最好输入一个密码,虽然可以为空(mac os下,请记住这个密码,第一次使用时需要输入)
3、第三次确认一次密码即可
生成的密钥文件有两个,以默认的为例,将会有一个id_rsa和id_rsa.pub,以.pub结尾的就是公钥,另外一个是密钥
- 添加rsa公钥到服务器上
使用scp将.pub文件复制到服务器上,使用如下命令添加新的密钥
cat id_rsa.pub >> ~/.ssh/authorized_keys
然后通过重启sshd就可以了
/etc/init.d/sshd restart
不同平台重启命令可能不同,可以参考http://www.cyberciti.biz/faq/howto-restart-ssh/
PS: 如果在设置好了这些还是提示要密码登录,请检查ssh是否打开了rsa验证的设置,具体包括:
- 在/etc/ssh/sshd_config中将以下注释去掉(去掉行首的#号)
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
- 在/etc/ssh/ssh_config中添加下面两句到host下:
Protocol 2
RSAAuthentication yes
再次重启下sshd就可以了,第一次使用rsa登录时mac os会弹出提示要输入rsa的密码,就是在创建rsa密钥时指定的。
Enjoy!
参考资料:http://news.softpedia.com/news/How-to-Use-RSA-Key-for-SSH-Authentication-38599.shtml
一、安装词典
为了安装一个好用的英汉词典,我找了很多方法,终于有一个文章提供的资料比较合适:http://yyq123.blogspot.com/2010/03/mac-built-in-dictionary.html,使用mac自带的dictionary已经足够了,问题是词典库哪去找,其实只要搜索stardict的词典库就可以了,可惜大多数的搜索结果都是该词典软件的,有一位好心的用户将自己找到的一些放到了网盘里了,虽然不多,已经基本够用了。
需要注意的是,网盘里下载的是rar格式的,需要先解压,然后压缩成.tar.bz2格式,具体方式是使用terminal终端执行如下命令
tar -cvyf dict.tar.bz2 stardict-langdao-ce
第三个是要生成的压缩文件的名称,一定要写名.tar.bz2,第四个是解压后实际的词典文件夹,然后就可以通过DictUnifer来转换了。转换好的文件将被放到/Library/Dictionary目录下,所以可以备份已经转换好的词典文件,下次只需要放到这个目录下就可以使用了。打开dictionary软件后进入偏好设置就可以找到新的词典了,默认是显示的。
迁移到Mac以后出现svn无法提交的情况,一开始以为是没有足够的权限去操作,经过努力终于以root身份登录了Mac以后还是如此。出现的错误提示如下:svn: Can't move '.svn/tmp/entries' to '.svn/entries': Operation not permitted
ls -l查看到这个文件的操作的确是不允许root操作的,只允许拥有者进行写操作,于是尝试使用chmod修改mode,结果被拒绝:chmod: Unable to change file mode on entries: Operation not permitted, 可怜的root。。。
看来root也是由很多被限制的,经过搜索在
StackOverFlow上找到了答案,原来是svn自己设置的结果,解决问题的方式是在svn的根目录下执行命令:
chflags -R nouchg .
(不要漏了“.”号)
第一次看到chflags命令,查询了下
文档,原来svn将一些文件的flag设置成了uchange(immutable),所以在提交或者更新svn前需要清除这个flag,好像只有root和owner由权限,上面的命令也就是做这个的,将当前目录以及所有子目录的flag清理,这样svn就可以正常使用了。
题目的确不好取,这篇仅记录下我花费了两个小时用来和eclipse的配置作的斗争。
起源:
我从windows迁移到mac,本想着直接copy workspace的目录过去就完事了,可惜总有意外在等待着我们
问题:
由于我之前的workspace中引用了很多源代码,而源代码记录是使用windows的绝对路径来完成,所以到mac下切换了workspace的目录后就会报错,说找不到XXX文件,一看就知道是硬编码的路径地址,以C盘开头,当然找不到,但是不可能就这样放弃使用吧
解决过程:
首先尝试将所有project下的.classpath文件中的source引用全部删除,然后重启eclipse,结果还在报错,经过查证是因为我引入了自定义的库(user library),所以当我添加对应资源库中的资源文件时,有部分信息一起写到user library的内容里了。
为了找出eclipse的user library写到哪了,我翻山越岭的查看文件修改时间,隐藏目录,终于在workspace跟目录下的.metadata里找到了eclipse的启动日志.log文件,通过这个文件确定是在启动org.eclipse.jdt.core时报错的,那么接下来去哪找这个组件的配置呢?就在.metadata/.plugin/org.eclipse.core.runtime/.setting目录下,这里有很多的prefs文件,而org.eclipse.jdt.core.prefs就是配置org.eclipse.jdt.core的,果然在搜索这个文件时发现了报错的那个地址,当然要一举全部消灭,所有以userLibrary开头的记录都是自定义库的内容,其实就是xml文件的字符串,导出功能估计就是把这个写成单独的文件的。
好了,删除完毕,重启下eclipse试试吧。Yeah,没有错误了,而且在设置里的userLibrary可以正常查看了,是空的,其实如果只将源代码的引用字符串删除,这里还会保留user library的记录的。不过为以防后患,还是老老实实的重新导入一次好了。
在之前删除所有项目的源代码引用之后就可以重新导入各项目了。
总结:
第一点就是知道了eclipse如何管理workspace的相关配置的,基本上所有的配置信息会被放到workspace/.metadata/.plugin/org.eclipse.core.runtime/.setting目录下,XXX.prefs对应的就是XXX的配置了,而各workspace的日志就记在metadata目录下,所有的这些文件都是隐藏的。
第二被迫学习了几个linux命令:
ls 加上-a可以显示所有文件,加上-ct可以安装最后修改时间排序输出,-l是每行一个记录的输出,所以查看所有文件,并按最后修改时间排序的命令是: ls -actl
vim中使用ctrl + b下翻一页,ctrl + f上翻一页,mac没有page down和page up还真的不习惯。
第三点其实还是教训,一开始没有直接查看日志,所以简单的以为都是project的classpath中引用了源代码,结果搞不定了反而自己不知道怎么办,幸好及时找到了日志输出,纪念下吧。晚安。
最近开始硬着头皮阅读Memcached的源码,记录下发现的细节和学习到小技巧吧,由于我自己很久没有写过c了,还随便复习了下c的基础知识。
1、第一个slab的chunk size值
当我试图修改memcached的起始slab大小以便用于存储非常小的缓存对象(往往值是没有意义的,只是用一个1之类的标志来表示key是否存在,这个通常用于判断缓存一种状态而不是数值,例如是否获得过当天的登陆奖励)时发现了这个问题。
通过启动memcached时添加参数: -n48 (48是要被设置的值,必须是正数) 可以指定第一个slab的chunk大小,但是经过尝试和跟踪代码发现,第一个slab的chunk size不止受此一个参数限制,具体计算第一个chunk size的过程如下:
- -n 指定的值被存放到 settings.chunk_size中
- 当memcached启动时,会初始化slab(Slabs.c中的slabs_init),第一个slab的chunk size大小首先会被指定为
unsigned int size = sizeof(item) + settings.chunk_size;
然后在实际确定前需要转换为8的整数倍
if (size % CHUNK_ALIGN_BYTES)
size += CHUNK_ALIGN_BYTES – (size % CHUNK_ALIGN_BYTES);
通过上面的计算过程可以发现,其实第一个slab的chunk size还受到struct item的大小决定。
在尝试使用最小值时(即指定-n1时),在我的机器32位机器上生成的第一个slab大小是48,原因是 sizeof(item) 为32,加上1以后33,而33不是8的倍数,所以放大到48;在64位机器上 sizeof(item) 为48,所以最小应该为 56。
2、chunk中不仅仅存放缓存对象的value
这个不知道是我自己理解的错误还是误听哪的说明,我一直以为chunk中只存放了缓存对象的value,所以在分配slab时只需要根据缓存的value大小来。但是这种情况下无法解释为什么在确定slab的chunk大小时要加上一个item的大小,如果只放1byte的数据却使用的是56byte(64位的服务器)的chunk未免太浪费了,而且不可能没有人发现这种情况,所以有理由怀疑我以前的认识了。
chunk中不仅保持了缓存对象的value,而且保存了缓存对象的key,expire time, flag等详细信息
经过查看memcached的源代码发现两个问题:
- memcached如何计算需要存放的缓存对象大小,以及如何选择slab
查找缓存对象应该放到哪个slab时,不仅适用了value的长度,而且使用很多其他信息,具体计算公式如下:
*nsuffix = (uint8_t) snprintf(suffix, 40, " %d %d\r\n", flags, nbytes – 2);
return sizeof(item) + nkey + *nsuffix + nbytes;
上式中item是存储缓存对象的struct,nkey为key的长度加1(用于存放字符串最后的''),nbytes为value的长度加2(存放'\r\n'),suffix为实际打印的字符数,memcached使用返回的大小来选择能够存放得下的最接近的slab。所以在选择slab时,memcached并不是只关心缓存值的大小。
例如:如果是最短的key(1位),最短的值(1位),则在64机器上需要使用的空间其实是:
48 + (1 + 1) + 6 + (1 + 2) = 59
需要找一个大于或者等于59的slab存放。
当指定-n1时第一个slab的大小为56,这个时候就出现了一个奇怪的现象,memcached的slab 1永远放不进值,因为最小的key和value需要的空间59都大于slab 1的56,必须放到slab 2(size为80),见下图:

slab 2中只存放了一个对象,而且dump出来显示名称为“t”,值只有1byte,但是却使用了size为80的chunk,而slab 1将永远用不到。这个也可以说明其实在做slab初始化时计算的可能值小于实际需要的最小值。
- 到底chunk中存放了些什么
为什么在选择slab时memcached需要计算那么多的空间进去,导致一个1byte的对象却需要59byte空间存放,从代码中得到的答案如下图:
在chunk中通过item存放了缓存对象的一些详细信息,包括key的长度,value长度,过期时间,flag等信息,具体可以查看item结构定义,后面紧跟的是key的实际内容、suffix实际打印的内容、value的实际值,所以chunk中存放远比value信息多,有一些值的作用目前还没有搞清楚,但是大部分都是在缓冲对象使用过程中有明显作用的。
关于导出memcached的全部数据,只是使用了memcached提供的几个功能接口而已,具体代码如下,但是有几个要注意的地方。
- 第一个是cachedump命令每次返回的数据大小只有2M,这个是memcached的代码中写死的一个数值,除非在编译前修改(见参考一)
- 第二个问题是在一个memcached做cachedump时,似乎不能在循环里面对另外一个memcached做set操作。这个只是在尝试的时候发现的问题,一开始我是在第一个foreach循环中获取数据并放到另外一个memcached里的,这个时候会出现放置的数据为2byte的一个假数据。经过测试,取的数据时对的,但是放的时候出现了错误,所以下面的代码先循环cachedump的key,再单独循环key列表去导出数据。
- 最后这个问题是有第一个引起的,根据我导入的情况看,2M一般只能拿到4万左右的key,有些slab的item达到了4千万,4万只是千分之一,所以只能边导出边删除,知道没有数据可以导出为止。
<?php
echo "Start time ".date("Y-m-d H:i:s")."\n";
$slabs = array_slice($argv, 1);
foreach ($slabs as $slabId) {
export($slabId);
}
echo "End time ".date("Y-m-d H:i:s")."\n";
function export($slabId)
{
$num = 0;
$total = 0;
$times = 0;
$deleteCount = 0;
$addCount = 0;
$fromCache = new Memcache();
$fromCache->connect("192.168.0.100", 11211);
for ($i = 0; $i < 200; $i++) {
$keys = array();
$cdump = $fromCache->getExtendedStats( 'cachedump' , intval( $slabId ) , 10000000 );
foreach( $cdump AS $entries )
{
if( $entries )
{
foreach( $entries AS $eName => $eData )
{
$keys[] = $eName;
}
}
}
$toCache = new Memcache();
$toCache->connect("192.168.0.101", 11211);
if (count($keys) == 0 ) {
break;
}
foreach ($keys as $key) {
$value = $fromCache->get($key);
if ($toCache->add($key, $value, MEMCACHE_COMPRESSED, 864000)) {
$back = $toCache->get($key);
if (strlen(serialize($value)) != strlen(serialize($back))) {
$toCache->delete($key);
} else {
$num++;
}
}
$fromCache->delete($key);
}
$deleteCount += count($keys);
$addCount += $num;
$num = 0;
}
echo "Total import $addCount items into slab $slabId.\n";
echo "Total remove $deleteCount items from $slabId.\n";
}
?>
参考链接:
1、Memcachd的cachedump最大返回值限制
2、关于导出memcached数据的讨论
3、另外的一篇博客
上篇解释了Memcached的内存分配机制,这篇总结下如何检测memcached是否发挥了优秀的性能。
二、Memcached性能检测
Memcached作为一个内存key-value存储容器有非常优秀的性能,但是在上次的使用中确发现大量的数据丢失情况发生,导致cache的功能基本消失。具体的检测方式如下:
- 检测命中率
检测命中率是一个最基本的、最宏观的方式,使用telnet连接到memcached服务器,然后执行stats命令就可以看到宏观的一些信息,如下图。

这个命令中比较关键的属性是get_hits和get_misses,get_hits表示读取cache命中的次数,get_misses是读取失败的次数,即尝试读取不存在的缓存数据。
命中率=get_hits / (get_hits + get_misses)
命中率越高说明cache起到的缓存作用越大。但是在实际使用中,这个命中率不是有效数据的命中率,有些时候get操作可能只是检查一个key存在不存在,这个时候miss也是正确的,这就像用memcached作为一种定时器,将一些临时数据在memcache中存放特定时间长度,业务逻辑会根据cache是否存在而作不同的逻辑,这种数据其实已经不是单纯的缓存了,也不应该统计到命中率中。再者,这个命中率是从memcached启动开始所有的请求的综合值,不能反映一个时间段内的情况,所以要排查memcached的性能问题,还需要更详细的数值。但是高的命中率还是能够反映出memcached良好的使用情况,突然下跌的命中率能够反映大量cache丢失的发生。
- Stats items
Stats items命令可以查看每个slab中存储的item的一些详细信息,具体可以见下图。

关键属性有:
Stats items属性
| 属性名称 |
属性说明 |
| number |
存放的数据总数 |
| age |
存放的数据中存放时间最久的数据已经存在的时间,以秒为单位 |
| evicted |
被剔除的数据总数 |
| evicted_time |
最后被剔除的数据在cache中存放的时间,以秒为单位 |
stats items可以详细的观察各slab的数据对象的情况,因为memcached的内存分配策略导致一旦memcached的总内存达到了设置的最大内存,代表所有的slab能够使用的page都已经固定,这个时候如果还有数据放入,将开始导致memcached使用LRU策略剔除数据。而LRU策略不是针对所有的slabs,而是只针对新数据应该被放入的slab,例如有一个新的数据要被放入slab 3,则LRU只对slab 3进行。通过stats items就可以观察到这些剔除的情况。
具体分析如下:
- evicted属性
如果一个slab的evicted属性不是0,则说明当前slab出现了提前剔除数据的情况,这个slab可能是你需要注意的。
- evicted_time属性
如果evicted不为0,则evicited_time就代表最后被剔除的数据时间缓存的时间。并不是发生了LRU就代码memcached负载过载了,因为有些时候在使用cache时会设置过期时间为0,这样缓存将被存放30天,如果内存慢了还持续放入数据,而这些为过期的数据很久没有被使用,则可能被剔除。需要注意的是,最后剔除的这个数据已经被缓存的时间,把evicted_time换算成标准时间看下是否已经达到了你可以接受的时间,例如:你认为数据被缓存了2天是你可以接受的,而最后被剔除的数据已经存放了3天以上,则可以认为这个slab的压力其实可以接受的;但是如果最后被剔除的数据只被缓存了20秒,不用考虑,这个slab已经负载过重了。
- age属性
age属性反应了当前还在缓存的数据中最久的时间,它的大小和evicted_time没有必然的大小关系,因为可能时间最久的数据确实频繁被读取的,这时候不会被LRU清理掉,但是如果它小于evicted_time的话,则说明数据在被下去读取前就被清理了,或者存放了很多长时间但是不被使用的缓存对象。
- Stats slabs
从Stats items中如果发现有异常的slab,则可以通过stats slabs查看下该slab是不是内存分配的确有问题。
Stats slabs结果如下图

Stats slabs的属性说明如下:
Stats slabs属性
| 属性名称 |
属性说明 |
| chunk_size |
当前slab每个chunk的大小 |
| chunk_per_page |
每个page能够存放的chunk数 |
| total_pages |
分配给当前slab的page总数 |
| total_chunks |
当前slab最多能够存放的chunk数,应该等于chunck_per_page * total_page |
| used_chunks |
已经被占用的chunks总数 |
| free_chunks |
过期数据空出的chunk里还没有被使用的chunk数 |
| free_chunks_end |
新分配的但是还没有被使用的chunk数 |
这个命令的信息量很大,所有属性都很有价值。下面一一解释各属性:
综合上面的数据,可以发现造成memcached的内存使用率降低的属性有:
- chunk_size, chunk_per_page
这两个属性是固定的,但是它反映当前slab存储的数据大小,可以供你分析缓存数据的散列区间,通过调整增长因子可以改变slab的区间分布,从而改变数据散列到的区域。如果大量的230byte到260byte的数据,而刚好一个slab大小是250byte,则250byte到260byte的数据将被落到下一个slab,从而导致大量的空间浪费。
- total_pages
这个是当前slab总共分配大的page总数,如果没有修改page的默认大小的情况下,这个数值就是当前slab能够缓存的数据的总大小(单位为M)。如果这个slab的剔除非常严重,一定要注意这个slab的page数是不是太少了。
我上次处理的那个项目因为和另外的一个项目共用的memcache,而且memcache已经运行了很长时间,导致page都已经全部被分配完,而刚好两个项目的缓存数据大小差别很多,导致新项目数据最多的slab 4竟然只有一个page,所以数据缓存不到22s就被替换了,完全失去了缓存的意义。
针对我遇到的那个情况,解决方案是重新分配page,或者重启memcache服务。但是page reassign方法从1.2.8版已经完全移除了,所以现在没有办法在线情况下重新分配page了。另外一种有些时候是不可以接受的,因为一次缓存服务器的重启将导致所有缓存的数据将重新从DB取出,这个可能造成db的压力瞬间增大。而且有的缓存数据时不入库的,这个时候我们就需要做memcache的导入和导出了。在下篇文章中我会总结下memcache的dump操作。
- total_chunks
这个的作用和total_pages基本相同,不过这个属性可以更准确的反应实际可以存放的缓存对象总数。
- used_chunks, free_chunks, free_chunks_end
这三个属性相关度比较高,从数值上来看它们满足:
total_chunks = used_chunks + free_chunks + free_chunks_end
used_chunks就是字面的意思,已经使用的chunk数;free_chunks却不是所有的未被使用的chunk数,而是曾经被使用过但是因为过期而被回收的chunk数;free_chunks_end是page中从来没有被使用过的chunk数。

从上图可以看出,slab 1只放了一个对象,但是已经申请了一整个page,这个时候used_chunks为1,但是free_chunks却为0,因为还没有任何回收的空间,而free_chunks_end却等于10081,说明这么多的chunk从来没有被使用过。下图就是这个数据过期后的stats slabs数据,可以发现free_chunks有值了,就是过期的那个chunk,所以是1,used_chunks为0,free_chunks_end不变。

为什么要分两种free chunk呢?
我的理解是这样的:如果free_chunks_end不为零,说明当前slab没有出现过容量不够的时候;而如果free_chunks始终为0,说明很多数据过期时间过长或者在过期前就被剔除了,这个要结合剔除数据和数据保留的时间(age属性)来看待。所以分开统计这两个值可以准确的判断实际空闲的chunk的状态,一旦所以的chunk被使用过一次以后,除非重新申请page,否则free_chunks_end始终为0。所以对于运行时间比较久的memcached,可能大部分这个值都是0。
- active_slabs, total_malloced
在stats slabs输出的最后两项是两个统计数据,一个是活动的slab总数,因为slab虽然带编号,但是这个编号不一定是连续的,因为有可能有些中间区间的slab没有值就没有初始化,这样以后该slab有值的时候就不用改变slab的编号了。所以活动的slab总数不一定等于slab的最大编号。
total_malloced这个是实际已经分配的总内存数,单位为byte,这个数值决定了memcached实际还能申请多少内存,如果这个值已经达到设定的上限,则不会有新的page被分配,以前分配的page也已经固定slab了。
综合上面的数据,可以发现造成memcached的内存使用率降低的属性有:
- page中从来没有被使用过的chunks;
- chunk中存放数据和chunk实际大小的差值;
- 由于短时间的数据集中在某个slab区域,导致大量page被分配,而之后被闲置的内存,这些即使有整个page的空闲也不会被分配给实际压力很大的slab区域(这个功能是不是以后memcached会考虑实现呢?)。
参考:http://hi.baidu.com/zhuguoneng/blog/item/aa5fbb3949e766f83b87cee4.html