qyb的博客

美国劳动生产率是中国的4倍?

这个数据是从今天的彩信报上看来的,应该是转自中国青年报,貌似是波士顿咨询集团的数据..

国庆期间租了一本《丰台生产方式》看,里面说二战前美国的劳动生产率是德国的三倍,而德国是日本的三倍——就是说美国劳动生产率是日本的9倍;战败后,麦克阿瑟在日本说,美国的劳动生产率是日本的八倍

Topic: 商业

Haraka website 上线

http://haraka.github.com/

按照技术难度,咱们来发展它依次有三个可能:

1. 作 out-bound 的 MTA,它的定制性比 postfix 应该是容易些。由于某些原因,向外投递如果出现问题需要一些更复杂的处理,而不是简单的产生退信了事。

2. 作 in-bound 的 MTA,尤其是如果要重新开始实现一个商用的邮件网关的话,应该考察一下这个项目。

3. 如果已经能当 out-bound,又搞定了 in-bound,那就作一个整套的 Windows 邮件系统吧。

另外刚刚又搜索了一下 Python 的 MTA,貌似最靠谱的是 http://www.lamsonproject.org,但是也有一年没有更新了

UPDATE: Python 最新的进展是 https://github.com/bcoe/smtproutes

Topic: 电子邮件

高通凶猛

有了i909后,我无意中装了一个淘宝,然后在这个app里面看到一个安卓专区,点进去一看,排名第一的手机是:中兴v880

再点进去一看,不到900的价格,大屏幕,高分辨率,难怪卖得那么火。

后来又看到了所谓中兴三剑客,针对于 TD、CDMA,中兴又有类似的两款手机。

再后来又看到了华为C8650,天翼定制机,外形和 iphone 3GS 几乎一模一样,也是 3.5 屏幕 + 320x480 分辨率,Android 2.3 系统,但是这个只卖 800,传说 19天内已经卖出去了30w部

不管电信联通如何厮杀,不管华为中兴怎么血拼,高通都是赢家。中兴v880用的是高通MSM7227,华为C8650是MSM7627,甚至中兴对抗C8650的N880s也是MSM7627...

Topic: 商业 技术

平板凶猛

联想刚刚推出了1000元的Android平板,我是国庆期间在天津岳父家的电梯里看到的广告招贴,很受震撼。

去年9月份我写了一篇研究了一下山寨Android平板的芯片,现在震惊于一线厂商的价格策略,于是又去专门研究了一番电容屏的低端平板:

  • 联想用的是TI的OMAP 3622,传说是德仪为联想定制的方案
  • 低端电容屏山寨平板貌似都是一水儿的瑞芯微的RK2918方案+7寸电容屏(800x480),RK2918是1.2G的主频,1080p高清解码,Flash硬件解码,至少硬件上看起来足够日常娱乐了
  • 上述配置淘宝上的山寨平板或者说三线品牌吧,价格约 600 元,超级给力!
  • 京东上的类似二线产品是 800 元左右,否则无法和lenovo竞争啊,别忘了lenovo还包括了内置GPS

当然软硬件还要调优,电池也是一个很大的瓶颈,WIFI还不普及,但是看起来已经没有什么能阻挡在2012年平板的大爆发了...除了Android自己——手机

Topic: 商业 技术

让网络更快一点儿

翻译:马少兵、林业
原文:LPC: Making the net go faster
By Jonathan Corbet

September 13, 2011

几乎所有google的服务都是通过 Internet 交付给用户使用,因此该公司特别有动力改进网络的运行模式。在2011召开的Linux Plumbers Conference featured presentations的网络会议上,三个google的工程师各提出了一个对网络有显著改变的建议。从他们三个人的建议可以看出,networking 还有很大的改进空间。

Proportional rate reduction

这个“拥塞窗口”主要取决于TCP发送者的想法:在中间环节超载的情况下,多少的数据能够被传送至末端。丢弃包常常意味着拥塞窗口过大,因此需要TCP正常实现过程中减少窗口当丢失发生时。但是减少拥塞窗口,就会减低性能;如果丢包仅是一次性事件,减少窗口大小是完全没必要的。RFC3517描述了一种算法,以使一次丢包后,加快连接速度。但是Nandita Dukkipati说,我们可以做的更好。

根据Nandita的说法,Google 的网络会话出问题的大部分原因集中在一个点上,它将导致花费7-10倍的时间才能完成会话。RFC3517是这个问题的一部分。这个算法当一次包丢失后,会立即减少一半的拥塞窗口,意味着发送者必须等待ACKs一半在传输途中的包(如果丢失包后拥塞窗口还是满的)。这就导致发送者将保持更长的等待时间。在简单的情况下(单个包丢失在长时间的传输过程中),这种做法是足够好的。但是在处理短数据流或很大比例的包丢失时,将阻碍工作。

现在的Linux系统没有使用严格的RFC3517。它被一个改进的算法“率减半”所代替。拥塞窗口不会立即减半。一旦 TCP 开始尝试恢复丢失包,每个ACK(主要是告诉末端两个包的接收者)将引起拥塞窗口大小减少。在传输过程中的全套发生上述过程,窗口大小将减半,但是发送者将持续发送(低速率)。这种方案最终的结果是减缓数据流和降低等待时间。

但是率减半还有提升空间。ACKs依赖于自身;延长的损失将显著引起拥塞窗口数量的减半和恢复的缓慢。这个算法也没有处理拥塞窗口的速率达到最高的可用值的过程,直到整个恢复过程完成后,速率才到达最高值。因此这将花费更长的时间来返回到最高速率。

成比例速率减少算法采用了一种不用的方法。第一步就是评估和计算传输的数据量,然后根据拥塞控制算法,计算拥塞窗口数量是多少。如果在管道中的数据量小于目标窗口的值,系统将直接进入TCP慢启动算法来备份窗口。然而当连接中发送大量丢失时,边开始重建窗口,而不是长时间匍匐一个小窗口。

相反如果传输的数据量至少达到了一个新的拥塞窗口,一个相似的率减半算法将被使用。相对新的拥塞窗口计算实际的减少量,而不是严格的减半。对于大和小的丢失,注重于使用评估的传输数据量,而不是请求的数据量。这使得恢复更加顺利和避免不必要的窗口数量的减少。

那多少是最合适的呢? Nandita认为,根据google在一些系统上已经运行的实验结果显示,平均等待实际减少3-10%。恢复实际减少5%。这个算法已经广泛应用于google服务器上;该算法也被3.2开发周期所合并。更多的信息请查看这份 draft RFC

TCP fast open

打开一个TCP连接需要一个three-packet 握手:客户端发送一个SYN(连接请求)数据包,服务端返回一个SYN-ACK(确认)响应,以及最后由客户端发出的一个ACK(确认)。直到握手完成,连接才可以传送数据,所以握手机制在每个连接都有一个不可避免的开始延迟。但是,问问Yuchung Cheng,如果想要在握手数据包中携带数据信息将会发生什么。对于一些简单的事务,例如一个接下来要发送一个页面内容的HTTP GET请求,伴随着握手数据包发送相关联的数据将会消除延迟。这个想法的结果就是TCP fast open的设想。

RFC 793(关于TCP的)确实允许数据包含在握手的数据包中发送,数据被限制为在握手完成之后再被 tcp 栈传递给应用程序。这样就可以通过避免最后一次请求来加速一次TCP连接发送数据的进程,但是还有一些障碍需要解决掉。一个很明显的问题就是会加大SYN泛滥攻击的几率,即使它们只影响内核后果也足够糟糕;如果每个接收到的SYN数据包都要占用应用程序的内核资源,那么拒绝服务的可能性就会变得很大。

Yuchung叙述了一种快速打开的方法试图解决大部分的问题。第一步是每个服务器创建一个 per-server secret,然后根据每个客户端的信息 hash,给每个客户端生产 per-client cookie。当客户首次发起 TCP SYN 请求时,这个cookie被作为一个special option包含在 SYN-ACK数据包中发送到客户端;客户端可以保存它,然后在未来的fast open时利用它。首先得到cookie的需求是一种低端的防止SYN泛滥攻击的方法,但是它确实让攻击变得有些困难了。另外,server端的secret可以相对频繁的更改,并且,如果当server发现有很多的连接时,fast open将会被禁用,直到连接数目回归正常。

一个仍然存在的问题是,互联网上大概有5%的线上系统将会丢弃那些包含了未知option数据的SYN数据包。这种情况下TCP fast open就无法使用了。客户端必须记住那些fast-open SYN数据包没有发送成功的cases,以后再遇到这些cases就使用普通打开。

缺省情况下fast open不会发生;连接双方的应用程序都必须特地的要求使用它。在客户端,sendto()系统调用就是用来请求一个fast-open连接;伴随着新的MSG_FAST_OPEN标志, 它的功能就像是connect()与sendmsg()的结合。在服务端,伴随着TCP_FAST_OPEN option 的setsockopt()调用将会允许fast opens。不管哪种方式,应用程序都不用担心去处理类似fast-open cookies这样的问题。

在google的测试中,TCP fast open已经被证实可以减少4%到40%的页面载入时间。自然的,在连接往返时间开销很大的情况下这项技术效果最好;延迟越高,移除它的价值就越大。很快,一个实现了这个特性的patch将会被提交。

Briefly: user-space network queues

之前的两个讨论都是在关注提高数据在网络上传输的效率问题。Willem de Bruijn则是关注与在本地主机上的网络进程。特别是,他是在使用高端的硬件工作:高速的网络连接,数目众多的处理机,并且,更重要的是,它拥有可识别特定流然后直接把包传入特定连接队列的智能网络适配器。当kernel感知到这个数据包的时候,它早已被接收并放置在合适的位置等着应用程序来请求数据了。

实际的对数据包的处理工作将会在应用程序的上下文环境中执行。所以"合适的位置"这里还包括了正确的上下文和正确的CPU。在软件IRQ级的中间处理就省略掉了。Willem甚至描述了一个新的接口,靠它应用程序可以通过一段共享内存段直接从kernel接收数据包。

换句话说,这段讨论描述了几种网络通道的概念,通过它们数据包被尽可能近的推送到应用程序。还有大量的细节问题需要涉及,包括为了类似防火墙等原因导致的通道挂起。利用 sysfs 向用户空间发送数据包的建议很难通过评审。但是这项工作最终可能会达到一个普遍有用的地步;有兴趣的人可以在 the unetq page 处找到patches

Topic: sohulinux

确保数据存入磁盘

翻译:靳彬
原文:Ensuring data reaches disk
September 7, 2011
This article was contributed by Jeff Moyer

在理想的情况下,系统崩溃、断电、磁盘访问失败这些情况是不会出现的,开发者编写程序时也不用为这些情况担忧。不幸的是,这些情况比我们想像的还经常出现。本文描述了数据是怎样一步步被写入磁盘上的,尤其是其中被缓冲的几个步骤。本文也提供了数据被正确写盘的最佳实践,以确保意外发生的时候,数据不会丢失。主要是面向 C 语言的,其中的系统调用也有其它语言的实现。

I/O缓存
考虑到开发系统时数据的完整性,有必要理解系统的整体架构。在数据最终存入稳定存储器前,可能会经过多个层,如下图所示:

处于顶层的是需要将数据写入永久存储的应用程序。数据最初存在于应用程序的内存或缓存中的一个或多个块中。这些缓存中的数据可能被提交给一个具有自己缓存的库。抛开应用程序缓存与库缓存,这些数据都存在于应用程序地址空间中。数据经过的下一层是内核,内核有一个叫做页缓存的回写缓存。脏页会存放在页缓存中一段时间,这段时间的长短取决于系统的负载与I/O模式。最后,当脏数据离开内核的页缓存时,会被写入存储设备(如磁盘)。存储设备可能会进一步将数据缓存在临时的回写缓存中。如果这时发生了断电的情况,数据可能会丢失。最后一层是稳定存储。当数据到达这层时,就可以认为数据安全存入稳定存储器了。

为进一步说明分层的缓存,来看一个在 socket 上监听连接的程序,它把从各个客户机收到的数据写入一个文件的应用程序。在关闭连接前,服务器要确保数据写入稳定存储设备中,并向客户机发送确认信息。

  1.  0 int
  2.  1 sock_read(int sockfd, FILE *outfp, size_t nrbytes)
  3.  2 {
  4.  3      int ret;
  5.  4      size_t written = 0;
  6.  5      char *buf = malloc(MY_BUF_SIZE);
  7.  6
  8.  7      if (!buf)
  9.  8              return -1;
  10.  9
  11. 10      while (written < nrbytes) {
  12. 11              ret = read(sockfd, buf, MY_BUF_SIZE);
  13. 12              if (ret =< 0) {
  14. 13                      if (errno == EINTR)
  15. 14                              continue;
  16. 15                      return ret;
  17. 16              }
  18. 17              written += ret;
  19. 18              ret = fwrite((void *)buf, ret, 1, outfp);
  20. 19              if (ret != 1)
  21. 20                      return ferror(outfp);
  22. 21      }
  23. 22
  24. 23      ret = fflush(outfp);
  25. 24      if (ret != 0)
  26. 25              return -1;
  27. 26
  28. 27      ret = fsync(fileno(outfp));
  29. 28      if (ret < 0)
  30. 29              return -1;
  31. 30      return 0;
  32. 31 }

第5行是一个应用程序缓存的例子;从socket中读取的数据被存入这个缓存中。现在,要传输的数据量已经知道,由于网络传输的特性(可能会是突发的或缓慢的),我们决定使用libc的流函数(fwrite() and fflush(),由上图中的"Library Buffers"表示)进一步缓存数据。10到21行负责从socket中读取数据,并写入文件流。在22行时,所有的数据都已经被写入文件流了。在23行,文件流进行刷新,并把数据送入内核缓存。然后,在27行,数据被存入稳定存储设备。

I/O APIs

既然我们已经深入了解了API与层次模型的关系,现在让我们更详细的探寻接口的复杂性。对于本次讨论,我们将I/O分为3个部分:系统I/O,流I/O,内存映射I/O。

系统I/O可以被定义为任何通过内核系统调用将数据定入内核地址空间中的存储层的操作。下面的程序(不全面的,重点在写操作)是系统调用的一部分:

Operation Function(s)
Open open(), creat()
Write write(), aio_write(),
pwrite(), pwritev()
Sync fsync(), sync()
Close close()

流I/O是用C语言库的流接口进行初始化的I/O。使用这些函数进行写的操作并不一定产生系统调用,即在一次这样的函数调用后,数据仍然存在于应用程序地址空间中的缓存中。下面的库程序(不全面)是流接口的一部分:

Operation Function(s)
Open fopen(), fdopen(),
freopen()
Write fwrite(), fputc(),
fputs(), putc(), putchar(),
puts()
Sync fflush(), followed by
fsync() or sync()
Close fclose()

内存映射文件与系统I/O类似。文件仍然使用相同的接口打开与关闭,但对文件数据的访问,是通过将数据映射入进程的地址空间进行的,然后像读写其它应用程序缓存一样进行读写操作:

Operation Function(s)
Open open(), creat()
Map mmap()
Write memcpy(), memmove(),
read(), or any other routine that
writes to application memory
Sync msync()
Unmap munmap()
Close close()

打开一个文件时,有两个标志可以指定,用以改变缓存行为:O_SYNC( 或相关的O_DSYNC)与O_DIRECT。对以O_DIRECT方式打开的文件的I/O操作,会绕开内核的页缓存,直接写入存储器。回想下,存储系统仍然可能将数据存入一个写回缓存中,因此,对于以O_DIRECT打开的文件,需要调用fsync()确保将数据存入稳定存储器中。O_DIRECT标志仅与系统I/O API相关。

原始设备(/dev/raw/rawN)是O_DIRECT I/O的一种特殊情况。这些设备在打开时不需要显式指定O_DIRECT标志,但仍然提供直接I/O语义。因此,适用于原始设备的规则,同样也适用于以O_DIRECT方式打开的文件(或设备)。

同步I/O(O_DIRECT或非O_DIRECT方式的系统I/O,或流I/O)是任何对以O_SYNC 或O_DSYNC方式打开的文件描述符的I/O.以下是POSIX定义的同步模式:

  • O_SYNC: 文件数据与所有元数据同步写入磁盘。
  • O_DSYNC: 仅需要访问文件数据的文件数据与元数据同步写入磁盘。
  • O_RSYNC: 未实现。

用以对文件描述符进行写调用的数据与相关的元数据,在数据进入稳定存储时,生命周期结束。注意,那些不是用于检索文件数据的元数据,可能不会被立即写入。这些元数据包括文件的访问时间,创建时间,和修改时间。

值得指出的是,以O_SYNC 或 O_DSYNC方式打开文件描述符,并将其与一个libc文件流联系在一起的微妙之处。记住,对文件指针的fwrite()操作会被C语言库缓存。直到fflush()被调用,系统才会知道数据要写入磁盘。本质上来说,将文件流与一个同步的文件描述符关联在一起,意味着在fflush()操作后,不需要对文件描述符调用fsync()。

什么时候执行fsync操作?

可以根据一些简单的规则,决定是否调用fsync()。首先,也是最重要的,你必须明白:有没有必要将数据立即存入稳定存储中?如果是不重要的数据,那么不必立即调用fsync(). 如果是可再生的数据,也没有太大的必要立即调用fsync()。另一方面,如果你要存储一个事务的结果,或更新用户的配置文件,你很希望得到正确的结果。在这些情况下,应该立即调用fsync()。

更微妙之处在于新创建的文件,或重写已经存在的文件。新创建的文件不仅仅需要fsync(),其父目录也需要fsync()(因为这是文件系统定位你的文件之处)。这类同步行为依赖于文件系统(和挂载选项)的实现。你可以对专门为每一个文件系统与挂载选项进行特殊编码,或者显示调用fsync(),以确保代码的可移植性。

类似的,当你覆盖一个文件时,如果遭遇系统失败(例如断电,ENOSPC或I/O错误),很可能会造成已有数据的丢失。为避免这种情况,通常的做法(也是建议的做法)是将要更新的数据写入一个临时文件,确保它在稳定存储上的安全,然后将临时文件重命名为原始的文件名(以代替原始的内容)。这确保了对文件更新操作的原子性,以使其它读取用户得到数据一个副本。以下是这种更新类型的操作步骤:

  1. create a new temp file (on the same file system!)
  2. write data to the temp file
  3. fsync() the temp file
  4. rename the temp file to the appropriate name
  5. fsync() the containing directory

错误检查

进行由库或内核缓存的写I/O时,由于数据可能仅仅被写入页缓存,例如在执行write()或fflush()时,可能会产生不被报告的错误。相反,在调用fsync(),msync()或close()时,由写操作产生的错误会被报告。因此,检查这些调用的返回值是很重要的。

写回缓存

这部分介绍了一些关于磁盘缓存的一般知识,与操作系统对这些缓存进行控制的知识。这部分的讨论不影响程序是如何构建的,因此,这部分的讨论是以提供信息为目的的

存储设备上的写回缓存有多种形式。有我们在这篇文章中假设的临时写回缓存。这种缓存会由于断电而丢失数据。大多数存储设备可以通过配置,使其运行在 cache-less 模式,或 write-through 模式。对于写操作的请求,每一种模式,只有当数据写入稳定存储时,才会成功返回。外部存储阵列通常具有非临时的,或具有后备电源的写缓存。这种配置,即使发生了断电的情况,数据也不会丢失。程序开发者可能不会考虑到这些。最好能够考虑到临时缓存与程序防护。在数据被成功保存的前提下,操作系统会尽可能的进行优化,以获得最高性能。

一些文件系统提供挂载选项,以控制缓存刷新行为。从2.6.35的内核版本起,ext3,ext4,xfs和btrfs的挂载命令是"-o barrier",以打开写回缓存的刷新(这也是系统缺省的),"-o nobarrier"用以关闭写回缓存的刷新。之前的内核版本可能需要不同的命令("-o barrier=0,1"),这依赖于不同的文件系统。程序开发者不必考虑这些。当文件系统的刷新被禁用时,意味着fsync调用不会导致磁盘缓存的刷新。

Topic: sohulinux

Mr. - 暗湧(Live Version)

国庆假期无意中在 QQ 音乐中的香港电台排行榜里看到了这支乐队的这个版本的演绎

背景音是浮夸,另外一个伟文填词的作品

Topic: 音乐

一周来的记载

  • -我问达达,爸爸马上就要去西安了,你能告诉我西安有啥好吃的吗?
    -达达神秘的一笑,你知道 "biang biang 面" 的 biang 是怎么写的吗?

    我家姑娘这一点最让人头疼,总是不正面回答问题

  • "上帝总是拿走一些你最珍贵的东西,以此时时提醒我们,你已经得到太多。"——方刚

    感悟:得到任何东西,都有代价

  • 老樊说:谈判是需要实力对等的

    感悟:增强自己的实力最重要。你就那么一个碗,水再怎么倒,也是一碗水

  • 本周俺们的测试组做了一个selenium以及相关工具的技术分享,邹科学评价:看你们的小姑娘熟练的调出eclipse,打开一个项目工程,短信会议室整个场面都被Hold住了
Topic: dada 生活
订阅 RSS - qyb的博客