境外DNS解析缓慢

在阿里云部署了自己的服务器,一直使用Linode做DNS解析。当初使用Linode的原因是不想去做备案,不过最近遇到了新的问题。

原本Linode的DNS解析速度还是很快的,从没想过访问服务速度缓慢是名称解析的问题。最近两天访问自己的开发服务器以及git服务器非常缓慢,ping值破千ms,在服务器上top看下来,也找不到任何性能问题,满头疑惑。

后来测试支付宝接口的时候,发现原本可以走通的支付宝接口,在成功支付的情况下,支付宝服务器没有给我们调用回调函数,反复查找原因都没有找到。

多种异状结合在一起,终于开始想到,会不会是名称解析的问题。果然,测试代码改用IP而不是域名作为接口后,速度大大加快,支付宝的回调也成功接收到了。更为可观的是,由于测试用例中大量使用域名作为数据库地址,原本10分钟才能跑完的测试用例,现在仅需几秒钟就能完成。

这才意识到名称解析对于提高服务性能的重要性,开始考虑切换到使用国内名称解析了。不想做免费广告,就不提目前试用的是哪家的服务了。总之先试一试,看一看服务的情况如何,再做进一步的考虑。

linux 文件目录权限批量处理

在linux上有时遇到这样的需求,希望将一个目录下所有子目录的权限批量设置为新的权限。
这其实很容易,只需chmod -R XXX path即可。
问题是,如果我们只想让其他用户可以访问到这个文件目录,同时需要保持原有的读写权限,该怎么办呢?
使用chmod的权限字母表示法,可以表示该文件当前的权限

The permissions that the User who owns the file currently has for it	u
The permissions that other users in the file's Group have for it	g
Permissions that Other users not in the file's group have for it	o

通过以下符号可以表示将要设置的文件权限

User	                           letter
The user who owns it	                u
Other users in the file's Group	        g
Other users not in the file's group	o
All users	                        a

通过这个就可以知道我们想要的命令


chmod -R a+u path

这样就可以让所有用户都按照文件当前用户权限访问。

参考:
[1] chmod man page

DSS 源码阅读指南[0]

最近在读Darwin Streaming Server源代码,刚刚开始,随意记录一些信息。

DSS 代码非常旧,MacOS forge上的版本还停留在6.0.3,看样子应该是2003年的陈年老酒,不过即便如此还是有许多值得学习的地方。

说到阅读源码,是让人感到压力山大浑身不自在的事情,无论是别人写的,还是自己写的。好在DSS的Documentation目录下有许多非常值得阅读的资料,可供参考。读完 AboutTheSource.html , DevNotes.html, FAQ.html 和 QTSSAPIDocs.pdf 之后,感觉DSS的代码框架已经一目了然,并且有迫不及待去看相关代码实现的冲动了。

DSS的RTP实现建立在所谓“reliable UDP”之上,何谓“可靠UDP”,让人非常疑惑,在Documentation中找到Reliable RTP Whitepaper,可窥端倪。网上也有介绍苹果自家的“reliable UDP”的设计、实现的相关介绍,可以参考。

这些文档从系统设计的角度介绍了DSS的全貌。系统设计一直是我很感兴趣的一个话题,DSS的系统设计理念很值得学习和思考。模块化、异步执行(不阻塞)、消息队列与派发,这些也都是现代服务器/操作系统的设计理念。

这是阅读学习DSS代码的一篇小小指引,后续会逐渐增加一些自己的发现。

痴汉人生

一转眼发现已经快半年没有写博客了,上一篇bo还是去年10月份的。

自我安慰一下,这一段时间倒没有虚度,还是读了不少书,见了不少世面的。对人生的看法也慢慢有了新的理解。最近读了一本书,《醉汉的脚步》,我非常喜欢。这是一本讲概率的书,我本是因为,对于“随机性”这个问题,其真实的含义到底是什么,没有足够的认识,正好在网上看到这本书的风评很好,就买来读读。没想到这居然成了一本洗刷我的三观的书。

随机这个东西,究竟是什么意思,一直找不到最好的方式去理解。当然并不是说数学课讲的期望啊方差啊这些东西没学会。不是的。问题是这些都只是从一个侧面去描写一种随机分布的指标,却仍然不能知道随机事件发生时,到底是什么样子的。比如抛一枚硬币,1/2概率是正面,1/2概率是反面。这个1/2究竟是什么意思呢?并不是说,每抛两次硬币就会出一次正面。说抛100次硬币,出现50次正面的概率最大,这种说法似乎是对的。但假如前99次中出现50次反面,49次正面,也不意味下一次抛硬币出现正面的概率会更大。事实上,假设前99次连续抛出反面,下一次抛硬币,出现反面和出现正面的概率还是一样。理论上会计算概率,并不表示直观上理解了概率到底是什么意思。

读《醉汉的脚步》这本书,让我收获颇丰。其第一点,就是告诉我,概率是用来分析那些人类理解不了的事物的。文中提到,人类会习惯性的寻找规律,其中的例子很有趣,给被实验者观察一串连续的颜色变化,红绿红红绿红红红绿……实际上,红色和绿色出现毫无规律,完全随机,只是红色出现的概率是2/3,绿色出现的概率是1/3。但是受试者会情不自禁地分析这段颜色出现的规律,例如上面一段,可能会分析出下一组应当是红红红红绿。因此如果让受试者去猜下一个颜色是什么,很可能会猜错。而同样的实验受试者换成老鼠,它猜测下一个永远会猜红色,因为红色的几率高嘛。结果老鼠的得分反而比人类的得分高。

这一下就解决了我自认“理解不了概率”这个问题。我所说的“理解不了概率”其大概的意思,或许是说,即使知道了概率,也还是不明白按这样的概率运行的事物(无论是抛硬币、股市、足球的胜负还是人生的浮沉、世界的治乱),其运行的规律究竟如何。而这一解释是自明的,正是因为无法明了其运行的规律,才不得不用概率去归纳。概率是无需“理解”的,只需“知道”即可。如果硬要“理解”,就像上述实验中的人类受试者一样,硬要从一堆随机的信号中寻求规律,结果反倒输给老鼠。

这本书给我的另一个收获,是“贵在坚持”的另外一种解释。概率,是要通过统计,得出的。而概率影响的范围之广,上至全球金融、政治,下至日常生活,黄油面包,无处不在。连续抛3次硬币,都出现正面,并不能就此确信,这个硬币不平衡。连续3次猜拳输给对手,并不能认为对手一定有超能力。然而,连续3年业绩低迷的基金经理人会被开除,连续3次点球罚失的球星会坐冷板凳,或许连续3次失恋的少男少女也会对生活失去希望。而岂不知人生处处都有随机性存在,而区区3次失败,并不具备任何统计意义上的证据可以说明被观察的对象本身品质有严重缺陷。可惜的是人生短暂,往往等不及几十次上百次的测试,再去挑选那个千锤百炼的好手。俗语说,事不过三,往往以三次为界。这也是无可奈何的事情。只是作为审查者,不应只根据业绩、成绩,去评价一个人,而更多从多方综合因素去冷静分析评估;作为被审查者,即使遭遇连续的挫折,假定相信自己的路是有道理的,就不应仅因为业绩、成绩,就放弃自己的路。当然这是万难的。这也是因为,人类习惯性的从现象中试图分析出规律,而往往许多事情,股票的走势、考生的成绩、足球的比分,其实没有什么办法可以准确预测的。当你看到连续的下跌,或许这仅仅是一个波动。

这让我想起庄子的话,“朝菌不知晦宿,蟪蛄不知春秋”,“小智不及大智,小年不及大年”。人生短暂,像是用放大镜去观察印象派油画的一角,看到的仅仅是斑斑驳驳的色点,可谓瞎子摸象,管中窥豹。当然,这是人类固有的局限性,不可能就此超越。但知道自己具有这样的局限性,“认识你自己”,总比认识不到自己的局限性要略好一些吧。犹如五十步笑百步,如能知道自己是五十步,而能不笑百步,就可以说是巨大的进步了。

当然这本书内容很丰富,绝不仅这一点营养。只是拿出我最受震动的部分记录一下而已。也是因为自己荒废博客许久,作为给自己的一个小小的交代吧。接下来的时间里,还是要不停地学习不停地进步。争取博客也不要荒废,更多地记录自己的见闻吧。

恭喜银桑成功升级为银他妈~~

前两天银桑闹腾得特别厉害,到周二晚上周三凌晨,那一宿就没让我睡,拼命想叼着我的手拉我到他躲着的墙角里去。。
一开始搞不明白什么意思,到了凌晨三四点钟终于悟了,估计是快要生了(对了,之前没搞清银桑的性别就给他起名字了,实际人家是姐姐。。才不是大叔呢)

IMAG0290
刚出生的小猫湿淋淋的,银他妈在帮他们舔毛

正好最近买了笼子要带他搬家,就奉献了自己的枕巾跟毛巾被,把笼子里面垫好外面包好,给他一个谁也看不见的封闭空间。一弄好都不用我招呼他自己就钻进去了,也不像之前一样哀嚎折腾我了。我也是一宿没睡就死猪一样瘫床上睡过去了。没想到到了早晨八点钟被闹钟闹醒一看,银桑已经生完了!直接升级为银他妈!想想猫咪也真是厉害,都是自己给自己助产的。淌了一阳台的血(羊水?)。。我趴下去往里一瞧,四只小家伙都挤在银他妈怀里吃奶呢,还不会喵叫,发出像家禽一样细声细气的叫声,萌萌的。

小猫出生没两天毛就长全了,四只都是白猫啊!
小猫出生没两天毛就长全了,四只都是白猫啊!

当了妈的银桑比以前老实多了,不再到处乱跑,这两天也不在夜间折腾我了。对啊人家要照顾孩子啊。好几次跑到我身边像往常一样撒娇,还没蹭两下就赶紧跑回去招呼孩子们了。

嘿嘿,不知为啥,看着这样的一家子有一种安心的感觉。莫名的“幸福”感吧。希望能把这一家子养活~等小猫三个月大了可以送人~~

程序员日记-银桑

仲春的午后,打开窗户,让温暖的阳光洒进小屋,和煦的春风轻轻抚着泥草香潜入室内,是一种美妙的惬意。

银桑

在这惬意之中,伴随着清脆的雀鸣,打开广播听着怀旧的音乐,品一杯香茗,一只小白猫悄然走上我的窗台,没什么比这更让人感到幸福的了。

我称呼他银桑,跟他初次见面至今也有几个月了。不知是野猫还是隔壁邻居养的,总归经常来玩。我也很乐意奉献些自煮的牛肉汤、鲫鱼汤与他。慢慢跟他熟络起来,如今只要做了饭,在阳台打开窗户,没一会他就会翩翩而至。

猫的性格,可谓谨慎之至。我喂给他吃的,只要是之前尚未接触过的新鲜品种,总要怀疑我是不是害他:我若是怀着期待的眼神盯着他看,他必一副高贵态对香喷喷的牛肉块视若无睹;倘我转过身去,装作对他不在意,却私下里偷眼看他,准看到他急不可待地把鼻子凑过去,三口两口便把肉块吞下。

我在一边慢慢吃饭,他便站在窗台上一副高瞻远瞩的表情,藐视万物。忽然一阵风吹草动,只听咻的一声,以及“咣”的回声许久的金属窗框的哀鸣,待我急忙回头望去,银桑早已在五米开外的草地里了。其多疑与身手敏捷如是。

能在紧张的连续疲劳作战中偶尔有这样一只洁白的小猫陪伴,可谓人生幸事。可惜自己没有时间精力养他,只能尽量惯着他的野性,让他能凭自力在这凄楚的世界中生存。在这一点上,相对于他,我并没有太多优势来着,哈哈。

与一只猫有这一番淡如水的君子之交,若何~

ftp 客户端小心得

很少用到命令行的FTP工具,今天用到,碰到点问题,记录一下。

ftp批量上传的命令是mput。但是mput /…/path/file 会报invalid file name 错。具体没有细究,网上查下来,似乎mput命令后面不能带路径,可能是filezilla自己的问题。我并没有多想解决方案,而是按照网上的说法,先cd进目标路径,再mput *,解决这个问题。

另外,进防火墙的FTP服务器,需要用passive模式,这点以前没注意过。
最后就是ftp的prompt命令可以实现无交互。

一句话搜索

俺记得原先用google搜索东西的话,他的网络参数是这样子的:


http://www.google.com/?q=search+key+word

有阵子没用这玩意了,最近正好被人问起,发现这招不灵了。试了几下发现原来是这样:


http://www.google.com/#q=search+key+word

至于说不是地址栏输入直接就能search吗为何如此麻烦,嘿嘿你不知道我想干嘛。
注意,直接用wget去访问这样的link是没用的,需要修改UA让他觉得你是个浏览器才行。

[编辑]
感谢zhiqiang的提醒,是我记错了,正确的search命令应该是这样:


http://www.google.com/search?q=search+key+word

[/编辑]

又是命名法

命名法是个我不想再纠结的东西,不过最近又遇上了…
碰巧过完年,脑子锈掉了,居然读不懂自己年前写的代码了。我向来奉行“代码即注释”原则,也就是说…几乎不写注释…完全依靠函数和变量命名的含义来表达代码的意图和思路,除非真有复杂到需要注释的地方,例如莫名其妙的需要多线程同步的地方之外,其余一律不写注释。不过反作用就是,年前那阵子贪玩,没认真好好写代码,导致命名有点糟糕,过了年回来再读就有点绕人了…

一边改那些变量的名字,一边就遇到这个命名法的问题。我还在用匈牙利前缀,整数用n,浮点数用f,字符串用sz。现在需要自己增加几个自己的规则。
iterator类型,我原先用it做前缀,打出的代码看上去非常丑陋,例如:


for(std::vector<Phone>::iterator itPhone = phoneList.begin(), 
    itPhoneEnd = phoneList.end(); itPhone != itPhoneEnd; ++itPhone) {
  //...
}

单纯就觉得这两个字母放在前面不搭,不美…现在我用小写t做前缀,好看多了。


for(std::vector<Phone>::iterator tPhone = phoneList.begin(),
    tPhoneEnd = phoneList.end(); tPhone != tPhoneEnd; ++tPhone) {
  //...
}

当然了,这是古董代码了,有了foreach,这样的代码已经可以进垃圾堆了。不过难免用到iterator的时候俺就该记得用这个t前缀。还有就是项目里的代码我不想霰弹枪一起动,先这样放着比乱改安全很多…

受这个启发,typedef出来的变量类型用大写T前缀,例如


typedef std::vector<Phone> TPhoneList; 
for(TPhoneList::iterator tPhone = phoneList.begin(), 
    tPhoneEnd = phoneList.end(); tPhone != tPhoneEnd; ++tPhone) {
  //...
}

我喜欢typedef出几个项目中常用的容器类型。仅仅到容器类型,而iterator类型直接使用Type::iterator引用,而不进一步typedef。这样恰好保持代码的简洁程度适中,容易理解。

std::string类型用str前缀,而raw string类型(0结尾的字节序列)用sz类型,从而区分两者。这一点通常不重要,但是当你使用printf的时候:


std::string strName = "Peter Pan";
printf("hello %s\n", strName.c_str());

str前缀会提醒你记得用上c_str()方法。事实上这个问题惹恼我好几回了,最倒霉的一回是同事从北京打电话跟我联调,他那边输出的log出现乱码,而我这边丝毫没有,他通过IM给我看输出,告诉我printf打出来的。我不相信我的眼睛,好像就是变戏法。直到调了好久他才突然说,噢!忘记.c_str()了!
当然这仍旧不是好方法。真正问题出在printf不是一个类型安全的函数,编译器无法为你做编译时检查。但是类似printf, sprintf这类函数使用方便,即使最终产品不使用,调试阶段输出log还是会经常使用的。这个时候区分std::string和raw string就变得有意义了。

堆上空间使用p前缀,而栈上空间不使用。这里主要说的是数组。主要目的是当你使用p前缀的变量时候,就会提醒着自己记得思考该让谁delete掉他这个问题了。
例如


char szName[] = "Peter Pan";
char* pszName = new char[10];

我忽然在思考,是不是应该用q前缀来命名那些堆空间的拥有者,而用p前缀来命名那些弱引用。但如果是这样,那么不明拥有者,或者拥有者变更的情况怎么办?再引入一个ps前缀(p_shared_)?也许会弄得太复杂了。也许既然想了这么多,还不如一开始就用智能指针。为什么我不想引入智能指针?我不想引入复杂度。因此如果仅仅为了区区命名而导致复杂度增加,还不如一开始就简单化。所以还是所有指针都用p前缀。到底谁负责,自己好好想清楚。我想,引导读程序的人思考,比用带有暗示意味却可能是错误的命名要好得多。
在使用弱引用时,我经常使用的名字,例如pRead, pWrite, pBegin, pEnd, pCurrent, 等等,这些名字具有强烈的暗示性,说明他们是弱引用,正常人是不会去释放这样名称的变量的,更不会给这样的变量开辟空间。而另一些名字则比较危险,比如pNext, pChild, pParent, pSibling。这些名字的变量,可能你需要去释放他,可能你不需要(例如这是一个树状数组)。这个时候注释是必须的,否则很可能今天写的代码,明天就忽然觉得,不对,这里既然pNext被移动了,那么原来那个东西就应该先释放掉。然后Boom!程序崩溃。还好,现代程序员几乎不需要自己编写类似这样的基础数据结构,直接用酒精久经考验的标准库就行了。而且,就算偶尔碰上了,只要仔细调试通过,以后几乎不会再去改他了(毕竟最多的改动还是在上层嘛)。所以不算什么太大的麻烦。

呜,暂时想记录的就这么多了,给以后想要偷懒的自己看。