設計 EmRiak 的背後
其實 Riak 也出來好久, 在社群的力強其實以一個新秀來說也還算強勁.
光以他 client 的數量就可得知. 其中 ruby clinet 就有將近 10 個?
但有三個好像都是官方貢獻的… :p
其實設計 EmRiak 的背後動機並不多, 除了覺得大部分的 client 對 em 的支援度並不好外, 大概就是使用起來的爽度了..
使用別人的東西就是要習慣&接受他的寫法..
如果自己有能力, 又很難接受別人寫法, 那麼自己寫是比較 Happy 的..
只是多數狀況我們是沒時間, 沒心力, 或是有心無力..
以 gem 來說, 繼上次自己寫 oAuth Server 之後. 這是第二個.
但想來自己之前也做了一個 micro framework 級別的東西.. 不過這就是話外了.
算起來, 這次的 gem 才是真的有 release 出來給公眾使用的..
所以 Coding Style, 寫法, 嚴謹度都是會被審核, 所以自己寫起來也格外的戰戰兢兢..
當然, 怎樣用心也還是不會寫得太好, 畢竟大神多, 自己是小咖..
所以到最後就是秉持著 「可以動& 不要髒」的原則下去設計.
反正大神有用到&看不下就大概就會 commit 一堆 code 上來了.. :p
EmRiak 目前的支援有 :
- 基本的 crud
- async 的 crud
- Hybrid code style
- MapReduce
- SecondaryIndex
希望在 0.3 版會有 :
- FullTextSearch
- LinkWalk (其實已經寫一半了..@@)
- MapReduceDeploymentTools
- OrmModelWithSequel
加油..
如果你對它有興趣, Commit 他吧 : EmRiak
為何選擇 Riak 高於其他的 NoSQL
接觸 NoSQL 兩三年之中, 不算長的時間內, 接觸了許多各種不同的 NoSQL .
使用 NoSQL 的原因多半還是基於
1. 資料量太大, 現有架構很難負荷. ( 儘管已有很多解決方案, 但 SQL 擴展不好搞仍是事實… )
2. 特殊需求, 複雜的運算導致現有 DB 不好處理. ( Schema 及 SQL 語法的設計是跨時代, 但有時候它也是兩面刃 )
3. SQL 太貴.. ( 好吧. 很多 NoSQL 是免費的. 這也算是個理由)
換個說法, 其實就是沒事不會也不要用 NoSQL.
上面那句話對於舉辦 NoSQL 聚會的我來說好像是打臉.. 但其實真的是這麼一回事..
MySQL 其實很不錯, 只是一旦把一個簡單的東西放大 100 倍, 1000 倍, 問題就來了.
我也常在聚會上說, 其實 MySQL 很好, NoSQL 只是 Not Only SQL.
而我們實際內部也是 MySQL + NoSQL 的處理方式.
至於打臉.. 跟這篇主題沒關係, 所以也就無所謂了…
實際使用過的大概有 Redis, Cassandra, CouchDB, Neo4j, MongoDB, InfoGrid, InfiniteGraph, Sones…etc
當然,眾多的選擇之中, 最後我選擇了 Riak.
原因 :
基於 Dynamo 的擴展性設計 :
這樣的設計有好有壞, 最大的優點是可以在 Partition 部份大大加分.
我們不會因為一個 DB Instance 死掉, 就讓資料無法存取, 或某幾台負荷大增.
也因為 Erlang 語言本身的特性, 所以在 穩定度 和 容錯率 上是無庸置疑.
一般來說, 目前對於 Scale 的部份要嘛是 基於 Dynamo ( Riak, Cassandra, Amazon Dynaom.. ) , 不然就是 Master/Slave ( Neo4j, SQL, Redis…) .
Dynamo 自身就是 Scale 的一個機制, 無須借助其他工具或方式.
而 Master/Slave 則需要使用類似 ZooKeeper 來管理主從關係, 進而決定 誰寫誰讀 .
Riak 除了基於 Dynamo 之外, 更設計了一個叫做 「 Ring 」 的擴張方式.
Ring 的設計理念很簡單. 透過上圖我們可以看到, Riak 預設將 db cluster 區分為 64 個區塊 ( partition ). 每一個顏色代表一個 node .. 我們可以看到顏色每四個就循環一次..
代表每 4 個 node 為一組, 而每一組的同顏色, 其資料理論上是相同的.
對於 Partition 的預設數, 如果 64 不是你喜歡的數字, 你也可以設成 32, 16, 或著喜歡大數字 512, 768.
這個數字代表的是有幾個 partition 和資料備份數.
在初期, 我們可能還是使用 4 台實體機器, 每台機器有一個 riak instance.
此時的以 64 partition 來說, 代表每台機器實際上存在著 16 個 partition.
當你的 riak 擴展至很大規模時, 則可以讓每台機器就是一個 partition.
這樣的優點是效能快, 資料安全度提高.搜尋的高靈活度以及優秀效能表現 :
對我來說, 雖然 Map/Reduce 永遠不等同於使用 Graph .
但,如果公司的產品是需要一些 Graph 關係處理, 但是更需要效能表現以及未來擴展考量, 而且也還有其他地方需要 map/reduce ..
那麼拋棄方便好用的 graph 而寫點難寫的 map/reduce 是完全可以接受的事.
Map/Reduce 說難不難, 說簡單其實也不簡單. 如何設計良好的 key, 並寫出好的 map/reduce 其實並不是一件那麼輕鬆的事.
尤其當需求複雜化, 演算法的困難度是以倍數提升..
現階段的 Riak 在 Map/Reduce 上仍是有點缺陷, 比如不能直接使用 Reducer ( 似乎在 1.2 版已修正 ).
以及透過 JS VM 來處理 Map/Reduce 效能比使用 Erlang 慢許多..
而且 Protocol Interface 是不能做 Map/Reduce的. ( 透過 HTTP 的 JS VM 才可以)
但如果你願意寫點 Erlang , 那麼這些問題全部都能被解決..
關於 Riak Map/Reduce 的實作, 可以參考 Introduce to Riak map/reduce
幾個Riak 的 Map/Reduce 優點 :
可以用 Javascript, Erlang 寫
可調整多執行緒的數量, 而若使用 js, 也可以調整 js vm 的執行數量
愈多台速度越快
KeyFilter 可以在進行 map/reduce 前就先過濾資料, 加快搜尋速度
當然, 除了 MR, Riak 還提供其他的搜尋方式, 包含 Secondary Index 以及 Full-Text Search.
Secondary Index 簡單來說就是可以對每筆資料加上一個 Index 索引.
我則很喜歡把這個概念講成是對資料加個 tag. 所以加了 tag 之後就可以用 tag 來搜尋資料.
值得一提的是, 當 Riak 的 Partition 數量超過 512 個時, Secondary Index 會有效能問題.
這與 Secondary Index 的實作方法有關係, 有興趣可以看這裡 : When not to use secondary indexes
而 Full Text Search 顧名思義,特別適用在大篇文章檢索, 或斷詞斷句, 文意判斷 之類的功能上.彈性靈活的架構設計
BitCast 為預設的儲存元件, 我們對 Riak 操作的其實是 Riak-Core .
如果我們對於 BitCast 的儲存效能不甚滿意, 其實可以轉換其儲存元件.
目前 Riak 支援較好的是 LevelDB. 如果會調校 LevelDB.. 據說可以比原始的快上十幾倍..
當然, 也可以透過上層再加載 Hadoop , 比如替換掉 Riak 本身的 Map/Reduce.
至於為何要替換掉 Riak 的 Map/Reduce 那就又是另一回事了….
再來, 也可以使用 Memory 當儲存元件, 如此, 我們就可以把 Riak 當 cache 使用, 幹掉 redis 了 (大誤可預期的操作及擴展環境
「可預期的操作及擴展環境」聽起來很模糊, 這樣說好了 :
我們不用半夜不睡覺一整晚當英雄, 跟 database 對幹, 然後隔天醒來大家還問你說為什麼精神不好, 然後你解釋之後大家還覺得沒什麼了不起.
Riak 的可預期是當你第一天建立一個 Node, 到一年後你建立 1000 個 Node, 其過程都一樣簡單, 容易, 沒有問題.
你不用再做什麼 repliaction, 搞一堆 backup, 然後考慮一堆 failover.
因為 riak 本身都幫你處理好了.
我想, 這有很大一部分的原因是因為 Erlang.
Erlang 本身是一個 Functional Programming Language. 對 Erlang 稍微理解的, 應該都知道, 它最著名的是穩定性 和 容錯能力.
常見的 Case 大概就是提款機這種不能斷線, 容錯力要高 的產業.
如果我們使用一般的語言, 要更新一些程式大概就得先停機, 更新後再重啟.
儘管有 load balance 這類的解決方案.. 但這些方案都還是有自己的問題..
而最著名, 而且也被實際驗證的大概就是 apache hadoop 專案下的 zookeeper, 但那又是另一回事了.
也許 NoSQL #10 會來個 「從 Zookeeper 和 Dynamo 來看大資料擴展」.
這幾點講完之後, 相信一定沒有說服任何人..
不管是 MongoDB 的使用者, 或是 Redis, 甚或其他DB..
對於沒接觸過的 DB 不敢講, 但就個人觀點來和目前接觸過的 DB 比較..
也許不盡客觀, 也許資料過時, 歡迎討論 & 幫忙勘誤. :)
Btw, 這是在 NoSQL #5 關於 Riak 的 Slide, 有興趣的可以去看看 : Meet Beautiful Riak
不過還是老話一句, 不管是 NoSQL, MySQL, 適合自己的最好.
NoSQL 是 Not Only SQL .. :)
Riak Ring 操作
操作多台以上的 riak 而形成 riak-ring.. 我們有幾個地方要注意.
1. aws 上 riak 需使用 private ip.
2. port 開 0-65535 ??
3. riak stop
4. rm -rf /var/lib/riak/ring/* 來清除所有 ring 的資料.
5. riak start
6. riak-admin join 其他 ring ip .
Install Riak
Install Riak
All in 1 Script
This script is for R15B02 & riak_1.2.0 and has been tested under Ubuntu with GCC install.
wget http://www.erlang.org/download/otp_src_R15B02.tar.gz; tar -xvf otp_src_R15B02.tar.gz; cd otp_src_R15B02; CC=gcc-4.2 CPPFLAGS=’-DNDEBUG’ MAKEFLAGS=’-j 3’ ./configure —enable-hipe —enable-smp-support —enable-ssl —enable-threads —enable-kernel-poll —enable-darwin-64bit; make; sudo make install; cd ..; wget http://s3.amazonaws.com/downloads.basho.com/riak/CURRENT/riak-1.2.0.tar.gz; tar -xvf riak-1.2.0.tar.gz; cd riak-1.2.0; make all; make devrel; cd dev; ls; dev1/bin/riak start; dev2/bin/riak start; dev3/bin/riak start; dev4/bin/riak start; ps aux | grep beam; dev2/bin/riak-admin cluster join dev1@127.0.0.1; dev3/bin/riak-admin cluster join dev1@127.0.0.1; dev4/bin/riak-admin cluster join dev1@127.0.0.1; dev2/bin/riak-admin cluster plan; dev2/bin/riak-admin cluster commit
What this script included ?
1. Install erlang
2. Install riak
3. have 4 riak nodes
4. start riak nodes
5. join riak nodes to cluster
Some Notes
If you use riak1.2.0.. You need use R15B01 and after.
If you use riak1.1.x.. You need use R14B03 and after.
Configurations
You should take care with “open files” when you operate riak.
Deal with it. Add following into .bash_profile
ulimit -4096
關於 RDS 的效能
這一陣子在重構後台的過程中, 雖然也解掉了很多 bugs, 並加快非常多效能.
但, 資料庫 CPU 爆衝 100% 的問題仍偶有發生.
我一直以為是自己的程式寫得不好, 但後來才發現應該是 RDS 本身的問題..
為何會如此推測? 因為基本 test 都有通過.. 所有動作也都大量 try 過.
再加上這篇討論 : https://forums.aws.amazon.com/message.jspa?messageID=296482
所以代表著也有人遇到同樣的問題..
至於為何當初使用時沒注意到, 因為當初設計是以 prototype 下去設計, 主要是給我們的人 demo 和 private test 用.
壓根沒想到使用者成長的速度那麼快..
顯然目前我們的使用成者, 和同時在線的人數頗高.. 這應該是要高興的.. :)
查了一下 Xeround .. 可以看比較表
往下拉可以明顯看到, rds 在 concurrent 過 15 之後 through output 就明顯往下掉.. 而 latency 明顯往上升..
這數據可能某個程度再次證明我們所遭遇的狀況..
接下來.. 我們會停止使用 rds, 改用 xeround 或其他家. ( 正在研究)
同時, 也會開始啟用 nosql .. :)
給 Ruby 愛好者的 iphone 開發利器 : RubyMotion
寫 Ruby 久了的人很難再去寫其他的語言..
因為 Ruby 本身的語法特性, 更接近人性, 基於 Ruby 原作者的「Ruby是設計給人的程式語言,而非機器」( We are masters, they are the slaves ).
Objective-C 有其好處, 對於熟悉 C, C++ 的人要上手及轉換可能頗快.
但它比較 Ruby 有個嚴重讓人無法忍受的, 就是語法過於冗長..
當然, 同樣的情形也出現在 Java ( 所以我從Java逃走了… )
於是乎 MacRuby 也就因此而生..
MacRuby 是一套開源 ( 免費 ) 的 Ruby -> Mac 工具.
讓我們可以透過寫 Ruby 來產生 Mac 上的應用, 可以直接呼叫 cocoa API.
而 RubyMotion 則是前幾天發佈的一套 「 基於MacRuby 」 的 iphone 開發工具.
在實際使用幾天之後, 會發現 :
1. 雖然是寫 Ruby , 但仍然有許多的 Objective-C 影子, 不過怎樣都比直接寫 Obj-C 好多了
2. 目前 Debug 的工具不算太好(或著說等於沒有??)
3. 文件不算太齊全, 很多都要參考 MacRuby 的文件, 而不是RubyMotion 自身準備給你
4. 比起 XCode 畫面可以拉一拉就生成, RubyMotion 需要自己用程式刻 UI
5. 它要錢.. NTD 6000 左右
6. 比起 XCode 速度慢, 常當掉.. 至少我們可以用自己最喜歡的 IDE 來寫 Code..
如果你是 textmate 或 sublime, 那麼也有相關套件可以使用.
7. 很多 Gems 在 MacRuby 無法使用…
8. 生成的 app 跑起來速度頗快, 不會有 phonegap 那類工具的 delay.. 於事乎也可以拿它開發遊戲??
大致幾點就是如此..
我個人還在玩它, 至於產品.. 應該是不會用它開發..
畢竟要考慮到它是小眾工具, 而且正統的 iphone 開發者都還是使用 Objective-C
雖然 Objective-C 的人仍是難找, 但要找到會 Ruby 又會 Objective-C (或著說同時學兩套) 的人就更難了..
以上..
關於 EBS 增加容量的流程
最近面臨了 ebs 空間不足的問題,被我寫爆了..
於是紀錄一下流程..
1. 進 ec2 console, 選 volumes
2. 對現有的 ebs 做 snapshot
3. 將現有的機器關機, 然後 detach ebs
4. 用建好的 snapshot 來建立新的 ebs
5. 啟動機器
6. sudo resize2fs (然後等一下..)
7. df -h (應該就會看到空間變成你新的 ebs size)
Cardinal Blue: 3 Must-Have SDKs for Mobile App Developers
Are you developing mobile apps? Here are 3 SDKs which we have found extremely helpful in deploying and debugging our PicCollage app for iOS/Android, which has been downloaded more than 5 million times.
- Testflight helps you deploy iOS apps to your test users.
- Crittercism helps you find…
Nginx subdomain 轉址設定.
由於跨 domain 的 browser 安全性問題.
所以這幾天一直在考慮是否將網址直接用成 subdirectory 的方式.
所以試著在 nginx 下把 mydomain.com/abc 轉到 localhost:8080 .
但這看來很簡單很合邏輯,應該是加個
location/abc{
proxy_pass http://localhost:5984;
}
結果卻完全不是這麼一回事…
所以google了兩個小時多終於找到,解法如下 :
location /couchdb {
rewrite /couchdb/(.*) /$1 break;
proxy_pass http://localhost:5984;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
請各位孝納.. :p ps, 原文在此 : Nginx as a reverse proxy
幾個關於CSS&JS的Memo
最近在調整 IE 的 CSS , 幾個關於 IE Buggy 的 Memo 如下 :
max-width 需使用 min-width 並加上 width: expression(this.width > your_size ? your_size : true);
padding無效.
可以使用 \9 對 IE9 做特殊處理. 而 !important 則是對所有.
而 JS 的部份如下 :
jquery window key bind 不運作. 可能的話請對 dom 做 bind.
jquery getJSON 跨網域不運作. 請加上 jQuery.support.cors = true;
const 不運作. 請改用 var.
Ruby中超強悍的 Non-Blocking 的框架 : Goliath
Goliath 是一套 ruby 的 asynchronous (non-blocking) 的 Framework .
它建構在 EventMachine, Rack 之上. 讓開發者很簡單的就能架設一些 API 或 non-blocking 的服務.
有使用過 Rails 的人都知道, 像 Thin, Mongrel 這類的 Server 是會 Block 住.
也就是說如果我們開了 3 個 Thin Instance ,而每個 Request 需時 1 秒.
當同時有四人連線到我們的 Server , 其中某一個就會因為 server 還在 handle 其他人的 request 而出現 error.
我們的API也是使用 Goliath 所架設. Goliath 簡單易用. 而且強大. 以目前我們實際使用單個 API Instance , 只有速度反應的快或慢. 沒有 block 或 error 的問題.
Goliath 個人認為也能拿來直接架設網站 Backend .
也就是後端完全使用 Goliath, 前端完全使用 apahce, nginx 來 render html+js+css .
如此,強悍無比.
建立 Routes
透過如下範例,我們就能建立一個簡單的 Goliath API, 具有 Get/Post Method.
如果在 Console 下輸入 ruby goliath_file.rb -p 8080 ,打開 Browser 連結 localhost:8080/hihi
就會看到 “hello world”.
class Hihi < Goliath::API
def response(env)
params=params=env['params']
puts "params #{params}"
[200,{'Content-Type' => "text/plian"}, "hello world."]
end
end
class Api < Goliath::API
use Goliath::Rack::Params
get '/hihi', Hihi
post '/hihi', Hihi
end
關於使用 Goliath 當服務的思考
其實所有的東西都可以在 Goliath 完成. 只是如此一來 Model 和 Controller 就比較緊密連接.
但只要設計得當,也是能分得很開.
透過加入 Datamapper, ActiveRecord, Sequel… etc 就能達成資料庫連結.
前端使用 Nginx,Apahce 來 render 網頁. 超級快!
如果要更快, 直接將網頁丟在cdn. 快速無比. :)
唯一目前讓我還沒有徹底使用的原因,很大部份是 Keep Session 的處理.
這事其實不算非常困難,但就是麻煩啊.. Ruby的愛用者好像都很懶.. :p
如果有人有興趣,看是對 Goliath 的哪個面向. 可以再多作介紹.. :)
使用EventMachine建立高Concurrent的Worker.
我們的 Worker 並不是使用 Beanstalk 或 AMQP 之類的處理. 雖然曾經有想過…
取而代之的是使用純粹的 EventMachine.
透過 EventMachine 的 Defer. 我們可以在同時處理非常大量的資料.
但同時也帶來了幾個問題.
啟動及管理Worker :
EventMachine 可以透過啟動 Web Server 的方式來綁定特定 Port. 然而如果是以 Worker 的方式執行卻難以維護.
我們嘗試過幾個Gem比如 Daemon, Foreverb. 但都不盡理想.
於是我們就看了一下比如 Thin, Goliath 等 Framework 內部是如何實作. 才得知,其實也就是使用 Fork Process 的方式. 透過 Fork Process ,將原本的 Process 砍掉. 作法如下 :def store_pid(pid) FileUtils.mkdir_p(File.dirname(@pid_file)) File.open(@pid_file, ‘w’) { |f| f.write(pid) } end
Process.fork do Process.setsid exit if fork
@pid_file ||= ‘./your_code_name.pid’ @log_file ||= File.expand_path(‘your_code_name.log’) store_pid(Process.pid)
File.umask(0000)
stdout_log_file = “#{File.dirname(@log_file)}/#{File.basename(@log_file)}_stdout.log”
STDIN.reopen(“/dev/null”) STDOUT.reopen(stdout_log_file, “a”) STDERR.reopen(STDOUT)
#Start to run your code or worker here. end
這裡必需提一下.
Foreverb 這個 Gem 在幾次Von和原作者信件往返,得知如 Twitter ,等內部很多地方都用到這個 Gem.
而 Von 使用了也覺得這個 Gem 使用起來很不錯.
無奈在現有時間下很難將架構整個改成適合 Forverb. 只好留待下次.資料重覆性 :
透過 Defer 在處理時,有可能發生比如 A 抓取資料 1 ,並打算寫入,而同時 B 也嘗試寫入(因為此時 A 尚未寫入).
關於這樣的資料重覆,我們目前能處理的只有在寫入前確認一次,寫入後也再確認一次資料重覆性.
但關於這問題,應該可以找時間來參考 NoSQL 各 Node 之間的 Consist 處理方式. :)Defer的處理即時性 :
EM.Defer 簡單講就有點像是 Fork 一個 Thread 去處理某件事.
所以包含在 EM.Defer{ } 之間的 Code 將不會 Block 住 Main Loop. 根據官方文件對 Defer 的解釋 :
Note carefully that the code in your deferred operation will be executed on a separate thread from the main EventMachine processing and all other Ruby threads that may exist in your program. Also, multiple deferred operations may be running at once! Therefore, you are responsible for ensuring that your operation code is threadsafe. [Need more explanation and examples.] Don’t write a deferred operation that will block forever. If so, the current implementation will not detect the problem, and the thread will never be returned to the pool. EventMachine limits the number of threads in its pool, so if you do this enough times, your subsequent deferred operations won’t get a chance to run. [We might put in a timer to detect this problem.]然而很多時候 Von 在 Defer 時卻不是馬上處理. 當然,有時也會做一做,那個工作就消失了..
儘管上面文字說明了它們對 Threads 有數量限制.
而這數字似乎沒有被標示出來? 但 Von 只做了 20 個 Defer… :p
所以關於這方面的技巧處理,應該要更小心操作才是.關於跨Server資料傳遞 :
透過之前開發一套 Web Socket Server 端聊天室的經驗. 讓 Von 很想在下次的 Worker 加入 Channel 和 WebSocket 來讀取 Event .
如此一來不僅可以簡單的透過 web 傳遞資料,速度會比寫入資料庫,或是 http request 來得快.
而且維護上也比較容易. 這樣的作法就有點像是實現了一套輕量化的 Beanstalk, AMQP. 只是它使用 WebSokcet .
接下來還有許多工作得處理. 下次來分享一下 Goliath 的 Async 和穩定性.
團隊內部的大家都對它很滿意喔. :)
如果您對這樣的工作挑戰有興趣,我們正在找創業夥伴. 請點我
myNoSQL: Redis Guide: What Each Redis Data Type Should Be Used For
Salvatore Sanfilippo offers a very detailed answer to this question on StackOverflow. Just to give you a glimpse.
- strings:
- to avoid converting your already encoded data (JSON, HTML)
- bitmaps and in general random access arrays of bytes
- lists:
- when you are likely to touch only the…
Paginating With Riak
Alexander Sicular explaining why pure key-value stores require a different approach when an application needs to paginate through result sets:
Riak at its core is a distributed key/value persisted data store that also happens to do a lot of other things. Now break that down. Looking at those words individually we have “distributed”, meaning that your data lives on a number of different machines in your cluster. Good thing, right? Yes. However it also means that no single machine is the canonical reference for all your data. Which in turn means that you need to ask multiple machines for your data and those machines will return data to you when they see fit, ie. not in order. Moving on, we have “key/value”. In regards to the topic at hand, this means that Riak has no insight into any data held within your keys, ie. Riak does not care if your stored json object has an age value in it. Next, we have “persisted”. Riak has no native internal index, meaning Riak will not store on disk the data you send it in any useful way - useful to you at least. Lastly, we have “happens to do a lot of other things.” Thankfully for us, one of those other things is Map/Reduce.
Original title and link: Paginating With Riak (©myNoSQL)
myNoSQL: Bump Chose Basho's Riak for Both Scale and Reliability
From the PR announcement about Bump’s usage of Riak1:
To ensure consistent up-time and user engagement, Bump chose Basho’s Riak for both scale and reliability. Riak ensures that the Bump application can be continually fed with information without the worry of a system fail. Bump…