Archive for 八月, 2011

1、广东地区用户DNS解析出错,无法访问try8.info。分析,ISP可能缓存了错误的dns信息,nameserver在godday上,不够安全。考虑迁移到dnspod。

2、合作方提供的服务器(硬件负载均衡,两台服务器),访问本地图片url时特别慢,将host配置到127.0.0.1上就很快。

3、/tmp下的文件,会被tmpwatch定时清理!所以,不要在tmp下放置需要长久使用的东西。

淘宝开放平台提供的营销API可以创建定向优惠(即针对某些淘宝用户,提供商品的优惠价格)等。该类别的API需要店铺授权,即调用的时候需要传入session值。

淘宝现有的app类别中,在线订购和店铺模块两种,卖家购买后,授权的时长是等于购买时长的。比如一个店铺卖家购买了3个月的该app,那么他授权该app后的session key在3个月内都是有效的。虽然多次通过container.open.taobao.com/container?appkey=进入到该app的session值可能不同,但都有效。

不过我们比较shui,我们是店铺模块类别(有前台和后台两个appkey),但是通过监测发现半小时就过期了。把后台appkey发给top小二,请他帮忙查询了一下,发现我们的过期时间真的是被设置为了半小时!!不过小二很好,立刻就帮我们改掉了。所以,当发现过期时间不对的时候,可以请教一下top小二。

我们希望实现的功能是利用营销api,帮助店铺创建“商品定向优惠策略”和“人群标签”,并且在用户进行了某些操作之后,打上该“人群标签”。设想的实现方式是,在店铺许可的情况下,存储他的session。然后分别调用:

taobao.marketing.tag.add

taobao.marketing.promotion.add

taobao.marketing.taguser.add

这里还有一些疑问是,店铺续订app,session的有效时长是否会随之继续?我认为会~不过还需要时间的检查,test的方式是,现在找几个卖家,记录他们的session,看到期是否过期、续订后是否继续。

创建了这些活动之后,店铺卖家在哪里可以看到呢?

给用户打标签,会有失败的风险,所以除了重试机制之外,也要给管理员一个手工设置的后台。

同时,需要有一个界面,能查看到所有通过我们设置的优惠活动。

———————————————————————-

正常情况下,“店铺模块”后台key仅能被购买该服务的卖家授权,若是未购买服务的用户访问,则提示:

您无法访问这个应用,请先订购再使用

错误码:106

去服务平台订购

所以,店铺模块,如果希望给普通用户也提供一个后台的话,需要使用前台app key,而前台key是不需要手工授权,top container会自动授权,但是不含有session,所以无法调用那些敏感api。

之前没有怎么接触过session,而接手的项目中,由于session,遇到了一些问题:php使用NFS目录存储session PHP的session与ajax的性能冲突 。虽然通过将session的save_handler改为memcache,而消除了性能的问题,但是为了了解为什么,看了下php的session的ext代码,以补充我对session的了解不足。

首先了解下php.ini中对于session的配置:

session.save_handler = memcache
session.save_path = “tcp://192.168.80.27:11211″
;session.save_handler = files
;session.save_path = “/tmp/stry/php_session”
session.use_cookies = 1
session.cookie_secure = 0
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly = 1
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor     = 100
session.gc_maxlifetime = 1440
session.bug_compat_42 = 1
session.bug_compat_warn = 1
session.referer_check =
session.entropy_length = 0
session.entropy_file =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 4

这里我主要关注了save_handler,默认的是file,在多服务器环境常用到数据库、memcache等。

php的session代码位于php-src/ext/session,主要代码中session.c文件中。从session_start函数看起:

php-session-start函数流程图

php-session-start函数流程图

可以看到,其实session的存储,都是交给handler处理的,默认的file handler在mod_files.c中。一个标准的handler会含有以下黑体函数:

#define PS_MOD(x) \

#x, ps_open_##x, ps_close_##x, ps_read_##x, ps_write_##x, \

ps_delete_##x, ps_gc_##x, php_session_create_id

查看mod_file.c可以看到,PS_OPEN_FUNC(files)中,仅将存储的文件名等准备好,并不真的打开,而PS_READ_FUNC中,才真正调用ps_files_open函数打开文件并加锁:

data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY, data->filemode);

flock(data->fd, LOCK_EX); #Place  an  exclusive  lock.  Only one process may hold an exclusive lock for a given file at a given time.

这里可以看到使用了互斥锁!!该锁在文件关闭的时候释放,对于file handler来说,也就是在显示调用session_write_close或者本次请求结束的时候。所以,如果没有调用session_write_close,就会造成对同一请求的session,在使用file handler的时候,是串行的!从而减慢了访问的速度!

memcache的session handler在memcache-src/memcache_session.c中,大致看了下,没有与lock相关的操作,所以,并不是memcache的读写速度远超过file,而是由于它没有ex锁,才造成将handler换成memcache后,大大提高了访问速度!

手头上有一个利用session登录的项目,需要从单服务器迁移到双服务器环境,偷懒使用了NFS作为session的存储介质:

session.save_handler = files
session.save_path = “/tmp/stry/php_session”

其中,/tmp/stry/php_session是在192.168.80.49上的NFS,共享给另一台服务器192.168.80.27。

测试时,发现,当vip指向49的时候,响应很快,在1s之内。而如果指向了27,在firebug里看到等待响应的时间为30+s,接收数据的时间更长。

修改为memcache作为session的存储介质后,响应就很快了:

session.save_handler = memcache
session.save_path = “tcp://192.168.80.27:11211″

考虑测试一下NFS的性能问题,并深入了解一下session。

使用别人的api,就得面临人家升级、变动的情况,跟着变很烦,所以就得借助自动化工具了~

–TEST–
# vim: filetype=php
Sina Weibo SDK Test
–SKIPIF–
–FILE–
<?php
require(‘../weibooauth.php’);
define(‘TEST_KEY’, ‘3850844033’);
define(‘TEST_KEY_SECRET’, ‘9cd35fea86acd3c666d0fbddc42c0ba0′);
# http://apps.weibo.com/flykobe/ to get token
define(‘TEST_USER_ID’, ‘2298045197’); # a38672@nepwk.com
define(‘TEST_USER_TOKEN’, ‘5ffa72ac5e0baffd604e487196ff41cd’);
$_SERVER[‘REMOTE_ADDR’] = ‘127.0.0.1’;
# be careful, token generated by different sdk is different
$weiboClient = new WeiboClient(TEST_KEY, TEST_KEY_SECRET, TEST_USER_TOKEN);
# test get self info
$ret = $weiboClient->verify_credentials();
var_dump($ret[‘id’]);
# test send text weibo
$text = ‘Auto test by PHPT. ‘.rand();
$ret = $weiboClient->update($text);
var_dump($ret[‘id’]);
# test send pic weibo
$text = ‘Auto test by PHPT. ‘.rand();
$pic_path = ‘http://tp2.sinaimg.cn/1257818405/180/5607577090/0′; # make sure this pic can be visit by sina
$ret = $weiboClient->upload($text, $pic_path);
var_dump($ret[‘id’]);
# test un-follow
$friend_id = ‘1442255022’;
$ret = $weiboClient->unfollow($friend_id);
var_dump($ret[‘id’]);
# test follow
$friend_id = ‘1442255022’;
$ret = $weiboClient->follow($friend_id);
var_dump($ret[‘id’]);
# test friends_ids
$ret = $weiboClient->friends_ids(-1, 10);
var_dump($ret[‘ids’][0]);
?>
–EXPECTF–
float(%d)
float(%s)
float(%s)
int(1442255022)
int(1442255022)
int(%d)

全局性的vim配置可以写在.vimrc等配置文件里,而有的时候,希望针对某些特殊文件配置,也希望这些文件即使分发到其他人那里,也可以保留这些配置,这个时候,就需要vim modeline了!

在文件开头,或者最后,按照如下写法:

# vim: filetype=php

就可以把当前文件指定为php类型的文件。具体配置语法与vimrc没有区别。

具体参考:http://vim.wikia.com/wiki/Modeline_magic

我的开发机上,出现了一个奇怪的现象:之前有个项目A,使用了cake框架,目录是/wwwroot/A。因为要进行改版,且将web server从lighttpd改成apache,我一时懒惰,就直接将A cp 到/wwwroot/A_v2,域名也没变,缓存、db等配置都没变。之后,要用到旧版,我就启动lighttpd,用新版就启动apache~

后来,由于种种原因,A和A_v2上都有了一些不同的改动。当我stop了apache,切换到lighttpd的时候,cake总给我报,找不到control下的一个action,而这个action明明是存在于A目录文件中的,只是不存在于B中而已。

这时,怀疑是缓存的问题,看了下app/config/下的文件和cake/config/path.php等,与cache相关的define是app/tmp/cache,但是我的A和A_v2的cache目录都是空的。

跟踪发现,/wwwroot/A/index.php和/wwwroot/A/app/webroot/index.php都访问正常,而加载dispatch的时候,就不正常了~开始怀疑是不是用了autoload之类的,结果搜索__autoload 和spl_autoload_register都没有。搜索发现,cake没有自带autoload之类的,而是在cake/bootstrap.php中显示的App::import(‘Core’, array(‘Dispatcher’));

所以问题就出在这个APP::import中了。该函数中有这么一行 $_this =& App::getInstance(); ,在getInstance中,果然出现了cache的字样:

function &getInstance() {
static $instance = array();
if (!$instance) {
$instance[0] =& new App();
$instance[0]->__map = Cache::read(‘file_map’, ‘_cake_core_’);
}
return $instance[0];
}

再跟下去,发现cache使用域名跟上固定字符串,形成key,而我的A和A_v2使用了同样的域名,所以file_map就互相覆盖了~~

看来偷懒不得啊~由于我的缓存用的是memcache,app/config/core.php中配置的default是本地、11211端口,重启就ok了。

web项目中,图片上传功能很常见,对于小应用来说,一般没有用到DFS,就直接存储到本地磁盘上。

现在需要把包含这样功能的一个项目,从单点服务器迁移到双机vip上去,而且由于服务器是由合作方提供的,我没法通过ip或者域名指定访问哪一台服务器。

考虑了两种方案:

1、使用一台机器作为文件存储服务器。上传图片时,仅存储在该服务器上。读取图片时,web server通过内网ip访问该文件服务器,缓存在本地。

2、每台web server都存储同样的图片。上传图片时,同步到所有web server上。读取图片时,直接读取本地图片。

考虑到,我最好能在半天内完成该部分工作,而我们的功能决定,图片上传是少数功能,且目前看来,admin上传的图片占绝大多数,所以写时的体验不是很重要。所以,以一种简单的方式,实现方案2。即,综合使用php的remote file读写功能,和ftp。

首先配置ftp。

  • yum install vsftpd,安装ftp daemon。
  • adduser -d /tmp/ftpbasedir/ -g ftp -s /sbin/nologin ftpusername
  • passwd ftpusername 更改密码
  • 配置/etc/vsftpd/vsftpd.conf (http://www.linuxsir.org/main/node/152?q=node/152#8.5) :这里禁止匿名访问,允许local用户upload
  • chmod 0777 /tmp/ftpbasedir/ -R 允许所有人读写
  • service vsftpd start 启动服务。最好加入到/etc/rc.local中,使开机自动启动
  • ftp 尝试连接和上传,确保没有错误

然后修改php代码,原先代码里可能会有这样的code:

if (move_uploaded_file($fileTmp, $output)) {
chmod($output, 0644);
}
修改为:
global $img_hosts;
if (strpos($output, GLOBAL_IMG_ROOT) === 0){
$output = substr($output, strlen(GLOBAL_IMG_ROOT));
}
foreach($img_hosts as $i){
if ($i != $_SERVER[‘SERVER_ADDR’]){
$remote_file = sprintf(“ftp://%s:%s@%s%s”,SECRET_FTP_USER, SECRET_FTP_PWD, $i, $output);
if (!($fp = fopen($remote_file, ‘w’))){
error_log(“Sync to $remote_file fail”);
continue;
}
if(false === fwrite($fp, file_get_contents($fileTmp))){
error_log(“Sync-write to $remote_file fail”);
}
error_log(“Sync-write to $remote_file OK”);
fclose($fp);
}
}
unlink($fileTmp);
这里,用了sync的方式,将file同步到多台server,如果server较多,可以考虑使用异步或者队列的方式。并且,最好开一个cron,检测是否有同步失败的情况,进行重传。
————————————————————————-

内网情况下,也可以使用NFS实现,具体参看:http://linux.vbird.org/linux_server/0330nfs.php 进行配置。

注:rpcbind改名为portmap了,所以只要有portmap命令运行着,就可以尝试启动nfs。

注:更改了NFS server的配置 /etc/exports 之后,通过exportfs -ra来重新载入。

个人非常喜欢VIM来写代码,简洁、易用,但是刚开始使用的时候,有些命令还是很难记忆的。这里整理一下。

以下/代表或者。比如p/P代表p或者P;ctrl+f/b/u代表ctrl+f或者ctrl+b或者ctrl+u。

VIM分为几种模式:普通模式、插入模式、命令行、可视模式、执行shell命令等。

其中普通模式为打开vi的默认模式,它响应键盘,进行光标操作、复制、粘贴等。

插入模式,或者说是编辑模式,使用i、I、a、A、o、O、s、S等可以由普通模式进入,然后进行编辑。

命令行模式,在屏幕的最下方,使用Ctrl+c由插入模式转化到普通模式,再:由普通模式转化到命令行模式。该模式下执行VIM的命令,比如保存、退出、查找、替换等。

可视模式,使用V或者v,由普通模式转化到可视模式。这样可以按行、或者区块选定区域(使用上下左右键),然后复制等。

执行shell命令,在命令行模式下,使用:! 后面跟上shell命令,就可以执行了。

普通模式下,光标移动比较常用:hjkl和方向键一样的效果,还有ctrl+f/b/u等进行翻页,^$进行行首尾的定位,w/b按单词位移,gg回到文件首,G到文件末尾等。

普通模式下,字母的替换为:在当前光标位置按r,则当前字母被替换为下一输入的字母。

普通模式下,撤销与反撤销: u,U,ctrl+r。

普通模式下,复制与粘贴:yy是复制一行,3yy是复制3行(依此类推);dd是删除当前行,3dd是删除3行;p/P是粘贴(可以粘贴y或者d的内容)。vi中可以使用多个复制缓冲区,(”ay是复制到缓存区a,”ap是从缓冲区a粘贴,可以用26个字母命名缓冲区)

普通模式下,给文章加个行标记,下次从文件别的地方跳转回来:ma是给当前行标记为a,然后用’a跳转回来。

命令行模式下,查找:/为向下查找,?为向上查找,比如/aaaa,是查找匹配aaaa的字符串。n/N向下/上的下一个。为了避免输入,可以在当前光标所在单词处,使用*/#,向下/上查找当前单词(但是注意,这里实际上是匹配“整个”单词,就是包括单词边界,比如split实际上是/,也就是不可以匹配vsplit。)

命令行模式下,替换:语法为 :%s/aaaa/bbb/g,将所有的aaaa替换为bbb;后面的g代表全部替换,否则仅替换一次。这里支持一些正则。

命令行模式下,保存退出等: :w 保存; :q 退出; :wq保存并退出; :q!不保存退出。(在普通模式下,ZZ就是保存退出了)

命令行模式下,打开新窗口:split filename(水平打开),vspilt filename(垂直打开)。之后,使用ctrl+w加一些组合键来操作这些窗口。(Ctrl+w ctrl+w)在窗口间切换,(ctrl+w ,)方向键也是切换。(ctrl+w =)窗口等大小。(ctrl+w _)当前窗口最大化。(ctrl+w +/-)当前窗口变大/小一行。(移动窗口:ctrl+w H|J|K|L)

更方便的移动方式,在.vimrc中加入:

nmap j

nmap k

nmap h

nmap l

这样就可以利用 ctrl+h|j|k|l 来模拟 ctrl+w 再加hjkl的命令了。

命令行模式下,打开其他文件: :e filename,缓存会切换到新文件处,所以打开之前需要保存当前文件(不保持也没关系,它会提醒你的)。然后使用ctrl+^在文件间切换。

使用:e打开的多个文件其实都在文件缓冲区内,可以通过 :ls 命令查看,然后通过 :buffer Num 或者 Num ctrl+^ 切换。

(vim其实一下子可以打开多个文件,vi file1 file2 .. filen,之后使用:n/N在文件间切换)

(vi -d file1 file2打开两个文件,并且使用diff比较它们的异同)

可视模式,我唯一使用它的就是区域选择,然后可以使用yy、dd,或者命令行下的替换。

插入模式,经常使用的是补完,比如之前输入过单词verylong,那么下次输入到very的时候,ctrl+p/n可以补完。(ctrl+x ctrl+f)是在系统中搜索,补完文件名。(ctrl+x ctrl+l)是补完一条句子。

写代码的时候,可能想看看某个文件在什么地方,或者执行一些shell命令,这时可以(:! ls *)。

ps: set indentexpr=

最后,要多用help命令。在命令行模式下 :help pattern可以看到pattern相关的帮助,如果不带参数,就会看到vi的帮助文档。

使用ctrl+]|T (同ctags)在帮助文档的主题之间跳转。

—————————————————

重要能把ctags用到php上面了,这里总结一下(ps:同时说说Project插件  http://www.vim.org/scripts/script.php?script_id=69)

1、下载vim的project插件,解压到home的.vimrc下面就可以了(具体我记得我上面博客说过)

2、使用\C,\R来新建和更新project,空格来缩放窗口

3、首先看看ctags的默认语言映射(就是用什么语言机制来解析一种后缀名的文件):

ctags –list-map

为了使.inc后缀的文件也映射到PHP,我们使用以下命令生成tag:

ctags –langmap=PHP:+.inc -R *

ctags 可以结合vim的taglist扩展,比如~/.ctags里可以修改各种语言的function/variable等的意义:

–regex-php=/^[ \t]*[(private| public|static)( \t)]*function[ \t]+([A-Za-z0-9_]+)[ \t]*\(/\1/f, function, functions/

–regex-php=/^[ \t]*[(private| public|static)]+[ \t]+\$([A-Za-z0-9_]+)[ \t]*/\1/p, property, properties/

–regex-php=/^[ \t]*(const)[ \t]+([A-Za-z0-9_]+)[ \t]*/\2/d, const, constants/

结合~/.vim/plugin/taglist.vim里的:

” php language

let s:tlist_def_php_settings = ‘php;c:class;f:function’

4、使用ctrl+] 、ctrl+t来在function之间跳转

5、如果报找不到tag,那么看~/.vimrc有没有一些关于ctags的配置,默认vim会在当前目录去load tag文件的

——————————————————-

在用鼠标粘贴内容到vim中的时候,它的自动补完、缩进等有时会很讨厌,这时可以这样:

在粘贴文本到 vim 前,先:

<span>:</span>set paste

完了再恢复:

<span>:</span>set paste<span>!</span>

其实先禁用 <code>smartindent</code>

也一样的,不过至少 <code>paste</code>

 比 <code>smartindent</code>

 短 6 个字符,呵呵。

———————————————————

vim配置问题:

1、打开vim,恢复到上次关闭的位置

if has("autocmd")

   autocmd BufRead *.txt set tw=78

   autocmd BufReadPost *

     / if line("'/"") > 0 && line ("'/"") <= line("$") |

      /   exe "normal g'/"" |

      / endif

endif

参考文档: http://man.lupaworld.com/content/manage/ringkee/vim.htm

———————————————————–

vim +Tlist +Project

参考文档: http://www.ibm.com/developerworks/cn/linux/l-tip-vim2/index.html

1、下载并按照project插件

2、下载 vim的taglist插件 :http://www.vim.org/scripts/download_script.php?src_id=7701

unzip taglist.zip -d ~/.vim

该插件特性:

  • 可以显示宏(macro)、函数(function)、变量(variable)、类型定义(typedef)、类(class)、结构(struct)等多种内容信息;
  • 打开多个文件时,可以同时看到多个文件的结构信息;
  • 在左边的 taglist 窗口显示的名称上双击鼠标或按回车键,右边主窗口中会跳转到相应的定义位置;
  • 右边窗口中光标的位置改变,左边的窗口也会在 4 秒内(缺省值,参见“:help ‘updatetime’”)黄色加亮显示相应的名称;
  • 在启用/关闭 taglist 时,插件能够自动改变当前 Vim 窗口的大小(不管是文本模式的 Vim 还是图形界面的 Vim),除非使用“:let Tlist_Inc_Winwidth=0”关闭这一功能(当使用这一功能导致兼容性问题时)。

图8

3、 vim +Tlist +Project filename

使用ctrl+ww在窗口之间切换。或者ctrl+w — h|l 控制向左|右窗口。

taglist 的折叠使用 – 控制。

—————————————————-

vim对grep和make的支持:

Make [17] 和grep [18] 应当算是 Unix 世界里无人不晓的基本工具了吧。很自然的,Vim

对它们有着特殊的支持。该支持主要通过访问一个特殊的快速修订窗口(quickfix window)来实现。直接在 Vim 的命令模式里输入相应的

make 或 grep 命令(如“:grep foo *.c”)即可将命令的执行结果放入该窗口,同时根据返回的结果跳转到第一个错误(make

的情况;在使用 grep 时是匹配成功之处)。以下是常用的“快速修订”命令:

  • :cn(显示下一个错误)
  • :cp(显示上一个错误)
  • :cl(列出所有的错误及其编号)
  • :cc(跳转到指定编号的错误)
  • :copen(打开快速修订窗口,在其中显示所有错误,可在错误上双击鼠标或按回车键跳转至该错误;示例参见图 4)图4
  • :cclose(关闭快速修订窗口)

Vim 的这个特性也可以与 make 和 grep 以外的程序一起工作(事实上,在 Windows XP

上,“:grep”命令一般调起的是“findstr /n”)。具体调用那个程序由选项 makeprg(Linux 下缺省为“make”)和

grepprg(Linux 下缺省为“grep -n $* /dev/null”)控制,而如何解析返回的内容则由选项 errorformat

和 grepformat 控制。鉴于在 Unix/Linux 下一般不需更改这些选项的内容,此处不再详述

———————–

vim 查找 取反:

:g!/searchkeyword

———————————-

查看vim插件等的加载位置::set runtimepath?

———————————-

以下zz from http://hi.baidu.com/newkedison/blog/item/d9704d8fcd63ade8f01f3688.html

1、滚屏

先用命令设置每次滚屏的行数,默认值是半个屏幕

:set scroll=3

设置每次滚动3行

然后用Ctrl+u上滚,Ctrl+d下滚

08.08.19补充

可以用3Ctrl+u实现先设置scroll为3,再上滚3行,这个比较实用,我的vimrc里面定义了两个映射

map 3 “定义空格键代替Ctrl+d,就是向下滚屏,相当于鼠标滚轮

map 3 “定义Alt+空格代替向上滚屏

这样就可以用空格和Alt+空格来模拟滚轮了

2、q/

在Normal模式输入q/就可以显示前面查找过的语句,这样对测试正则表达式非常有用,另外也可以先输入/然后按方向键的向上来看前面的记录

3、:reg

查看所有寄存器

08.08.19补充

:marks 查看所有书签,用m{a-z}定义的

4、自定义热键的作用范围

:nmap 键只对普通模式有效

:imap 键只对插入模式有效

:vmap 键只对可视模式有效

:cmap 键只在命令行下有效

:map 键在普通模式和可视模式都有效

:map! 键在插入模式和命令行下都有效

5、命令行中使用粘贴

Ctrl+R,然后跟寄存器名,可以将指定寄存器的内容粘贴到当前位置,特别的,用*(星号)寄存器表示剪贴板中的内容,这样以后看到网页上的命令,就不需要自己手打了.

:h i_CTRL-R   查看详细解释,输入时要注意大小写,可以直接试试复制的效果,先复制冒号后面的内容(不要复制冒号),然后在normal模式下按冒号,再按Ctrl+R,光标下会出现一个双引号,那是提示输入寄存器名,按Shift+8输入星号即可

6、复制中也能用正则表达式

比如按y,然后输入一个/开头的正则表达式,会从光标当前的位置,复制到正则表达式匹配的地方,包括光标下的字符,但是不包括正则表达式匹配到的内容,只复制到匹配内容的前面,我用\zs试了一下,无法使正则表达式中\zs前面的一部分也一起复制

7、粘贴在下一行

以前我是按o,然后ESC,再p,后来发现,其实:pu就可以了,这个命令还有其他扩展功能,见:h pu

08.08.19 补充

这里说的复制不包括用yy整行复制,如果是整行复制的话,用p就直接复制到下一行了

8、字符串

在需要用到字符串的函数,或者是定义一个变量作为字符串,我们都可以用一对双引号或一对单引号表示一个字符串.他们有一定的区别,

在单引号里面,除了单引号本身,其他任意符号(如双引号,斜杆等)均表示其本身,没有任何特别含义,而用两个单引号,可以表示一个单引号,其实就和VB的字符串的双引号是一样的

如果是在双引号里面,则斜杆\作为转义字符,可以有很多特殊的用法,如\t跳格,\n换行等,如果要表示双引号,则用\”,单引号不需要转义

详见:h 41.2

08.08.19

字符串可以用小数点.拼接一些变量,类似于VB中的&符号

9、命令行中使用函数

在输入命令的时候,也可以调用函数还输入一些内容,方法是按Ctrl+r,再按=,然后前面输入的内容就不见了(隐藏起来了)前面变成了一个=号,光标停在等号上面,这里就可以输入函数,输入结束后按回车,函数执行的结果就紧跟在你刚才按Ctrl+r的地方了.

比如

:split =expand(“%:p:h”)

注意,表示按Ctrl+r,不是原样输入

这个执行的效果是把当前的路径显示到命令行,然后回车后会出来一个可以选择打开哪个文件的窗口,关于expand函数详见:h expand

10. 让光标可以停在任意位置

默认的效果是,光标只能停在有字符的区域,可以用

:set ve=all

使光标可以到达任意位置

如果要恢复默认的设置,用:set ve=

具体内容查看:h virtualedit

11. 不保留备份文件

:set nobackup

具体内容查看 :h backup

12. 设置Tab键宽度,以及用空格代替Tab

我喜欢Tab键宽度为两格,而且是用两个空格替换Tab,这样有个好处,文件的格式不会因为各个编辑器不同的设置而改变样子

set tabstop=2     “实际Tab键的宽度

set expandtab     “用空格代替Tab键,这样当按了Tab键后,会被替换成两个空格,删除的时候也是按空格来删除

set autoindent    “自动缩进,在VIM能识别的语法下,会自动输入Tab,缩进的宽度由下一行的设置确定

set shiftwidth=2 “设置自动缩进的宽度

12. modeline

查看VIM帮助时,可以看到最后都有一行vim:开头的内容,这行东西在vim中叫modeline,具体用法通过

:h modeline

查看

转载自:张宴  http://blog.s135.com/read.php/362/ 。原文标题为《利用Tokyo Tyrant构建兼容Memcached协议、支持故障转移、高并发的分布式key-value持久存储系统》。

以下为原文:

——————————————————————————

[文章作者:张宴 本文版本:v1.4 最后修改:2010.06.11 转载请注明原文链接:http://blog.s135.com/read.php/362/]

Tokyo Cabinet 是日本人 平林幹雄 开发的一款 DBM 数据库,该数据库读写非常快,哈希模式写入100万条数据只需0.643秒,读取100万条数据只需0.773秒,是 Berkeley DB 等 DBM 的几倍。

点击在新窗口中浏览此图片


Tokyo Tyrant 是由同一作者开发的 Tokyo Cabinet 数据库网络接口。它拥有Memcached兼容协议,也可以通过HTTP协议进行数据交换。

Tokyo Tyrant 加上 Tokyo Cabinet,构成了一款支持高并发的分布式持久存储系统,对任何原有Memcached客户端来讲,可以将Tokyo Tyrant看成是一个Memcached,但是,它的数据是可以持久存储的。这一点,跟新浪的Memcachedb性质一样。

相比Memcachedb而言,Tokyo Tyrant具有以下优势:

1、故障转移:Tokyo Tyrant支持双机互为主辅模式,主辅库均可读写,而Memcachedb目前支持类似MySQL主辅库同步的方式实现读写分离,支持“主服务器可读写、辅助服务器只读”模式。

点击在新窗口中浏览此图片

这里使用 $memcache->addServer 而不是 $memcache->connect 去连接 Tokyo Tyrant 服务器,是因为当 Memcache 客户端使用 addServer 服务器池时,是根据“crc32(key) % current_server_num”哈希算法将 key 哈希到不同的服务器的,PHP、C 和 python 的客户端都是如此的算法。Memcache 客户端的 addserver 具有故障转移机制,当 addserver 了2台 Memcached 服务器,而其中1台宕机了,那么 current_server_num 会由原先的2变成1。

引用 memcached 官方网站和 PHP 手册中的两段话:

http://www.danga.com/memcached/
If a host goes down, the API re-maps that dead host’s requests onto the servers that are available.

http://cn.php.net/manual/zh/function.Memcache-addServer.php
Failover may occur at any stage in any of the methods, as long as other servers are available the request the user won’t notice. Any kind of socket or Memcached server level errors (except out-of-memory) may trigger the failover. Normal client errors such as adding an existing key will not trigger a failover.


2、日志文件体积小:Tokyo Tyrant用于主辅同步的日志文件比较小,大约是数据库文件的1.3倍,而Memcachedb的同步日志文件非常大,如果不定期清理,很容易将磁盘写满。


3、超大数据量下表现出色:

点击在新窗口中浏览此图片

但是,Tokyo Tyrant 也有缺点:在32位操作系统下,作为 Tokyo Tyrant 后端存储的 Tokyo Cabinet 数据库单个文件不能超过2G,而64位操作系统则不受这一限制。所以,如果使用 Tokyo Tyrant,推荐在64位CPU、操作系统上安装运行。


一、安装
1、首先编译安装tokyocabinet数据库

wget http://www.1978th.net/tokyocabinet/tokyocabinet-1.4.45.tar.gz
tar zxvf tokyocabinet-1.4.45.tar.gz
cd tokyocabinet-1.4.45/
./configure
#注:在32位Linux操作系统上编译Tokyo cabinet,请使用./configure –enable-off64代替./configure,可以使数据库文件突破2GB的限制。
#./configure –enable-off64
make
make install
cd ../

2、然后编译安装tokyotyrant

wget http://www.1978th.net/tokyotyrant/tokyotyrant-1.1.40.tar.gz
tar zxvf tokyotyrant-1.1.40.tar.gz
cd tokyotyrant-1.1.40/
./configure
make
make install
cd ../

二、配置
1、创建tokyotyrant数据文件存放目录

mkdir -p /ttserver/

2、启动tokyotyrant的主进程(ttserver)
(1)、单机模式

ulimit -SHn 51200
ttserver -host 127.0.0.1 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 1 -rts /ttserver/ttserver.rts /ttserver/database.tcb#lmemb=1024#nmemb=2048#bnum=10000000

(2)、双机互为主辅模式
服务器192.168.1.91:

ulimit -SHn 51200
ttserver -host 192.168.1.91 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 91 -mhost 192.168.1.92 -mport 11211 -rts /ttserver/ttserver.rts /ttserver/database.tcb#lmemb=1024#nmemb=2048#bnum=10000000

服务器192.168.1.92:

ulimit -SHn 51200
ttserver -host 192.168.1.92 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 92 -mhost 192.168.1.91 -mport 11211 -rts /ttserver/ttserver.rts /ttserver/database.tcb#lmemb=1024#nmemb=2048#bnum=10000000

(3)、参数说明
ttserver [-host name] [-port num] [-thnum num] [-tout num] [-dmn] [-pid path] [-log path] [-ld|-le] [-ulog path] [-ulim num] [-uas] [-sid num] [-mhost name] [-mport num] [-rts path] [dbname]

-host name : 指定需要绑定的服务器域名或IP地址。默认绑定这台服务器上的所有IP地址。
-port num : 指定需要绑定的端口号。默认端口号为1978
-thnum num : 指定线程数。默认为8个线程。
-tout num : 指定每个会话的超时时间(单位为秒)。默认永不超时。
-dmn : 以守护进程方式运行。
-pid path : 输出进程ID到指定文件(这里指定文件名)。
-log path : 输出日志信息到指定文件(这里指定文件名)。
-ld : 在日志文件中还记录DEBUG调试信息。
-le : 在日志文件中仅记录错误信息。
-ulog path : 指定同步日志文件存放路径(这里指定目录名)。
-ulim num : 指定每个同步日志文件的大小(例如128m)。
-uas : 使用异步IO记录更新日志(使用此项会减少磁盘IO消耗,但是数据会先放在内存中,不会立即写入磁盘,如果重启服务器或ttserver进程被kill掉,将导致部分数据丢失。一般情况下不建议使用)。
-sid num : 指定服务器ID号(当使用主辅模式时,每台ttserver需要不同的ID号)
-mhost name : 指定主辅同步模式下,主服务器的域名或IP地址。
-mport num : 指定主辅同步模式下,主服务器的端口号。
-rts path : 指定用来存放同步时间戳的文件名。

如果使用的是哈希数据库,可以指定参数“#bnum=xxx”来提高性能。它可以指定bucket存储桶的数量。例如指定“#bnum=1000000”,就可以将最新最热的100万条记录缓存在内存中:

ttserver -host 127.0.0.1 -port 11211 -thnum 8 -dmn -pid /ttserver/ttserver.pid -log /ttserver/ttserver.log -le -ulog /ttserver/ -ulim 128m -sid 1 -rts /ttserver/ttserver.rts /ttserver/database.tch#bnum=1000000

如果大量的客户端访问ttserver,请确保文件描述符够用。许多服务器的默认文件描述符为1024,可以在启动ttserver前使用ulimit命令提高这项值。例如:

ulimit -SHn 51200

3、停止tokyotyrant(ttserver)

ps -ef | grep ttserver

找到ttserver的进程号并kill,例如:

kill -TERM 2159

三、调用
1、任何Memcached客户端均可直接调用tokyotyrant。

2、还可以通过HTTP方式调用,下面以Linux的curl命令为例,介绍如何操作tokyotyrant:
(1)、写数据,将数据“value”写入到“key”中:

curl -X PUT http://127.0.0.1:11211/key -d “value”

(2)、读数据,读取“key”中数据:

(3)、删数据,删除“key”:

——————————————————————–

转载完毕。

注:

1、启动ttserver时,指定的host ip为监听ip,如果使用127.0.0.1,则仅有本地才允许访问。所以,如果允许网络访问,应该使用192之类的ip。

2、参数含义如下,适用于TT(tokyo tyrant):

  • capnum :设置记录的最大容量
  • capsiz :设置内存型database的内存容量,内存不足记录将按照顺序移除
  • mode : 可选的选项:w (写)、r (读)、c (创建)、t (截断)、t (无锁)、f (非阻塞锁)。默认值为 :wc
  • idx :设置索引的列名,用:分割
  • opts :可选的选项:l (64位bucket数组,database容量可以超过2G)、d (Deflate压缩)、b(BZIP2压缩)、t(TCBS压缩)
  • bnum :bucket的数量
  • apow :specifies the size of record alignment by power of 2. 如果负数,设置无效
  • fpow :specifies the maximum number of elements of the free block pool by power of 2. 如果负数,设置无效
  • rcnum :设置缓存记录的最大数,如果数值不是大于0则会禁用缓存,默认禁用
  • lcnum :设置缓存叶节点(leaf nodes)的最大数,如果数值不是大于0则会禁用缓存,默认值4096
  • ncnum :设置缓存非叶节点(non-leaf nodes)的最大数,如果数值不是大于0则会禁用缓存,默认值512
  • xmsiz :设置额外内存映射容量,如果数值不是大于0则会禁用内存映射,默认值67108864
  • dfunit :specifie the unit step number. If it is not more than 0, the auto defragmentation is disabled. It is disabled by default.
  • width :设置记录的固定大小,如果数值不是大于0,则默认是255
  • limsiz :设置数据库文件的大小,如果数值不是大于0,则默认是268435456
  • lmemb :设置每个叶节点页(leaf page)的成员数,如果数值不是大于0,则默认是128
  • nmemb :设置每个非叶节点页(non-leaf page)的成员数,如果数值不是大于0,则默认是256

lmemb和nmemb是B+tree的参数,规定了叶节点和非叶节点个数。回忆下B+ tree哦。

—————–

TCHDB 哈希数据库、TCBDB B+Tree数据库、TCFDB 定长数据库、TCTDB 表格数据库、TCMDB内存哈希数据库、TCNDB 内存B+Tree数据库