Category Archives: 翻译

五种类型的企业家

作者:Brian
翻译:ShiningRay
原文:Defining The 5 Classes of Entrepreneurs
最近我一直在思考是什么成就伟大的企业家以及有些人努力成为其中之一背后的动机。常有人向我咨询关于创办公司和集资的建议,我还在不同的活动上讲演我那微不 足道的企业家经历。我发现我很难回答那么多问题,而且如果没有某种“情景语境”,关于哪些行得通哪些行不通,我也难以给出无可辩驳的论述。关于情景语境,我的意思是比如你想尝试创办下一个Google或者如果你想创办一个新的鞋厂。我略微思考之后,总结出实际上有5“类”企业家形式,每个有着不同的动机。希望借此文能抛砖引玉。
五类企业家

I. 投机型(Opportunist) – Class I Entrepreneur
II. 追求生活方式型(Lifestyle Entrepreneur) – Class II Entrepreneur
III. 解决问题型(Problem Solver) – Class III Entrepreneur
IV. 梦想型(Visionary) – Class IV Entrepreneur
V. 改变游戏型(Game Changer) – Class V Entrepreneur
在我的观念中每个“类型”代表了目标、动机和成果的不同层次,当然人可以从一个层次变成另一个层次。
I. 投机型企业家 (Class I): 投机者认为特定的局势能代表赚钱的机会,然后就上了。这些机会可以是在雨天卖雨伞,在盛夏烈日中午卖冰水,也就是说,扑向一个热门以及适时的潮流中,并提 供相关的某种服务。很多企业家都是这样起家的,因为最佳的“投机”机会往往不需要很多启动资本,但需要对它的一种紧迫的直觉。
我在大学的时候也有一段投机者的经历。那还是90年代初期,那时候的人还在用usenet新闻组,Web还处于lynx/mosaic的阶段。当时我很饭体 育卡(比如棒球卡),我发现了一个机会,我从本地的针对团队和卡片零售商那里接手体育卡的库存,然后通过Internet销售那些在当地没什么需求的卡 (如,49人的卡在波士顿常常卖得不好)。这个小小的兴趣带来的业务,让我能够支付相当多的大学费用。不过,创办一个网站让我和朋友能在线交换货物则是另外一个故事了。 :)
技能要求:3 / 耐久力要求:2 / 眼光:4

II. 追求生活方式型 (Class II): 这种类型的企业家想建立他/她自己的事业,他/她自己做老板,和他/她的朋友、家人一起工作,也就是追求一种迷人但并不是全部投入的事业机遇同时还能维持生活上的平衡。很多此类事业都是白手起家的,因为一旦业务上有外部投资,那么就会有来自外部的更快扩展或者是寻求某种退出的压力。这种企业家可能会从事各种行业,从运营一个成功(且有趣的)的饭店到操作一个软件业务。然而,定义这种事业的关键特征在于它是为了达到工作/生活的平衡或者是个人的满足而开始的,而并不是为了事业的成长。
我曾经为这种追求生活方式型企业家工作过,那是一段很开眼界的经历,从那里我了解了人们不 同的动机和目标。我个人完全尊重这些寻求生活方式和事业平衡的人。其实一个人真的需要多少钱呢?同时,也不是每个人都想要35岁退休,那么何尝不去做些刺 激而有趣的工作,同时还能到处去玩玩。
要求: 自给自足的事业; 人生目标.
III. [...]

OTP设计原理

春节在家没有闲着,把整个OTP Design Principles给翻译了——原来看到过一份文档,但是它只翻译了很少一部分。
由于文档内容比较多,我用了Sphinx编写了文档,HTML版在 http://erlang.shiningray.cn/otp-design-principles/
由于个人水平问题,翻译中的疏漏再所难免,希望大家发现后在本帖后面留言,我会即时修正。

建立一个OTP应用

概述
第一部分:建立服务器
第二部分:打造一个发布
第三部分:测试我们所构建的东西

原文:Building An OTP Application
作者:Martin Logan
译者:ShiningRay

概述
Erlang是一门干净简洁的语言,也容易学习。这只是Erlang,我们现在要讨论OTP。当进入到OTP之后,学习曲线就一下子上去了。各种各样的问题就来了,比如:我怎么启动一个应用,监督员(supervisor)的功能是什么,还有我要怎样使用gen_server?这还只是开始,后面还有更让人迷惑的……“.app文件是啥,怎么发布,还有,有人知道.script和.boot文件是干嘛的吗?”
本教程将带你一起创建一个叫做location_server的OTP应用。这个应用可以储存客户端的位置,允许别人从连接的节点查询这些位置,同时还允许客户端订阅位置变更时间所发出的通知。在整个创建location_server的过程中,我将解答以上那些关于OTP应用的问题,以及一些别的东西。
第一部分:建立服务器
首先要下载本教程的引用构建系统,可以在www.erlware.org上的downloads otp_base-<vsn>中找到。你在自己本地的Unix/Linux机器上下好这个代码之后,将构建系统解压出来。
> tar -xzfv otp_base-R1.tgz
> cd otp
> ls
build lib licence.txt Makefile README release tools

我们首先要做的是对这个构建系统进行初始构建,只要在otp目录下输入make即可。注意:如果你的Erlang没有安装/usr/local/lib/erlang下的话,你可以创建一个指向你所安装的目录的符号链接,或者也可以将环境变量ERL_RUN_TOP设置为安装目录(确保使用的是绝对路径)。
然后第二件要做的事情是搭好应用程序的骨架。完成之后我就会剖析这个骨架并解释它的各个部分的含义。使用appgen工具来创建location_server的应用程序骨架。
> cd tools/utilities
> ./appgen location_server ls
> cd -

我们已经在lib/location_server中创建好了一个应用、并在release/location_server_rel中创建好了一个发布。现在转入lib/location_server目录看看都有些什么。
> cd lib/location_server
> ls
include Makefile src vsn.mk

其中include目录包含了一个叫作location_service.hrl的文件。我们会把所有共享的宏(macro)和记录定义放在这里。src目录包含了所有的Erlang文件(.erl)。vsn.mk文件包含了make变量LOCATION_SERVER_VSN=1.0,表示我们的应用的初始版本(可以随意更改)。这个版本在处理发布的时候会起到作用,我们会在后面讲到。
> cd src
> ls
location_server.app.src location_server.erl ls_sup.erl
location_server.appup.src ls_server.erl [...]

Rails SQL Session Store优化版

问题根源
原始的ActiveRecord会话仓库很慢。对于低流量的网站而言没有什么问题,但是对于大一点的而言就慢了。首先,它的慢是因为ActiveRecord本身比较慢。虽然这是一个强大的ORM框架,但对于像会话管理这种简单的任务而言就是杀鸡用牛刀了。
还有其他的解决方案如cookie会话仓库(会话长度有限,不能在会话中存放敏感数据),memcached(无法持久化+难以实现高可用性方案)。
这就是为何要创建SqlSession仓库的原因。它直接操作mysql的数据库API,要比原始的AR会话仓库快很多。不过有时候它还是比较慢,因为:

每次访问都会创建、更新会话 – 任何机器人或者偶然的访客都会在数据库中创建一条会话记录,最后导致会话表里面会有成千上万的无用记录,但其中99%的访问其实是不需要任何会话更新的。
它使用32位字符串作为会话记录的键 – 所有RDBMS在处理字符串索引都要比整数慢很多,所以使用整数更好,然而我们的会话ID非常长,同时这些会话仓库都直接使用他们作为表索引。
使用了auto_increment 主键,对于MySQL 5.1.21之前的版本都会导致InnoDB使用表级锁。在不必要的插入上使用表级锁会给大型网站造成奇怪的问题。

解决方案
FastSessions Rails插件便是作为对于以上几个问题的解决方案而诞生的。
首先,我们从会话表中去掉了id字段,所以我们无须用到auto-increment锁。接下来为了让查找更快,我们使用了以下这些技术:不使用(session_id)作为查找索引,使用(CRC32(session_id), session_id)——双列键,可以帮助MySQL更快地找到会话记录因为键的基数更高(这样,mysql可以更快地找到记录而不用检查很多索引行)。我们测试过这种方法,在大会话表中显示了10-15%的性能提升。
最后,也是最强的优化是,对于空会话不创建数据库记录,同时如果数据没有在请求处理过程中没有更新过,则会话数据不会存回数据库。这个更改基本上可以减少50-90%的插入数量(根据应用程序的情况)。
那么,你肯定在想,用了这个插件之后会话究竟能快多少?这很难说。结果要看你是怎么操作会话的:如果你很少更改会话数据(如登录时储存用户id),那么可能会有90%的性能提升,但如果每次访问,你都要给用户会话写入些信息(比如最后一次访问时间last_visit_time),那么根据服务器的负载和会话表的大小,可能有5-15%的性能提升。
你只需要安装一个简单的插件,便可以自动实现上面这些更改。
我们解决了AUTO_INC锁的问题并去掉auto-increment键之后,又引入了一个新的问题,我在这里想说一下。这个问题是这样的。InnoDB会根据主键将所有数据分组。这意味着当我们使用自增长主键并向表插入记录时,会话记录会被组到一起,顺序地存储在磁盘上。然而如果使用比较随机的值(如一个随机会话id的crc32值)作为主键,那么每一个会话记录会被插入到属于它自己的不同的地方,那么会产生一些随机I/O,这对于I/O有限制的服务器不是很理想。所以,我们决定让用户自己选择在部署的时候使用何种主键,当你想在MySQL 5.1.22+上使用这个模块的话,可以设置

CGI::Session::ActiveRecordStore::FastSessions.use_auto_increment = true

这样在InnoDB中会连贯地插入数据。另一个情况当你的MySQL服务器的I/O有限制,不想因为随机主键而增加随机I/O,也可以这样设置。
如果你不想丢失使用AR会话插件创建的旧会话数据,你可以设置

CGI::Session::ActiveRecordStore::FastSessions.fallback_to_old_table = true

这样当某些session_id在新的会话表中找不到的时候,就会回去访问旧的会话表。旧会话表的名字可以使用CGI::Session::ActiveRecordStore::FastSessions.old_table_name 变量进行设置.
这个选项会使会话变慢所以我建议只要在升级到新会话表的时候才使用。在这种情况下,新的会话数据就会存入新表中,当到了会话超时期限的时候,就可以删除旧表了(我们用了两个月的期限,过了两个月之后,我们就可以删除旧表,并将此选项关闭。)。
安装
安装FastSessions插件十分简单,只需以下几个步骤:

将该插件代码从我们的SVN库中安装到vendor/plugins目录中(可以使用./script/plugin install安装,或者piston import命令进行安装——看你喜欢)例如:

$ piston import http://rails-fast-sessions.googlecode.com/svn/trunk/ vendor/plugins/fast_sessions

在config/environment.rb文件中启用ActiveRecord会话仓库:

Rails::Initializer.run do |config|
……
config.action_controller.session_store = :active_record_store
……
end

为新的会话表创建数据库迁移:

$ ./script/generate fast_session_migration AddFastSessions

如果需要,可以打开新创建的迁移脚本并更改表名table_name和插件use_auto_increment参数。
运行数据库迁移:

$ rake db:migrate

启动应用程序并尝试进行一定会保存数据到会话的操作。然后检查fast_sessions会话表(如果你没有改名字的话)有没有这条记录。

下载
该插件的最新版本可以在它的项目网站或在 SVN仓库中找到。该插件由Alexey Kovyrin(Percona的MySQL性能专家)制作。开发由Scribd.com赞助。

Facebook对memcached的提升

原文:Scaling memcached at Facebook
作者:Paul Saab
翻译:ShiningRay

如果你翻阅过一些关于大型网站扩展(Scaling)的资料,那么你可能听说过一个叫memcached的东西。memcached是一个高性能、分布式的内存对象缓存系统。我们Facebook可能是世界上最大的memcached用户了。我们利用memcached来减轻数据库的负担。memcached确实很快,但是我们还要让他更快、更高效。我们使用了超过800台服务器,提供超过28TB的内存来服务于用户。在过去的一年里,随着Facebook的用户量直线上升,我们遇到了一系列的扩展问题。日益增长的需求使得我们必须对操作系统和memcached进行一些修改,以获得足够的性能来为我们的用户提供最好的体验。
因为我们有好几千台机器,每个都运行了几百个Apache进程甚至更多,最终导致到memcached进程的TCP链接有几十万个。这些链接本身并不是什么大问题,但是memcached为每个TCP链接分配内存的方法却很成问题。memcached为每个链接使用单独的缓存进行数据的读写。当达到几十万链接的时候,这些累计起来达好几个G——这些内存其实可以更好地用于存储用户数据。为了收复这些内存,我们实现了一个针对TCP和UDP套接字的每线程共享的链接缓存池。这个改变使每个服务器可以收回几个G的内存。
虽然TCP上我们改进了内存的使用效率,但我们还是转向了UDP,目的是让get(获取)操作能降低网络流量、让multi-get(同时并行地获取几百个键值)能实现应用程序级别的流量控制。我们发现Linux上到了一定负载之后,UDP的性能下降地很厉害。这是由于,当从多个线程通过单个套接字传递数据时,在UDP套接字锁上产生的大量锁竞争导致的。要通过分离锁来修复内核恐怕不太容易。所以,我们使用了分离的UDP套接字来传递回复(每个线程用一个答复套接字)。这样改动之后,我们就可以部署UDP同时后端性能不打折。
另一个Linux中的问题是到了一定负载后,某个核心可能因进行网络软终端处理会饱和而限制了网络IO。在Linux中,网络中断只会总是传递给某个核心,因此所有的接受软终端的网络处理都发生在该内核上。另外,我们还发现某些网卡有过高的中断频率。我们通过引入网络接口的“投机”轮询解决了这两个问题。在该模型中,我们组合了中断驱动和轮询驱动的网络IO。一旦进入网络驱动(通常是传输一个数据包时)以及在进程调度器的空闲循环的时候,对网络接口进行轮询。另外,我们也用到了中断(来控制延迟),不过网络中断用到的数量大大减少(一般通过大幅度提升中断联结阈值interrupt coalescing thresholds)。由于我们在每个核心上进行网络传输,同时由于在调度器的空闲循环中对网络IO进行轮询,我们将网络处理均匀地分散到每个核心上。
最后,当开始部署8核机器的时候,我们在测试中发现了新的瓶颈。首先,memcached的stat工具集依赖于一个全局锁。这在4核上已经很令人讨厌了,在8核上,这个锁可以占用20-30%的CPU使用率。我们通过将stats工具集移入每个线程,并且需要的时候将结果聚合起来。其次,我们发现随着传递UDP数据包的线程数量的增加,性能却在降低。最后在保护每个网络设备的传送队列的锁上发现了严重的争用。数据包是由设备驱动进行入队传输和出队。该队列由Linux的“netdevice”层来管理,它位于IP和设备驱动之间。每次只能有一个数据包加入或移出队列,这造成了严重的争用。我们当中的一位工程师修改了出队算法,实现了传输的批量出队,去掉了队列锁,然后批量传送数据包。这个更正将请求锁的开销平摊到了多个数据包,显著地减少了锁争用,这样我们就能在8核系统上将memcached伸展至8线程。
做了这些修改之后,我们可以将memcached提升到每秒处理20万个UDP请求,平均延迟降低为173微秒。可以达到的总吞吐量为30万UDP请求/s,不过在这个请求速度上的延迟太高,因此在我们的系统中用处不大。对于普通版本的Linux和memcached上的50,000 UDP请求/s而言,这是个了不起的提升。
我们希望尽快将我们的修改集成到官方的memcached仓库中去,我们决定在这之前,先将我们对memcached的修改发布到github上。

Rails内置缓存引擎与线程安全

升级到Rails 2.1之后,使用Rails内置的缓存之后,发现使用mem_cache_store总是报错,于是干脆研究了Rails内置缓存引擎的代码。阅读的结果发现,Rails的内置引擎只应该应用于进程模式,尤其是mem_cache_store,因为mem_cache_store是每进程建立一个到memcached的链接,即便是读取,也需要写入套接字,所以为了同步,必须使用锁。因此即使在读取缓存的时候,也会出现争用的情况。mem_cache_store也必须像Rails2.2中的ActiveRecord一样实现一个到memcached的线程池,或者使用异步链接,否则是发挥不出memcached的效率的。
我研究了另外几个cache_store,

memory_store则根本连锁机制都没有,但对应有个多线程的synchronized_memory_store,使用了Monitor;
drb_store没有用过,可能Drb本身有一些同步机制,但估计也可能会出现与mem_cache_store一样的问题;
file_store应该是在多线程中应该比较理想的,因为使用了文件系统自身的同步机制,使用了File.atomic_write,无论是多线程还是多进程都能共享同一个file_store。

所以,Rails的线程安全还有很长一段路要走。
PS:前面的我说的我遇到的mem_cache_store的错误是Rails.cache.fetch误加了:raw => true 参数。

横向扩展(Facebook)

原文:Scaling Out
作者:Jason Sobel (notes)
翻译:ShiningRay
我于2007年四月加入了Facebook,在结束了几周的课程之后,我的经理Robert Johnson来找我。我们谈了很久,不过内容可以归结为:
Bobby: “那么,Jason,我们要在2008年之前在弗吉尼亚开一个新的数据中心。你能去帮点忙吗?”
Me: “呃…. 可以?”
Bobby: “很好!”
我在Facebook的第一个项目上投入的要比我预期的多一点点,但是我认为这是为何我们拥有如此一个非常强大的工程组织的原因;我们还有很多难题有待解决,这里每个人都迫不及待要立刻去解决他们。我开始了解为何我们需要建造一个新的数据中心以及我们需要解决什么问题才能让他正常工作。
有何必要?
在东海岸建造一个新的数据中心的主要原因就是“延迟”。在一个高速连接上发送一个包横穿大陆需要大概70微秒的时间,而对于普通的互联网用户而言,可能会需要的时间就长得多。通过将服务器放在弗吉尼亚,我们可以大大减少给东海岸和欧洲的用户传送网页的时间。
第二个关注点是空间、能源和灾难恢复。在我们位于加利福尼亚的主数据中心中已经没有多少物理空间了,而弗吉尼亚的点可以给我们充分的空间添加东西。我们还有一个类似问题就是要给予充足的电能驱动所有的服务器。最后,如果把我们限制在某个单独的地方,意味着如果出现灾难事件(断电、地震、怪兽),可能会导致Facebook长时间无法访问。
开始构建!
在我们能处理应用级的问题之前,我们的小组在弗吉尼亚投入了大量的心血构建服务器和物理空间。他们还完成了数据中心之间的网络和低延迟光线通道连接。这些工作是非常巨大的工程,然而我们顶尖的团队使之看上去像是小菜一碟。
网络和硬件都到位后,我们搭建了标准的3层架构:Web服务器,memcache服务器和MySQL数据库。在弗吉尼亚的MySQL数据库作为西海岸的数据库的从数据库(Slave)运行,所以我们花了几周的时间复制所有的数据,然后建立同步复制流(replication stream)。
现在硬件、网络和基础的设备都已经建立好,那现在就要面对两个主要的应用级的挑战:缓存一致性(Cache Consistency)和流量路径选择(traffic routing)。
缓存一致性
先说一下我们的缓存模型:当一个用户修改了数据对象后,我们的底层设施会向数据库写入新的值,并且从memcache中删除旧的值(如果存在)。下一次用户请求该用户对象的时候,我们从数据库中取出新的结果并写入memcache。后续的请求就会直接从从memcache中取出数据直到缓存过期或者被另外一次更新删除。
这种设置在只有一套数据库的时候运行得很好,因为我们只有当数据库完成了新值的写操作之后才删除memcache中的值。这种方式保证了我们能够从数据库中获得新值并且放入memcache中。然而,当在东海岸有一个从数据库后,情况就有些棘手了。
当我们在西海岸的主数据库中更新了一些数据之后,在东海岸的从数据库能正确反映这些新数值之前,中间有一个同步复制的延迟。通常这个延迟小于一秒钟,但是在高峰时期,它可能会延长到20秒。
现在我们假设在更新了加利福尼亚的主数据库的同时,我们从弗吉尼亚的memcache层中删除了旧值。然后有一个对弗吉尼亚的从数据库的读操作可能由于复制延迟还是看到的旧数值。然后弗吉尼亚的memcache可能会更新为旧的(不正确)的数值,然后它可能被“困住”直到被删除。如你所见,最差的情况是弗吉尼亚的memcache层可能总是同一个版本而非正确的数据。
考虑下面的例子:

我将我的名字从“Jason”改成了“Monkey”
我们把“Monkey”写入了加利福尼亚的主数据库并且从加利福尼亚和弗吉尼亚的memcache中删除了原来的名字
有个人在弗吉尼亚访问我的信息
在memcache中没有找到我的姓名信息,所哟我们从弗吉尼亚的从数据库中读取,由于复制的延迟获得了“Jason”
我们将姓名“Jason”存入弗吉尼亚的memcache
同步复制上来了,我们将名字信息在从数据库中更新为“Monkey”
另一个人在弗吉尼亚访问我的信息
我们在memcache中找到了名字并返回“Jason”。

在我再更新我的名字或者数据过期需要再访问数据库之前,我的名字在弗吉尼亚会一直显示为“Jason”,在加利福尼亚显示为“Monkey”。混乱吧?确实。欢迎来到分布式系统的世界,在这里一致性确实是一个难题。
幸好,解决方案要比问题容易解释。我们对MySQL做了一个小小的改动,让MySQL能在同步复制流中附加一个额外的信息。我们利用这个功能将要变更的所有数据对象追加到给定查询上,然后当从数据库“看到”这些对象后,要负责在进行了数据库更新后将这些值从缓存中删除。
我们是怎么做到的呢?MySQL是用了一个词法解析器和yacc语法来定义查询的结构然后对其进行解析。为了解释方便,我对其进行了简化,这个语法最顶层差不多如下:
query:
statement END_OF_INPUT {};

statement:
alter
| analyze
| backup
| call
… (insert, replace, select, 等.)
很直观吧?一个query(查询)是一个能分解成某种我们熟知的MySQL表达式的statement(语句)。我们将这个语法修改为允许在任意查询后追加memcache键,如下:
query:
statement mc_dirty END_OF_INPUT {};

mc_dirty:
{}
| MEMCACHE_DIRTY mc_key_list;

mc_key_list:
mc_key_list ‘,’ text_string { Lex->mc_key_list.push_back
($3); }
| text_string { Lex->mc_key_list.push_back($1); };

查询现在可以有一个额外的组件;在语句statement之后有mc_dirty可以为空或者为一个关键词MEMCACHE_DIRTY后面跟着一个mc_key_list。一个mc_key_list只是一个逗号隔开的字符串列表,该规则会告诉解析器将所有字符串一个接一个存入某个叫做mc_key_list向量中,这个向量将被存入每查询解析器对象中。
看个例子,某个老式的查询看上去像:
REPLACE INTO profile (`first_name`) VALUES (‘Monkey’) WHERE `user_id`=’jsobel’
在新语法下会变成:a
REPLACE INTO profile (`first_name`) VALUES (‘Monkey’) WHERE `user_id`=’jsobel’ MEMCACHE_DIRTY ‘jsobel:first_name’
新的查询会告诉MySQL,除了要将我的名字更改为Monkey外,它还需要将一个对应的memcache键设脏。这很容易实现。由于每对象解析器对象现在储存了所有的memcache键,我们在mysql_execute_command最后添加了一小段代码——如果查询成功了,就设脏这些键。看看,我们成功地按照我们的目的——缓存一致性——劫持了MySQL同步复制流。
新的工作流变成了(更改的内容为粗体):

我将我的名字从“Jason”改为“Monkey”。
我将“Monkey”写入加利福尼亚的主数据库并从加利福尼亚的memcache中删除我的名字,但不包括弗吉尼亚的memcache。
某个人在弗吉尼亚访问了我信息。
在memcache中找到了我的名字,并返回“Jason”。
同步复制到了之后,将从数据库中我的名字更新为“Monkey”。还需要从弗吉尼亚的memcache中删除我的名字因为缓存对象出现在同步复制流中了。
另一个人在弗吉尼亚访问了我的信息
没有在memcache中找到我的名字,所以从从数据库读出名字,得到了“Monkey”。

页面路径选择
我们还需要解决的另一个主要的问题是只有在加利福尼亚州的主数据库才可能接受写操作。这个情况就是说我们需要避免在弗吉尼亚服务那些需要进行数据库写操作的页面,因为他们都需要穿越整个大陆访问我们在加利福尼亚的主数据库。幸好,我们最频繁访问的页面(首页、档案、照片页面)在正常情况下都不会进行写操作。这样这个问题就归结于,当一个用户请求某个页面时,我们怎么判断它是否可以被“安全”地送到弗吉尼亚,或者它必须被引导到加利福尼亚?
这个问题最后有一个比较直观的答案。某个用户请求Facebook时,命中了第一批服务器其中的一个,这个服务器称之为负载均衡器;该机器的主要职责是选择一个Web服务器来处理该请求,不过它也进行一些其他目的的服务:防御拒绝服务攻击,多路复用用户连接等。这个负载均衡器拥有可以在第7层模式运行的能力,这样他可以检查用户请求的URI并根据这个信息进行路由选择决定。这个特性意味着,我们可以很容易地告诉负载均衡器哪些是“安全”页面,然后可以根据页面的名字和用户的位置决定是否要将请求发送到弗吉尼亚或者是加利福尼亚。
不过,这里还有一点问题。假设你访问editprofile.php来更改家乡信息。该页面没有被标记为安全所以他被引导到了加利福尼亚,并且进行了更改。然后你访问你的档案页面,同时由于这个页面是安全页面,所以被引导到了弗吉尼亚。然而因为前面提到的同步复制延迟,你可能不能立刻看到你刚刚做过的改动!这种体验会令用户感到非常混乱,同时会导致双重提交。我们通过在浏览器中设置一个包含(有过写入数据库操作的)当前时间cookie来绕开这个问题。负载均衡器会查看该cookie,如果它注意到20秒内你写入了些东西,将无条件地传送到加利福尼亚。过了20秒之后,我们确保数据已经同步到弗吉尼亚,这时便允许你回来访问安全页面。
回顾
从我们第一个用户在弗吉尼亚数据中心访问页面后的九个月中我们一直在运行同样架构获得了很好的效果。当然,一路上还有挫折;在头一两个月中,缓存一致性的框架非常地不稳定,逼我们在诊断和修复错误的时候每隔一段时间就要把流量从弗吉尼亚转移出去。当然,过了一段时间,我们消灭了这个问题,现在这个数据中心在Facebook的流量中占了很大的比重。
这个架构中主要的伸缩方面的挑战很明显:所有的写操作必须在同一个地方发生。更进一步我们对开发新的可以让我们在任何位置进行写操作的技术非常感兴趣。我们也在思考如何将新的数据中心做成一个灾难恢复点,以防怪兽要进攻加利福尼亚!想来帮帮我们吗?www.facebook.com/jobs!

亚原子粒子有自由意志吗?

作者:Julie Rehmeyer
原文:Do subatomic particles have free will?
翻译:ShiningRay

如果我们有自由意志,那么亚原子粒子也有,有数学家说可以证明。
“如果原子永不为创始那些攫取命运的纠葛和永恒的因果循环的新运动而转向,那么什么才是这地球上的生物所拥有的自由意志的源泉?”
——卢克莱修,罗马哲学家兼诗人,公元前99-55。
人类自由意志可能哲学主题中最模棱两可的,超出数学证明范畴。然而两位德高望重的普林斯通数学家,表示他们已经证明了如果只要人类有那么一点点最小量的自由意志,那么原子本身的行为就一定无法预测。
该发现不会给多数物理学家造成困扰,因为量子力学的传统解释已经包含了不确定性了。量子原理表示,最好的方式是预测一个粒子的某种方式的行为的可能性。
但是爱因斯坦开始的物理学家则对这个想法非常不满。爱因斯坦最著名的抱怨——“上帝不掷筛子”。确实,自从量子理学诞生那刻起,一些物理学家给出了它的等式的替代解法,旨在消除其不确定性原理。最著名的替代法由物理学家David Bohm给出,他在1950s争论说,亚原子粒子的行为完全由无法被观测的“隐变量”决定。
Conway和Kochen说该研究是没戏的,同时他们表示不确定性是继承自这个世界本身,而不是在量子理论中。并且他们二人对支持Bohm的物理学家以及其他类似想法的人说:放弃确定性,要么就放弃自由意志。即使是一点点自由意志。
他们的论点源自Kochen在40年前用Ernst Specker创建的证明。亚原子粒子有一个特性叫做“自旋”,它可以绕任意轴进行。已有实验证明了一类自旋为1粒子有一中独特的属性:选择三个相互垂直的坐标,然后探测该自旋为1的粒子确定它绕哪个轴为的自旋0。确切地结果是,其中一个轴会自旋为0,另外两个会有非0自旋。Conway和Kochen称之为1-0-1规则。
自旋是目前物理学家尚不能在探测之前事先预测的特性之一。然而,任何人都可能会想象粒子绕任意轴的自旋是在任何人去探测它之前就已经确定好的。这也是我们在生活中的常见假设。我们不会想象,比如,一个栏杆是因为我们看到了它,所以它变成了白色——我们认为它应该一直都是白色。
但是Kochen和Specker证明了这个假设——栏杆一直是白色——在奇异的亚原子粒子的世界中是说不通的。他们是用了一个纯数学的论据表明了粒子无法用一种与1-0-1规则一致的方式来选择绕每一个可想到的轴旋转。实际上,一个只有33个轴的集合已经足够令粒子变成一个悖论。它可以选择绕前32个符合该规则的轴自旋,然而对于最后一个,无论0或者非0都不可能。选择零自旋将会创建一套有两个零点的正交的三个轴,选择非零自旋则会创建另一套,有正交的三个轴,以及三个非零点,两种方式都会打破1-0-1规则。
这也就意味着,粒子在被测量之前不可能在任何一个方向都有一个确定的自旋,Kochen和Specker总结到。如果该情况成立,那么物理学家应该能偶然观察到它打破了1-0-1规则,而这个从未发生过。相反,它必须在瞬间“决定”怎么自旋。
Conway将该情况与“二十个问题”游戏进行了比较。如果你公平地玩该游戏,你在一开始就确定了某个对象,然后诚实地回答每个问题,然后祈祷对手不会过早推出你的想法。然而一个机灵的玩家会去骗人,在玩了一半就去改变自己选的对象。在这种情况下,它的答案就不能事先确定了。Kochen和Specker说,粒子就像一个会骗人的玩家。他们发现没有哪个单一的对象能一次完全满足所有“问题”(或者说所有33个轴)。
但是还有另外一种可能的解释。如果粒子的自旋是完全确定的——但是依赖于和这个宇宙的状态相关的别的东西。这就好像“二十个问题”中的一个玩家它不管对手问什么问题,只要对方问的问题是以“是不是”开头,那么这个玩家就在脑子里确定选一个驴子,并回答是,否则,这个玩家就选马,并回答否。在这种情况下,它的回答也是可预先确定的即使他在脑子里一个对象也没选。
Conway和Kochen说他们闲在证明了粒子的响应是无法被预先确定的,即使后面这个认为可行的解释中。“我们可以证明没有任何算法和方法,能让粒子可以事先给出唯一以及确切的答案,”Conway说。“我还是很惊奇我们居然能证明这一点。”
他们为他们的证明编造了一个想法上的实验。可以纠结两个自旋1的粒子这样他们的自旋就在每一个可能的轴上都一样,并且保持如此,即使他们彼此相隔很远。这样纠结两个粒子,然后将其中一个发给位于火星的叫做Alice的物理学家,另一个发给位于地球叫做Bob的物理学家。根据相对论,这两个粒子之间是不能传递信息的。Alice和Bob分别在某个他们自由选择的轴上探测粒子。如果 Alice和Bob碰巧选择了相同的轴,那么他们会得到相同的答案。
现在,想象该粒子就像“20个问题”的玩家,它选的对象有时候是一头了驴,有时候是一匹马,根据不变的规则决定什么时候回答哪种动物。无论规则是什么,它都作用于纠结的两个粒子中的每一个,并且可以造成他们有同样的自旋。这就好像“20 个问题”的玩家被克隆了,并且二者都被强制针对相同的动物给出回答。
但是Conway和Kochen证明了这种情节对于互不通信的粒子是不可能的。他们调用了老的Kochen-Specker悖论来证明如果自旋1粒子的行为是可预先确定的那么它就不允许“改变它的动物”,它就不能给出与1-0-1相一致的答案。所以如果Alice和Bob幸运地选择了同样的轴,那么他们应该能强迫粒子要么结果不同要么违反1-0-1理论——这与实验结果相矛盾。
Kochen和Conway说解决悖论的最佳方法就是接受粒子的自旋只有到它被测量的时候才存在这个论断。不过还有一种方法跳出他们的套:假设当时Alice和Bob对于选择哪个轴进行测量并非自由的选择。那么大自然会神秘地阻止他们去选择会触犯规则的那些轴。Kochen和Conway不能完全消除这种可能性,不过Kochen说,“任何走在大街上的人都会说:‘别搞笑了’很自然的感觉是,当然了,我们会根据我们自己的自由意志来做。不能完全消除这种可能性,但是就目前我们所知而言,无疑我们可能选择在实验中按哪个按钮。”
理想情况下,一个数学证明应该解决一切的不确定性,但是Kochen和Conway并没有让很多他们提到的物理学家相信。“我不相信”,Rutgers大学的Sheldon Goldstein说,他是一名Bohm支持者。他认为这些言论没有包含什么新东西,而且他对自由意志只是实际存在(而非原理上)的观点感到满意。四年前,两位数学家发布了他们的成果后,他和他的助手花了很长时间与两位科学家探讨了这些问题。两位科学家的新版理论,在7月21日,发表在了 Arxiv.org,旨在根据批评的观点来强化理论结果。然而,大家还未达成共识。“当人们不能互相沟通的时候,还是非常郁闷的”Goldstein 说,“我们知道在原则上是对的,但是你认为这不可能。”
不过,荷兰的Utrecht大学的Gerard’t Hooft——他获得了1999年的诺贝尔物理学奖——说他俩的解决是合法的,不过他选择了确定性原理而非自由意志。“作为一个坚定的确定论者,我会说那没错,一个实验者选择去测量什么是从开天辟地那时就已经确定了,包括那些东西——他决定称之为光子——的属性,”’t Hooft说。“如果你坚信确定性原理,你必须自始至终坚信它。不能逃避。Conway和Kochen这里用一种优美的方式证明了对伪确定性原理的半心半意的信仰是无以为继的。”

关于Erlang和SMP的一些说明

原文:http://groups.google.com/group/erlang-questions/browse_thread/thread/7827f5e32681ca8e
by.Kenneth Erlang/OTP team, Ericsson
译:ShiningRay
以下是一些Erlang SMP实现的细节和与性能与伸缩性相关一些简单介绍。
几周之内还有有一个关于多核如何运作以及未来如何发展的更详细的介绍。我打算将一些内容放在我的报告中,将于9月27日的ICFP2008,Erlang Workshop在Victoria BC展示给大家。
没有SMP支持的Erlang VM只有1个运行在主处理线程中的调度器。该调度器从运行队列(run-queue)中取出可以运行的Erlang进程以及IO任务,而且因为只有一个线程访问他们所以无须锁定任何数据。
而带有SMP支持的Erlang VM可以有一个或多个调度器,每个运行在一个线程中。调度器从同一个公共运行队列中取出可运行的Erlang进程和IO任务。在SMP VM中所有的共享数据结构都会由锁进行保护,运行队列就是这样一个由锁保护的数据结构。
从OTP R12B开始,如果操作系统报告有多于1个的CPU(或者核心)VM的SMP版本会自动启动,并且根据CPU或者核心的数量启动同样数量的调度器。
你可以从“erl”命令打印出来的第一行看到它选择了哪些参数。例如:

Erlang (BEAM) emulator version 5.6.4 [source] [smp:4] [asynch-threads:0] …..

其中“[smp:4]”表示SMP VM运行了4个调度器。
默认值可以用“-smp [enable|disable|auto]”来替换,auto是默认的。如果smp被启用了(-smp enable),要设置调度器的数量可以使用“+S Number”其中Number是调度器的数量(1到1024)
注意1:运行多于CPU或核心总数的调度器不会有任何提升。
注意2:在某些操作系统中一个进程可使用的CPU或者核心的数量可以被限制。例如,在Linux中,命令“taskset”就可以实现这个功能。Erlang VM目前还只能探测CPU或者核心的总数,不会考虑“taskset”所设置的掩码。正因如此,例如可能会出现(已经出现过了)即使Erlang VM运行了4个调度器,也只使用了2个核心。OS会进行限制因为它要考虑“taskset”所设置的掩码。
每个Erlang VM的调度器都运行于一个OS线程上,是OS来决定线程是否执行在不同的核心上。一般来说OS会很好地处理这个问题并且会保证线程在执行期间运行于同一个核心上。
Erlang进程会被不同的调度器运行,因为他们是从一个公共运行队列中被取出,由首先可用的调度器运行。
性能和伸缩性
只有一个调度器的SMP VM要比非SMP的VM稍微慢那么一点点。SMP VM内部需要用到各种锁,不过只要不存在锁的争用,那么由锁引起的开销不会非常大(就是锁争用上面需要花时间)。这也解释了为何在某些情况下,运行多个只有一个调度器的SMP VM要比包含多个调度器的单一SMP VM更加高效。当然运行多个VM要求应用可以按照多个并行任务的方式运行并且之间没有或者几乎不通讯。
一个程序是否能在多核上的SMP VM中良好地进行提升很大程度上取决于程序的性质,某些程序可以保持线性提升至8核甚至16核,同时其他某些程序基本不能提升,连2核都不行。实际应用中很多程序都能在主流市场的核心数上得到提升,见下文。
若并行的持续“通话”由每个核心一个或多个Erlang进程来表示,实际的支持大量通话的电信产品已经先现出在双核和四核处理器上不俗的伸缩性。注意,这些产品是在SMP VM和多核处理器出现很久以前按照普通的Erlang风格来写的,他们也能无须任何修改甚至不需重新编译代码就能从Erlang SMP VM中获益。
SMP性能得到持续改进
SMP实现正被不断改进以便能得到更好的性能和伸缩性。在每个服务发布版R12B-1,2,3,4,5…,R13B等等中,你都能发现新的优化。
一些已知的瓶颈
单一的常见运行队列随着CPU或核心的数量的增加会成为一个显著的瓶颈。
这从4核开始往上就会显现出来,不过4核仍然可以为多数应用程序提供不错的性能。我们正在从事一个每个调度器一个运行队列的解决方法作为目前最重要的改进。
Ets表格会引入锁。在R12B-4之前在每次对一个ets-table的访问中会用到两个锁,但是在R12B-4中meta-table的锁被优化过,可以显著减少争用(前面已经提到争用是有很大代价的)。如果很多Erlang进程访问同一个表格,就会有很多锁争用造成性能降低尤其当这些进程主要工作是访问ets-table。锁存在于表级而非记录级。注意!这也会影响到Mnesia因为Mnesia用到了很多ets-table。
我们关于SMP的策略
当我们开始实现SMP VM的最初,我们就确定了策略:“首先让它可以运行,然后测量,然后优化”。自从2006年五月我们发布了第一个稳定的SMP VM(R11B)以来,我们一直遵循着这个策略。
还有更多已知的东西可以改进,我们会按照性能的收益大小先后各个击破。
我们将主要的精力放在多核(大于4)上更好的连续伸缩性上。
卓越典范
即使SMP系统有还有一些已知的瓶颈不过已经有不错的整体性能和伸缩性,同时我相信在让程序员利用多核机器事半功倍方面,我们是一个卓越的典范。

Slapp: 简易聊天墙的Merb教程

有问题或评价,请联系: socialface@gmail.com
程序截图: http://www.socialface.com/slapp/screenshot.jpg
简介
欢迎来到Slapp的教程。本文的主要目标是通过构建一个简易的聊天墙应用来介绍一下Merb微框架的主要组件。
本文其次的目标是成为最好的Merb开放教程并能不断更新。同时,我们希望本教程可以逐渐变得丰富来展现Merb框架的所有方面和开发方式。
许可
This tutorial is Copyright 2008 Social Corp. and is licensed under a Creative
Commons Attribution-Noncommercial 3.0 United States License, available at:

http://creativecommons.org/licenses/by-nc/3.0/us/

相关的源代码以MIT形式的开发源代码许可:

http://www.socialface.com/slapp/source

直接浏览代码:

http://gitorious.org/projects/slapp/repos/mainline/trees/master

也可以直接下载:

http://www.socialface.com/slapp/binary

参与人员名单
本教程最初由来自#merb的Slurry撰写。Slurry在撰写本文时主要参照了Merb的官方文档[^a]以及#merb IRC频道的内容。
在学习Merb的RSpec的过程中,还咨询了John Hornbeck的Blerb[^b],参考了Tim Connor的“Isolate controller and view testing in merb”一文[^c]——虽然帮助很大,真正掌握Merb/Rspec还是得益于来自#merb的benburkert。
中文版由ShiningRay翻译
前期决定
设计上来说,Merb是一个ORM无关的框架。当然,这仅仅是表示有不同的模型层可以选择。对于Merb v0.9.2来说,包括:DataMapper、Sequel和ActiveRecord(来自Rails)。
尽管DataMapper和Sequel都是很好的选择,但现在关注Merb的主流人群基本上都是来自Rails背景;因此,我们在本教程中会继续使用ActiveRecord。
1.) 创建模型
在像Merb这样快速成长的社区中,一个问题可能只需更新或者重装Merb相关的包(gem)就能简单解决,所以让我们先花点时间这样准备一下:
# gem sources -a http://merbivore.com
# gem install merb activerecord merb_activerecord merb_helpers rspec merb_rspec

$ merb-gen app slapp
$ cd slapp

完成了前两行命令后,Merb、ActiveRecord以及Rspec应该已经安装好或已经更新了,同时后两行命令则应该创建了一个初始的空Merb应用。
从这里开始,我们就要告诉Merb:我们要怎样用ActiveRecord,要使用哪个测试框架,以及需要载入哪些确切的merb_helpers包(如表单相关的东西)
编辑:slapp/config/init.rb 并取消第27和42的注释,同时将:dependency “merb_helpers” 添加在
Merb::BootLoader.after_app_loads do 这一行之前:
use_orm [...]