JvmTI hello world
JvmTI (Jvm Tools Interface) 作为一个强大的jvm工具接口,提供很多很强大有用的功能。最近尝试下使用,简单记录下。
中文参考的是Ken Wu的博客,太具体的细节我就不累述了,这里直接解释我的hello world的过程吧。
JvmTI (Jvm Tools Interface) 作为一个强大的jvm工具接口,提供很多很强大有用的功能。最近尝试下使用,简单记录下。
中文参考的是Ken Wu的博客,太具体的细节我就不累述了,这里直接解释我的hello world的过程吧。
作为一个unix/linux小白,今天折腾了下ssh登录,使用rsa,不再需要输入密码了,具体步骤如下:
ssh-keygen -t rsa
这个命令会要提示三次输入:
1、第一次是存储rsa密钥的文件名称,默认的是id_rsa,可以直接回车使用默认的,也可以自己定义新的名称,最好还是放到.ssh目录下就可以了;
2、第二次是输入密码,最好输入一个密码,虽然可以为空(mac os下,请记住这个密码,第一次使用时需要输入)
3、第三次确认一次密码即可
生成的密钥文件有两个,以默认的为例,将会有一个id_rsa和id_rsa.pub,以.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验证的设置,具体包括:
RSAAuthentication yes PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys
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
chflags -R nouchg .
(不要漏了“.”号)
题目的确不好取,这篇仅记录下我花费了两个小时用来和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的过程如下:
通过上面的计算过程可以发现,其实第一个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的源代码发现两个问题:
在chunk中通过item存放了缓存对象的一些详细信息,包括key的长度,value长度,过期时间,flag等信息,具体可以查看item结构定义,后面紧跟的是key的实际内容、suffix实际打印的内容、value的实际值,所以chunk中存放远比value信息多,有一些值的作用目前还没有搞清楚,但是大部分都是在缓冲对象使用过程中有明显作用的。关于导出memcached的全部数据,只是使用了memcached提供的几个功能接口而已,具体代码如下,但是有几个要注意的地方。
<?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";
}
?>
参考链接:
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命令可以查看每个slab中存储的item的一些详细信息,具体可以见下图。
关键属性有:
| 属性名称 | 属性说明 |
|---|---|
| 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就可以观察到这些剔除的情况。
具体分析如下:
从Stats items中如果发现有异常的slab,则可以通过stats slabs查看下该slab是不是内存分配的确有问题。
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的内存使用率降低的属性有:
综合上面的数据,可以发现造成memcached的内存使用率降低的属性有:
参考:http://hi.baidu.com/zhuguoneng/blog/item/aa5fbb3949e766f83b87cee4.html
上周由于接手个一个新的项目,该项目对于memcache的依赖非常大,从而导致我不得不真的开始深入了解memcache的内存使用情况,这里总结下我个人的收获,也算是一次小的memcache优化吧。
一、Memcache内存分配机制
关于这个机制网上有很多解释的,我个人的总结如下。
Memcached的内存分配以page为单位,默认情况下一个page是1M,可以通过-I参数在启动时指定。如果需要申请内存时,memcached会划分出一个新的page并分配给需要的slab区域。page一旦被分配在重启前不会被回收或者重新分配(page ressign已经从1.2.8版移除了)
Memcached并不是将所有大小的数据都放在一起的,而是预先将数据空间划分为一系列slabs,每个slab只负责一定范围内的数据存储。如下图,每个slab只存储大于其上一个slab的size并小于或者等于自己最大size的数据。例如:slab 3只存储大小介于137 到 224 bytes的数据。如果一个数据大小为230byte将被分配到slab 4中。从下图可以看出,每个slab负责的空间其实是不等的,memcached默认情况下下一个slab的最大值为前一个的1.25倍,这个可以通过修改-f参数来修改增长比例。
Chunk是一系列固定的内存空间,这个大小就是管理它的slab的最大存放大小。例如:slab 1的所有chunk都是104byte,而slab 4的所有chunk都是280byte。chunk是memcached实际存放缓存数据的地方,因为chunk的大小固定为slab能够存放的最大值,所以所有分配给当前slab的数据都可以被chunk存下。如果时间的数据大小小于chunk的大小,空余的空间将会被闲置,这个是为了防止内存碎片而设计的。例如下图,chunk size是224byte,而存储的数据只有200byte,剩下的24byte将被闲置。
Memcached在启动时通过-m指定最大使用内存,但是这个不会一启动就占用,是随着需要逐步分配给各slab的。
如果一个新的缓存数据要被存放,memcached首先选择一个合适的slab,然后查看该slab是否还有空闲的chunk,如果有则直接存放进去;如果没有则要进行申请。slab申请内存时以page为单位,所以在放入第一个数据,无论大小为多少,都会有1M大小的page被分配给该slab。申请到page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk的数组,在从这个chunk数组中选择一个用于存储数据。如下图,slab 1和slab 2都分配了一个page,并按各自的大小切分成chunk数组。
综合上面的介绍,memcached的内存分配策略就是:按slab需求分配page,各slab按需使用chunk存储。
这里有几个特点要注意,
知道了这些以后,就可以理解为什么总内存没有被全部占用的情况下,memcached却出现了丢失缓存数据的问题了。
关于memcached命令行参数可以参考:http://techgurulive.com/2010/01/26/how-to-configure-memcached-memcached-configuration-parameters/
今天为了能够成功访问公司另外一个部门的资源,不得不跨域设置cookie,因为对方使用了cookie做身份验证,否则请求会被拒绝。解决方案如下:
假设我现在使用的域名是 tank.tkiicpp.com,而我需要访问 subdomain.tkiicpp.com的一个资源,并且需要在cookie里指定一个特殊值以标识身份,例如: vendor = tkiicpp,这样才能通过 subdomain.tkiicpp.com 的身份验证,这个时候出现了一个问题,我必须在 tank.tkiicpp.com 域下设置一个 cookie 能够在 subdomain.tkiicpp.com 域使用。幸好这两个域名都是 tkiicpp.com 的子域名,这个就是解决这个问题的关键,通过设置一个cookie到父域名( tkiicpp.com ) 下,在访问 subdomain.tkiicpp.com 的时候,这个cookie会被默认带上,java代码如下:
Cookie cookie = new Cookie("vendor", "tkiicpp");
//设置为-1指定当前cookie不持久化,将随浏览器的关闭而被清理
cookie.setMaxAge(-1);
//指定cookie的域为父域名,注意域名开头必须为“.”
cookie.setDomain(".tkiicpp.com");
//指定cookie影响的域名下的路径,默认是没有的,如果不写,cookie将被忽略,这里设置为所有路径都使用
cookie.setPath("/");
response.addCookie(cookie);
为了能够在IE里设置父域名的cookie,必须添加下面在header属性,关于P3P的详细资料可以查看http://www.w3.org/TR/P3P/#P3PPolicies
response.addHeader("P3P", "CP=CAO PSA OUR");
参考资料: