STF项目,全称”Stepover Toehold Facelock“,原因是项目发起人喜欢这个动作,我勒个去……当然作者也给它找了个靠谱一点的解释,叫STorage Farm。

目前主要是日本三大门户之一livedoorloctouch在使用。livedoor称其图片集群规模在70TB,400,000,000个对象(1,300,000,000个复制份),高峰流量带宽400Mbps。按照这个数据计算,大概图片的平均大小是50KB的样子。

perl系原先已经有一个非常著名的分布式文件系统,叫MogileFS,作者说STF与MogileFS的不同时说到:

  1. STF整个是基于HTTP的,而且是PSGI的。这里我理解MogileFS内部是HTTP的,但是fs对外的api是非http的。而且因为时间较早的原因,mogile内部的http服务器是Danga的socket基础的perlbal,现在perl世界都转向使用psgi了。

  2. 代码简单。MogileFS有28000行代码,STF只有6000行。我觉得这里因为mogile全套除了metadata用了mysql之外,全都是perl实现。而STF中采用了Q4M、mysql、memcached、nginx/apache等多种外部组件,加上psgi本身也很省代码。

关于实际工作流程,作者坦言和MogileFS基本一样。

  1. dispatcher,类似mogile里的tracker,主要配置内容就是数据库连接。前端还有个proxy,要点是处理X-Reproxy-URL这个HTTP的header。STF中使用apache+mod_reproxy或者nginx,mogile中使用perlbal。

  2. job queue,STF中使用Q4M或者theSchwartz,mogile中使用gearmand。用来通知worker进行replica等。

  3. MySQL,存储除了文件实际内容以外的所有数据,这里STF和mogile一致。

  4. memcached,为了提高性能,给mysql做缓存的。这里mogile没有,不过很容易在调优时改造加入。

  5. admin interface,mogile是cli端的,STF是psgi的web端。

  6. worker,做数据的replica,delete等,从Q4M里取任务。这个STF和mogile类似。

  7. Storage,支持CRUD即GET/PUT/DELETE的HTTP服务器即可。mogile里是mogstored,STF里是storage.psgi。同样都要在admin interface里添加管理。

然后介绍一些概念:

  1. object,一个url对象,因为STF和mogile一样设计目的是小图片,所以一般来说不会有超过大小的分多块的文件(原文a piece of data),mogile里cli专门针对大于64M的文件要指定–largefile一样。

  2. bucket,一个逻辑上的group。object必须存在于bucket里。这里stf和mogile有些类似又别扭的地方。mogile中,逻辑顺序是这样的:domain->class->keyvalue;stf中,逻辑顺序是这样的:bucket->object。所以一个完整的GET请求会看到object的url是两层目录的样子。

  3. entity,也就是replica的份数。

然后是CRUD的协议:

  1. 创建bucket:PUT /bucket HTTP/1.0即可,成功创建返回状态码201,已存在返回204,url格式不对返回400,其他返回500。因为apache的mod_reproxy模块不支持chunk,所以使用HTTP/1.0协议,不清楚nginx的话,是否可以用HTTP/1.1,不过我记得有文章说在处理小图片的时候,其实HTTP/1.0比HTTP/1.1更好,因为浏览器可以开更多并发连接。

  2. 删除bucket:DELETE /bucket HTTP/1.0\r\n\X-STF-Recursive-Delete: 1\r\n\r\n即可。这个多余出来的header可以指定删除bucket里所有的文件,否则会只清楚bucket保留文件,但是还不清楚这种情况下能否访问到这些孤儿文件呢?

  3. 创建object:PUT /bucket/path/to/my.png HTTP/1.0…即可。有两个附加的header,一个叫X-STF-Replication-Count,一个叫X-STF-Consistency。前者在保存好第一份之后返回响应,然后通过Q4M让worker开始replica完指定的其他份数;后者则等到指定的份数都完成后才返回响应。

  4. 获取object:GET /bucket/path/to/my.png HTTP/1.0即可。这里可以使用If-Modified-Since,也可以只使用HEAD请求。如果bucket不存在,响应状态码是500。

  5. 修改object:POST /bucket/path/to/my.png HTTP/1.0即可。不清楚为什么会提供modify功能。一般分布式系统都是搞追加而已。还需要测试的一个是如果直接POST新object会如何?

  6. 重命名object: MOVE /bucket/path/to/my.png HTTP/1.0\r\nX-STF-Move-Destination: /newbucket/newpath/to/my.png即可。又是一个古怪的需求。另外不清楚这两个是真修改了呢,还是在mysql里修改标记了而已。