<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
   <channel>
      <title>demo@virushuo</title>
      <link>http://blog.devep.net/virushuo/</link>
      <description>霍炬的网络日志 | huoju&apos;s blog</description>
      <language>en</language>
      <copyright>Copyright 2009</copyright>
      <lastBuildDate>Wed, 01 Jul 2009 10:09:16 +0800</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/?v=4.23-en</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

      
      <item>
         <title>xcode,cocoa开发：如何使用第三方的dylib</title>
         <description><![CDATA[<p><strong>update:留言中jjgod的方法更为正宗和简单。请参考。不过如果dylib之间有依赖关系，你又不想重新编译。那大概还是要用我这个办法的。</strong></p>

<p>所谓dylib，就是bsd风格的动态库。基本可以认为等价于windows的dll和linux的so。mac基于bsd，所以也使用的是dylib。</p>

<p>如果你需要引用一个第三方的dylib，在xcode下编译出cocoa程序，在本机上运行是不会出问题的。但是发布出来，给其他用户用，就可能出问题。因为用户不一定有这个库。</p>

<p>这个问题给我造成了相当的困扰，我到现在也没找到正规的方法。但是我确实解决了这个问题，虽然方法不一定正宗。不管怎么说，写下来，<strong>如果暂时没有更好的办法，那么先这样做。如果谁有更好的办法，也请一定不吝留言或邮件给我</strong>。</p>

<p>我的办法是这样的: </p>

<p><br />
<strong>1 otool -L yourapp.app/Contents/MacOS/yourapp</strong></p>

<p>这一步的意思是对你编译出的app使用otool命令，以便获得依赖哪些dylib的信息。注意这个路径。cocoa的app在命令行下表现为目录。所有相关的东西都在里面。<br />
结果如下所示：<br />
yourapp.app/Contents/MacOS/yourapp:<br />
	/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 12.0.0)<br />
	<font color="#FF0000" >/usr/local/lib/lib01.dylib (compatibility version 0.0.0, current version 0.1.0)</font><br />
	<font color="#FF0000" >/usr/local/lib/lib02.dylib (compatibility version 0.0.0, current version 0.1.0)</font><br />
	<font color="#FF0000" >/usr/local/lib/lib03.dylib (compatibility version 0.0.0, current version 0.1.0)</font><br />
	/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)<br />
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)<br />
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)<br />
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 476.0.0)<br />
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 949.0.0)<br />
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 677.12.0)</p>

<p>注意我标红的地方。假如lib01,lib02,lib03是本程序引用的第三方库，那么在这个程序里面，他们的引用地址是位于/usr/local/lib上的。这是开发机上的安装情况。而使用这个程序的客户机未必安装这些东西，所以程序就要出错。</p>

<p>显然，我们需要做2件事。a 把这些库附带在app上  b 把他们的引用地址修改到正确的位置。</p>

<p><strong>2 mkdir yourapp.app/Contents/dylib</strong></p>

<p>在编译出来的app中，创建dylib目录</p>

<p>然后把所有需要的库复制过去</p>

<p>cp /usr/local/lib/lib01.dylib yourapp.app/Contents/dylib/<br />
cp /usr/local/lib/lib02.dylib yourapp.app/Contents/dylib/<br />
cp /usr/local/lib/lib03.dylib yourapp.app/Contents/dylib/</p>

<p><strong>3 install_name_tool -change  /usr/local/lib/lib01.dylib @loader_path/../dylib/lib01.dylib "yourapp.app/Contents/MacOS/yourapp"<br />
</strong></p>

<p>install_name_tool 是苹果提供的用来修改dylib安装名称的命令。这个命令执行之后，再用otool -L 就可以看到变化了</p>

<p>yourapp.app/Contents/MacOS/yourapp:<br />
        /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 12.0.0)<br />
        <font color="#FF0000" >@loader_path/../dylib/lib01.dylib (compatibility version 0.0.0, current version 0.1.0)</font><br />
        /usr/local/lib/lib02.dylib (compatibility version 0.0.0, current version 0.1.0)<br />
        /usr/local/lib/lib03.dylib (compatibility version 0.0.0, current version 0.1.0)<br />
        /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)<br />
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)<br />
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)<br />
        /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 476.0.0)<br />
        /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 949.0.0)<br />
        /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 677.12.0)</p>

<p>注意标红的位置。已经变化了。@loader_path 指的是应用程序运行的位置，也就是yourapp.app/Contents/MacOS/yourapp，所以要用一个..，以便定位到第2步创建的dylib目录。<br />
重复这个命令，修改lib02,lib03</p>

<p><br />
<strong>4 otool -L yourapp.app/Contents/dylib/*.dylib</strong></p>

<p>继续用otool 来检查dylib下面使用的第三方库是否还有其他依赖，install_name是否正确，重复1，2，3的步骤，把所需要的dylib复制过来，修改install_name。</p>

<p>如果都改对了，那么这个app就附带上了dylib，可以在其他机器上正确运行了，不用非要寻找/usr/local/lib下面的库了。</p>

<p><br />
刚才我们修改的结果是一个build的结果。当然，每次build都这么折腾一下很麻烦。所以继续这样做：</p>

<p>1 前面的步骤得到了一个完整的dylib目录。把这个dylib复制一份备用。比如放在你的xcode项目下面。</p>

<p>2 编写一个脚本：</p>

<p>mkdir "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/dylib"<br />
cp -f /your/path/to/xcode_project_name/dylib/*.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/dylib/"</p>

<p>install_name_tool -change  /usr/local/lib/lib01.dylib @loader_path/../dylib/lib01.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME"<br />
(用这个格式重复前面对app使用过的dylib)</p>

<p>3 在xcode中，展开targets节点，右键点工程名称，在菜单中选Add->New Build Phasa->New Run Script Build Phasa，在打开的对话框里面，把刚才的脚本贴进去。如图所示。</p>

<p>这个脚本会在build之后自动运行。不过我这里有个奇怪的问题，如果Shell里面写了/bin/sh，会报告找不到这个文件(实际上存在)，而让shell为空，反而可以正确的运行shell命令。<br />
<a href="http://picasaweb.google.com/lh/photo/FwVjnl4gM7iRUH5yMbTXQA?feat=embedwebsite"><img src="http://lh4.ggpht.com/_fMpSudYvJOo/Skq16lg_8yI/AAAAAAAAAhw/5PAtplmUj_Q/s400/Picture%205.png" /></a></p>

<p><a href="http://picasaweb.google.com/lh/photo/PO8ZsBhdcFBWogeMuu2cmQ?feat=embedwebsite"><img src="http://lh6.ggpht.com/_fMpSudYvJOo/Skq16mBp44I/AAAAAAAAAh0/ASKXHFDGems/s400/Picture%206.png" /></a></p>

<p>经过这些处理，每次编译出来的app就可以拿到其他机器上运行了。可真够麻烦的...</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/07/01/xcodecocoadylib.html</link>
         <guid>http://blog.devep.net/virushuo/2009/07/01/xcodecocoadylib.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Wed, 01 Jul 2009 10:09:16 +0800</pubDate>
      </item>
      
      <item>
         <title>email问答: 最快的seo方法是什么？</title>
         <description><![CDATA[<p>说实话，我曾经想写过很多个系列文章，但最终都是挖了个坑，没坚持下来。综合起来，大概就是话题太大，或是涉及的方面太多，太难表达清楚。速食年代，太长的东西没多少人愿意看，写起来压力也太大。</p>

<p>这次试试短点的。几乎每天，都有朋友会发邮件或是msn问我一些问题，从技术架构，语言细节，学习方法，seo都有，比较杂。其中颇有一部分是值得琢磨和分享的。好吧，我也学学"我爱问连岳"，做个问答，但是隐去所有真实信息。希望能对同样困扰的人有帮助。</p>

<p>---------------------------------</p>

<p>问题：你说seo没什么快捷的方法，我们公司新上线的频道a，仅仅半个月，pagerank就达到了8。这是怎么做到的？</p>

<p>回答：</p>

<p>从pagerank上看来，确实有8。分析一下：</p>

<p>(1) 用google的link:命令，搜索到这个a频道子域名的连接，发现有接近2w个。2w个连接，如果质量不错，确实能达到8。</p>

<p>(2) 用google的site命令，看看收录数量。发现只有2。这就有问题了，如果有8的pagerank，那么收录应该的数量应该相当大。</p>

<p>(3) 看一下这个网站其他频道，发现首页也是8。再用link来查看首页的连接数，发现和到a频道的连接数量一样。打开几个快照，可证明，确实是连接到首页，而不是a频道的。</p>

<p>结论：曾经有人用重定向把a频道转向了首页，所以导致google认为2者完全等价，于是给予了一样的pagerank。这个pagerank当然不可能被复制出来2份。所以解除重定向之后，要么pagerank变成本页真实的，要么就再也不抓取这个页面上面的其他连接，这取决于当初用的是301还是302。</p>

<p>------------------------------</p>

<p>这大概是seo的常见手法。这事情和技术无关，只和逻辑有关。只要有逻辑，几下就能看穿原因。遗憾的是受骗的人还是相当多，其中不乏大网站。就好像"<a href="http://www.google.com/search?hl=en&client=safari&rls=en-us&q=中奖+笔记本+骗术&aq=f&oq=&aqi=">中奖骗术</a>"虽然老套，但永远有效一样。究其原因，无非是总有人喜欢捷径，喜欢快速见效。那自然有人投其所好。</p>

<p><a href="http://www.ginkgotek.com">银杏咨询</a>早期做过一些SEO项目，效果不如预期。某著名音乐网站至今仍欠我们的咨询费未付。[1]</p>

<p>原因嘛，在我们的观念上，SEO不是小项目，需要产品，技术，公司经营者的共同努力，而且至少要有半年才能有比较好的效果。紧一段松一段是没用的，做做表面功夫是没用的，想快速见效是不可能的。但如果真的严格按照我们的方法来做，半年之后你一定会惊喜的发现，效果非常好。</p>

<p>可惜，人家不信。</p>

<p>换个说法，如果这世界上真的存在一种有效，快速，可复制的方法，那么这方法一定所有人都知道了，包括你在内。比如"去携程订酒店比你自己去柜台便宜"。</p>

<p>假如你月薪3000，这时候如果有人跟你说："你给我2万块钱，我教你个办法，半个月之后，你就能每月赚至少30万。" 估计谁也不信。同样的道理，换成pagerank，通过SEO带来多少流量，怎么就有人信了呢？[2]</p>

<p>笑来老师讲英语学习，也讲过<a herf="http://www.xiaolai.net/index.php/archives/6791.html">关于捷径</a>这事。道理和现状何其相似。昨日不可重现，时间只有一次，所以一定要选好道路，不要忽悠别人，也不要被别人忽悠。</p>

<p><br />
----<br />
[1]曾经著名，但现在已经被后来者迅速超过。这个力量对比显然也不太可能有变化了。<br />
[2]这个例子不夸张，要达到 pagerank 8 ，至少是门户级别的网站。这样的网站，按照每月收入30万来算，实在是少的不能再少了。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/06/23/email_seo.html</link>
         <guid>http://blog.devep.net/virushuo/2009/06/23/email_seo.html</guid>
         <category>问答</category>
         <pubDate>Tue, 23 Jun 2009 02:45:15 +0800</pubDate>
      </item>
      
      <item>
         <title>绿坝的技术错误及其可能导致的后果</title>
         <description><![CDATA[<p>简单谈几点绿坝的技术上的错误。如果不改进，我相信未来会造成巨大的损失。</p>

<p>1 不应该用木马的方式来保护自己。</p>

<p>站在绿坝的观点上，认为不能被孩子随便卸载和杀掉，所以就要强力的保护自己。于是用了一系列只有病毒和木马才会用的办法。这是典型的方法错误。正确的方法应该是给孩子一个单独的账号，降低此账号权限。然后绿坝以管理员身份运行。这样就不用靠流氓手段保护自己。家长和成年人也可不受其干扰。眼前使用的办法，其实也保护不了自己的安全和不被卸载。</p>

<p>2 缓冲区溢出的问题必须要重视。</p>

<p>到目前为止，密歇根大学提出的缓冲区溢出漏洞没有被修正。而根据电脑报文章，用户在正常使用中时而会导致浏览器崩溃。这大概也是溢出的迹象。在我的周末的简单研究中，觉得确实如密歇根大学报告所说"使用了较陈旧的编程方法"，系统中存在缓冲区溢出的机会大大增加。</p>

<p>简单的反编译就可以发现，程序中大量数组和内存操作是不安全的。导致缓冲区溢出的机会很大。还有相当数量的硬编码，把一些密码之类的东西直接写了进去。这些不良的编程习惯都会带来安全问题</p>

<p>缓冲区溢出并非让程序崩溃退出那么简单，事实上利用这种漏洞是可以完全控制一台计算机的。历史上几次大的病毒传播，比如nimda，比如红色代码，都是缓冲区溢出引起的。缓冲区溢出不仅困扰小公司，对微软这种大公司也是巨大的安全威胁。但是像绿坝这样，把漏洞百出的代码做最广泛的推广和强制安装，实在是匪夷所思。如果真的这么推广下去，真的都安装了，未来还不知道出什么事。</p>

<p>如果被用来攻击电子政务系统或是骨干网的路由设备，造成的损失很非常大。不知道到时候政府会不会后悔现在的行为。</p>

<p>3 不加密的升级方式很危险<br />
绿坝的升级都是通过http的，并且频繁调用gethostname来做dns解析。一方面，简单的dns欺骗就可以让系统安装恶意代码。另一方面，如果升级服务器被攻击掉，也很有可能导致前几天的"暴风断网"事故重演。规模恐怕还要大的多。</p>

<p>4 杀毒软件怎么办<br />
绿坝的很多行为，和木马很相似，这些行为必然会被杀毒软件和木马清除软件识别。如果工信部强令杀毒软件把绿坝加入白名单，最终就等于在系统里面为病毒制造一个保护伞。病毒和木马可以通过附着在绿坝上面，躲避杀毒软件的扫描。这也是严重的安全问题。</p>

<p>总结：一般来说，大规模安装的软件要特别注意安全问题。最有效的办法是降低自己的权限，那么就算出现问题也不至于影响太大。但是绿坝反而用不正当的方式获得了很高权限。而高权限的软件则要至少能保证自己的安全，绿坝显然也做不到这点，绿坝调用各种dll并没有做校验，这都是非常容易被利用的。</p>

<p>一个具有高权限，又被普遍安装的软件，一定会吸引大量的攻击，这个诱惑太大了。这在windows一贯历史上都得到了验证。而一个不严谨，具有高权限，又广泛安装的软件，一旦被攻击，结果会怎么样呢？历史上没有过先例。但我想一定不是个好结果。</p>

<p>另外，在我研究的这部分(xnet2.exe,gn.exe,xdaemon.exe)中，我没有发现往服务器发送用户隐私的行为。但这不代表其他部分没有。大正的引擎是和绿坝是完全独立的，只是通过exe进行了简单调用，这部分也存在前面提到的问题，很容易被冒充或注入。在卸载方面，我看到了绿坝的卸载代码，就软件开发者来说，他们确实是想完全卸载，不留痕迹的。但是因为技术原因未必能做到。而且在某些其他程序干扰下，可能卸载也不能顺利完成。这也造成了"不能卸载"的假象。</p>

<p>如果工信部真的想解决未成年人保护问题，请将此软件开源，以便保证其中立和完善。苹果操作系统甚至自带了未成年人保护功能，这确实是应该的。但不应该是用目前这种危险的方式进行。</p>

<p>说到担心计算机被政府控制用来限制言论自由的观点，我觉得也不用太在意。事实上，所有政府都希望做到这事，但在操作上是如此的不具备操作性。如韩寒所说，计算机上有个东西叫做键盘。这就决定了不可能有超越用户存在的软件，哪怕是最厉害的病毒。一个试图当上帝的程序，最后的命运往往是去见上帝。</p>

<p>计算机是完全开放的，互联网也是。他们的体系和架构就决定了这一特点，任何与这个特点相反的努力都是徒劳的，好像螳臂挡车，阻挡历史的车轮。必然是不可实现的。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/06/15/post_66.html</link>
         <guid>http://blog.devep.net/virushuo/2009/06/15/post_66.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Mon, 15 Jun 2009 20:53:57 +0800</pubDate>
      </item>
      
      <item>
         <title>新浪科技，您这事做的也太扯淡了吧</title>
         <description><![CDATA[<p>新浪科技，做了一个"传刘晓人涉嫌集资诈骗被检察院批捕"的专题。其中红鼎投资的公司里面，我们的<a href="http://www.ginkgotek.com">银杏泰克</a>赫然在列。还给放了一大图标。</p>

<p>我翻了翻此专题的所有文章，这些文章都是来自传统媒体的(好像...sina是没有新闻采访权的，只有转载权吧？)，所有文章都没提到我们公司。那么sina科技是从哪转载来的呢？这还真不知道。</p>

<p>当然了，写就写了，不过作为一个最大(新闻)门户(之一)的最大频道(曾经的之一)，至少应该有基本的严谨性吧--当然，新浪科技也一直不怎么严谨--我的意思是说，消息不确认就写了，那也就罢了，但您至少应该给我们加上连接吧?一方面，这是互联网的基本道德准则，另外一方面，这也是为了方便读者嘛。要不您的读者为了知道银杏泰克是谁，还要专门去百度一下，那事实上不等于新浪科技频道为竞争对手百度创造了流量进而创造了广告收入吗？这种自毁城池，吃力扒外的事，咱不能干吧？</p>

<p>这篇也就算个声明吧。银杏泰克并非红鼎投资所投，而是另外一位相当负责的天使投资人投资的，公司运营状况还不错。看起来也不像要倒闭的。所以我们的客户也不用担心什么。</p>

<p><br />
顺便再说一下sina科技的报道中关于我们部分的其他错误吧：</p>

<p>时间：2007年5月1日  <- 本公司是2007年11月成立的<br />
融资性质：VC <- 本公司只接纳过一次天使投资(并非红鼎)，没有进行过VC<br />
涉及轮次：Series A <- 这当然也不对了，不过现在有人有兴趣投Series A，我们还是愿意谈谈的</p>

<p><br />
总的来说，我对这个事情的概括是：别的无所谓，但是新浪科技欠了我们一个连接。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/06/12/post_65.html</link>
         <guid>http://blog.devep.net/virushuo/2009/06/12/post_65.html</guid>
         <category></category>
         <pubDate>Fri, 12 Jun 2009 12:30:43 +0800</pubDate>
      </item>
      
      <item>
         <title>beta技术沙龙－iPhone开发</title>
         <description><![CDATA[<p>这次<a href="http://club.blogbeta.com/">Beta技术沙龙</a>是关于iphone开发的。对iphone开发有兴趣的人非常多，一方面是appstore造成的财富神话，另一方面也确实是有iphone的人越来越多。大家都偶尔想写点小程序玩玩吧。</p>

<p>作为一个mac用户，能感觉到企业对苹果平台的兴趣在逐渐变大，甚至连腾讯这种以不兼容为美的公司都做了QQ for mac/QQ for iphone。几个做共享软件的朋友跟我说,iphone程序是个富矿，很可能重现当年共享软件的疯狂。(其实国外现在做共享软件也是不错的)</p>

<p>我虽然用了很多年苹果，不过一直也没开发过"真正的"苹果的应用程序。我已经很多年不写图形界面的程序了，通常只写人们看不到的东西，就算有需要，也是三两下扒拉出来一个命令行程序用。而<a href="http://www.tinydust.net">Tiny</a>自从抽奖赚到了一个iTouch之后，就一直尝试着iPhone的开发，我偶尔去看看他做的东西，总觉得Objective-C这东西很古怪，非常不符合我对C的审美，因此也更加没兴致尝试了。</p>

<p>在这次沙龙活动中，听了robin和Tiny的介绍，倒是发现了一些以前没注意到的东西，所以觉得还是值得做个笔记。</p>

<p>Objective-C的古怪之处，主要是一些语法看起来很晦涩。奇怪的定义和符号混合起来，让这种语言看着一点也不像C。Tiny在演讲中多次强调了，阻挡人们学习Objective-C的主要原因就是这种奇怪的语法，容易让人不适应。</p>

<p>当然，仔细想想，似乎所有用来写图形界面的语言都扩展了大量的独有特性。这句话也可以反着理解成：凡是没做特殊扩展的语言，在写图形界面程序的时候都比较困难。</p>

<p>以我的认识，这种困难主要来自图形界面设计的复杂性，和消息/事件传递的难度。如果不写图形界面程序，C足够完成任何功能。而一旦要处理复杂的界面和消息响应，复杂度陡然上升，这就需要面向对象了。在以往，delphi改造了pascal，VC改造了C++，主要的目标都是为了基于面向对象，简化消息处理，事件相应和界面设计。MFC固然难以理解，不过还是比手工用API处理消息容易一些，程序越复杂，这个差距就越明显。</p>

<p>Objective-C要解决的问题也差不多是这些。Objective-C用可视的方式设计界面，用拖拽的方式来创建事件关系，扩展了一些语法，把C改造成了面向对象语言。用引用计数和autorelease池，使内存管理变的简单，对于字符串处理这种容易出问题的操作进行了封装。感觉用起来很像delphi。有人甚至做了一个<a href="http://home.arcor.de/christian_grau/macdev/objcvsdelphi.htm">Objective-C和delphi的语法对比</a>，确实有很多相似之处。</p>

<p>和C++不同，Objective-C是基于消息传递的，后来我猛然想到，这是来自Smalltalk的思想（其实Wikipedia中，关于<a href="http://en.wikipedia.org/wiki/Objective-C">Objective-C</a>的介绍第一句就是"Objective-C is a reflective, object-oriented programming language, which adds Smalltalk-style messaging to the C programming language."），想到了这个也就知道那些古怪的语法是怎么来的了。在Smalltalk中更极端，连运算都是以消息形式完成的。Objective-C中似乎还没到这个地步。但是已经有Smalltalk的感觉了。这些特性让Objective-C成为一种非常具有动态特征的语言，这也造成了一些错误在编译检查是正确的，但是到运行时出错。所以写程序的思想也要随之调整一下。</p>

<p>明白了这些东西，也就更容易理解Objective-C的思想。觉得别扭是大家都被C++和Java带到坑里了，其实Smelltalk才是纯粹的面向对象语言。如果对Smalltalk不太熟悉，可以来看看徐宥的<a href="http://blog.youxu.info/2008/11/30/pearl-in-smalltal/">这篇关于Smalltalk文章</a>,明白了这些思想，对理解Objective-C有很大帮助。</p>

<p>写程序最难的事情，就是逻辑的描述，内存管理和字符串处理。Objective-C很顺利的解决了这几个问题。所以按照我的判断标准，这就是一种不错的语言了。就目前的语言特性看，不太容易成为C++那么混乱和让人抓狂的语言。再加上苹果的精心维护和推动，未来应该很看好。甚至将来成为最常用的语言之一也说不定呢。</p>

<p>如果你来参加了这次活动，应该已经能动手写iPhone和mac程序了。其实一些要点点破了之后，mac/iPhone的开发一点也不难，比其他平台上简单的多。程序员可以不太关注语言的多义性和复杂表述，更容易专心于写程序本身，也更容易获得高质量的程序。</p>

<p>PPT在这里：<a href="http://club.blogbeta.com/63.html">http://club.blogbeta.com/63.html</a></p>

<p>另请在twitter上follow betasalon : <a href="http://www.twitter.com/betasalon ">http://www.twitter.com/betasalon</a></p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/05/29/betaiphoneiphoneappstoreiphone.html</link>
         <guid>http://blog.devep.net/virushuo/2009/05/29/betaiphoneiphoneappstoreiphone.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Fri, 29 May 2009 18:39:09 +0800</pubDate>
      </item>
      
      <item>
         <title>优化和架构之服务切分</title>
         <description><![CDATA[<p>切分是最基本，且最多变的思路之一，说基本，是因为在学习程序设计的第一天就应该知道，说多变，是因为在未来的很多年里，你会不停的应用这个方法来解决问题。不幸的是，切分这个思路并没有得到应有的重视。</p>

<p>大概是因为这个词比较土，说起来也比较普通，远不如并行，集群，负载平衡这些词听起来大。所以碰到一个问题的时候，往往被拿出来的解决方案会是以上3个大词之一，很少有人去认真的考虑切分问题。但事实上，这3个大词所需要的技术，其实也是建立在良好可切分的系统之上的。</p>

<p>最近碰到了2个项目，都是典型案例。</p>

<p>案例1 ，小公司，发展的不错。一台服务器眼看不够用了，于是就买了第二台，希望能做一个"负载均衡"系统。很多人大概认为负载均衡，是类似自来水一样的技术，只要打开笼头，清水就汩汩涌出。往往忘记了水龙头后面的水管和自来水公司。</p>

<p>一个服务器上放了很多个服务，是很难应用负载均衡这种技术的。必须先要把服务拆开，找到性能薄弱的点，对这个点进行负载均衡，才能得到比较好的效果。否则很可能用了80%的力气，但是只得到20%的结果。</p>

<p>案例2，某外企。之前我们给他们做过咨询，解决了一次问题，上次我们找到了系统最慢的地方，去掉了老系统中性能消耗多的地方，用通用的缓存(squid/memcached)系统来代替他们用php写的硬盘文件缓存，上次的改动让性能困扰远离了他们一年，随着业务发展，性能又显得不够了。</p>

<p>比起来一年前，他们的服务器数量增长了一倍。其中大量服务器用于做mysql集群和web集群。服务器是复杂的网状关系。前面说过，这种不分主次的架构往往只能解决20%的问题。而且很容易到达瓶颈。</p>

<p>套用回那3个大词，这个系统确实是集群的，负载平衡的。因为所有服务器的功能是完全一样的，任何一台单独拿出来，都是完整的系统镜像。看上去很美，但实际用起来可没有这么理想。在实际应用中，一台服务器出了问题，几分钟之后，所有的服务器都出问题了。并没能如预期想像的，损坏一两台不影响正常工作。</p>

<p>这个案例中，实际使用了6台服务器做mysql集群。每台服务器的数据是完全镜像。可以想像，如果6台服务器中有一台出了故障，所有的压力就会被平均分到其他5台上。在集群负载大的情况下，增加1/5压力，很可能让另外的5台直接被压垮。这时候发生的情况，就好像最近株洲的塌了的大桥一样，一个桥墩一个桥墩，好像多米诺骨牌一样，一路塌了下去。</p>

<p>从任何角度看来，这都不是一个好架构。别说稳定了，连基本的服务都保证不了。</p>

<p>对于2个案例，我给出的解决方案都是先做切分，然后再分别进行优化。首先可以按照业务切分，把现有服务器分成多个组。对于web前端和mysql集群，每组2~3个足够应付大多数情况。每组服务器数量太多，不仅造成单点故障的概率增加，也容易在自身的数据同步中消耗大量的资源。</p>

<p>比较以下两张图：</p>

<p>改造前：<br />
<a href="http://picasaweb.google.com/lh/photo/sGfY2lFMyYsTlhAg1CjAKA?feat=embedwebsite"><img src="http://lh5.ggpht.com/_fMpSudYvJOo/ShauEXpZh_I/AAAAAAAAAg0/iNgdoNK4G7E/s800/Picture%204.png" /></a></p>

<p>改造后：<br />
<a href="http://picasaweb.google.com/lh/photo/2cHL4tgGuN71-1481vhbYg?feat=embedwebsite"><img src="http://lh4.ggpht.com/_fMpSudYvJOo/ShauEalQZtI/AAAAAAAAAgw/adFGuuNoBvQ/s800/Picture%203.png" /></a></p>

<p>之前的结构是所有web服务器放着同样的应用，所有数据库服务器放着同样的数据。改进后的结构是将整个系统按照服务内容和性质拆成了几组。从ServiceA到Service n 采用了不同的配置方式，简单的只用一组机器，复杂的用多组。在实践中，其实还可以分的更细致，甚至几个Service公用一组机器。(之前<a href="http://club.blogbeta.com">beta技术沙龙</a>，有道讲他们的<a href="http://blog.devep.net/virushuo/2009/03/09/betasalon_youdaoreader.html">阅读器架构的时候</a>，也提到了类似的办法)</p>

<p>后者的好处很明显，最明显的：</p>

<p>1 可以有效的使用资源。比如：服务A是低负载型的，并非核心业务，可以给予较少的资源。(较少的机器，较差的机器) ，而服务B是核心服务，需要全力支持。<br />
2 可以简单的监控性能。所有服务都混在一起的时候，碰到性能问题很难下手分析。很有可能是最不常用的服务A中有bug，导致了整个集群性能低下。寻找这种bug要耗费大量的人力和时间。<br />
3 易于备份，升级时切换服务平滑。<br />
4 为下一步优化做好准备。综合以上2点，下一步可以集中资源，对重要服务专门进行优化，保证稳定和性能。</p>

<p><br />
在以上的例子中，我们可以看到，专门对重要服务B进行负载均衡，无论在成本上还是性能受益上都比对整个应用进行处理划算的多。</p>

<p>除了根据明显的业务边界进行切分，还有很多种方式，比如按照时间，按照读写频率等。</p>

<p><br />
这种思路也不仅仅应用于web server/database。比如，设计缓存的时候，也应该进行一定的切分。以squid为例，应该把文件大小差不多的文件放在一个squid中，把更新频率接近的文件放在一个squid中。这些都是让架构清晰，性能提高的办法。</p>

<p>从系统设计的初期，就应该贯彻这个思路，用子域名来标记不同的服务(img.yourdomain.com,bbs.yourdomain.com...)，比用虚拟目录的方式(www.yourdomain.com/img,www.yourdomain.com/bbs)更便于切分。</p>

<p>很多人咨询过我这个问题，不过他们都是从seo和产品方面考虑，从来没想过这是和技术相关的。如果所有的应用都放在www之下，未来一旦想把一个服务挪到另外一台服务器上，就很困难----不是没有办法，只是难度比较高。 子域名只需要设置一下域名解析，把要挪走的服务指向新的ip，几分钟就搞定了。</p>

<p>这个办法的实质，仍然是降低系统耦合度。必要的关联数据，宁可采用http请求的api形式，也不要跨数据库进行查询。http请求可以很方便的跨服务器，可以设置页面缓存等，跨数据库请求则只能在数据库上花力气，最后又退回了对全部数据做数据库集群，master/slav的老路上e(当然，这不是一条原则，还是要根据应用的具体情况而定)。诸如此类，尽量要将思路放远，不要贪图眼前的小得失。（常见的说法：数据库怎么也比http快吧...这没错，不过要看应用场合）</p>

<p>能在一个单一的服务中承载尽量多的数据和请求，这当然是所有技术工作者不懈的追求。在此之前，如果先进行合理的切分，再令每个服务的性能最大化，一般都能得到更大的好处。简单是美，简单就是力量。<br />
</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/05/22/split-services.html</link>
         <guid>http://blog.devep.net/virushuo/2009/05/22/split-services.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Fri, 22 May 2009 22:55:15 +0800</pubDate>
      </item>
      
      <item>
         <title>在你自己的软件中应用snmp和agentx协议传递信息</title>
         <description><![CDATA[<p>我曾经想自己写一个udp server来接受我的服务器程序发回来的状态，然后做跟踪和统计。后来被<a href="http://www.dbanotes.net">Fenng</a>批评为自己重复造轮子。于是转向试图利用snmp协议来做。</p>

<p>用snmp有几个原因：</p>

<p>1 snmp是基于udp协议的，具有udp的所有好处(数据状态这种东西，用tcp是不合适的)<br />
2 snmp比较成熟，周边的软件非常多，后面可以很方便的处理收集数据，绘图等等一系列的功能。(rrdtool/cacti....)<br />
3 因为我们要监控的服务非常多，所以希望能设计一个尽量免配置的方案，snmp的树型结构正好获取节点下面所有的被监控值。</p>

<p><br />
snmp在网管系统中有很大规模的应用，但是似乎没什么人用来监控软件服务。而，目前我们知道的对snmp和cacti的应用，似乎大部分都只停留在了用来监控服务器状态(mem,load average,net io,disk)上，有点可惜。</p>

<p>在这篇blog里面，我提到的用法应该不是最正宗的，但是有效。其实很多大厂商甚至自己修改snmp协议，做出自己的分支协议来。比起他们，虽然我做的不太正宗，但是也不为过。</p>

<p>我要实现的东西大概可以用这张图来描述：</p>

<p><a href="http://picasaweb.google.com/lh/photo/Xbm2ZwIqFpJL_CmSJ0vBvA?feat=embedwebsite"><img src="http://lh4.ggpht.com/_fMpSudYvJOo/SgMKDdoPiAI/AAAAAAAAAgQ/Xnauxy8Rg6o/s400/snmpagent.png" /></a></p>

<p>概括起来：很多个服务分布在很多台机器的很多个端口，所以我们需要在每台机器上放一个snmp代理，得到他们的状态，然后再统一通过snmp协议获取这些状态。由于服务太多了，必须要免于配置，这就更显示出了snmp协议的优点。</p>

<p>扩展snmp有几种方法，不过综合起来，我认为最简单和灵活的还是agentx协议。agentx完全是独立在snmp server之外的，可以一层层的套起来。其他的协议要么要在snmp上加东西，要么要写mib的模块文件，都相当麻烦。</p>

<p>不过，最常用的snmpd，反而对agentx支持不好。至少他们自称还是试验性质，不建议用。我试图在snmpd.conf中允许agentx协议，也几经挫折。最终决定找别的方案。似乎大家都习惯把snmpd当作唯一的snmp server，其实类似产品还有很多，snmpd时间比较久，但我认为并非最好的。在ubuntu的apt源里面，都有几种其他方案可用。</p>

<p>当然，由于我并非希望取得系统的硬件状态，所以我也并不一定要找一个通用的产品。所以最后我决定用jagentx(http://eden.dei.uc.pt/agentx/)。</p>

<p>jagentx实现了snmp v1 协议和agetnx协议，一般来说足够用了。他们网站首页的那张图，很好的说明了agentx方式的系统结构。</p>

<p>jagentx提供了比较友好的api和demo，不过还是有一些bug，我做了一些修改。</p>

<p>1 jagentx的master(相当于server)，对于master mib的读取，只能支持snmpwalk，不能支持snmpget。其实是一个状态设置错了。<br />
在 Master_Engine.java中</p>

<p>        if (!any_subagent_queried){<br />
          int error_index = 1;</p>

<p>          int error_status = Pdu.NO_SUCH_NAME;</p>

<p>后面，加上</p>

<p>	if(value != null)<br />
         {<br />
                 error_status = Pdu.NO_ERROR;<br />
         }<br />
就可以了。</p>

<p>2 是关于session的。如果客户端退出，没有注销，就要等自己的session超时，不然连不上。这个在实际应用中很容易出问题。服务不正常退出的情况发生几率很高。于是我做了一些改动，可以通过sessionid来注销其他进程。这样确实会造成一些安全问题。不过可以用防火墙或是其他方式弥补。总比之前要等超时好。<br />
改动的地方分布在几个文件里面，就不挨个列举了。</p>

<p>本来我给jagentx的开发者发了个邮件，告诉他这些改动，不过被退信了。所以我就把代码放这里，有需要的可以<a href="http://blog.devep.net/virushuo/upload/jagentx.tar.gz<br />
">下载</a>。</p>

<p>修改了这两处之后，这个东西很就好用了，jagetnx网站上的文档有demo代码，可以参考。</p>

<p>为了让我的山寨服务器正规点，我还是去申请了一个enterprise number。申请的方法是到iana 的<a href="http://pen.iana.org/pen/PenApplication.page">申请页面</a>添一张简单的表格，几天之后能收到回复，如果顺利通过，就会分配你一个数字号码，以后这个号码的snmp消息就代表你的组织的了。全部企业的enterprise number可以在<a href="http://www.iana.org/assignments/enterprise-numbers">http://www.iana.org/assignments/enterprise-numbers</a> 这个页面查到(很大的文本文件)。可以看到，我们的<a href="http://www.ginkgotek.com">银杏搜索ginkgotek</a>是33364。</p>

<p>所以我们的snmp消息就在1.3.6.1.4.1.33364这个节点下面，我用snmpwalk就可以获得所有节点，包括新增的，这样就达到了免配置的目的。当然，到目前为止，我们还只是自己用于服务监控。</p>

<p><br />
一切就绪之后，就可以选择你喜欢的工具来收集监控数据和画图了。比如常见的cacti。</p>

<p>这里是一张隐去了部分信息的cacti做出来的图。数据是从前面写到的这套东西收集上来的。<br />
<a href="http://picasaweb.google.com/lh/photo/Elr095kWjXzO2NGA4OkeWw?feat=embedwebsite"><img src="http://lh6.ggpht.com/_fMpSudYvJOo/SgMKDlmMhQI/AAAAAAAAAgU/UeADz1lb_aw/s400/graph_image.png" /></a><br />
总结起来，这种办法适应于:</p>

<p>1 你有一个长期需要稳定运行的服务程序<br />
否则你根本不需要监控</p>

<p>2 该程序有大量实例在运行<br />
否则你用脚本把数据输出到snmpd都可以，没必要和我一样希望免配置</p>

<p>3 你不希望通过http或tcp连接来干扰该程序运行<br />
否则你没必要用udp</p>

<p>写完了这篇blog，我也很希望能够侧面证明ginkgotek在保护客户利益上做的比别人多一些，选择我们的服务是可以放心的。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/05/08/custom-snmp-by-agentx.html</link>
         <guid>http://blog.devep.net/virushuo/2009/05/08/custom-snmp-by-agentx.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Fri, 08 May 2009 01:26:18 +0800</pubDate>
      </item>
      
      <item>
         <title>一次足够了</title>
         <description><![CDATA[<p>一次就够了</p>

<p>本来我都忘了这个故事了，不过，因缘巧合，看来还是值得讲一下。</p>

<p>这个故事是我和<a href="http://www.tinydust.net">tinyfool</a>刚刚开始创业时候的事情。众所周知，我们做了一家<a href="http://www.ginkgotek.com">站内搜索的服务商</a>，主要靠按月收服务费盈利。</p>

<p>某年某月某日，碰到一个客户。此客户在行业内很有名，也有钱。是某著名外企旗下网站。我们当然非常欢喜，这个生意显然是个赚钱又赚声望的事，也就特别的留意。</p>

<p>客户负责技术的人，曾经在某个会议上认识，这又让我们觉得不错，熟人好办事嘛。合作就这么开始了。</p>

<p>没花多少时间，一切顺利的上线测试。按照我们的习惯，免费试用15天，之后开始收费。这位老兄就说了，能不能多让我们试一段时间，比如*半年*什么的。我们当时就一楞，还有这么提要求的？</p>

<p>不过听听解释，也合理，诸如公司大，要汇报，决策比较麻烦，等等。此君几乎就是拍着胸脯说，咱是朋友嘛...</p>

<p>我们思量了一下，觉得也未必真能用半年时间吧，且就这样吧。反正早晚的事嘛。</p>

<p>随后，搜索效果很好，流量暴涨。我们的带宽被用光了，于是我们又买了一些带宽。不过付款这事看起来还是没什么消息。</p>

<p>后来又涨，我们实在是买不起了，于是跟对方协商，能不能先付一部分款。那位老兄也不含糊，当即答应准备一台机器，放在他们机房里，这样通过内网访问，没什么带宽压力了。</p>

<p>好吧，是个办法。转天，新机器就位，我们把服务部署上去了一套。</p>

<p>此网站更多的频道开始用上我们的搜索，客服，支持，都好一阵忙乱。我们还跑了几趟，和他们部门的一些同事开会，讨论怎么用搜索。此间再次提到付款问题，不过还是老样子，再让我们用几天。另外还应承，我们母公司还有不少其他网站，也可以介绍用你们的东西，别着急。</p>

<p>听起来不错。</p>

<p>半年时间，说快不快，说慢不慢，就这么到了。</p>

<p>某一天，我们突然发现流量下降了。某个频道的搜索完全没有流量了。还以为是对方网站出问题了，赶快联系。那位老兄没接电话。后来找到了他们部门的程序员，说了说情况，当时觉得有点奇怪，躲躲闪闪的。过了2天，也没见变化。我们考虑要找到这个"好朋友"问个究竟。手机仍然是没人接。于是我们请前台转他的座机试试看，竟然有人接了。</p>

<p>听到了我的声音，对方明显慌乱。一通问，跟我们猜的差不多。人家号称自己做了一套。不用我们的了。然后这人就又跟消失了一样了。</p>

<p>我这才明白，原来上来人家要先"试"半年是什么意思。</p>

<p>做了这么多年生意，我和tiny在这行也有点小名气。自认为朋友不少，我们两个人为人也算爽快。其实，如果开始直说"我们想自己做，付半年的钱，行不行？"那我们当然很欢迎。服务嘛，本来就是可以随时停止的，也有客户是这么做的，希望我们帮他们度过过渡期，大家合作愉快。或者，实在不愿意付钱，也直说"我们想自己做，就这半年没的用，能不能帮我个忙？"我们估计也同意。多个朋友，没坏处。</p>

<p>可惜，他选了最没意思的一个办法。</p>

<p>虽然很气人，也亏了不少钱，不过，事情最后这样了，也就这样了。我甚至没跟别人说过这事，就让他过去了吧，谁做生意还不碰几次钉子，虽然我到现在也不能理解一个大公司干嘛要占2个苦哈哈的创业者的便宜。</p>

<p>--------------------时间的分隔线---------------------------</p>

<p>为什么我今天突然想起来写这个事呢？</p>

<p>早晨，我接了一个朋友的电话，问我，是不是tiny比较懂iphone的开发，说他有个朋友，有一些开发问题想请教。我说没问题，tiny解答不了的，我还有几个朋友都做这个，我也可以介绍。</p>

<p>然后我这个朋友说，那个人说有tiny的电话，但是不太好意思打。我就多嘴问了句是谁。结果竟然是前文所述的那位"好朋友"</p>

<p>于是我说，这个还是算了吧，我也不想和他打交道了。我的朋友告诉我，对方说，之前合作过，但是我们能力有限，支持不了他们的应用，最后没有用。这个可给我气坏了，您占了便宜，不说好话也就算了，也没必要这么诋毁我们吧？</p>

<p>我说，我们系统是否能支持，我这里有当年所有服务的log，一看就知道了。没出现过不能支持的事，既然他这么说，那就让他滚蛋吧。</p>

<p><br />
半个小时之后，我们公司电话响了，找tiny。这位"好朋友"终于亲自现身了，先道了个歉，说当时觉得我们的服务太贵了，所以没用。tiny说，我们的服务从来都是按照报价来的，当时你们的应该是XX元，哪里贵了？对方立刻表示是误会，误会。 （注意，半个小时之内，已经由支持不了，变成价格贵了）然后就开始请教他的iphone开发问题，还要请tiny当面给他们的程序员讲讲。</p>

<p>我简直被雷倒了。</p>

<p><br />
后来tiny跟我说，他这样该得到教训了吧？最后还是要来找咱们。</p>

<p>而我估计，他不仅没得到教训，甚至连后悔都没有。因为，他占了便宜，最后还仍然可以厚着脸皮来找我们帮忙。他从来也没亏什么。</p>

<p>这样的事，真是一次足够了。我这辈子也不想再跟他有任何关系，我也不希望我的朋友们再遭遇一次了，故为记。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/04/29/post_64.html</link>
         <guid>http://blog.devep.net/virushuo/2009/04/29/post_64.html</guid>
         <category>胡言乱语</category>
         <pubDate>Wed, 29 Apr 2009 00:04:35 +0800</pubDate>
      </item>
      
      <item>
         <title>beta沙龙－手机之家架构的发展和变化</title>
         <description><![CDATA[<p>这次beta沙龙请了<a href="http://www.paulgao.com.cn">高春辉</a>的团队来讲他们的经验。本来我是希望老高讲，不过他说最近的系统主要是许超前在带人开发，所以实际的演讲人是许超前。</p>

<p>国内最早让大家意识到网站的发展阶段的文档大概就是于敦德翻译的LiveJournal发展历程的ppt。这次许超前的演讲非常类似LiveJournal的那篇。</p>

<p><br />
手机之家用了7年时间，发展到1000万以上用户，3000万以上帖子，1.1TB附件，每天780万以上的PV这个规模。这个数字虽然比不上大型互联网公司，但是对一个只有几个人的技术团队，已经是一个很令人骄傲的数字了。</p>

<p>LiveJournal在发展中一边用着开源软件，一边造轮子，最后造出来了memcached这个简单而强大的工具，最终成了这一代网站开发离不开的东西。</p>

<p>这次演讲有意思的部分就是从memcached相关的事情开始的。</p>

<p>一 关于memcached的应用和管理。</p>

<p>memcached确实是个简单，好用，见效快的东西。不过简单也有简单的问题，程序员各有各的习惯，结果导致key很不规范，用什么方式的都有。这个问题恐怕用过memcached的人都深有体会。当然，用开发规范来限制程序员的行为是一个办法，但这不是技术的方法。技术的方法，是增加一个层。于是手机之家开发了一个cache管理器，把程序员和memcached隔离开，由这个层来统一管理缓存。</p>

<p>这是个不错的思想。当key被一个中间层接管了之后，事实上就可以给被缓存的对象实现更复杂的结构了。memcached是扁平的，只有一层。数据保存的方法仍然可以保持一层，但是通过对key的结构设计，就可以实现多层的结构，甚至在层和层之间实现继承关系，或是树结构。手机之家称之为namespace。通过这种方式，可以批量的管理和控制缓存对象。</p>

<p>换言之，索引结构可以复杂，但存放对象本身的地方是个key-value型的。friendfeed关于mysql应用的文档也提到了这种方法。用这种方法，可以在一个比较小的索引库中进行各种操作，无论是遍历还是查找，甚至处理一个节点下所有的值。最终得到key-value库的key。这个思路应该可以用于很多地方。</p>

<p>手机之家在cache上下的功夫很多，演讲稿中很多页是在讲cache系统的演变。对他们的应用方式来说，如果cache被击穿了，所有的压力到达了数据库，那么性能就会急剧下降，所以对cache的管理变的尤其重要。手机之家的这种尝试确实解决了很多问题。</p>

<p>二 仍然和cache有关</p>

<p>完成了前面说的cache管理器，他们还想更近一步，把数据访问，缓存，尤其是对库的切分整个包装起来，给程序员一个透明的接口。这样程序员不用关心到底存在多少个库，怎么分布，是否需要从cache中取数据等等细节问题。</p>

<p>这也是个常见问题。所有从数据库取数据的地方都要先从memcached读一次，代码很难看，也很罗嗦。这个包装完成之后，这就是一个能提高生产力的工具了。直接有效，也确实节约了开发成本。这个被他们称做DAL，很俗的名字啊:D</p>

<p>三 这样用java</p>

<p>php用来做以上的2个部件，效果并不好，效率很低。事实上php就不是干这个用的。最后他们用java+nio实现了一个性能不错的服务。把所有问题都解决了。</p>

<p>用在网页上java/jsp确实不如jsp，但是用来做服务器还是很合适的。我询问过他们是否在GC的时候遇到性能问题，答案是目前还没有。如果稳妥起见，对于这种方案，我更愿意采用C，不过考虑到团队情况，和java程序员比C更容易找到，手机之家用java来开发也是一个折中方案。</p>

<p>总结手机之家经验分享的意义，我觉得在于，我们很少有机会看到一个网站从0做到接近千万的PV。就算在一个大的互联网工作过，所看到也只不过是冰山一角，很难有操刀动手的机会。手机之家的成长用了7年，老高始终在带着团队做优化。这种经验很难获得。</p>

<p>我们常常讲，做网站好像爬山，一个陡坡，一个缓坡。我见过很多网站在50万pv之下就被技术卡住了。很多很多的公司，就在某一次上坡的时候死了。</p>

<p>沙龙结束后，晚上，我和老高在gtalk上又聊了很久。我觉得他们做出来的这套方案，对很多公司都有帮助。至少跨越几个困难阶段。这就好像memcached带来的，在没有memcached的时候，很多网站抗不住10万这个级别的pv，有了memcached，哪怕用的很糟糕，50万这个级别也能到了。老高这个方案或许能让很多网站进入"百万俱乐部"。</p>

<p>说起来做互联网，中国人比外国人难很多。我们面对的用户规模比他们大的多，但是广告价值小的多。我们做一个网站，可能在第一年就碰上了第一次性能极限，但这时候钱还没有影。外国人可能3年才到达，但是人家已经赚了不少钱，也有足够的资源来解决问题。对中国的互联网来说，有一些这种解决方案确实很有帮助。</p>

<p>当然，未来还是未知的。老高和手机之家是如何期待这个产品的未来的？是开源，还是做解决方案？不管怎么说，至少我相信，他们做一个不错的轮子，应该不至于只给自己用。</p>

<p>更细致的还是请看<a href="http://www.slideshare.net/Fenng/ss-1218991?type=powerpoint">他们的ppt吧</a>。</p>

<p>手机之家还在招聘 PHP/Java 人手，有意者给老高发邮件: gaochunhui@gmail.com </p>

<p><br />
其他相关的：</p>

<p>大辉的：<a href="http://www.dbanotes.net/arch/imobile_web_arch_ppt.html">手机之家的架构分享</a><br />
余晟的：<a href="http://www.luanxiang.org/blog/archives/594.html">老高之野望</a><br />
老高的：<a href="http://www.paulgao.com.cn/index.php?itemid=140">与"手机之家新系统介绍及架构分享"有关</a></p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/04/03/betasalon_imobile.html</link>
         <guid>http://blog.devep.net/virushuo/2009/04/03/betasalon_imobile.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Fri, 03 Apr 2009 00:26:51 +0800</pubDate>
      </item>
      
      <item>
         <title>弄了个让csdn blog输出全文的东西</title>
         <description><![CDATA[<p>某一天，喝了半瓶大二。然后我就想，我这到底算能喝酒还是不能喝酒呢？前几天喝的还没这个多，怎么就把笔记本丢了呢(这故事回头有时间再写)？</p>

<p>很久以前，喝多了酒，我就喜欢随便找个不规则物体，用微积分来算体积玩。后来就不玩这个了。现在比较喜欢写点好玩的程序或是找个命题来算概率。</p>

<p>想起来<a href="http://blog.youxu.info/2009/02/07/blog-recommendatio/">xuyou推荐过g9</a>的blog，而csdn blog因为不输出全文，基本被我排除出了订阅列表。于是就顺手扒拉了一个小程序，用来把全文抓出来，塞在rss里面，好订阅用。</p>

<p>结果今天比较清醒的看了看那天扒拉出来的程序，竟然还真能用。</p>

<p>所以就放这了。</p>

<p>这东西是基于magpierss做的。没什么特别的，写了一个基于token的解析器来解析文章，把需要的部分抓出来。这种方法在做语法分析器的时候很常见。当然了，您不能对醉鬼要求太高，所以我这个解析器只分析了单层标签，如果想支持多层的，只要加一个栈就可以了。我暂时用不到，不加了。</p>

<p>说起来php真是个不错的语言，简洁有力。字符串处理很强大。计算机这个家族里面，很大部分的机器是在做字符串处理和数据库工作，还有很大的一部分在做排序工作。所以一个字符串处理功能强大的语言就是最容易流行的语言。</p>

<p>我做了几个我要订阅的rss:</p>

<p>g9的： http://blog.devep.net/tool/magpierss/rss.php?url=http://blog.csdn.net/g9yuayon/rss.aspx</p>

<p>阿朱的: http://blog.devep.net/tool/magpierss/rss.php?url=http://blog.csdn.net/david_lv/Rss.aspx</p>

<p>用法很简单，就在后面加上csdn blog的rss地址就行了。你可以下载代码回去自己搭一个玩玩。</p>

<p>代码在：<a href="http://blog.devep.net/tool/magpierss_withparser.tgz">http://blog.devep.net/tool/magpierss_withparser.tgz</a> </p>

<p>很简单，很粗暴，很粗糙，也没什么版权，拿去随便干点什么用吧。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/03/23/csdn_blog.html</link>
         <guid>http://blog.devep.net/virushuo/2009/03/23/csdn_blog.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Mon, 23 Mar 2009 03:07:07 +0800</pubDate>
      </item>
      
      <item>
         <title>谢谢，请先发邮件给我</title>
         <description><![CDATA[<p>今天干了一件不大不小的糗事。</p>

<p>某网站打电话来："我是XXX"。听了个开头我就很烦躁，此网站给我推销过xx资料，xx活动若干，于是我就没让小姑娘说下去，告诉她，我对你们所有东西都没兴趣，资料不是我需要的，活动我也不想参加。谢谢。小姑娘有点委屈的说"可是..."，我说没什么可是的，没兴趣，谢谢。</p>

<p>后来下午有人问我，xx网站的活动，你是嘉宾啊，能不能给我搞点票？我这才明白，原来人家不是推销，是邀请啊...</p>

<p>错怪人家了。但是这个错怪也是有前提的。</p>

<p>愤怒这种情绪一般是累积的，就是同一件事情累积起来的大量的不满。说实话，骚扰我最多的不是这个网站，而是某个卖保险的。我反映最激烈的也不是这个网站，同样是那个卖保险的。</p>

<p>对付那个卖保险的方法是，我弄了一套某"直销"行业的培训资料，在卖保险的销售开口之前，就先开口给他念资料，然后威胁对方不许挂电话，不然我就去公司投诉他。这个办法很好用，一次管够，下次再也不会给我打电话了。</p>

<p>出现这些乱七八糟的事情，首先是个人资料保密太成问题了，人们完全是在裸奔。另一方面也说明商业机构太不拿用户信息当值钱的东西了。一切东西都有使用寿命。一次可以，二次可以，多了必然惹烦了。</p>

<p>对于我们这个职业，其实更严重。我最受不了的就是思考或是写程序的时候被打断。别管是谁我都想破口大骂。短信我已经基本不看了，但是电话总不能不接。这种时候接起来的电话别指望能有什么好结果。要么心不在焉，要么就是一口回绝。</p>

<p>我也没太多要求，再打电话之前，拜托请发个邮件给我。我查邮件比接电话及时，回邮件也比回电话及时。</p>

<p>也不知道为什么，是不是我人品特别不好，之前一段时间，每天我能收到至少5个垃圾短信和至少2个推销电话，当我开始启用了念直销文档这个办法之后，已经让这个数量大大减少了，不过还是挺烦人。</p>

<p>我在考虑是不是干脆拒绝所有通讯录里面没存在的电话....</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/03/18/post_27.html</link>
         <guid>http://blog.devep.net/virushuo/2009/03/18/post_27.html</guid>
         <category>胡言乱语</category>
         <pubDate>Wed, 18 Mar 2009 00:48:43 +0800</pubDate>
      </item>
      
      <item>
         <title>rss解析器magpierss笔记</title>
         <description><![CDATA[<p><a href="http://magpierss.sourceforge.net/">magpierss</a>是一个不错的rss抓取/解析工具，我本来打算自己写一个php的rss解析工具，不过试了一下magpierss，觉得还不错，能满足需要。</p>

<p>顺便看了看代码，记点笔记。</p>

<p>1 乱码问题<br />
magpierss过去时常出现乱码问题，从0.7版本解决了这个问题<br />
Version 0.7<br />
-----------<br />
    - support for input and output charset encoding<br />
      based on the work in FoF, uses iconv or mbstring if available</p>

<p>0.7之后的版本可以指定输入和输出字符编码，然后使用iconv或mbstring函数进行编码转换。这个工作在 create_parser 函数里面完成的，如果两个函数都不存在，可以在rss_fetch.inc 中让MAGPIE_DETECT_ENCODING为false，不检测和转换编码，否则就会出错。</p>

<p>一切正常的情况下，把rss_fetch.inc中MAGPIE_OUTPUT_ENCODING定义成你需要的输出编码，比如UTF-8: define('MAGPIE_OUTPUT_ENCODING', 'UTF-8'); 就可以获得正确的输出结果了。</p>

<p>2 抓取方法</p>

<p>magpierss用了<a href="http://sourceforge.net/projects/snoopy/">Snoopy</a>作为http客户端来抓取rss。这个库比较完善，支持https，支持gzip。</p>

<p>需要注意的是，Snoopy用exec命令调用curl，然后返回结果，而不是使用编译进php的curl函数。默认的路径是"/usr/bin/curl"，如果这里没有curl或是没有执行权限，就可能失败。不过只有https需要用到curl，普通的http访问是用fsockopen的。</p>

<p>同时，Snoopy可以使用代理服务器，但是magpierss没有使用，如果需要可以在rss_fetch.inc中的_fetch_remote_file函数里面添加$client->proxy_host 和$client->proxy_port。</p>

<p>3 缓存</p>

<p>magpierss设置了一个默认3600秒超时的缓存。在./cache下放了一堆文件，文件名是md5之后的url+MAGPIE_OUTPUT_ENCODING，格式是php的serialize。</p>

<p>所以cache目录要可写。超时时间在rss_cache.inc的var $MAX_AGE    = 3600;这行设置，也可以在创建cache对象的时候设置。</p>

<p><br />
综合起来，这个库还是不错的，优点很多，也考虑了主机的各种情况，兼容性很好。函数形式的接口，很容易调用。不过应该先用head来取rss的http header，根据Etag来判断是否抓整个页面回来，这样效率还能再有提高。这个改动之后，cache就可以存在更长的时间，而不是一个固定的3600秒。同时我比较想把文章保存起来，以便以后用，这就需要数据库了。</p>

<p>我将来应该会基于这个东西发布一个新版本，把我想要的功能加进来。</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/03/15/rssmagpierss.html</link>
         <guid>http://blog.devep.net/virushuo/2009/03/15/rssmagpierss.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Sun, 15 Mar 2009 14:31:21 +0800</pubDate>
      </item>
      
      <item>
         <title>关于有道阅读的beta技术沙龙</title>
         <description><![CDATA[<p>第一次<a href="http://club.blogbeta.com/">beta技术沙龙</a>邀请的是<a href="http://reader.youdao.com">有道阅读</a>来分享他们的技术和产品设计。阅读器这个东西听起来不大，但是技术含量并不低。</p>

<p>下面这个图是我根据当时听的情况随手画的，不一定很正确，但是应该基本能够看到产品的架子。简单说来就是前端，web server ，缓存，存储。当然了，任何网站都得这么设计架构。</p>

<table style="width:auto;"><tr><td><a href="http://picasaweb.google.com/lh/photo/dBzRFcUdJ00WItYNPBXl9A?feat=embedwebsite"><img src="http://lh6.ggpht.com/_fMpSudYvJOo/SbPy804X7XI/AAAAAAAAAfA/017WxFl0xZ0/s144/youdao_reader_arch.png" /></a></td></tr><tr><td style="font-family:arial,sans-serif; font-size:11px; text-align:right">From <a href="http://picasaweb.google.com/virushuo/Blogimg?feat=embedwebsite">blogimg</a></td></tr></table>

<p>大概可以分成几个部分：<br />
<ul><br />
	<li> 存储(这里主要说的是文章的存储)，是基于关系型数据库和key-value库的结合。这里可以简单理解为mysql+bdb，关系型数据库负责保存索引和基础信息，占用存储最大的文章全文在key-value库里面保存。使用的时候，根据查询结果，通过key到key-value库中取回全文。基本可以保证灵活性和效率，也是相对比较廉价的方案。<br />
</li><br />
 <li>缓存直接使用了memcached，memcached现在已经成了网站标准配置，在谁的架构中如果看不到类似的东西存在，反而会有点奇怪。有道阅读采用了一组memcached作为缓存，特别值得一提的是，他们在缓存中保存了24小时内所需要用到的全部数据。据说是经过多次实践的结果。我估计这个缓存的尺寸也不小，而且未来还会增加，不知道未来会通过什么方式来处理。但至少目前的一段时间内是够用了。围绕memcached的相关解决方案和patch已经相当成熟了，看起来有道也没有进行特别多的定制和改动。</li><br />
<li>web的部分比较值得一说。为了保证升级版本的时候，服务失效时间尽可能短，web的处理部分被拆成了一系列的Service，每个Service至少有一对实例承担正常的请求，在升级或是对某些模块进行改动的时候，可以依次对一对(或更多)实例中的某一个进行操作。这样整个应用并不会因为对某个Service的操作而停机。新旧模块的切换只在很短的瞬间(有道称之为"影子服务")。这种思想很类似SOA，不知道实际用起来感觉怎么样。我觉得接口的定义难度还是很大的。否则新旧Service切换的时候，其他相关的Service数据结构一旦不兼容，后果可能很严重。SOA的标准那么复杂，主要就是为了保持兼容和接口标准吧。当然，在一个产品之内，这种接口的定义相对容易点，毕竟复杂程度还是有限的。</li><br />
<li> 用户界面部分使用JQuery，实际用起来响应速度相当不错。JQuery也是成熟的标准产品了，还是值得推荐的。</li></p>

<p><li>最后就是备份，除了几层日常备份，全部数据还在网易的存储系统上有一个更全面的备份，目前已经有20T的数据。在大公司内做产品就是有这种好处，轻松的解决了最困难的问题，实在令人羡慕。</li><br />
</ul></p>

<p>总体上看，这个结构很规矩，没什么奇怪的地方，大量采用了现有的开源产品和方法。很务实。成熟的开源产品确实让开发工作变的简化了很多。</p>

<p>时间关系，还有很多细节没有说清楚。比如Service接口怎么定义，如何标准化，公司内部怎么来管理这些接口和文档，每天大量的文章如何抓取回来，如何管理等等。将来有机会再学习吧。</p>

<p>下面是现场的Keynote:<The Reader>。除了上面说的技术方面，在产品方面还有很多值得看看的。尤其是"12个有趣的发现"，这些发现是来源于有道阅读的数据统计的。做产品的同学们可以注意看看。</p>

<p><a href="http://docs.google.com/Present?docid=afm3f8898hwz_163fjp9gq4">ppt在此</a></p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/03/09/betasalon_youdaoreader.html</link>
         <guid>http://blog.devep.net/virushuo/2009/03/09/betasalon_youdaoreader.html</guid>
         <category>偶尔谈谈技术</category>
         <pubDate>Mon, 09 Mar 2009 01:35:52 +0800</pubDate>
      </item>
      
      <item>
         <title>自省的力量-关于《走出软件作坊》</title>
         <description><![CDATA[<p>一桌坐着5个人，其中4个是正在管软件项目的，包括我。4个人志同道合的吐着苦水。另外一个制造业管理出身的家伙很感兴趣的听我们发泄，估计他觉得这4个人倒的苦水特别不可思议。</p>

<p>不管其他行业的人觉得多古怪，软件行业就是这样的。我们的本质就是作坊，只不过是大作坊和小作坊的区别，一个作坊和多个作坊的区别。</p>

<p>所有人都希望软件做的好一点，管理做的有序点，进度可靠一点，这个在其他任何行业都觉得"再正常不过了"的需求，在软件行业的确很难达到。为了证实我上面的想法，我也确实问过很多朋友，这些人分布在各种公司，大型外企，大型国企，上市公司...不吝成本的公司不是没有，能容忍失败的雇主也不是没有。但是当我问到项目情况的时候，所有人都大摇其头。</p>

<p>好吧，在我长时间的工作中，不是没见过非常成功的项目，只是确实太少了。</p>

<p>比起好高骛远，想google如何，微软如何，不如先看看眼前，承认我们生活在作坊里面吧。当然，最终还是得找到一个适合自己企业的办法，把项目管起来。事实上，软件作坊并不丢人，无数伟大公司都是这样起步的，这对于未来的事业只不过是个开始点，而绝非终点。想到未来，自省的力量就变得更为重要起来。</p>

<p>阿朱的《走出软件作坊》，讲的就是这么一个过程。一个小公司，到底怎样才能找到适合自己的管理方法，怎样成长起来。</p>

<p>从《人月神话》第一次出版，到现在已经将近30年，在这已经相当于整个计算机历史一半的时间里，我们碰到的问题没有变少，甚至完全没有改变。《人月神话》提到的所有问题，仍然是目前困扰我们的问题。所以，阿朱这本书的意义与其说帮你解决问题，不如说帮你思考问题。这也是我所谓的自省的力量。</p>

<p>承认现状，认识不足，勤于思考，由小及大的解决问题，这才是正确的道路。阿朱为我们展示了一个工程师自省的历程，思考问题的方法，以及向管理人员转换过程。我想，原封照学，或许能解决一些问题，但并不够。其实我们的最终目标也并非走出一个作坊，而是提高可靠性和可用性。</p>

<p>请你在阅读时，拍着桌子喊"就是这么回事！"的时候，别忘了想想自己面临的问题，试着像阿朱展示的那样，多思考一些，多自省一些，如能借此有所提高，则善莫大焉！</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/02/25/introspection-in-software.html</link>
         <guid>http://blog.devep.net/virushuo/2009/02/25/introspection-in-software.html</guid>
         <category>读读书，写写字</category>
         <pubDate>Wed, 25 Feb 2009 01:42:27 +0800</pubDate>
      </item>
      
      <item>
         <title>blog迁移总算完成了</title>
         <description><![CDATA[<p>旧的主机正好到期，于是就趁机搬了一次家。</p>

<p>这次选择了fatcow的主机。同样不支持ssh。不过可以支持绑定无数的域名，空间和流量也不限。(当然我不太信这个，不过总比过去好吧。)</p>

<p>总共是46$ ，价格还算很是公道。</p>

<p>fatcow从1998年开始运营，也算10年老店了。比起来<strike>dreamhost这种新兴的，技术上确实也是落后了。</strike>经<a href="http://seo.g2soft.net/">DavidYin</a>留言提醒，发现dreamhost是1997年创立的，比fatcow还早。但是确实技术上比fatcow这种里老式主机先进了很多。</p>

<p>搬家过程碰到了很多麻烦。大半是完美主义所致。过去mysql是4.x的，这次挪到了5.x，想顺便把数据库编码从latin1转换成utf8，想把mt3.2升级到mt4...</p>

<p>整整折腾了一周，期间还骚扰了<a href="http://www.dbanotes.net">大辉</a>几次，最后也没搞定，只好妥协，继续用latin1编码了。mt4倒是升级成功了。</p>

<p>我发现, mt import出来的文件格式没有Permalink信息，如果用这个导出来备份，将来恢复的时候所有外联接都失效了。</p>

<p>在互联网时代这简直是不可想像的。没有联接就什么都没有，没有固定联接的页面等于不存在。尤其对于blog，想想看，别人引用了你的文章，转眼点过来什么都没有了，这多不像话。</p>

<p>所以mt一定要用mysql备份，不要指望那个import。</p>

<p>mt4在性能上确实比mt3好了很多，不过如果重新选择blog，说真的，要么wordpress，要么干脆和<a href="http://www.tinydust.net/prog/diary/diary.htm">tinyfool</a>一样，用blogger，生成到自己主机上。mt虽然有千好万好，就几个弱点就足够被否决了：</p>

<p>1 代码晦涩。mt4 比 mt3 更难看明白。而且perl本来就比php难读。<br />
2 占用cpu资源大，无论在什么主机上重建页面都会出500错误。折磨死人。<br />
3 备份难</p>

<p>不过我既然用了，还要继续用下去...现在用mt的人越来越少了.....熟悉的人里面只有<a href="http://www.dbanotes.net">大辉</a>和<a href="http://www.chedong.com">chedong</a>了....</p>]]></description>
         <link>http://blog.devep.net/virushuo/2009/02/23/blog_4.html</link>
         <guid>http://blog.devep.net/virushuo/2009/02/23/blog_4.html</guid>
         <category>胡言乱语</category>
         <pubDate>Mon, 23 Feb 2009 17:10:17 +0800</pubDate>
      </item>
      
   </channel>
</rss>
