<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
   <title>delphij&apos;s Chaos</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/" />
   <link rel="self" type="application/atom+xml" href="http://blog.delphij.net/atom.xml" />
   <id>tag:blog.delphij.net,2010://2</id>
   <updated>2010-02-03T09:34:53Z</updated>
   <subtitle>选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……</subtitle>
   <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 5.01</generator>


<entry>
   <title>安全：该做什么和不该做什么</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2010/02/post-591.html" />
   <id>tag:blog.delphij.net,2010://2.2064</id>
   
   <published>2010-02-03T01:08:23Z</published>
   <updated>2010-02-03T09:34:53Z</updated>
   
   <summary><![CDATA[很多事情都有Do's and Don'ts，这里试着整理一下与安全有关的。 本文版权所有 &copy; 2010 Xin LI &lt;delphij@FreeBSD.org&gt; 保留所有权利；非商业转载请注明出处 http://blog.delphij.net/， 谢绝商业转载。 安全不能建立在"别人不知道"的基础上 "别人不知道"是一种非常常见的安全 假象，举例来说，一种自己设计的山寨加密算法、一个系统中一般人不知道的位置等等，都属于这一类。 将安全建立在"别人不知道"的基础上是非常危险的。首先它会给设计者和用户带来"安全"的幻像，这会直接导致与系统交互的人放松警惕；其次，这样的设计往往留有"后门"，甚至是设计者不知道的后门（因为往往他们并不对这类设计进行充分的、专业的审计），容易被攻击者利用；最后，这种做法存在第三方泄密问题，即，使用这种系统的人，需要提防设计系统的人被其他人买通并泄漏一些秘密的情况。 延缓攻击的手段不能用来阻挡攻击 有许多延缓攻击的手段，例如改变服务的端口（比较常见的如将 ssh 改为 tcp/22 以外的端口），或禁止服务程序显示自己的版本等等，或仅仅简单地启用防火墙，这些手段起到的作用只是延缓攻击，而不应作为一种安全屏障。对于多层次式的安全设计来说，采取这些措施有助于提高检测到入侵的机会，但是它们本身并不会提高安全性。 与前一种情况类似，这种做法也只是让管理员放松警惕。例如以 ssh 为例，有人认为将端口改为一个非知名端口可以避免相关的攻击，但事实是，攻击者依然可以利用 ssh 实现或协议设计中存在的一些漏洞来攻破系统。拥有特定资源的攻击者甚至不需要直接对目标系统实施攻击。在较复杂的攻击手段中，包括简单的 port knocking 一类的保护手法，都可以使用类似分组重放这样的方法来逐步攻破。 采用层次式的安全设计 所谓层次式的安全设计，说的是在一套安全系统中包含不同层次的、存在层次式监控关系的安全结构。例如，将本地包含执行文件的那些文件系统通过一定的方式导出给监控网段的机器，就可以让那些机器在攻击者不知情，或至少不太容易注意到的情况下对入侵进行检测；通过将一些重要日志发到以不同的访问控制机制，甚至不同网络协议的记录设备上，则可以有效地检测入侵者的入侵行为，并为日后的分析留下更多的有用信息。 层次式安全在现实中也有应用。例如产品的质检，除了制造商自己进行的质量控制之外，有时分销商或政府也会进行一些抽样的检查。我们注意到，这些设计中的一个重要的特点是在不同的系统中使用不同的访问控制逻辑。例如，日志服务器必须从特定的客户端，甚至只能从某些隔离的内网登录。此时，延缓攻击的手段可以作为它的一项辅助设施，即其目的并不是阻止攻击，而是吸引攻击者在攻击目标上花费更多的时间，从而帮助入侵检测机制更容易地检测这些攻击。 不要轻信任何东西，包括X.509证书 安全系统的设计者必须对安全有全面的理解和认知。有一句很著名的话叫做 In God we trust, all...]]></summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="728" label="cryptology" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="691" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="198" label="security" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>很多事情都有Do's and Don'ts，这里试着整理一下与安全有关的。</p>

<p>本文版权所有 &copy; 2010 Xin LI &lt;delphij@FreeBSD.org&gt; 保留所有权利；非商业转载请注明出处 <a href="http://blog.delphij.net/">http://blog.delphij.net/</a>， 谢绝商业转载。</p>

<p><b>安全不能建立在"别人不知道"的基础上</b></p>

<p>"别人不知道"是一种非常常见的安全 <b style="color:red">假象</b>，举例来说，一种自己设计的山寨加密算法、一个系统中一般人不知道的位置等等，都属于这一类。</p>

<p>将安全建立在"别人不知道"的基础上是非常危险的。首先它会给设计者和用户带来"安全"的幻像，这会直接导致与系统交互的人放松警惕；其次，这样的设计往往留有"后门"，甚至是设计者不知道的后门（因为往往他们并不对这类设计进行充分的、专业的审计），容易被攻击者利用；最后，这种做法存在第三方泄密问题，即，使用这种系统的人，需要提防设计系统的人被其他人买通并泄漏一些秘密的情况。</p>

<p><b>延缓攻击的手段不能用来阻挡攻击</b></p>

<p>有许多延缓攻击的手段，例如改变服务的端口（比较常见的如将 ssh 改为 tcp/22 以外的端口），或禁止服务程序显示自己的版本等等，或仅仅简单地启用防火墙，这些手段起到的作用只是延缓攻击，而不应作为一种安全屏障。对于多层次式的安全设计来说，采取这些措施有助于提高检测到入侵的机会，但是它们本身并不会提高安全性。</p>

<p>与前一种情况类似，这种做法也只是让管理员放松警惕。例如以 ssh 为例，有人认为将端口改为一个非知名端口可以避免相关的攻击，但事实是，攻击者依然可以利用 ssh 实现或协议设计中存在的一些漏洞来攻破系统。拥有特定资源的攻击者甚至不需要直接对目标系统实施攻击。在较复杂的攻击手段中，包括简单的 port knocking 一类的保护手法，都可以使用类似分组重放这样的方法来逐步攻破。</p>

<p><b>采用层次式的安全设计</b></p>

<p>所谓层次式的安全设计，说的是在一套安全系统中包含不同层次的、存在层次式监控关系的安全结构。例如，将本地包含执行文件的那些文件系统通过一定的方式导出给监控网段的机器，就可以让那些机器在攻击者不知情，或至少不太容易注意到的情况下对入侵进行检测；通过将一些重要日志发到以不同的访问控制机制，甚至不同网络协议的记录设备上，则可以有效地检测入侵者的入侵行为，并为日后的分析留下更多的有用信息。</p>

<p>层次式安全在现实中也有应用。例如产品的质检，除了制造商自己进行的质量控制之外，有时分销商或政府也会进行一些抽样的检查。我们注意到，这些设计中的一个重要的特点是在不同的系统中使用不同的访问控制逻辑。例如，日志服务器必须从特定的客户端，甚至只能从某些隔离的内网登录。此时，延缓攻击的手段可以作为它的一项辅助设施，即其目的并不是阻止攻击，而是吸引攻击者在攻击目标上花费更多的时间，从而帮助入侵检测机制更容易地检测这些攻击。</p>

<p><b>不要轻信任何东西，包括X.509证书</b></p>

<p>安全系统的设计者必须对安全有全面的理解和认知。有一句很著名的话叫做 In God we trust, all others must submit an X.509 Certificate，需要注意的是，这里说的是 must submit，并没有说 submit 了就可以 trust 了。</p>

<p>和前面所说的层次式安全设计类似，我们的一个基本假定应该是，一个安全系统中的任何参与者，无论是用户还是计算机或程序，都是可能存在弱点的。安全系统，或用户，都不应轻信任何东西，例如，在特权隔离 (Privilege Separation) 这样一种设计中，特权进程除了完成那个非特权的子进程的请求之外，还有一个任务是维护一个"理性状态机"（Sanity DFA），这个状态机的作用是检测非特权进程的异常状况，如果发生这样的情况，则特权进程有拒绝提供服务，并杀掉非特权进程的责任。作为用户，对于系统给出的响应，除了验证对方的证书之外，也应有常识性的了解和适当的判断。</p>]]>
      <![CDATA[<p><b>不要把安全建立在不靠谱的基础设施上</b></p>

<p>举个现实生活中的例子，修一座桥，结果水泥标号不够；修一座楼，结果钢筋用竹签代替，有可能稳当吗？</p>

<p>然而在安全系统的设计中，很多人却往往忽视这样显而易见的问题。比较典型的就是许多网站所采用的所谓"安全控件"的技术。每一个这样的新设施，都意味着新增的攻击面和一组可能可以利用的新漏洞。</p>

<p>在一个安全系统中，防守的一方一定是弱势群体，因为他们必须按照一定的规矩去设计系统；而攻击者则可以采用最便宜的攻击方式。时刻牢记，在你花费时间去加强系统中最坚固的部分的时候，你的对手则正在靠近这个系统中最薄弱的环节，甚至可能是在你不知道的情况下！</p>

<p>下面是一些典型的不靠谱安全设施：</p>

<ul>
	<li>自己设计的算法。（公开的算法经过了更多的专业人士的验证；而自己设计的算法则没有，每个人的知识面都会有些局限，即使第一流的密码学设计者也可能设计出糟糕的算法，因此同行的验证很重要）</li>
	<li>监控键盘的驱动程序。（这类做法不仅不能对安全产生助益，反而会给其他木马带来监控用户键盘，从而攫取其他机密信息的便利）。</li>
	<li>基于明文的通讯协议。（当数据需要经过不受控制的网络节点的时候，端对端加密是非常重要的）。</li>
</ul>

<p><b>操作复杂不等于安全</b></p>

<p>一些安全措施在实施了之后，用户可能会发觉与之前相比会带来一些不便。有些不便可能是无法避免的，但这并不意味着，使用的时候给用户带来不适的安全设施就一定会提高安全性。</p>

<p>举例来说，一些银行在登录时，会在用户输入用户名之后，先显示一张用户自己定义的图片，然后再让用户输入密码。这种设施本身并没有改善任何安全性，因为中间人攻击仍然可以获得那个图片，更糟糕的是，由于看到了希望看到的那张图片，用户反而会对这个网站产生安全幻觉。</p>

<p>而另一种做法则是给用户一个小的token，这个token能够根据网站和token之间共享的信息和用户自己的密码来计算出一个登录用的一次性密码。拿到这个一次性密码的攻击者，并没有很好的办法再次使用这个密码来做别的事情。</p>

<p><b>代码开放和安全是不是一回事</b></p>

<p>许多人认为，开放源代码的东西更安全一些。这种说法并不完全正确。还有一些人认为，因为代码大家都可以看到，因此开放源代码的东西更安全，事实上，后面这种看法完全是逻辑混乱。</p>

<p>举个例子，面对来要求审计账目的税务局，一个CEO的回答是，我的账目绝对没有问题，因为我这家公司上上下下200多人都可以随时去看。毫不意外地，这个审计师决定自己再看一遍，因为这是一家广告公司，而"能看"和"看过的人都是内行"以及"有多少内行看过"也是完全不同的概念。</p>

<p>在选择一个解决方案的时候，如果一定要参考其他人的意见的时候，一定要看这个意见是来自什么人。开放源代码的产品一样有可能会存在漏洞，看它代码的人很可能并不是很有安全方面知识和经验的人，有这些经验的人可能在看其他的开放源代码，甚至不开放源代码的产品，等等。真正重要的是，找一个值得信任的专业人士去做这样的评估，而不是仅仅看一个和安全与否关系不大的指标就匆忙决定。</p>

<p><b>使用公开的、经过验证的安全算法和协议</b></p>

<p>算法和协议是实际应用中的安全系统中最关键的两个部件。经过验证的、公开的算法和协议有这样一些无法替代的好处：</p>

<ul>
	<li>设计它们的坏人有足够的专业知识。</li>
	<li>试图攻击它们，并且也有足够专业知识的坏人已经证明，攻破它们需要的代价大到不值得从这个方面去突破它们。</li>
	<li>坏人之间为了证明自己做了充分的对抗性的同僚复审。</li>
	<li>它们被破解的时候，你可能不是最先知道这件事的，但是也不会是最需要担心这件事的人。</li>
	<li>最重要的一点：设计一个自己破解不了的东西很容易，而设计一个 <b>别人</b> 破解不了的东西很难。我要提醒读者的是，你需要的是别人破解不了你的系统，而不仅仅是你自己破解不了。</li>
</ul>

<p><b>避免同一类型的弱点</b></p>

<p>攻击者在攻击的时候，往往会采用最"便宜"的方法去进行。例如，在发现一个由于程序设计问题而导致的安全漏洞时，除了修正这个问题本身之外，还应对系统中可能存在类似问题的其他环节进行类似的代码审计。对于开源项目来说这一点尤其重要。</p>

<p>例如，如果OS允许在地址0附近映射内存页，则由于欠锁一类原因导致的竞态条件所导致的可能就不仅仅是崩溃了。这类问题的典型用例是先将自己的代码映射到地址0附近，然后设法触发内核的一个可能导致空指针引用的函数指针调用，这样系统将会在内核的上下文运行那些代码（说明：出于性能考虑，一般来说内核并不会切换到一个完全不同的地址空间去运行）。尽管修正竞态条件本身很重要（例如FreeBSD SA 09:13.pipe），但通过禁止在地址0附近映射内存页，可以将这一类型的潜在漏洞全部由特权提升降级为崩溃或死锁，因此也就有了 FreeBSD EN 09:05.null 所做的改动。</p>

<p><b>避免过度设计，优先改进最薄弱的环节</b></p>

<p>过度设计是许多工程师会遇到的问题。例如，在内网交换机上传输加密数据，在多数情况下都是不必要的（听不到发到其他节点的包，而听包本身所需要的权限已经足够做其他事情）。</p>

<p>攻击者不需要遵循任何规则，而防守者则必须遵守一定的标准。因此，作为原则，防守的一方应假定攻击者会找到系统中最薄弱的环节，或者说，站在攻击者的角度去思考从什么地方去攻陷系统，并加强系统中最薄弱的那些环节。</p>

<p>不过，想要避免这些设计问题，必须拥有许多相关的知识和经验。</p>

<p>今天先写到这里，改天继续总结。</p>]]>
   </content>
</entry>

<entry>
   <title>李献计历险记</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2010/02/post-590.html" />
   <id>tag:blog.delphij.net,2010://2.2063</id>
   
   <published>2010-02-01T09:15:13Z</published>
   <updated>2010-02-01T09:18:47Z</updated>
   
   <summary>法师推荐的一个 短片，有关好爱情和不朽，我们还有很多不知道的。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Shared Chaos" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>法师推荐的一个 <a href="http://www.tudou.com/programs/view/4DcRkNPSYxQ">短片</a>，有关好爱情和不朽，我们还有很多不知道的。</p>]]>
      
   </content>
</entry>

<entry>
   <title>纪念消失的Sun</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2010/01/sun.html" />
   <id>tag:blog.delphij.net,2010://2.2062</id>
   
   <published>2010-01-29T00:13:57Z</published>
   <updated>2010-01-29T02:12:16Z</updated>
   
   <summary>欧盟日前正式无条件批准了Oracle收购Sun的交易，至此，有着28年历史（1982 - 2010）的Sun公司作为独立公司的历史正式宣告终结，今天，Sun的网站已经变成了301 http://www.oracle.com/。 &quot;For 28 years, Sun has stood for courage, innovation, a willingness to blaze trails, to envision and engineer the future.&quot; A tribute to Sun Microsystems...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Others" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="638" label="Oracle" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="224" label="Sun" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>欧盟日前正式无条件批准了Oracle收购Sun的交易，至此，有着28年历史（1982 - 2010）的Sun公司作为独立公司的历史正式宣告终结，今天，Sun的网站已经变成了301 http://www.oracle.com/。</p>

<p>"For 28 years, Sun has stood for courage, innovation, a willingness to blaze trails, to envision and engineer the future."</p>

<p><a href="http://www.thenetworkisthecomputer.com/">A tribute to Sun Microsystems</a></p>]]>
      
   </content>
</entry>

<entry>
   <title>用户口令的验证问题</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2010/01/post-589.html" />
   <id>tag:blog.delphij.net,2010://2.2061</id>
   
   <published>2010-01-28T22:29:02Z</published>
   <updated>2010-01-28T23:20:01Z</updated>
   
   <summary>口令是许多系统中用于判断用户身份的重要手段。当然，使用口令作为身份验证方法是很不靠谱的（例如，许多用户会使用弱口令，或者在多个系统中使用同样的口令，以及它存在对称失密问题，等等），不过因为口令便于携带（相对于私钥）和实现，因此仍然被广泛使用。 验证用户口令有很多种不同的方法。最原始的方法，就是将用户输入的口令与我们保存的口令相比较，如果相同，就认为是验证通过。但是这样一来，我们就必须保存用户的口令，而保存用户的口令会导致很多问题，例如，假如系统用于保存口令的数据库被攻陷，直接泄露用户的明文口令肯定不是一件好事。 于是，我们可以对前面的方法进行改进，即，只保存用户口令的散列（hash）字符串，而不是口令的明文。散列算法是一种单向的计算，即散列函数 H 对明文信息 p 计算出的结果 h： H(p) = h...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>口令是许多系统中用于判断用户身份的重要手段。当然，使用口令作为身份验证方法是很不靠谱的（例如，许多用户会使用弱口令，或者在多个系统中使用同样的口令，以及它存在对称失密问题，等等），不过因为口令便于携带（相对于私钥）和实现，因此仍然被广泛使用。</p>

<p>验证用户口令有很多种不同的方法。最原始的方法，就是将用户输入的口令与我们保存的口令相比较，如果相同，就认为是验证通过。但是这样一来，我们就必须保存用户的口令，而保存用户的口令会导致很多问题，例如，假如系统用于保存口令的数据库被攻陷，直接泄露用户的明文口令肯定不是一件好事。</p>

<p>于是，我们可以对前面的方法进行改进，即，只保存用户口令的散列（hash）字符串，而不是口令的明文。散列算法是一种单向的计算，即散列函数 H 对明文信息 p 计算出的结果 h：</p>

<p>H(p) = h</p>]]>
      <![CDATA[<p>从 p 根据 H 推算出 h 需要的计算工作很容易完成，而通过 h 则很难推出 p（一般来说，散列算法生成的输出结果是固定长度的，因此这个过程几乎一定会导致熵的减少，从而使 h 中包含的信息少于 p）。安全的散列算法还需要提供一些其他的特性，例如"雪崩效应（Avalanche effect）"，即明文信息p中哪怕仅仅改变1个bit，也会导致输出的h中多个bit的变化；输出的散列值均匀分布，等等。目前比较常用的安全散列算法是SHA2。</p>

<p>不过，仅仅使用散列算法来处理字符串并不能解决所有的问题。随着计算技术，特别是分布式计算和存储技术的不断发展，使得产生某种散列算法每一种散列输出，并保存一个可能的、与之对应的输入变得越来越容易。例如，SHA256 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad对应的一个可能的字符串是abc，如果我们只保存密码的hash数据的话，攻击者遇到ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad时，无论用户真正的密码为何，便总可以使用等效字符串"abc"来进入系统。</p>

<p>挫败这种攻击的方法是使用一个额外的随机串，并且在保存密码时，每次都生成一个新的随机串，将其以明文方式和散列串放在一起。例如，在保存密码时随机生成的随机串是hFaSV2，我们便把它和用户的密码abc连在一起去计算散列值，即，SHA256 ("hFaSV2abc") = 31945b4ad715f72214a8c84a3b63aa5aecf3ba9419a7687d90351da4d525d1fa，保存的时候可以写成$hFaSV$31945b4ad715f72214a8c84a3b63aa5aecf3ba9419a7687d90351da4d525d1fa$，这样在用户再次输入密码时，便可以配合这个串来进行验证。由于我们的随机串对每一个用户而言都不一样，攻击者就没有办法通过查找事先计算的字典来得到等价的字符串了。</p>

<p>然而，近几年的密码学研究成果还增加了另外一种形式的攻击，即，某些算法在有一部分已知明文的时候，可以以较低的代价推算出能够得到等价散列串的其他字符串。因此，前面的方法还需要进行进一步的改进。除了使用更好的散列算法之外，还可以通过多次散列得到的反馈来提高推算等价串的代价，也就是说，原先的系统中，我们计算的是：</p>

<p>H'(s, p) = H(s + p) = h</p>

<p>而改进的系统中，我们计算的则是：</p>

<p>H''(s, p) = H(H(s + p) + s+p) = h</p>

<p>上面的方法可以做多轮以加强效果，这里，我们将散列得到的信息以一定的方式反馈到散列函数的输入中。这样做的结果是，攻击者虽然了解我们生成的随机串 s，以及最后的结果p，但却没有很好的办法去推算我们在计算过程中使用的中间结果H(s+p)。这种做法可以挫败一整类这样的攻击。</p>

<p>在 *BSD 和 Linux 中的密码文件里所使用的 MD5 就是采用这样的方法，其实现中将散列串的输出结果以及原字符串不断地以输入的形式反馈到散列函数中，从而达到提高攻击门槛的目的。</p>]]>
   </content>
</entry>

<entry>
   <title>端到端(End to End)加密与安全</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2010/01/end-to-end.html" />
   <id>tag:blog.delphij.net,2010://2.2060</id>
   
   <published>2010-01-26T10:34:41Z</published>
   <updated>2010-01-26T09:53:55Z</updated>
   
   <summary>说明：这篇文章希望能够以比较通俗的方式介绍一下相关的概念。 端到端加密，通常是指两个通信实体之间在会话通道基础上进行的、由两个实体之间协商的密文会话。端到端加密的好处是能够减少会话通道本身的泄密或其他问题导致两个通信实体之间的通讯遭到第三方破译，并避免通讯的对方对通讯内容抵赖（即，不承认通讯内容来自自己）。相对而言，端到端加密的实施成本要比单独架设一条物理的通讯线路要便宜许多，因此有时它也用于架设这类通讯线路。端到端加密本身不能阻止由于使用的会话通道本身的丢包导致的干扰。然而，由于端到端加密可以工作在较高的抽象层次上，它可以使用多个实际的会话通道而提高抗干扰能力。 通常我们会希望在一个安全系统中设置多个层次的安全设施，或者说类似&quot;洋葱&quot;的模型，例如，在系统中，将所有与安全有关的信息记录日志并放到不可擦除的介质上、对连接进行加密，和对发送的消息进行加密，这几种方法分别考虑的是不同级别的信息安全，而这些方法可以在同一个安全系统中作为其不同的保护层次来使用。在这一类模型中，我们不仅视阻止入侵为目标，同时也将检测入侵做为目标，或者换言之，每攻破系统中的一个层次，入侵者都需要付出额外的努力，并冒更大的被发现的风险才能达到这样的目标。 以邮件系统为例，传统的电子邮件系统是完全不使用任何加密或签名的手段的。拥有接入层控制权的网络管理员，可以轻易地通过在网络上监听数据包来获知用户与自己所使用的邮件服务器之间交换的邮件内容。随后，当邮件到达了邮件服务器时，邮件服务器管理员也可以很容易地知道邮件内容；在邮件服务器将邮件传送到互联网上的另一台邮件服务器时，问题就更多了，每一跳路由，以及它们所经过的所有网络都可以被监听，并将邮件内容泄漏出去；最后，在另一台服务器和收件人之间，也有和发件人这一边一样的风险。 在Internet上传输电子邮件的过程，由于其经过的环节众多，并且几乎完全不受收发邮件的双方控制，因此很容易导致一些敏感信息的泄露。针对这种问题，人们设计出了一种叫做Transport Layer Security（TLS，用于替代SSL）的密码学协议来实现服务器之间，以及客户端到服务器的端到端安全。简而言之，这套协议首先使用公钥加密算法在通讯双方之间协商一个会话密钥，并用这个密钥完成之后的通讯加密/解密。公钥加密算法是一种加密和解密时使用不同密钥的加密算法，以对方公开密钥加密的数据，只能以（不公开的）解密密钥解密，而从公开密钥或已知明文、密文推算出解密密钥的代价非常大，因此它能够确保数据只能被&quot;正确的&quot;那个接收方解密。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>说明：这篇文章希望能够以比较通俗的方式介绍一下相关的概念。</p>

<p>端到端加密，通常是指两个通信实体之间在会话通道基础上进行的、由两个实体之间协商的密文会话。端到端加密的好处是能够减少会话通道本身的泄密或其他问题导致两个通信实体之间的通讯遭到第三方破译，并避免通讯的对方对通讯内容抵赖（即，不承认通讯内容来自自己）。相对而言，端到端加密的实施成本要比单独架设一条物理的通讯线路要便宜许多，因此有时它也用于架设这类通讯线路。端到端加密本身不能阻止由于使用的会话通道本身的丢包导致的干扰。然而，由于端到端加密可以工作在较高的抽象层次上，它可以使用多个实际的会话通道而提高抗干扰能力。</p>

<p>通常我们会希望在一个安全系统中设置多个层次的安全设施，或者说类似"洋葱"的模型，例如，在系统中，将所有与安全有关的信息记录日志并放到不可擦除的介质上、对连接进行加密，和对发送的消息进行加密，这几种方法分别考虑的是不同级别的信息安全，而这些方法可以在同一个安全系统中作为其不同的保护层次来使用。在这一类模型中，我们不仅视阻止入侵为目标，同时也将检测入侵做为目标，或者换言之，每攻破系统中的一个层次，入侵者都需要付出额外的努力，并冒更大的被发现的风险才能达到这样的目标。</p>

<p>以邮件系统为例，传统的电子邮件系统是完全不使用任何加密或签名的手段的。拥有接入层控制权的网络管理员，可以轻易地通过在网络上监听数据包来获知用户与自己所使用的邮件服务器之间交换的邮件内容。随后，当邮件到达了邮件服务器时，邮件服务器管理员也可以很容易地知道邮件内容；在邮件服务器将邮件传送到互联网上的另一台邮件服务器时，问题就更多了，每一跳路由，以及它们所经过的所有网络都可以被监听，并将邮件内容泄漏出去；最后，在另一台服务器和收件人之间，也有和发件人这一边一样的风险。</p>

<p>在Internet上传输电子邮件的过程，由于其经过的环节众多，并且几乎完全不受收发邮件的双方控制，因此很容易导致一些敏感信息的泄露。针对这种问题，人们设计出了一种叫做Transport Layer Security（TLS，用于替代SSL）的密码学协议来实现服务器之间，以及客户端到服务器的端到端安全。简而言之，这套协议首先使用公钥加密算法在通讯双方之间协商一个会话密钥，并用这个密钥完成之后的通讯加密/解密。公钥加密算法是一种加密和解密时使用不同密钥的加密算法，以对方公开密钥加密的数据，只能以（不公开的）解密密钥解密，而从公开密钥或已知明文、密文推算出解密密钥的代价非常大，因此它能够确保数据只能被"正确的"那个接收方解密。</p>]]>
      <![CDATA[<p>这种密码学协议的实现包括两件事：发起会话的一端需要生成一个随机的"会话密钥"，并以安全的方式（通过公钥加密）发给对方，而双方在稍后的通讯中，则以这个协商好的密钥进行对称加密（加密、解密使用同一个密钥，这种方法性能较好）对会话信息进行加密和揭秘。这样做除了性能方面的考虑之外，还有一个很 重要的是因为发起会话的这一方很可能没有自己的密钥对（公钥+私钥），由于对方的公钥公开，对方使用私钥对数据进行的处理只能看作是"签名"（可以使用公钥来进行验证）而不能作为传回数据时加密之用。这样，在建立加密会话时，接受会话请求的那一方很可能无法知道发起会话的那一方的身份（TLS事实上支持以包含公钥的证书的方式来验证身份，然而由于部署比较困难的原因，这一方法并没有得到非常广泛的使用，而只应用于一些强调安全而非易用性的场合）。</p>

<p>实施了TLS之后（由于兼容方面的考虑，通讯双方都需要启用TLS，否则邮件系统仍会以不加密的方式传输邮件），邮件系统在网络这个层次就无法被截获了。然而，这样做并不能阻止服务器端的管理员查看邮件的内容。我们注意到，在收发邮件时，实际上是两个人（当然，如果深究的话，事实上是代理他们的本地桌面终端）之间的端到端通讯，因此，在这里还应再进行一次端到端加密，使用PGP或S/MIME。这两种方法和前面所说的方法类似，但通讯双方均持有公钥/私钥对，使用自己的私钥来进行签名和解密，而对方的公钥则用于加密和验证对方签名，但在信任方式上则存在不同。S/MIME的信任关系依赖于各级发证机构（CA）所签署的身份证明，而PGP的信任关系则依赖于不同的个人之间对对方公钥进行的签名。S/MIME比较适合在企业内部迅速建立一套验证体系，而PGP则比较接近社会的关系，例如某甲是一个非常值得信赖的人，某乙、某丙虽然有时候满嘴跑龙套，但是还算靠谱，某丁则只有自己说话时候可以算数，说别人的事情的时候全是八卦，在PGP里面可以比较容易地对这些状态予以表达，并据此算出是否应信任某个签名。</p>

<p>说到这里，我们还必须强调一下端到端加密的缺点。首先，端到端加密只能提高通讯内容的保密性，它不能阻止通讯被彻底中断；然后是，端到端加密时，通讯双方的地址必须是公开的。这就好比通过快递公司去发运一个上了锁的保险柜一样，快递公司也许没有办法打开保险柜，但是保险柜本身并不能保证快递公司一定会把它送到目的地，而且，快递公司也必须知道发货人和收货人是谁，才能完成这趟物流。对于有更高保密需求的应用环境，还必须与其他层次的端到端加密结合，才能够达到所希望的效果。</p>]]>
   </content>
</entry>

<entry>
   <title>文件系统与大扇区</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/12/post-588.html" />
   <id>tag:blog.delphij.net,2009://2.2059</id>
   
   <published>2009-12-31T00:53:16Z</published>
   <updated>2009-12-31T01:48:57Z</updated>
   
   <summary>大扇区（超过旧式标准的512字节扇区）是改善硬件工艺或访问方式以后的一种直接提高存储密度的方法。对于磁介质来说，其盘片被分成若干的磁道（通常是同心圆）、每个磁道分成若干的扇区或称扇段，扇区是磁盘读写时的最小操作单元。对于基于闪存的存储设备而言，扇区则是一种模拟传统磁盘的概念。 对于磁盘来说，由于它是一种机械和电子一体化设备，由于各种原因的限制，其寻址和持续读写的可靠性方面都有一定的限制，例如，马达维持同样的转速，且磁头能够稳定在同一个位置，并将数据可靠地连续读写，可能只能持续8KiB或16KiB，为了提高可靠性，我们往往会需要在这之后重新校准设备。另一方面，对于随机写入的情形，较小的数据块有时会更为有利，同时，避免对磁介质的不必要的反复覆写，也有助于提高其使用寿命。因此，在磁道的基础上又引入了扇区的概念。 现代磁盘的设计中，扇区除了用户可见的部分之外，其前后还有一定的空隙用于定位和校验。这些空隙和其附近的介质一样可以用来保存数据，只是制造商和操作系统的撰写者通常不推荐使用这些空间。软盘上的这些空隙在DOS时代可以通过对控制器直接编程并改变扇区尺寸的方式强制覆写，并用类似的方法读出，从而起到一定的保密效果。 随着制造工艺的改善，现今的硬盘在十年前就早已不必受限于512字节的限制。由于在每个扇区前后都需要添加一些信息会浪费一部分空间并增加潜在的定位开销，因此硬盘制造商开始推出4KiB扇区的磁盘。这种磁盘在系统检测时会仍然汇报扇区尺寸是512字节，但物理扇区则是4KiB，并保持现有的512字节编址方式不便，从而与现有的BIOS保持兼容。 另一种已经存在一段时间的大扇区是Flash设备。这类设备采用的方法类似，不过其大扇区更多地是出于制造和避免不必要的擦写而不是提高存储密度考虑。 最后一种大扇区是RAID。许多RAID级别是一次性操作一整个stripe的，此时这种stripe也可以视为一种大扇区。 对于大扇区的支持主要是操作系统，特别是文件系统的责任，而应用程序只需确保自己操作的记录尽量是对齐的整块（例如，16K的记录，在文件中的偏移量都是从16K的整数倍开始）。文件系统需要保证应用程序对于磁盘的这种预期是能够满足的，换言之，文件系统的数据结构不应在磁盘上导致新的不对齐问题，这类不对齐可能是由于分区格式引起，也可能是文件系统本身的设计问题，如果存在这样的问题，操作系统中都需要予以纠正：例如，传统上从第63个512字节逻辑扇区开始的分区，可以牺牲掉一个512字节单元来换取对齐4KiB物理扇区的目的，由于对齐写入和读出操作需要的实际物理操作要少一半左右，因此这样做能够显著地改善性能并提高设备的使用寿命。 FreeBSD 9-CURRENT中目前已经支持通过GEOM子系统的stripe信息来描述磁盘或RAID的物理扇区尺寸以及GEOM相对于物理扇区的偏移量。新的ahci(4)驱动目前已经能够提供相关的GEOM信息给更上层的驱动程序了。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="*nix and Win32 Kernel" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="722" label="GEOM" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="723" label="offset" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="724" label="sector" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="725" label="storage" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="727" label="stripe size" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>大扇区（超过旧式标准的512字节扇区）是改善硬件工艺或访问方式以后的一种直接提高存储密度的方法。对于磁介质来说，其盘片被分成若干的磁道（通常是同心圆）、每个磁道分成若干的扇区或称扇段，扇区是磁盘读写时的最小操作单元。对于基于闪存的存储设备而言，扇区则是一种模拟传统磁盘的概念。</p>

<p>对于磁盘来说，由于它是一种机械和电子一体化设备，由于各种原因的限制，其寻址和持续读写的可靠性方面都有一定的限制，例如，马达维持同样的转速，且磁头能够稳定在同一个位置，并将数据可靠地连续读写，可能只能持续8KiB或16KiB，为了提高可靠性，我们往往会需要在这之后重新校准设备。另一方面，对于随机写入的情形，较小的数据块有时会更为有利，同时，避免对磁介质的不必要的反复覆写，也有助于提高其使用寿命。因此，在磁道的基础上又引入了扇区的概念。</p>

<p>现代磁盘的设计中，扇区除了用户可见的部分之外，其前后还有一定的空隙用于定位和校验。这些空隙和其附近的介质一样可以用来保存数据，只是制造商和操作系统的撰写者通常不推荐使用这些空间。软盘上的这些空隙在DOS时代可以通过对控制器直接编程并改变扇区尺寸的方式强制覆写，并用类似的方法读出，从而起到一定的保密效果。</p>

<p>随着制造工艺的改善，现今的硬盘在十年前就早已不必受限于512字节的限制。由于在每个扇区前后都需要添加一些信息会浪费一部分空间并增加潜在的定位开销，因此硬盘制造商开始推出4KiB扇区的磁盘。这种磁盘在系统检测时会仍然汇报扇区尺寸是512字节，但物理扇区则是4KiB，并保持现有的512字节编址方式不便，从而与现有的BIOS保持兼容。</p>

<p>另一种已经存在一段时间的大扇区是Flash设备。这类设备采用的方法类似，不过其大扇区更多地是出于制造和避免不必要的擦写而不是提高存储密度考虑。</p>

<p>最后一种大扇区是RAID。许多RAID级别是一次性操作一整个stripe的，此时这种stripe也可以视为一种大扇区。</p>

<p>对于大扇区的支持主要是操作系统，特别是文件系统的责任，而应用程序只需确保自己操作的记录尽量是对齐的整块（例如，16K的记录，在文件中的偏移量都是从16K的整数倍开始）。文件系统需要保证应用程序对于磁盘的这种预期是能够满足的，换言之，文件系统的数据结构不应在磁盘上导致新的不对齐问题，这类不对齐可能是由于分区格式引起，也可能是文件系统本身的设计问题，如果存在这样的问题，操作系统中都需要予以纠正：例如，传统上从第63个512字节逻辑扇区开始的分区，可以牺牲掉一个512字节单元来换取对齐4KiB物理扇区的目的，由于对齐写入和读出操作需要的实际物理操作要少一半左右，因此这样做能够显著地改善性能并提高设备的使用寿命。</p>

<p>FreeBSD 9-CURRENT中目前已经支持通过GEOM子系统的stripe信息来描述磁盘或RAID的物理扇区尺寸以及GEOM相对于物理扇区的偏移量。新的ahci(4)驱动目前已经能够提供相关的GEOM信息给更上层的驱动程序了。</p>]]>
      
   </content>
</entry>

<entry>
   <title>网址缩短服务</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/12/post-586.html" />
   <id>tag:blog.delphij.net,2009://2.2057</id>
   
   <published>2009-12-23T00:06:29Z</published>
   <updated>2009-12-23T01:15:37Z</updated>
   
   <summary>前一段时间帮一个朋友做了一个非常简单的网址缩短服务，已经上线运行了一段时间，这里把当时设计的一些想法分享出来，等有时间我会把代码也发布出来，程序很简单，用 web.py 做的。 网址缩短服务需要考虑两个问题，第一个问题是如何有效地查询，即，作为约束条件，在访问&quot;短网址&quot;的时候，它必须能够迅速的将结果返回；第二个问题是如何有效地将写操作复制出去。还有一点就是，缩短形成的短网址要真的越短越好。 接口 整个服务包括两个主要接口：一个是请求短网址，输入为网址（作为HTTP回应），输出为短网址；另一个是请求重定向，输入为短网址，输出为到短网址对应的真实网址的HTTP 302重定向回应。 设计 请求短网址的流程大致如下： 首先，检测输入的网址是否有效。 然后，计算输入的网址的 SHA256 散列值（计算时增加一个系统全局的salt值）的 URL-safe base64，并查找此散列串是否已经存在；如果已经存在，但对应的网址不同，目前版本将返回一异常（由于SHA256设计中的雪崩效应，这种情况基本可以忽略）。 如果不存在，则从前3位开始逐字向后取散列串，在查找表中查找到找到相同URL，或找不到结果为止；如果找不到结果，则将目前散列串的子串以及网址插入。 请求重定向的流程大致如下： 首先检测输入是否有效（不超长或超短）。 然后，直接从Berkeley DB中查找字符串对应的URL（实际实现中，将db文件以散列串首个字符命名，以利于未来将负载分散到不同的服务器）。 返回302回应。 未来的改进 目前的设计假定存在 2^0或2^1或2^2 .. 2^6 个节点能够提直接提供转向服务。转向回应信息可以在前端代理上永久缓存，因此可以通过增加前端代理服务器，而不是后端转向服务节点的方式来进行扩展。目前设计中故障转移等机制比较简单（根据SHA256计算出来的优先权值轮转），未来版本需要解决集群的原子提交问题。 目前的设计没有考虑自定义短网址，比如 foo.com/survey 这样的情况。这个问题可通过在长域名表（完整SHA256 base64与URL映射关系）基础上再增加一个查找表的方法来解决。 目前设计没有考虑删除以及禁止访问某些短网址的情况。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Development" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>前一段时间帮一个朋友做了一个非常简单的网址缩短服务，已经上线运行了一段时间，这里把当时设计的一些想法分享出来，等有时间我会把代码也发布出来，程序很简单，用 web.py 做的。</p>

<p>网址缩短服务需要考虑两个问题，第一个问题是如何有效地查询，即，作为约束条件，在访问"短网址"的时候，它必须能够迅速的将结果返回；第二个问题是如何有效地将写操作复制出去。还有一点就是，缩短形成的短网址要真的越短越好。</p>

<p>接口</p>

<p>整个服务包括两个主要接口：一个是请求短网址，输入为网址（作为HTTP回应），输出为短网址；另一个是请求重定向，输入为短网址，输出为到短网址对应的真实网址的HTTP 302重定向回应。</p>

<p><b>设计</b></p>

<p><u>请求短网址的流程</u>大致如下：</p>

<p>首先，检测输入的网址是否有效。</p>

<p>然后，计算输入的网址的 SHA256 散列值（计算时增加一个系统全局的salt值）的 URL-safe base64，并查找此散列串是否已经存在；如果已经存在，但对应的网址不同，目前版本将返回一异常（由于SHA256设计中的雪崩效应，这种情况基本可以忽略）。</p>

<p>如果不存在，则从前3位开始逐字向后取散列串，在查找表中查找到找到相同URL，或找不到结果为止；如果找不到结果，则将目前散列串的子串以及网址插入。</p>

<p><u>请求重定向的流程</u>大致如下：</p>

<p>首先检测输入是否有效（不超长或超短）。</p>

<p>然后，直接从Berkeley DB中查找字符串对应的URL（实际实现中，将db文件以散列串首个字符命名，以利于未来将负载分散到不同的服务器）。</p>

<p>返回302回应。</p>

<p><b>未来的改进</b></p>

<p>目前的设计假定存在 2^0或2^1或2^2 .. 2^6 个节点能够提直接提供转向服务。转向回应信息可以在前端代理上永久缓存，因此可以通过增加前端代理服务器，而不是后端转向服务节点的方式来进行扩展。目前设计中故障转移等机制比较简单（根据SHA256计算出来的优先权值轮转），未来版本需要解决集群的原子提交问题。</p>

<p>目前的设计没有考虑自定义短网址，比如 foo.com/survey 这样的情况。这个问题可通过在长域名表（完整SHA256 base64与URL映射关系）基础上再增加一个查找表的方法来解决。</p>

<p>目前设计没有考虑删除以及禁止访问某些短网址的情况。</p>]]>
      
   </content>
</entry>

<entry>
   <title>关系型数据库是为储存关系以及查询优化的</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/12/post-585.html" />
   <id>tag:blog.delphij.net,2009://2.2056</id>
   
   <published>2009-12-22T22:54:35Z</published>
   <updated>2009-12-22T22:59:10Z</updated>
   
   <summary>什么乱七八糟的东西都往数据库里面硬塞，该做的索引不做，不该做的索引一大堆，这再不慢等什么呢，天理难容嘛.........</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Development" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>什么乱七八糟的东西都往数据库里面硬塞，该做的索引不做，不该做的索引一大堆，这再不慢等什么呢，天理难容嘛......</p>]]>
      
   </content>
</entry>

<entry>
   <title>Buffer和cache的区别是什么？</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/12/buffercache.html" />
   <id>tag:blog.delphij.net,2009://2.2055</id>
   
   <published>2009-12-14T06:58:02Z</published>
   <updated>2009-12-14T07:55:56Z</updated>
   
   <summary>buffer和cache是两个经常被混为一谈的概念。从直观上说，两者都具备改善系统 I/O 吞吐量的能力，但是这两个概念是有区别的，其提高系统I/O吞吐量的原因也不尽相同。 cache改善系统性能的主要原因是数据访问的 局部性，即，通常应用程序在一段时间内操作的数据集的某个有限的部分，通常是很小的一部分。硬件实现的cache通常会只使用一小块（与主存相比）访问速度很快，但相对比较昂贵的存储部件，并放置于距离CPU较近的位置。 buffer改善系统性能的主要原因是减少不必要的状态切换和设备I/O。由于制造工艺等个方面的原因，系统中不同部件的速度往往是不一样的，一次进行批量的操作（例如，预先读取，或者将写数据凑成一个整数之后再写），往往要比到需要时等待这些操作完成要节省时间，并且有效地降低状态切换导致的开销。 还有一个比较显著的区别是，cache通常是硬件或OS提供，用户程序不需要（多数情况下也没有办法）为其分配存储的机制，通常它在使用者，如用户程序看来是透明的，它属于提供cache的一方而不是其使用者；而buffer往往是由用户程序知道并且与OS共享（换言之，用户程序需要分配一块内存，并告诉OS这块内存将要用于某种操作），或由OS分配，并在主机和外设之间共享（例如网卡的DMA buffer），在使用者看来它通常不是透明的，这些内存往往属于控制内存的程序，如用户程序，或OS，而不是向其传递数据的OS，或硬件。 不过，这个区别主要是传统意义上的cache。最近几年引入的一些新概念，特别是Internet cache并不能用这种方法来区分。我认为最关键的区别其实在于，buffer主要作用是在于减少实际的I/O操作次数，即，将多次操作尽量合并成一次的成批操作，通常其中的数据在操作完成之后，buffer不会被继续使用；而cache的主要作用在于更好地利用局部性原理，减少不必要的I/O，避免代价昂贵（例如，速度很慢）的I/O操作。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Development" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="719" label="buffer" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="720" label="cache" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>buffer和cache是两个经常被混为一谈的概念。从直观上说，两者都具备改善系统 I/O 吞吐量的能力，但是这两个概念是有区别的，其提高系统I/O吞吐量的原因也不尽相同。</p>

<p>cache改善系统性能的主要原因是数据访问的 <b>局部性</b>，即，通常应用程序在一段时间内操作的数据集的某个有限的部分，通常是很小的一部分。硬件实现的cache通常会只使用一小块（与主存相比）访问速度很快，但相对比较昂贵的存储部件，并放置于距离CPU较近的位置。</p>

<p>buffer改善系统性能的主要原因是减少不必要的状态切换和设备I/O。由于制造工艺等个方面的原因，系统中不同部件的速度往往是不一样的，一次进行批量的操作（例如，预先读取，或者将写数据凑成一个整数之后再写），往往要比到需要时等待这些操作完成要节省时间，并且有效地降低状态切换导致的开销。</p>

<p>还有一个比较显著的区别是，cache通常是硬件或OS提供，用户程序不需要（多数情况下也没有办法）为其分配存储的机制，通常它在使用者，如用户程序看来是透明的，它属于提供cache的一方而不是其使用者；而buffer往往是由用户程序知道并且与OS共享（换言之，用户程序需要分配一块内存，并告诉OS这块内存将要用于某种操作），或由OS分配，并在主机和外设之间共享（例如网卡的DMA buffer），在使用者看来它通常不是透明的，这些内存往往属于控制内存的程序，如用户程序，或OS，而不是向其传递数据的OS，或硬件。</p>

<p>不过，这个区别主要是传统意义上的cache。最近几年引入的一些新概念，特别是Internet cache并不能用这种方法来区分。我认为最关键的区别其实在于，buffer主要作用是在于减少实际的I/O操作次数，即，将多次操作尽量合并成一次的成批操作，通常其中的数据在操作完成之后，buffer不会被继续使用；而cache的主要作用在于更好地利用局部性原理，减少不必要的I/O，避免代价昂贵（例如，速度很慢）的I/O操作。</p>]]>
      
   </content>
</entry>

<entry>
   <title>SU+J</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/12/suj.html" />
   <id>tag:blog.delphij.net,2009://2.2054</id>
   
   <published>2009-12-14T06:28:05Z</published>
   <updated>2009-12-14T06:51:11Z</updated>
   
   <summary>Jeff Roberson 下周左右将会正式发表对于 UFS 的一项改进，为 Soft Updates 加入 Journal-ling，从而简化其恢复逻辑，并消除对 fsck 的依赖。 目前常见的保持元数据一致性的方法有四种：最原始的、将元数据以同步方式写盘的方法，性能非常差；常见的文件系统中使用的元数据回写日志（如ext3），缺点是无法检验日志本身的正确性，而且元数据需要写入两次因此对性能有潜在影响；Soft Updates，缺点是需要运行fsck来释放资源泄漏，而这个操作很耗时，且实现本身比较复杂；Copy-on-Write，在WAFL和ZFS中采用的技术，随着硬盘的淘汰随机存取时间不再是性能瓶颈，应该是未来的发展趋势，目前的缺点是会导致产生较多碎片。SU+J结合了Soft Updates和Journalling的优点，即，使用Soft Updates来确保写到磁盘上的数据的一致性，而使用Journalling来确保资源泄漏能够迅速回收，从而消除了fsck的必要性。 非常期待看到明年BSDCan的presentation。虽然目前我拿到的代码还有少量毛边，但是总体来说这次改进： 不需要修改磁盘上的文件系统数据结构，因此能够用于现有系统； 减少了 Soft Updates 本身的复杂性，每个事务所需的描述数据只需32个字节，扫完32K次操作（1MB日志数据）需要的时间只需2秒不到； 极大地减少了由于 fsck 需要吃很多内存、很多 I/O 导致的恢复速度慢的问题，这个实现基本上可以不再使用fsck了...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="*nix and Win32 Kernel" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="717" label="file system" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="718" label="journalling" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="713" label="Soft Updates" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="715" label="UFS" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p><a href="http://jeffr-tech.livejournal.com/">Jeff Roberson</a> 下周左右将会正式发表对于 UFS 的一项改进，为 Soft Updates 加入 Journal-ling，从而简化其恢复逻辑，并消除对 fsck 的依赖。</p>

<p>目前常见的保持元数据一致性的方法有四种：最原始的、将元数据以同步方式写盘的方法，性能非常差；常见的文件系统中使用的元数据回写日志（如ext3），缺点是无法检验日志本身的正确性，而且元数据需要写入两次因此对性能有潜在影响；Soft Updates，缺点是需要运行fsck来释放资源泄漏，而这个操作很耗时，且实现本身比较复杂；Copy-on-Write，在WAFL和ZFS中采用的技术，随着硬盘的淘汰随机存取时间不再是性能瓶颈，应该是未来的发展趋势，目前的缺点是会导致产生较多碎片。SU+J结合了Soft Updates和Journalling的优点，即，使用Soft Updates来确保写到磁盘上的数据的一致性，而使用Journalling来确保资源泄漏能够迅速回收，从而消除了fsck的必要性。</p>

<p>非常期待看到明年BSDCan的presentation。虽然目前我拿到的代码还有少量毛边，但是总体来说这次改进：</p>

<ul>
	<li>不需要修改磁盘上的文件系统数据结构，因此能够用于现有系统；</li>
	<li>减少了 Soft Updates 本身的复杂性，每个事务所需的描述数据只需32个字节，扫完32K次操作（1MB日志数据）需要的时间只需2秒不到；</li>
	<li>极大地减少了由于 fsck 需要吃很多内存、很多 I/O 导致的恢复速度慢的问题，这个实现基本上可以不再使用fsck了</li>
</ul>]]>
      
   </content>
</entry>

<entry>
   <title>服务器挂了</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/12/post-584.html" />
   <id>tag:blog.delphij.net,2009://2.2053</id>
   
   <published>2009-12-07T10:29:33Z</published>
   <updated>2009-12-07T10:34:06Z</updated>
   
   <summary>如题。其实已经算是超期服役了，这次是硬件故障，相当严重的硬件故障，不过还是希望能多用一段时间。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Life" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      如题。其实已经算是超期服役了，这次是硬件故障，相当严重的硬件故障，不过还是希望能多用一段时间。
      
   </content>
</entry>

<entry>
   <title>portsnap镜像的另一种实现方法</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/11/portsnap.html" />
   <id>tag:blog.delphij.net,2009://2.2052</id>
   
   <published>2009-11-17T05:37:14Z</published>
   <updated>2009-11-17T06:00:42Z</updated>
   
   <summary>FreeBSD 5.5和6.1开始内建了 portsnap，portsnap是一种新的 ports 套件同步机制。 与传统的 cvsup 更新方式相比， portsnap 有一些优越性： 对于经常进行更新的情况，portsnap很快：portsnap包含索引和具体的ports两部分，在更新的时候它首先会更新索引，而具体的更新则是下载两次索引描述的文件之间的差异，因此可以大大节省带宽。 portsnap有数字签名：cvsup并不包含任何加密或数字签名的机制，而portsnap的公钥则是通过光盘发给每一台机器的，相对来说安全性要好的多。 portsnap使用HTTP协议：通常，企业防火墙并不会拦截HTTP。 早先，架设portsnap镜像的方法比较复杂。由于portsnap的设计，架设portsnap镜像所产生的流量，在通常情况下大约会是仅做portsnap操作的3000倍左右。 之前听lwhsu提到了台湾那边的镜像所采用的方法，值得借鉴： 由于portsnap使用的是HTTP协议，而数据集相对较小，因此，实际上可以把这些内容全部作为反向代理放进内存。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>FreeBSD 5.5和6.1开始内建了 portsnap，portsnap是一种新的 ports 套件同步机制。</p>

<p>与传统的 cvsup 更新方式相比， portsnap 有一些优越性：</p>

<ul>
	<li>对于经常进行更新的情况，portsnap很快：portsnap包含索引和具体的ports两部分，在更新的时候它首先会更新索引，而具体的更新则是下载两次索引描述的文件之间的差异，因此可以大大节省带宽。</li>
	<li>portsnap有数字签名：cvsup并不包含任何加密或数字签名的机制，而portsnap的公钥则是通过光盘发给每一台机器的，相对来说安全性要好的多。</li>
	<li>portsnap使用HTTP协议：通常，企业防火墙并不会拦截HTTP。</li>
</ul>

<p>早先，架设portsnap镜像的方法比较复杂。由于portsnap的设计，架设portsnap镜像所产生的流量，在通常情况下大约会是仅做portsnap操作的3000倍左右。</p>

<p>之前听lwhsu提到了台湾那边的镜像所采用的方法，值得借鉴：</p>

<p>由于portsnap使用的是HTTP协议，而数据集相对较小，因此，实际上可以把这些内容全部作为反向代理放进内存。</p>]]>
      
   </content>
</entry>

<entry>
   <title>洗洗睡了吧......</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/11/post-583.html" />
   <id>tag:blog.delphij.net,2009://2.2051</id>
   
   <published>2009-11-15T09:35:40Z</published>
   <updated>2009-11-15T09:47:17Z</updated>
   
   <summary>前几天看了一下 iGoogle，感觉就是，做门户首页的真可以洗洗睡了（我说的是首页，我很少去门户网站的首页，而是直奔新闻之类的子站）。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Others" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>前几天看了一下 iGoogle，感觉就是，做门户首页的真可以洗洗睡了（我说的是首页，我很少去门户网站的首页，而是直奔新闻之类的子站）。</p>]]>
      
   </content>
</entry>

<entry>
   <title>基本搞定ibus了</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/11/ibus.html" />
   <id>tag:blog.delphij.net,2009://2.2050</id>
   
   <published>2009-11-15T06:47:52Z</published>
   <updated>2009-11-15T06:51:16Z</updated>
   
   <summary>感谢 Henry Hu 的帮助。ibus的一些代码在64位系统上有些问题，另外发现预编译的bytecode也有点小毛病，需要手工删除 /usr/local/share/ibus/ui/gtk/ 中的所有 pyc 和 pyo 文件，看来需要找时间看看到底是什么问题了。ibus拼音的效果要好过scim的智能拼音。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Development" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="712" label="输入法" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="711" label="ibus" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="210" label="scim" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>感谢 Henry Hu 的帮助。ibus的一些代码在64位系统上有些问题，另外发现预编译的bytecode也有点小毛病，需要手工删除 /usr/local/share/ibus/ui/gtk/ 中的所有 pyc 和 pyo 文件，看来需要找时间看看到底是什么问题了。ibus拼音的效果要好过scim的智能拼音。</p>]]>
      
   </content>
</entry>

<entry>
   <title>你会选择把源代码公开吗？</title>
   <link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/11/post-582.html" />
   <id>tag:blog.delphij.net,2009://2.2049</id>
   
   <published>2009-11-14T10:28:31Z</published>
   <updated>2009-11-14T10:38:12Z</updated>
   
   <summary>最近收到一封邮件邀请我参加一个调查，发现老外对参加代码公开的项目，特别是开源以及自由软件项目的动机总结的很透彻，多少也帮助我更深入地理解了为什么会存在开源和自由软件的分别。 许多参加开源项目的开发人员最初的动机纯粹就是回馈，或者希望自己能够从中受益----例如，他们受益于开源项目（例如，使用了这样的软件，等等），对这些项目进行了一些改进，而另一方面又不希望自己去独力维护一个fork版本，因为这样做比较浪费时间，或从成本上来算不合适，等等。 而参加自由软件的开发人员则是希望社会对其有所回馈。例如，他们会希望别人使用自己的东西的时候能够把改进送回来，等等。 许多人会同时有这两种想法。态度比较强硬的会更倾向于使用自由软件的授权，如GPL；而其他人则会希望使用更宽松一些的授权，如Apache、MIT、ISC或BSD。 我个人倾向于使用BSD和MIT授权。...</summary>
   <author>
      <name>Xin LI</name>
      <uri>http://www.delphij.net/</uri>
   </author>
   
      <category term="Development" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
      <![CDATA[<p>最近收到一封邮件邀请我参加一个调查，发现老外对参加代码公开的项目，特别是开源以及自由软件项目的动机总结的很透彻，多少也帮助我更深入地理解了为什么会存在开源和自由软件的分别。</p>

<p>许多参加开源项目的开发人员最初的动机纯粹就是回馈，或者希望自己能够从中受益----例如，他们受益于开源项目（例如，使用了这样的软件，等等），对这些项目进行了一些改进，而另一方面又不希望自己去独力维护一个fork版本，因为这样做比较浪费时间，或从成本上来算不合适，等等。</p>

<p>而参加自由软件的开发人员则是希望社会对其有所回馈。例如，他们会希望别人使用自己的东西的时候能够把改进送回来，等等。</p>

<p>许多人会同时有这两种想法。态度比较强硬的会更倾向于使用自由软件的授权，如GPL；而其他人则会希望使用更宽松一些的授权，如Apache、MIT、ISC或BSD。</p>

<p>我个人倾向于使用BSD和MIT授权。</p>]]>
      
   </content>
</entry>

</feed>
