EC2 笔记

最近两个多月来一直在折腾AWS EC2,感觉需要做一些笔记了

  1. aws api tools 的安装和设置要正确,这个是首要的事情。
  2. firefox elesticfox 这个extension 很方便。也需要设置key-pair
  3. 在instance上要打开端口不仅仅要在 instance 的 firewall 上打开, 还需要通过 aws api tools 的 ec2-authorize 命令来打开端口
  4. 及时把 instance shapshot备份到 aws ebs。 最好能够设定一个日常备份的脚本。 把mysql 的data,以及常用软件的配置文件也放到 aws ebs上
  5. 有重要的更改之后,一定要重新创建一个image,因为每一个instance 在启动之后都是全新的。
  6. ebs volume 需要和 instance 处于同一个地理位置。
  7. 写一个脚本,开机自动运行 associate ip 以及 mount ebs volume 以及 自动启动服务。
Posted in rails | Tagged , | Leave a comment

把yahoo yql 当做 crawler 来使用

在我眼里,yahoo.com 是一个在技术上努力,并锐意进取的公司,从 yahoo.com 开放的众多服务就可以看得出来。 yahoo.com 的这些创意十足的技术人员是 yahoo 的最大资产,也是MS 当初对 yahoo.com 发出收购邀约的主要目标之一。当然yahoo.cn 就另当别论了。

yql 是 yahoo.com 推出的另一项重要的搜索api,yahoo.com 在搜索方面已经有了一些重量级的api,比如说 BOSS 以及 SearchMonkey。 我觉得 yql 对于开发者来说则是另一个惊喜的礼物,通过 yql 的api,开发者就可以通过类似于 sql语法的对internet 上所有的网络资源进行 “查询”。 “查询”的意思就是说,internet 上的所有网络资源相当于一个超级大的数据库 ,通过 yql 的语法,你可以查询到你想要的结果。

yql 的限制非常少,public data 的 access limit 是1000 req/hour, 对于普通的应用来说已经足够了。另外可以通过 yql console 来运行 yql 的测试, yql console 也是学习和了解 yql 语法的最好的地方。

对于yql 来说,有一个另类的做法就是把 yql 当做 crawler 来使用。任何一个website,只要它不禁止 yahoo 爬虫,那么从 yql 里面都可以得到这个website 公开的web pages。

前段时间,我想去抓 aibang.com 的数据,自己写了crawler,后来发现 aibang.com 把我的ip block掉了,于是给自己的crawler 加上了 tor proxy。这样的效果也不好, tor proxy ip 都不知道从哪来的,抓一个 aibang.com 页面都要 1 秒多时间。后来换成使用 yql,省时又省力,问题轻松解决了,因为yql 估计有一堆的服务器帮你去抓数据,aibang.com 还能把这一堆服务器的ip 都 block 掉? 小样。。

如果你要去抓aibang.com的数据,你的yql可以这样写:select * from html where url="http://www.aibang.com"

如果你只需要网页的一部分数据,你可以给yql加上xpath 解析,比如:select * from html where url="http://www.aibang.com" and    xpath='//div[@id="weatherUseInMapview"]'   。 这样就可以得到 aibang.com首页 的天气预报的详情了。

那么 yql 抓到的数据会不会是cached 的数据? 在我的实践中,yql 抓到的数据都是即时的数据,基本上没有cached。

yql现在已经成为我的工具箱里面的必备工具,希望它能对你也有帮助。

Posted in ruby | Tagged , , | Leave a comment

在rails中使用 couchdb 以及 solr

随着项目的向前推进,有一些的问题浮现出来。比如说,有一个model已经有了很多属性,但随着需求的增加,还有不同的属性需要加到这个model里面去。通常的做法就是再往这个model对应的数据库表里添加相应的 column,有些属性有可能只是一部分的数据才需要,往数据库表里添加column的做法也会使得表结构复杂或者臃肿。boss 前些天给了一些key-value db 和 couchdb的资料,让我调研一下,看一看能否解决这些问题。

 key-value db 和 couchdb 这一类什么都能往里仍的数据库最近很火爆,但我觉得这一类数据库还没有具有成为解决关系数据库问题的“银弹”的能力。 在看了一些资料了和做了一些尝试之后,我觉得对于应用来说,固定不变和固定格式的数据适合于使用关系数据库来存储,对于不固定格式(或者说是弹性格式需要?)的数据可以使用couchdb来存放。

 如果只是得出这样的结论的就可以的话,那这篇文章就可以到此为止了。但是 boss 说,使用了 couchdb 以后,那我们原来需要使用 solr 来做搜索的那部分数据如果放到 couchdb 里面去,需要怎么修改来建索引? ok,那我还得继续努力。

介绍使用 couchdb 的rails 资料都是介绍如何在一个全新的项目里面来使用couchdb,如何对couchdb里面的内容进行全文搜索的资料也很少。 这里有一篇 ,不过我不想也不推荐使用这种方法,搜索还是应该交给搜索引擎来做,数据库做数据库的事情就可以了。couchdb-solr 使用了couchdb 的calllback 来将 couchdb 和 lucene(solr)结合的,但是需要编译安装它修改过的 couchdb,这样似乎也不可取。

我今天研究了一下,找到了一个稍微简单的方法,至少不需要改动现有的插件和太多代码。

要在rails 中结合使用 mysql ,couchdb 和 solr ,我们需要使用另外一个插件-- stuffing。 stuffing 可以让你把一部分数据存储在 mysql,另外一部分数据存储在 couchdb,只需要加入 stuffing 的声明,很酷。

 把数据放到 couchdb 里面只是第一步,第二步需要把放到couchdb的数据做成索引,让solr 可以搜索得到。比如说我们有一个叫 Book 的model, Book 有一个tags 的属性需要放到couchdb里面,我们可以这样声明:

class Book< ActiveRecord::Base

  stuffing

  acts_as_solr :fields => [

  :title, :body,

  :tags,

  :facets=>[:title, :body, :tags]

  def tags

    self.stuffing_tags

  end

end

book = Book.new

book.stuffing_tags = "book, couchdb"

book.save

ok,就这样,tags这个属性就已经被存储到couchdb,并且也放进了 solr 的索引里面去了,就可以使用 Book.find_by_solr("book")来找到新建的 book了。定义 tags 方法的目的就是告诉 acts_as_solr 怎么找到 tags 的值。

如果我们放在 couchdb里面的数据是 hash,那么我们需要做的工作稍微多一点,但是原理是一样的。比如说一本书在不同的商店的价格是不一样的。那么我们需要想下面这样来定义 Book model。

class Book< ActiveRecord::Base

  stuffing

  acts_as_solr :fields => [

  :title, :body,

  :tags,

  {:dangdang_price => :range_float},

  {:zoyo_price => :range_float},

  {:chinapub_price => :range_float},

  ],

  :facets=>[:title, :body, :tags]

  def dangdang_price 

    self.stuffing_price['dangdang']

  end

  def  zoyo_price

    self.stuffing_price['zoyo']

  end

  def chinapub_price

    self.stuffing_price['chinapub']

  end

  def tags

    self.stuffing_tags

  end

end

 book = Book.new

book.stuffing_tags = "book, couchdb"

book.stuffing_price = { 'dangdang' => 123.8, 'zoyo' => 120.5,  'chinapub' => 110.6}

book.save

这样price的价格就以hash的形式存在 couchdb,并且可以使用 Book.find_by_solr("dangdang_price:[100 TO *]") 来找到相应的book了。定义这些多余的方法的目的就是把 price 这个 hash flatten。 这种方法对于多重hash 也可以使用,但是要做的工作也稍微多一点。如果你能有其他的方法,请告诉我。

Posted in rails | Tagged , , | 1 Comment

再见,2008

回过头来想,2008年对地球来说,这都算是不平凡的一年。对我来说,也许是转折的一年。

08年的差不多这个时候,我开始自学ruby 和 rails,差不多半年之后开始接手第一个离岸外包,再三个月以后离开原来所在的小公司,投入到另一个更小的小小公司,然后开始了在家 soho 的生活。我离开以后,原来的公司现在差不多已经分崩离析,坚持不下去了,这当然和我没什么大的关系。

 所谓小小公司,意思就是说人相当的少,基本上也就只能敏捷开发和敏捷管理。但幸好小小公司现在还没有被金融危机影响到,可以作为一个避风港,幸好我们都还有一些梦想(也就赚钱而已),幸好我还能有一股学习的冲劲。只不过发现soho的最大的一个坏处是,你拼命的想把工作在一天内做完,因为你随时都可以工作,但其实工作是怎么也做不完的。。。

 希望2009能更好一点,至少金融危机能过去,大家都有饭吃。 

再见,2008。 

Posted in 生活 | Leave a comment

第一个android程序

最近看了一些android的教程,在元旦的时候,利用休息时间写了一个 android 程序。这个程序基于 mapactivity,调用了 yelp(相当于美国的口碑网) 的api,可以用来查看美国部分城市的生活咨询,比如说那条街上有哪些饭馆和酒吧。感觉写android程序还是挺有意思的,但是android sdk1.0 对于sound的支持不够好,貌似 sdk1.1 也没有解决。iphone上与声音或者音频相关的程序是相当不错的,android 还需要更加努力才行。

[http://www.youtube.com/v/cPkM0w2mf3s&hl=zh_CN&fs=1]

Posted in ruby | Tagged , | Leave a comment

awesome! Evernote + Eye-Fi = Instant Photographic Memory

老外的创意还真是可以。。。 具有 WIFI 功能的 SD卡!

不说什么了,你都不用把SD卡插到电脑上,再把相片从SD卡倒到电脑,然后再从电脑倒到你的网络相册。使用这种带WIFI功能的SD卡,一不搞定,直接上传到网络相册,而且还可以附带相片的地理位置信息的功能。

 连接:http://blog.evernote.com/2008/12/10/evernote-teams-up-with-eye-fi/

Posted in 创意 | Leave a comment

D90 入手,牛刀小试

dsc_0102.JPGdsc_0083.JPGdsc_0098.JPGdsc_0118.JPGdsc_0200.JPG

Posted in 生活 | Leave a comment

acts_as_geocodable: 最好的rails geokit!

也许你用过这个rails geokit,在这个帖子里面对一些现有的ruby/rails geokit进行了对比。但是我要说的是,到现在为止,acts_as_geocodable 是最好的rails geokit。

acts_as_geocodable  的特点在于,不仅仅支持对于精确location 的查找,还在与能够支持对 locality 的查找。 关于 location 与 locality 的区别,请看这个文章

demo:

比如说我创建了在 san francisco bay area 附近的几个parking garage 的位置:
>> l = Location.create :street => "123 Ofarrell St", :region => "CA", :postal_code => 94102, :locality => "San Francisco"
=> #<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">
>> l = Location.create :street => "500 Beach St", :region => "CA", :postal_code => 94133, :locality => "San Francisco"
=> #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">

只要我们保证location的输入是正确的,

我们就可以以各种方式来查找到这些位置,比如
>>  Location.find(:all, :within => 100, :o rigin => "San Francisco, ca")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>>  Location.find(:all, :within => 100, :o rigin => "San Francisco bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>>  Location.find(:all, :within => 100, :o rigin => "bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>>  Location.find(:all, :within => 100, :o rigin => "sf bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>>  Location.find(:all, :within => 100, :o rigin => "silicon valley")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]

按照zipcode来查找
>>  Location.find(:all, :within => 100, :o rigin => "94101")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>>  Location.find(:all, :within => 100, :o rigin => "94108")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]

我们创建一个位置的时候,只要保证street正确,可以不输入 zipcode, geocodable 会自动调用 google map 返回 zipcode
>> l = Location.create :street => "3 Embarcadero Ctr", :region => "CA", :locality => "San Francisco"  (no zipcode)
=> #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">
>>  Location.find(:all, :within => 100, :o rigin => "silicon valley")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">]

比如说 University of California-Berkeley 离 bay area 和 Oakland 都比较近,那么都可以在这两个地方附近找到:
>> l = Location.create :street => "2921 Adeline St", :region => "CA", :locality => "Berkeley"
=> #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">
>>  Location.find(:all, :within => 30, :o rigin => "bay area")
=> [#<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>>  Location.find(:all, :within => 10, :o rigin => "oakland")
=> [#<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]

最后有一点,silicon valley 和 bay area 在google maps 上的精确位置是不一样的,因此要限定范围的大小才能找到相应的目标。
>>  Location.find(:all, :within => 10, :o rigin => "San Francisco")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">, #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>>  Location.find(:all, :within => 80, :o rigin => "silicon valley")
=> []
>>  Location.find(:all, :within => 90, :o rigin => "silicon valley")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">, #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>>  Location.find(:all, :within => 10, :o rigin => "bay area")
=> []
>>  Location.find(:all, :within => 30, :o rigin => "bay area")
=> [#<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>>  Location.find(:all, :within => 40, :o rigin => "bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">, #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]

 

geocodable 还有一点非常的好,就是它会把所有已经查询过的请求生成的结果放到数据库去,比如说执行
Location.find(:all, :within => 40, :o rigin => "bay area")之后,就会把 bay area 的经纬度信息保存到 geocodes 这个表里面去,下一次再执行相同的查询的话,就直接从 geocodes 这个表获取 bay area的信息,而不需要再调用 google maps 的api 了。

还可以通过Location.find(:nearist, :within => 40, :o rigin => 'bay area')来查找距离最近的位置。可以通过 Location.find(:all, within => 40, :o rigin => 'bay area', :o rder => 'distance') 来将查找结果按照距离排序。

Posted in rails | Tagged , | 2 Comments

翻译:当下,怎么启动一个新公司

原文:If I Started A Company Today  by Andrew Hyde

经济危机?正是开公司的好机会。

 Chris Brogan发表了一篇非常好的文章--如果今天开公司,我该怎么办?这篇文章也让我思考了同样的事情。由于我已经做足了功课 ,所以看起来这对于我来说会稍微容易一点,但我仍然会按照下面的一些步骤来进行:

第一步:倾听

什么是你的激情所向?是的,什么才是你真正喜爱 的? 什么东西还没有达到市场的需求? 这些东西可能很明显,可能是一个机会。什么是你朋友经常向你抱怨的?什么才是用户使用某种服务的真正目的(这些目的也许和该服务被期望使用的方式大不相同)?

Niel Robertson 告诉我们不需要自己产生那么一个原创的创意,只需要倾听别人的想法。下面是一些你在倾听的时候可以提的问题:

  • 你是否看见别人在太空中赚钱 ? (原文:Do you see others making money in the space)
  • 你是否知道你要解决的是什么问题?
  • 你的专长在什么地方?

比起自己,你更需要倾听别人的想法,但是两者都很重要。

第二步: 建立团队

在你有这么一个创意之前,我建议首先建立你自己的团队,因为这一点很重要。但在团队建立之前,你需要了解你的业务领域。你可以和团队一起实现你的创 意,但那些仅仅想要开一家餐馆的人是不会和那些想要进行在线零售业务的人成为好的创业伙伴。对于团队成员,要制定好权益分配,要尽可能的公平,要丑话说在 前面。

 挑选合伙人意味着这件事情是一个长期的事情,因此你要认真的挑选一个合伙人。

第三步: 时间表

你的创意会在最开始的几个月里面会有很大的改变。下周一晚上,我会和团队讨论一个常规的时间表,目标是在一个月后能够实现一个原型。

  • 挑选一个工作主题
  • 创建一个博客(这里有一个不错的例子
  • 调研相关的法律规制
  • 为你的商业计划挑选一个宗旨。在早期,宗旨会指引着你们的团队前进,并且让你们处于一个更好的位置。可以看一下Kawasaki的例子

创建一个六个月的计划,该计划要包括里程碑。让你和团队都坚持诚恳的态度(对待时间表)。

把公司的名字确定下来,用它注册在你能想到的每一个服务(twitter,wordpress,myspace,etc)上。

第四步: 反馈

尽可能的和你认为是聪明的家伙讨论你的创意。学会如何去倾听别人的意见,把每一个人的建议记录下来并且考虑。 询问别人是否曾经听说过你们的团队/公司/领域。在TechStars, Knight News Challenge 或者当地的小额信贷这些地方,询问别人觉得是否这些机会适合你。在将来如果你要找一些资金的话,那你需要和一些投资者搞好关系(你要知道筹集资金将会是一个很长,有时甚至是痛苦的过程)。

第五步: 参与

我会找一些最初的客户,并且尽可能的让他们参与我们的项目中来。我把这一部分称为"创建你的产品",如果你离开你的客户的参与或者不考虑客户就自行 创建产品的话,那么你就失去了在当下创建一个公司的最大的优势。我喜欢这种想法,就是公司不是在创建产品,而是在鼓励真正的客户(不局限于早期的用户)参 与并由此产生驱动产品的路线图。

我写了这些步骤,并想把它应用于类似Startup Weekend这样的项目,这个项目应该是一个Web2.0的、基于客户的web 应用程序。这些步骤应该也适用于创建一个实体店或者一个产品线。

轮到你了

这些对你有帮助吗?我是否有遗漏了什么?你准备动手干点什么吗?

Posted in 翻译 | Leave a comment

在ruby 中使用MemcacheDB

MemcacheDB 并不是一个 cache 的方案,而是由 sina团队开发的一个key-value 数据库,而我更愿意把它称为一个大 Hash。 MemcacheDB的指南请看 这里MemcacheDB 的协议与 memcache协议大部分是兼容的,因此可以用任何支持 memcache 协议的客户端来对它进行读写访问。

 最近一个项目,我们需要存储一些临时文件,将来可能还需要存储一些小的文件,这些文件将来必须可以在多台主机之间共享,因此我们选择了MemcacheDB 来完成这些功能。

MemcacheDB 的安装指南在这里MemcacheDB 依赖 Berkeley-DBBerkeley-DB做了大部分和存储相关的事情。MemcacheDB使用一下命令启动:

 memcachedb -p21201 -d -r -u root -H ./env -N -v

可以使用 -P 选项来指定 MemcacheDB 的Pid。如果你想以备份模式启动MemcacheDB,需要运行以下的命令:

  start a master (read&write):

memcachedb -p21201 -d -r -u root -H ./env1 -N -R 127.0.0.1:31201 -M

start a replcas (read-only):

memcachedb -p21202 -d -r -u root -H ./env2 -N -R 127.0.0.1:31202 -O 127.0.0.1:31201 -S

在ruby中,据说 ruby memcache client有一些bug(据说而已),因此我们使用了fiveruns-memcache-client 来连接  MemcacheDB

require 'rubygems'
# require fiverun-memcache-client,
# see http://github.com/fiveruns/memcache-client/tree/master
require 'memcache'

MEMCACHEDB_SERVER_ADDRESS = 'localhost:21201'
CACHE = MemCache.new MEMCACHEDB_SERVER_ADDRESS

# write memcachedb

file_name = File.join(File.dirname(__FILE__), 'test-text.txt')
raw_data = File.open(file_name, 'r'){|f| f.read }
CACHE.set(file_name, raw_data, 0, true)

 # read memcachedb
result_data = CACHE.get(file_name, true)
file = File.new(file_name + '.restore.txt','wb+')
file.write(result_data)
file.close

代码很简单,只需要注意一点,如果你使用 fiveruns-memcache-client往 memcachedb 写入的不是字符型数据,而是ruby中的对象的时候,需要把ruby 对象序列化以后才能写入。要做到这一点,只需要在 CACHE.set(file_name, raw_data, 0, true) 的方法中设置最后一个参数为true就可以了,同时,读出数据的时候,也需要CACHE.get(file_name, true)。

Posted in ruby | Leave a comment