最新文章

近期迴響

  • Debbie: Perfect. blog.xdite.net is killer....
  • ㄚ琪: 之前在愛麗絲那邊也讀過工人智慧! 在這裡又看到! 有一點瞭解工人智慧的意義了...
  • 佶也: 沒做起來 原因是什?...
  • 奈奈: 你真的是.... 太強了...
  • micmic3: 因為 博客來 被您報料了啊...XD...
  • 路人: 我跟91樓有相同的問題,有沒有能人才士可以告訴我們該怎麼辦。...

VerXD 作品集


 絕望網

 VeryXD 2.0

 Twitio.us

無分類雜文 04 Mar 2010


[閒聊] 豆瓣的購書單

最近要買一些大陸書看,就上了豆瓣找評價,發現多了這個新功能:購書單….

如果我是大陸地區的消費者,這功能真的還蠻棒的就是了…:D

可惜當年博客來的松鼠窩沒做起來啊 :(

豆瓣購書單

Ruby & ScalingRailsSite 01 Mar 2010


Scaling Rails Site:Reading Material # 5

6. Distributed Filesystem / Database , Database Optimization, NoSQL

基本上如果你的網站規模不到一定規模(這邊的定義是,用到幾十台機器),是不需要去研究 Distributed Filesystem / Distributed Database 的。不過我還是稍微聊一下它們的使用情境好了。

Distributed Filesystem 我們在做完網站後,可以使用 Load Balancer 把 request 分散到各台 web-front 機器上,但隨之就會產生一個問題,全站上的靜態檔案要怎樣讓這麼多台的 web-front 存取呢?基本想法當然是用 NFS,但是隨著網站成長,很快的 NFS 就不夠擔當這種重責大任了。於是另一種簡單的作法又出現了,用大量的 rsync + script 將檔案複製到多台 來*暫時* 解決 NFS 不夠用的情況。這個方法勉強夠用,但是會隨之產生架構維護上的難度缺乏整體的管理與監控…。而且在有大量小檔案需要同步,或者是檔案數量到達了百萬級、千萬級時,純用 rsync 非常的傷…

所以這時候才會用上 Distributed Filesystem 來解決這個問題。DFS 的作用是讓 Application 不用理會檔案資源實際會存在哪裡,往裡扔就對了,接下來的事情 DFS 會自己處理掉。Opensource 中比較出名的 Distributed Filesystem 當屬 Hadoop Distributed File System 。

HDFS 想做到的是 Google File System (GFS)能提供的:

1. 易於擴充的分散式檔案系統
2. 可運作於廉價的普通硬體上,又可以提供硬體錯誤容忍能力
3. 給大量的用戶提供總體性能較高的服務

解決以上情景會遇到的問題,同時又提供擴充性、移植性、資料一致性,而且支援相當大的資料規模(Perabytes)。Facebook 本身也是用 HDFS。

有關於這部分的閱讀資料,可參考國網中心的 Hadoop Distributed File System 這份投影片

Distributed Database 這個主題 DK 講過也講的蠻清楚了,我就不重複寫一遍了。最重要的目標是 CAP theorem 的 Eventual Consistent(資料最終一致性)。比較知名的 Distributed Database 有 HBase 、Cassandra、Voldemort 等等….

=====

Database Optimization

這方面的主題能談的非常多。而且每個主題也都相當博大精深。既然這系列的重點是 Reading Martrial,我就挑重點講好了。

首先是:MySQL 的調校 (軟硬體、版本、設定),這一段 DK 也已經專門整理過一篇文章了。內容是有關於機器、硬碟的挑選,架構的設計。挑選適合 MySQL 使用的 FileSystem ,my.cnf 的調校。

而跟 MySQL 各方面都不是很熟,看原文書又覺得很痛苦的人。我推薦看對岸簡朝陽寫的 MySQL 性能調優與架構設計 這一本書。基本上如果想瞭解 MySQL 的各樣基礎知識甚至進階知識,這本書大部分都含括了,而且寫的相當深入淺出….

架構設計上的需求,可直接看這本書的第三篇 (Ch12-Ch18),以及 High Performance MySQL 這本書。追求極致的 Performance Optimizaion 可追 MySQL Performance Blog 這個 blog …

DB 永遠是 Web Application 的瓶頸。而使用 ActiveRecord 想對 query optimize 的幾個 tips 是:

1. 不要忘記打 index,這一點很常在寫 model code ,寫著寫嗨了就忘記了,忘記打 index 可能會造成 slow query,可用 rails_indexes 這個 plugin。
2. 只 SELECT 你要的資料,而非 SELECT *。這一點可以透過 scrooge 這個 plugin 辦到。
3. 避免產生 n+1 query。
4. 記得加 counter_cache。( 3. 與 4. 都可用 bullet 這個 plugin 抓出來 )
5. 記得打開 my.cnf 裡面記錄 slow query log 的選項,然後善用 EXPLAIN 抓出真正的原因。
6. 儘量使用 find_in_batch,而不要使用迴圈跑 find(i)
7. 少用 join,多用幾次 select 做到相同的事。
8. 必要的時候,使用 SQL Antipattern 技巧,denormalize,實作 eav 等等….這方面可以看 SQL Antipaatern 這本書。

=====
NoSQL

對岸 JavaEye 的站長 Robbin 寫過一篇「NoSQL數據庫探討之一 - 為什麼要用非關係數據庫?」。整理了為什麼世界上比較大型的 Web 2.0 Site 要捨棄 RDBMS 轉而開發/使用 NoSQL 的原因:

1. High performance - 對數據庫高並發讀寫的需求
2. Huge Storage - 對海量數據的高效率存儲和訪問的需求
3. High Scalability && High Availability- 對數據庫的高可擴展性和高可用性的需求

這些 production 網站,對 DBMS 特性的要求 :

1.數據庫事務一致性需求
2.數據庫的寫實時性和讀實時性需求
3.對複雜的SQL查詢,特別是多表關聯查詢的需求

以及市面上滿足這些需求的各種 NoSQL (依照分類)以及簡單介紹,相當值得一看。

另外 High Scalability 這兩天也出了一篇 Paper: High Performance Scalable Data Stores

而我個人比較有在玩的是 MongoDB,他比較貼近 MySQL 的用法,但速度上快少 MySQL 不少。MongoDB 貼近 MySQL 的用法和一些其它的 feature,也比較滿足我在開發網站上的需求,比如說我就相當喜歡它以下的特色:

* Document-oriented # BSON ( Binary JSON)
* schema-less
* full index support
* dynaminc query (MongoDB - Ruby document store that doesn’t rhyme with ouchP.34)
* MM replication & auto sharding
* 可用來做 Real-Time Analytics …# upsert 特性
* subdocument 甚至是 nested document # 做巢狀 comment 特別簡單。知名留言系統 Disqus (支援 Nested Comment )的 backend 就是 Mongodb。

2009 的 Rubyconf 就有一個關於 MongoDB 的 Talk :Getting Non-Relational with MongoDB,相當值得一看。

====

以上就是我關於 Scaling Rails Site 的五篇文章,感謝收看…

另外推薦幾本 General Scaling 的書:
* Building Scalable Web Sites (Cal Henderson 著) # 這本是經典中的經典
* 構建高性能 Web 站點 (郭欣 著)# 這是對岸出的新書,也是講了相當多 general topic

還有這一個 blog: High Scalability

Ruby & ScalingRailsSite 28 Feb 2010


Scaling Rails Site:Reading Material # 4

4. Asynchrony Processing (Message queue)

想法是將需要耗費大量資源或耗費大量時間的 job 都丟到 backgroud 去非同步執行。比如:寄信、縮圖、轉影片等等….

@ihower 在上次的 RubyTuesday 已經針對 Distributed Ruby and Rails 做了一次很好的 presentation。基本上看這份投影片就差不多了。

書單部分,推薦:
Distributed Programming in Ruby

網路文章部分,關鍵字建議使用:
[Background processing Ruby Rails]

5. Partition Component using SOA

也推薦閱讀同樣一份投影片,SOA 的內容從 P.91 開始。什麼是 SOA 呢?SOA 的全名是 Service Oriented Architectures.

* SOA is a way to design complex applications by splitting out major components into individual services and communicating via APIs

* a service is a vertical slice of functionality: database, application code and caching layer

為什麼談 Scaling 要扯上 SOA 呢?

1. 當一套系統日漸龐大時,一定會開始出現需要將各樣 Component 做水平拆分的動作。就比如說,為了 Scale DB 方面的表現,可能就會做 Database Sharding。但 DB Sharding 會造成新的問題,Application 必須配合 DB Sharding 做處理,也許當初用自己寫的 ORM 可以處理掉這個問題。但是系統更大了以後,需要以 其他語言/ Framework / 架構去擴充 Application,另外一個問題就產生了:原先的 ORM 可能不能直接使用,這時候要直接 access db ?還是用新語言重寫一套 ORM?但是,ORM 維護的不同步性會不會造成靈異現象呢? 重新刻第二套第三套輪子是否有必要呢?

2. 我有一套 Bussiness Web Application,做的還不賴,想要拿來再外面架一套當分站,action 和 view 的架構大致上都不變,model 有一些關於 buisness 的部分 稍稍不同。這個不同說大不大,但說小也不小。比如說我開個賣電子書的網站好了,A 站收費是 a 模式,老闆突然說想開個 B 站,計價採 b 模式。也許為了趕上線,我們用了大量的 copy code 辦到了這件事。但是因為這網站實在太賺錢了,又要開 C 站….請問是要繼續 copy code 嗎?

遇上這兩種場景,我想 RD 應該都會想哭。如果真的繼續造輪子 / copy code 下去,擴充 + 維護難度會變得相當的高

3. 假如今天外部廠商想要與我們合作,我們為了合作,必須開放部分資料讓對方可進行讀寫。能讓他直接讀寫我們的 DB 嗎?當然不行。給他們我們的 ORM Lib 嗎?也不行,ORM 可能也是商業機密。而且 ORM 可能也沒有關於 Security 和 權限方面的控管。那我要針對這次合作案,寫出一次性的 API 讓他使用嗎?好像也不對,有點太昂貴了….

4. 我今天想對 DB query 出來的 result 做 cache,到底是要在 cache 在哪裡呢?application 層?ORM 層?混合在以上場景裡,好像在哪裡做都不對…..

所以這就是為什麼做 Scaling 也要配合做出 SOA 的架構,以 API 和 WebServices 的模式,降低不同系統介接的難度,提供一致性的存取介面,並且在這一層就可以把該做的 Cache 和Security 做上去。如果不做 SOA,很多系統根本想 Scale 都 Scale 不上去….

====
坊間關於 SOA 的書籍和資料很多,因為 SOA 已經是一門獨立的學問了。這裡我舉 SOA for Rails 的部分就好,這個議題,我推薦閱讀:

Service Oriented Design With Ruby and Rails
Enterprise Rails
Enterprise Recipes with Ruby and Rails

Ruby & ScalingRailsSite 28 Feb 2010


Scaling Rails Site:Reading Material # 3

3. Caching & HTTP Reverse Proxy Caching

不管是用什麼語言什麼架構做出來的網站,Scaling 很重要的一點的原則就是儘量 Cache Everything讓每個 request 都去 hit db、用程式即時去產生頁面,對整體資源來說是相當昂貴的一件事。因此這兩個部分要儘量都用 Cache 做掉。

Caching 可粗分為 DB Caching 和 Webpage Caching。

- DB Caching:MySQL 本身就有 Query Cache 的機制,不過這裡談的是如何用 memcache cache 住 query result,減輕對 DB 的壓力。

基本的想法是,要做 Read-Through 和 Write-Through。Read-Through 的意思是:程式要拿 result set 必須要先去問 memcache 有沒有資料,有的話直接拿回去用,沒有的話才從 DB 直接拿資料,然後 cache 在 memcache 裡。而 Write-Thorugh 的作法是,當 object 被 新建、更新、刪除時,被 cache 住的部分也要同步被更新到。

聽起來很簡單,但實作起來就 ….。幸好,我們有 cache money 這一套 plugin。它是一套 write-through and read-through caching library for ActiveRecord。要做這件事就相對比較無痛。

還有一套 Rails Community 常用的 cache library 是 cache_fu ,作用主要是可以對 cache 加上 expire time 的處理。

另外,Rails 有 API 可支援直接對 Cache ( memcache )的讀寫操作。請閱讀:Scaling Rails - 第八章 Memcached

- Webpage Caching: Webpage Caching 又分三種:Page Caching(整頁)、Action Caching、Fragment Caching。

Page Caching 談的就是把整頁的內容,cache 成 html / xml / json,塞進 Cachestore(是的,Rails 有 Cachestore 的設計,你可以在 config 裡指定 cache 是塞到 filestore、memory 還是memcahe 等等…)。

[ 推薦閱讀:Scaling Rails - 第二章 Page CachingScaling Rails - 第五章 Advanced Page Caching ]

但是只要是 Cache 就會有 Cache Expiration 的問題,如果在 controller 裡,一個一個針對資料變動的 action 做 page 的 expiration,程式很快的就會變髒。比較好的方式是引進 Sweeper 的設計。Sweeper 是 Observer 的一種,可以同時 Observe controller 和 model。

[推薦閱讀:Scaling Rails - 第三章 Cache Expiration ]

Action Caching 和 Page Caching 有什麼不一樣呢? Page Caching 通常是用在同一頁面,但須要吐針對不同條件式需要不同結果的 action,比如說身份判別。當該頁針對 一般 user 和 anonymous 是吐出不同資訊時,就需要用到 Action Caching 。Action Caching 是配合 filter 去實做。在這個 case 中,如果沒登入就直接吐已經 cache 過的結果或將 client 重導到 Login 頁,通過驗證的再向 mongrel 要。

[推薦閱讀:Scaling Rails - 第六章 Action Caching ]

那什麼時候會用到 Fragment Caching 呢?當這個頁面很多區塊需要分別 Cache 起來時,比如說以 妝頭條 這個網站來說,很多側邊欄是用 partial 實作的。同時,不少列表部分也是用 partial 搭配 collection 去做的。這時候就是使用 Fragment Caching 的使用時機。

[延伸閱讀:Scaling Rails - 第七章 Fragment Caching ]

一樣的,只要是 Cache 就會遇上 Expiration 的問題。這實在相當棘手。不過我在 Fragment Caching 這一塊,是改用了不同於 Scaling Rails 系列的作法,我用了 ihower 寫的 Handcache 和 Yehuda 的 Moneta 來做到對 cache 加上 expire time 的機制,使用 Moneta 也可以擴充使用更多不同的 cache backend,而不僅止於 memcache。

以上談的都是程式裡內部做的 Cache,接下來要談的是外部的 Cache。一般實務上的作法都是用使用 Load Balancer 加上 HTTP Reverse Proxy 實做。

窮人版的作法有幾種:

1. 使用 mongrel 做 web server, 利用 apache 做 rond-robbin 以及 Reverse Proxy。
2. 使用 mongrel 做 web server, 利用 ngninx 做 load balancer(有個 module 叫 fair proxy) 以及 Reverse Proxy。
3. 利用 Passenger (mod_rails)本身可以做到類似的架構,它有個 global queueing 的機制,蠻多設定可以調的,建議直接看 Passenger 的 document
4. 架 HAProxy 當 load balancer(教學),後面自己架 SquidVarnish 當 Reverse Proxy。

[延伸閱讀:Scaling Rails - 第十二章 Jesse Newland & Deployment]

不過,其實如果如果你的量已經夠大了。每個月淨賺幾百萬,但是苦在於 RD 不夠或者是 SA 不夠強能堆出/維護日漸龐大的架構。應該做的事是買一台 F5 比較實際…。

Ruby & ScalingRailsSite 28 Feb 2010


Scaling Rails Site:Reading Material # 2

2. Front-end web performance

一般來說,在測量用網頁開一張網頁需要多少時間時,其實會發現瓶頸大多是落於 loading 頁面上所需要的 data,而非 Server 產生頁面的速度上。開一張網頁,loading 頁面所需要的東西要花 3 秒,可是 loading 頁面本身只需要 0.2 秒,加起來需要 3.2 秒。tune Rails Application tune 了老半天,才將 0.2 秒降低成 0.1 秒。但是針對 Client Side 部分隨便 Tuning 一下,本來需要 3 秒可能馬上降到 1 秒不到。所以有時候先 Tune 這部分反而是比較合算的。

而使用 YSlow 這個工具,基本上就能幫忙檢測出很多網站上的問題和給出實際的建議。

[ 閱讀 Best Practices for Speeding Up Your Web Site ]

以下是我基於 YSlow ,能利用 Rails 本身或網路上已有的工具 / 技術給出的實作建議:

Minimize HTTP Requests
Optimize CSS Sprites
過多的 http request 是 loading page 效率低落的主要原因之一,造成這種問題的原因多半出自於開啟該頁面需要下載的靜態檔案太多(css 和 js 太多支、css 裡用到的 images 太多張)。

解法:在一般網站架構的情形,可用 YUI Compressor 做到打包多支 css / js 成一支檔案的目標,減少 http request,但是每次在 production 的現實操作中,deploy code 都要手動做一次,忘了做就會有災難發生,一般的解法可能是利用 vim 的 script 做到編輯完自動打包 。而在 rails 裡,helper 可以幫你自動做到打包的動作。

RUBY:
  1. <%= javascript_include_tag , "product", "cart" ,"chckecout" , :cache => "shop" %>
  2. <%= stylesheet_link_tag :all , :cache => true %>

至於 CSS Sprites,是一種技巧,將原本很多張的小圖合併成一張圖,再利用 CSS 定位切割,用來解決 css 裡 images 太多張的問題。網路上搜尋 auto css sprite 就有一大堆相關的工具。不過這裡要特別講一個最近才新出的 Ruby Gem:Auto Sprite,可搭配 Rails 自動處理這件事 ..

Use a Content Delivery Network
Split Components Across Domains

Serve Static File 對一些 httpd 是一件很痛的事。因此在實務上,通常會以拆不同 domain、不同 server 的技巧,將靜態檔案 Server 與 Application Server 拆開。把靜態檔案上 Reverse Proxy 或 CDN 處理。上 CDN 除了可以減輕對 httpd 的壓力,還可以更多其他明顯的好處:提供 delivery 檔案的速度品質(尤其是服務的對象是 global)、有的廠商會幫忙上 gzip(甚至多幫忙處理 IE6 下 gzip 的問題)等等...

但是切換 static file 的 server,如果在架構上面沒設計好,換 server 就要大幅改寫 application 裡的 code,是很傷開發成本的一件事。

解法: 這一點 Rails 很聰明的幫開發者想到了,只要在 config 裡設定

RUBY:
  1. config.action_controller.asset_host  = 'http://asset.example.org"

靜態檔案的來源通通都會自動改成 asset.example.org。更進階的,browser 同時間只能對同一 domain 最多兩個 persistent connections,所以實務上還要將靜態檔案 server 拆成多個 domain,加速平行下載。這一點 Rails 也想到了,

RUBY:
  1. config.action_controller.asset_host  = 'http://asset%d.example.org"

就可以同時分散到 asset0-3 去。

另外,上了 CDN 後,靜態檔案在 client-side 的 flush 又是一個問題。這一點 Rails 也是自動處理好了,一般 Rails Application 所產生的 html,靜態檔案檔名的部分通常會有一串數字 ?123456,這就是用來解決 browser cache 住靜態檔案的問題,利用後面 query string 的不同,讓 browser 以為跟原先之前 cache 住的檔案不同而重新下載。由 Rails 的 helper 自動加上,數字是最後修改時間的 unixtime。

Add an Expires or a Cache-Control Header
Configure ETags

這是 Client Caching 技巧之一

header["Cache-Control"] = "max-age=600",就是 Content 在 600 秒內都是 valid 的,600 秒內都不用重抓。除非 broswer 送出 refresh 指令。要做到這件事:只要在 action 裡簡單的添加一行:

RUBY:
  1. expires_in 10.minutes

至於如果最前面的 web server 是 apache 的話,還有一招是在 public/stylesheets 和 public/javascripts 下放置一個有以下內容的 .htaccess 。

Header add Cache-Control "max-age=86400"

至於 etag 以及 last-modified,都已經整理在以前寫的 Scaling Rails - 第十章 Client-side Caching 的文章裡了。

Minify JavaScript and CSS

在 Minimize HTTP Requests 這章裡,已經提過了 Rails 的 helper 內建了打包功能,但這個打包功能只有純打包沒有幫壓。於是有人開發了一個 plugin: Smurf 搭配 Rails helper 原有的機制,做到打包並壓縮這件事。

最後,關於 Rails Front-end web performance 的 Scaling 的閱讀材料,我推薦閱讀以下資料:

Yehuda 的 Making Rails Even Faster by Default
Scaling Rails : Client-side Caching
Scaling Rails : Advanced HTTP Caching

至於一般 General 的 Front-end web performance scaling 我推薦的是:

High Performance Web Pages
。Steve Souders 的兩本書:High Performance Web Sites以及 Even Faster Website,以及他老人家的 blog

Ruby & ScalingRailsSite 28 Feb 2010


Scaling Rails Site:Reading Material # 1

昨天 @ihower FW 了一封信給我。 內容大概是有 Ruby Community 的朋友寫信給他,想要瞭解 Rails Production site 的架構設計與 Scaling 觀念與技術,想請 ihower 給他一點方向。於是 ihower 又把這封信 FW 給我,我們稍微聊了幾分鐘。所以就有了這一系列的文章。

目前市面上並沒有一本專書是專門教 Scaling Rails Application 的。但是有關於這個議題,是真的有不少東西可以讀的。

大致上可規類幾個方向:

1. Rails performance
2. Front-end web performance
3. Caching & HTTP Reverse Proxy Caching
4. Asynchrony Processing (Message queue)
5. Partition Component using SOA
6. Distributed Filesystem / Database , Database Optimization, NoSQL

1. Rails (Application) performance

Rails 這個框架本身的 Performance 並不在這個議題討論之內。原因是 Rails 2 本身的 req/s 已經在 framework 界的表現算是不錯,還電掉一堆 PHP framework,而且對於 Rails 本體的表現,很多時候 Application 純開發者是沒有什麼作為能力的。Tuning 的原則建立在於認定 Rails 能夠有一定的效率表現,因此方向改於著重於避免設計出爛架構、寫出爛 code 造成效率低落,以較為良好的架構設計達到避免將壓力加諸於 Rails 身上的目標。

* 換掉 Ruby 版本

如果要提升 Rails framework 的速度,換掉 Ruby VM 是最快的。但如果還是希望使用純 C 寫的 Ruby ( gem compatible 問題),可考慮使用 Ruby Enterprise Edition (REE)。光換成 REE,記憶體用量馬上就少上 1/3,而速度也快上 1/3。

關於 REE 能夠做到這件事的原理,已經寫在 FAQ 裡,而他們在 2009 年底也在 Google Tech Talk 上給了一場相關的 talk

[關鍵字: Ruby VM ]

* 抓出 slow action / slow ruby code,並針對這些部分改善

[ 可安裝 NewRelic RPM 抓出內部的問題。 ]

很多時候,Rails Application 的緩慢,並不是 Rails 這個 framework 產生的問題。而是開發者 *完全* 不熟 Rails API 或者是 Ruby 這個語言 本身,或者是濫用 Rails 的開發方便度寫出爛架構所造成的問題。常見的情形有以下幾種狀況:

- 不熟 Ruby。可以用 Ruby 本身提供的 method 一行就解決的事情,自己寫了迴圈處理,造成了 object 大量的被 clone 出來浪費記憶體。

解法:閱讀 Writing Efficient Ruby Code,以及閱讀 The Well-Grounded Rubyist( Ruby for Rails 的新版)、Refactoring: Ruby Edition

- 不熟 Rails API。比如說:不熟 ActiveRecord,導致一個簡單 action,就產生了極大量的 query。或者是不懂做 counter cache,造成了 database 極大的壓力;大量使用 render :partial,卻不知道 render :partial 是極其昂貴的,應該把常用的 partial cache 住。

解法:閱讀 Advanced ActiveRecordAdvanced Active Record Techniques: Best Practice RefactoringThat’s Not a Memory Leak, It’s BloatRails Code ReviewRailsrescue Handbook

- plugin 的錯。plugin 作者並不是全知全能,他們開發 plugin 只是為了順手解決自己手邊遇到的問題。你安裝的 plugin 若是熱門 plugin,效能上應該可能沒什麼問題,因為大多已經在許多人的 production 上千錘百鍊過,有問題也幾乎 patch 掉了。但若是比較冷門或比較新的,可能這個 plugin 就是造成你 performance 低落的元兇。

- 特殊 action 造成的效能低落。在 Rails Application 上,有一個常見功能是開發者的痛,就是上傳檔案的問題。上傳檔案這個行為,常常會造成 block 住整個站的現象。而 Merb 這個 Framework,當初就是設計來解決 Upload File 的問題的。很痛的還有寄信的這個功能,Rails 的 AR Mailer 真的頗廢 :/ ,它原始的設計初衷是要讓開發者在 Framework 輕鬆寫出寄信功能之用的,不過總會有天兵開發者會寫出在 action 裡一次寄一千封這種會死人的事....

解法:將效率低落的 action,諸如 upload 功能。利用 Metal 的機制,bypass 到其他 framework 或者是直接用 Rack middleware 做掉。如果你的 Web Server 最前面是 Nginx 的話,有人寫了一個十分有用的 upload module,解決了這個問題。至於寄信或者需要耗費大量資源的 action(如擷圖、縮圖、縮影片),應該用 queue + worker 加上 3rd party service 做掉。比如說寄信的方式,我就會推薦用 Delayed Job + Madmimi gem 解決。網站截圖就直接丟 bluega 處理。

- API 不應該直接使用 Rails 實作。API 通常多屬於邏輯簡單但 Request 數量又很大的行為,request 打進 Rails 本身就會造成一定量的負擔。這部分的實作部分也建議 bypass 到其他 framework 、直接用 Rack middleware 做掉,或乾脆切出去用其他語言/架構 implement。

至於更多 profiling memory usage 以及 measure code efficiency 的工具,ihower 將在 Ruby Tuesday #10 講到,這方面就交給他了,它的主題是 Rails Performance。而我本人也會在 Ruby Tuesday #10 講一場 Scaling Rails Site。

我個人推薦這方面的閱讀材料是:


Scaling Rails : On The Edge - Part 1

Scaling Rails : On The Edge - Part 2
Scaling Rails : On The Edge - Part 3

無分類雜文 27 Feb 2010


PageRank 6

不知不覺的,這個 blog PageRank 6 了。

賀 XD

無分類雜文 23 Feb 2010


RubyConf Taiwan 2010 開始報名啦!

RubyConf Taiwan 2010 已經開始報名啦
詳情請見 http://rubyconf.tw/2010/

中文講者有:

weijen 會講如何在一個 legacy Rails 專案上加上BDD測試
ihower 會介紹 Ruby 裡面怎麼設計出漂亮的 APIs
xdite 會介紹 Ruby 生態圈中有哪些服務可以幫助團隊開發及上線
Josh Moore 會介紹 Rails 3 的 generators 功能

英文講者有:

Gregg Pollack 會深入講解 Rails3 的實作技巧
Foy Savas 是 Merb way 的作者, 他還沒給我講題 XD
新井俊一 會介紹他們公司做的 ruby web framework
角谷信太郎 會分享 Ruby DSL 對非英語為母語的程式設計師有什麼意義
高橋征義 是日本 Ruby 協會會長

無分類雜文 22 Feb 2010


Python 與 WSGI

基本上只要 將我上一篇文章 Rack 與 Rack middleware 裡的 Ruby 與 Rack 換成 Python 與 WSGI 就又是一篇了 XD

延伸閱讀: Wikipedia : Web Server Gateway Interface

這大概是我這個部落格內容最短的一篇文章了吧 orz

---
但 Django middleware 並不與 WSGI compatible,這使得 Django 難以跟其他 framework 接軌。而 Rack 相較於 WSGI,多的是 Rack 並不僅只是一套規範而已,它同時還是一套 library。詳細的 Post 可見 Yehuda Katz 的這篇 Rack as a Transformative Figure

Ruby 21 Feb 2010


Rack 與 Rack middleware

Rails 2.3 引進了 Rack,不少 ActionController 內部裡的 component 都改成用 Rack middwares 實做了。一般在 rails project 內,鍵入

rake middle

可以看到這個 project 用了哪些 rake middleware 。

use Rack::Lock
use ActionController::Failsafe
use ActionController::Session::CookieStore, , {:secret=>"", :session_key=>"__session"}
use Rails::Rack::Metal
use ActionController::RewindableInput
use ActionController::ParamsParser
use Rack::MethodOverride
use Rack::Head
use ActiveRecord::QueryCache
run ActionController::Dispatcher.new

在 Rails3 中,更是針對這部份做了大大的強化:新的 route 部份任何一個 endpoint 都可以輕易接上支援 Rack 的 App、ActionController::Base 也繼承自 Metal (出處 : My Five Favorite Things About Rails 3 #2 )。

但是,到底什麼是 Rack、什麼是 Rack middleware,Rails 如此大幅的支援 Rack,會帶來什麼樣重大的變革,恐怕很多開發者還是一頭霧水。而這就是我寫這篇文章的目的。

什麼是 Rack?

如果你在網路上,搜尋 Rack 相關的資料的話,或許會找到這一篇文章: Ruby on Rack #1 - 與Rack的第一次親密接觸

裡面寫到 Rack 是:

Rack為使用Ruby開發web應用提供了一個最小的模塊化和可修改的接口。用可能最簡單的方式來包裝HTTP請求和響應,它為web 服務器,web框架和中間件的API進行了統一併提純到了單一的方法調用。

看不懂 ...換成原文好了 ...

Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.

有點清楚了,但是實在還是不懂 Rack 的意義在哪裡?

"Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby"

一般的印象,不是 Framework 跟 Web Server 對接就好,為什麼需要 Rack 這個東西卡在中間呢?

現實的世界當然沒有這麼直觀,隨著 Ruby Community 蓬勃的發展, 為了不同的開發目的,出現了很多 Framework:Rails , Sinatra , Merb ...,而大家為了自己的 production 需求,又出現了相當多不同的 web server : Mongrel / Thin / Passenger / Unicorn ...。

多對多的混亂就會出現了,我是 web server 的開發者,需不需世界上每誕生一套 Framework 就支援它呢?每一套 Framework 還有版本上的問題 ...

這時候

"Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby"

就顯得相當重要了

Rack / Server / Framework ( 圖片出處:Rack in Rails3

Rack 的出現,使得混亂的情形不再。它提供了一套 Rack SPEC 給 Server 和 Framework 遵循,解決了這個問題。

Rack 的 SPEC 非常簡單,就是一個 call method,吃一個 enviroment 參數,然後回傳一個 array,裡面包含 status , header, body。

什麼是 Rack middleware?

那有了 Rack,為什麼不能在 Rack 和 Application 中間幹點壞事呢? Rack middleware 說穿了,其實就是一些 follow Rack SPEC 的 application。Rack middleware 是可以堆疊的,基本上它的概念有點像 before / after / around 這種 filter。像 Rails 2.3 以後,其實每個 request 進來是要經過很多層 middleware 才打進 application 的,每一層都攔下來作某些事再傳到下一層去。

rack stack
寫 Rack middleware 和用 Rack middleware 有什麼好處呢?

Well, 很多邏輯簡單但 Request 數量又很大的行為(比如 Ajax Call , API )就可以寫 Rack middleware ,一旦符合 Pattern 就攔截下來處理掉,直接傳回去。而不需要真正打進 Framework 裡面進去處理,畢竟用 Fraemwork 去處理小事是殺雞焉用牛刀...

List of Middlewarerack-contribCoderack,這些地方提供了一大堆非常有意思的 Rack middleware !!

為什麼 Rails 要大幅支援 Rack ?

理由很顯見的:

1. 支援標準,可以輕易的跟各種 Web Server 接在一起。
2. 透過 Rack middleware 和 Rails metal 可以輕易的在內部,跟其他 Framework 整合在一起。

像上一段提到的 邏輯簡單但 Request 數量又很大的行為,除了可以用 Rack middleware 處理外,還可以透過 Rails Metal 的機制 bypass 到其他比較輕量的 framework 去處理。

在 Rails 2.3 之中,Rails Metal 算是獨立出來的一塊,進來的 request 會 "跳過" ActionController stack,直接給 Rails Metal Application 處理。

但在 Rails 3 中,Metal 成為了 ActionController 的一部份。

metal inher

Rails3 更進一步的將 "controller 每一個 action" 都變成了 Rack app,除了在 route 中每一個 endpoint 可以輕易的接上 Rack app 之外,甚至你可以使用 controller 中的 redirect 直接接上 Rack App. 以下是原理:

redirect rack ( 圖片出處:Rails 3: From Vaporware to Awesomeness in 12 Months

將"在 Rails 整合其他 Framework "的這件事的方便程度提升至一個極致。好處當然就是能讓 code 變得更乾淨,節省更多效能,以及在 Rails 做出以往無法做出的應用(搭配其他 Framework 在內部使用)。

比如說最近這篇文章 Building Real-time web apps with Rails3 就是一個很好的例子 ( Rails + Cramp )。

支援 Rack 不重要嗎?很重要 :D

That is "Why Rack?".

Next Page »