好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > 對優化Ruby on Rails性能的一些辦法的探究

對優化Ruby on Rails性能的一些辦法的探究

熱門標簽:徐州網絡外呼系統哪個好 高德地圖標注客服 常德電銷平臺外呼系統軟件價格 湖州u友防封電銷卡 地圖標注賺錢項目注冊 電銷機器人廠商代理 白銀外呼paas系統 百度地圖標注自定義圖片 滴滴外呼系統

1.導致你的 Rails 應用變慢無非以下兩個原因:

  1. 在不應該將 Ruby and Rails 作為首選的地方使用 Ruby and Rails。(用 Ruby and Rails 做了不擅長做的工作)
  2. 過度的消耗內存導致需要利用大量的時間進行垃圾回收。

Rails 是個令人愉快的框架,而且 Ruby 也是一個簡潔而優雅的語言。但是如果它被濫用,那會相當的影響性能。有很多工作并不適合用 Ruby and Rails,你最好使用其它的工具,比如,數據庫在大數據處理上優勢明顯,R 語言特別適合做統計學相關的工作。

內存問題是導致諸多 Ruby 應用變慢的首要原因。Rails 性能優化的 80-20 法則是這樣的:80% 的提速是源自于對內存的優化,剩下的 20% 屬于其它因素。為什么內存消耗如此重要呢?因為你分配的內存越多,Ruby GC(Ruby 的垃圾回收機制)需要做的工作也就越多。Rails 就已經占用了很大的內存了,而且平均每個應用剛剛啟動后都要占用將近 100M 的內存。如果你不注意內存的控制,你的程序內存增長超過 1G 是很有可能的。需要回收這么多的內存,難怪程序執行的大部分時間都被 GC 占用了。

2 我們如何使一個 Rails 應用運行更快?

有三種方法可以讓你的應用更快:擴容、緩存和代碼優化。

擴容在如今很容易實現。Heroku 基本上就是為你做這個的,而 Hirefire 則讓這一過程更加的自動化。其它的托管環境提供了類似的解決方案。總之,可以的話你用它就是了。但是請牢記擴容并不是一顆改善性能的銀彈。如果你的應用只需在 5 分鐘內響應一個請求,擴容就沒有什么用。還有就是用 Heroku + Hirefire 幾乎很容易導致你的銀行賬戶透支。我已經見識過 Hirefire 把我一個應用的擴容至 36 個實體,讓我為此支付了 $3100。我立馬就手動吧實例減容到了 2 個, 并且對代碼進行了優化.

Rails 緩存也很容易實施。Rails 4 中的塊緩存非常不錯。Rails 文檔 是有關緩存知識的優秀資料。不過同擴容相比,緩存并不能成為性能問題的終極解決方案。如果你的代碼無法理想的運行,那么你將發現自己會把越來越多的資源耗費在緩存上,直到緩存再也不能帶來速度的提升。

讓你的 Rails 應用更快的唯一可靠的方式就是代碼優化。在 Rails 的場景中這就是內存優化。而理所當然的是,如果你接受了我的建議,并且避免把 Rails 用于它的設計能力范圍之外,你就會有更少的代碼要優化。

2.1 避免內存密集型Rails特性

Rails 一些特性花費很多內存導致額外的垃圾收集。列表如下。

2.1.1 序列化程序

序列化程序是從數據庫讀取的字符串表現為 Ruby 數據類型的實用方法。

class Smth  ActiveRecord::Base
 serialize :data, JSON
end
Smth.find(...).data
Smth.find(...).data = { ... }

它要消耗更多的內存去有效的序列化,你自己看:

class Smth  ActiveRecord::Base
 def data
 JSON.parse(read_attribute(:data))
 end
 def data=(value)
 write_attribute(:data, value.to_json)
 end
end

這將只要 2 倍的內存開銷。有些人,包括我自己,看到 Rails 的 JSON 序列化程序內存泄漏,大約每個請求 10% 的數據量。我不明白這背后的原因。我也不知道是否有一個可復制的情況。如果你有經驗,或者知道怎么減少內存,請告訴我。

2.1.2 活動記錄

很容易與 ActiveRecord 操縱數據。但是 ActiveRecord 本質是包裝了你的數據。如果你有 1g 的表數據,ActiveRecord 表示將要花費 2g,在某些情況下更多。是的,90% 的情況,你獲得了額外的便利。但是有的時候你并不需要,比如,批量更新可以減少 ActiveRecord 開銷。下面的代碼,即不會實例化任何模型,也不會運行驗證和回調。

Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
后面的場景它只是執行 SQL 更新語句。

update books
 set author = 'David'
 where title LIKE '%Rails%'
Another example is iteration over a large dataset. Sometimes you need only the data. No typecasting, no updates. This snippet just runs the query and avoids ActiveRecord altogether:
result = ActiveRecord::Base.execute 'select * from books'
result.each do |row|
 # do something with row.values_at('col1', 'col2')
end

2.1.3 字符串回調

Rails 回調像之前/之后的保存,之前/之后的動作,以及大量的使用。但是你寫的這種方式可能影響你的性能。這里有 3 種方式你可以寫,比如:在保存之前回調:

before_save :update_status
before_save do |model|
model.update_status
end
before_save “self.update_status”

前兩種方式能夠很好的運行,但是第三種不可以。為什么呢?因為執行 Rails 回調需要存儲執行上下文(變量,常量,全局實例等等)就是在回調的時候。如果你的應用很大,你最終在內存里復制了大量的數據。因為回調在任何時候都可以執行,內存在你程序結束之前不可以回收。

有象征,回調在每個請求為我節省了 0.6 秒。

2.2 寫更少的 Ruby

這是我最喜歡的一步。我的大學計算機科學類教授喜歡說,最好的代碼是不存在的。有時候做好手頭的任務需要其它的工具。最常用的是數據庫。為什么呢?因為 Ruby 不善于處理大數據集。非常非常的糟糕。記住,Ruby 占用非常大的內存。所以舉個例子,處理 1G 的數據你可能需要 3G 的或者更多的內存。它將要花費幾十秒的時間去垃圾回收這 3G。好的數據庫可以一秒處理這些數據。讓我來舉一些例子。

2.2.1 屬性預加載

有時候反規范化模型的屬性從另外一個數據庫獲取。比如,想象我們正在構建一個 TODO 列表,包括任務。每個任務可以有一個或者幾個標簽標記。規范化數據模型是這樣的:

  • Tasks
  •  id
  •  name
  • Tags
  •  id
  •  name
  • Tasks_Tags
  •  tag_id
  •  task_id

加載任務以及它們的 Rails 標簽,你會這樣做:

這段代碼有問題,它為每個標簽創建了對象,花費很多內存。可選擇的解決方案,將標簽在數據庫預加載。

tasks = Task.select -END
  *,
  array(
  select tags.name from tags inner join tasks_tags on (tags.id = tasks_tags.tag_id)
  where tasks_tags.task_id=tasks.id
  ) as tag_names
 END
 > 0.018 sec

這只需要內存存儲額外一列,有一個數組標簽。難怪快 3 倍。

2.2.2 數據集合

我所說的數據集合任何代碼去總結或者分析數據。這些操作可以簡單的總結,或者一些更復雜的。以小組排名為例。假設我們有一個員工,部門,工資的數據集,我們要計算員工的工資在一個部門的排名。

SELECT * FROM empsalary;
 depname | empno | salary
-----------+-------+-------
 develop |  6 | 6000
 develop |  7 | 4500
 develop |  5 | 4200
 personnel |  2 | 3900
 personnel |  4 | 3500
 sales  |  1 | 5000
 sales  |  3 | 4800

你可以用 Ruby 計算排名:

salaries = Empsalary.all
salaries.sort_by! { |s| [s.depname, s.salary] }
key, counter = nil, nil
salaries.each do |s|
 if s.depname != key
 key, counter = s.depname, 0
 end
 counter += 1
 s.rank = counter
end

Empsalary 表里 100K 的數據程序在 4.02 秒內完成。替代 Postgres 查詢,使用 window 函數做同樣的工作在 1.1 秒內超過 4 倍。

SELECT depname, empno, salary, rank()
OVER (PARTITION BY depname ORDER BY salary DESC)
FROM empsalary;
 depname | empno | salary | rank 
-----------+-------+--------+------
 develop |  6 | 6000 | 1
 develop |  7 | 4500 | 2
 develop |  5 | 4200 | 3
 personnel |  2 | 3900 | 1
 personnel |  4 | 3500 | 2
 sales  |  1 | 5000 | 1
 sales  |  3 | 4800 | 2

4 倍加速已經令人印象深刻,有時候你得到更多,到 20 倍。從我自己經驗舉個例子。我有一個三維 OLAP 多維數據集與 600k 數據行。我的程序做了切片和聚合。在 Ruby 中,它花費了 1G 的內存大約 90 秒完成。等價的 SQL 查詢在 5 內完成。

2.3 優化 Unicorn

如果你正在使用Unicorn,那么以下的優化技巧將會適用。Unicorn 是 Rails 框架中最快的 web 服務器。但是你仍然可以讓它更運行得快一點。

2.3.1 預載入 App 應用

Unicorn 可以在創建新的 worker 進程前,預載入 Rails 應用。這樣有兩個好處。第一,主線程可以通過寫入時復制的友好GC機制(Ruby 2.0以上),共享內存的數據。操作系統會透明的復制這些數據,以防被worker修改。第二,預載入減少了worker進程啟動的時間。Rails worker進程重啟是很常見的(稍后將進一步闡述),所以worker重啟的速度越快,我們就可以得到更好的性能。

若需要開啟應用的預載入,只需要在unicorn的配置文件中添加一行:

preload_app true
2.3.2 在 Request 請求間的 GC

請謹記,GC 的處理時間最大會占到應用時間的50%。這個還不是唯一的問題。GC 通常是不可預知的,并且會在你不想它運行的時候觸發運行。那么,你該怎么處理?

首先我們會想到,如果完全禁用 GC 會怎么樣?這個似乎是個很糟糕的想法。你的應用很可能很快就占滿 1G 的內存,而你還未能及時發現。如果你服務器還同時運行著幾個 worker,那么你的應用將很快會出現內存不足,即使你的應用是在自托管的服務器。更不用說只有 512M 內存限制的 Heroku。

其實我們有更好的辦法。那么如果我們無法回避GC,我們可以嘗試讓GC運行的時間點盡量的確定,并且在閑時運行。例如,在兩個request之間,運行GC。這個很容易通過配置Unicorn實現。

對于Ruby 2.1以前的版本,有一個unicorn模塊叫做OobGC:

require 'unicorn/oob_gc'
 use(Unicorn::OobGC, 1) # "1" 表示"強制GC在1個request后運行"

對于Ruby 2.1及以后的版本,最好使用gctools(https://github.com/tmm1/gctools):

require 'gctools/oobgc'
use(GC::OOB::UnicornMiddleware)

但在request之間運行GC也有一些注意事項。最重要的是,這種優化技術是可感知的。也就是說,用戶會明顯感覺到性能的提升。但是服務器需要做更多的工作。不同于在需要時才運行GC,這種技術需要服務器頻繁的運行GC. 所以,你要確定你的服務器有足夠的資源來運行GC,并且在其他worker正在運行GC的過程中,有足夠的worker來處理用戶的請求。

2.4 有限的增長

我已經給你展示了一些應用會占用1G內存的例子。如果你的內存是足夠的,那么占用這么一大塊內存并不是個大問題。但是Ruby可能不會把這塊內存返還給操作系統。接下來讓我來闡述一下為什么。

Ruby通過兩個堆來分配內存。所有Ruby的對象在存儲在Ruby自己的堆當中。每個對象占用40字節(64位操作系統中)。當對象需要更多內存的時候,它就會在操作系統的堆中分配內存。當對象被垃圾回收并釋放后,被占用的操作系統中的堆的內存將會返還給操作系統,但是Ruby自有的堆當中占用的內存只會簡單的標記為free可用,并不會返還給操作系統。

這意味著,Ruby的堆只會增加不會減少。想象一下,如果你從數據庫讀取了1百萬行記錄,每行10個列。那么你需要至少分配1千萬個對象來存儲這些數據。通常Ruby worker在啟動后占用100M內存。為了適應這么多數據,worker需要額外增加400M的內存(1千萬個對象,每個對象占用40個字節)。即使這些對象最后被收回,這個worker仍然使用著500M的內存。

這里需要聲明, Ruby GC可以減少這個堆的大小。但是我在實戰中還沒發現有這個功能。因為在生產環境中,觸發堆減少的條件很少會出現。

如果你的worker只能增長,最明顯的解決辦法就是每當它的內存占用太多的時候,就重啟該worker。某些托管的服務會這么做,例如Heroku。讓我們來看看其他方法來實現這個功能。

2.4.1 內部內存控制

Trust in God, but lock your car 相信上帝,但別忘了鎖車。(寓意:大部分外國人都有宗教信仰,相信上帝是萬能的,但是日常生活中,誰能指望上帝能幫助自己呢。信仰是信仰,但是有困難的時候 還是要靠自己。)。有兩個途徑可以讓你的應用實現自我內存限制。我管他們做,Kind(友好)和hard(強制).

Kind 友好內存限制是在每個請求后強制內存大小。如果worker占用的內存過大,那么該worker就會結束,并且unicorn會創建一個新的worker。這就是為什么我管它做“kind”。它不會導致你的應用中斷。

獲取進程的內存大小,使用 RSS 度量在 Linux 和 MacOS 或者 OS gem 在 windows 上。我來展示下在 Unicorn 配置文件里怎么實現這個限制:

class Unicorn::HttpServer
 KIND_MEMORY_LIMIT_RSS = 150 #MB
 alias process_client_orig process_client
 undef_method :process_client
 def process_client(client)
 process_client_orig(client)
 rss = `ps -o rss= -p #{Process.pid}`.chomp.to_i / 1024
 exit if rss > KIND_MEMORY_LIMIT_RSS
 end
end

硬盤內存限制是通過詢問操作系統去殺你的工作進程,如果它增長很多。在 Unix 上你可以叫 setrlimit 去設置 RSSx 限制。據我所知,這種只在 Linux 上有效。MacOS 實現被打破了。我會感激任何新的信息。

這個片段來自 Unicorn 硬盤限制的配置文件:

after_fork do |server, worker|
 worker.set_memory_limits
end
class Unicorn::Worker
 HARD_MEMORY_LIMIT_RSS = 600 #MB
 def set_memory_limits
 Process.setrlimit(Process::RLIMIT_AS, HARD_MEMORY_LIMIT * 1024 * 1024)
 end
end

2.4.2 外部內存控制

自動控制沒有從偶爾的 OMM(內存不足)拯救你。通常你應該設置一些外部工具。在 Heroku 上,沒有必要因為它們有自己的監控。但是如果你是自托管,使用 monit,god 是一個很好的主意,或者其它的監視解決方案。

2.5 優化 Ruby GC

在某些情況下,你可以調整 Ruby GC 來改善其性能。我想說,這些 GC 調優變得越來越不重要,Ruby 2.1 的默認設置,后來已經對大多數人有利。

我的建議是最好不要改變 GC 的設置,除非你明確知道你想要做什么,而且有足夠的理論知識知道如何提高性能。對于使用 Ruby 2.1 或之后的版本的用戶,這點尤為重要。

我知道只有一種場合 GC 優化確實能帶來性能的提升。那就是,當你要一次過載入大量的數據。你可以通過改變如下的環境變量來達到減少GC運行的頻率:RUBY_GC_HEAP_GROWTH_FACTOR,RUBY_GC_MALLOC_LIMIT,RUBY_GC_MALLOC_LIMIT_MAX,RUBY_GC_OLDMALLOC_LIMIT,和 RUBY_GC_OLDMALLOC_LIMIT。

請注意,這些變量只適用于 Ruby 2.1 及之后的版本。對于 2.1 之前的版本,可能缺少某一個變量,或者變量不是使用這個名字。

RUBY_GC_HEAP_GROWTH_FACTOR 默認值 1.8,它用于當 Ruby 的堆沒有足夠的空間來分配內存的時候,每次應該增加多少。當你需要使用大量的對象的時候,你希望堆的內存空間增長的快一點。在這種場合,你需要增加該因子的大小。

內存限制是用于定義當你需要向操作系統的堆申請空間的時候,GC 被觸發的頻率。Ruby 2.1 及之后的版本,默認的限額為:

New generation malloc limit RUBY_GC_MALLOC_LIMIT 16M
Maximum new generation malloc limit RUBY_GC_MALLOC_LIMIT_MAX 32M
Old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT 16M
Maximum old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT_MAX 128M

讓我簡要的說明一下這些值的意義。通過設置以上的值,每次新對象分配 16M 到 32M 之間,并且舊對象每占用 16M 到 128M 之間的時候 (“舊對象” 的意思是,該對象至少被垃圾回收調用過一次), Ruby 將運行 GC。Ruby 會根據你的內存模式,動態的調整當前的限額值。

所以,當你只有少數幾個對象,卻占用了大量的內存(例如讀取一個很大的文件到字符串對象中),你可以增加該限額,以減少 GC 被觸發的頻率。請記住,要同時增加 4 個限額值,而且最好是該默認值的倍數。

我的建議是可能和其他人的建議不一樣。對我可能合適,但對于你卻未必。這些文章將介紹,哪些對 Twitter 適用,而哪些對 Discourse 適用。

2.6 Profile

有時候,這些建議未必就是通用。你需要弄清楚你的問題。這時候,你就要使用 profiler。Ruby-Prof 是每個 Ruby 用戶都會使用的工具。

想知道更多關于 profiling 的知識, 請閱讀 Chris Heald's 和我的關于在 Rails 中 使用ruby-prof 的文章。還有一些也許有點過時的關于 memory profiling 的建議.

2.7 編寫性能測試用例

最后,提高 Rails 性能的技巧中,雖然不是最重要的,就是確認應用的性能不會因你修改了代碼而導致性能再次下降。

3 總結感言

對于一篇文章中,對于如何提高 Ruby 和 Rails 的性能,要面面俱到,確實不可能。所以,在這之后,我會通過寫一本書來總結我的經驗。如果你覺得我的建議有用,請登記 mailinglist ,當我準備好了該書的預覽版之后,將會第一時間通知你。現在,讓我們一起來動手,讓 Rails 應用跑得更快一些吧!

您可能感興趣的文章:
  • ruby on rails 代碼技巧
  • 在阿里云 (aliyun) 服務器上搭建Ruby On Rails環境
  • Windows下Ruby on Rails開發環境安裝配置圖文教程
  • win7安裝ruby on rails開發環境
  • 舉例理解Ruby on Rails的頁面緩存機制
  • 在Docker中自動化部署Ruby on Rails的教程
  • 詳解Ruby on Rails中的Cucumber使用
  • Ruby on Rails基礎之新建項目

標簽:張家界 遼寧 梧州 荊門 三沙 公主嶺 永州 普洱

巨人網絡通訊聲明:本文標題《對優化Ruby on Rails性能的一些辦法的探究》,本文關鍵詞  對,優化,Ruby,Rails,性能,的,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《對優化Ruby on Rails性能的一些辦法的探究》相關的同類信息!
  • 本頁收集關于對優化Ruby on Rails性能的一些辦法的探究的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 免费精品视频一区二区三区| 美女露胸视频| 人人揉人人人人澡人人| 深夜成人????视频在线| 经典复古欧美老A片vⅰde0| 精品三级AV在线导航| 花花公子嫩模裸乳写真| 翁与小莹最新第九部周梦莹| zO0O与人XXX欧美另类| 快穿h万人迷c哭| 中文字幕奈奈美抱公侵犯| 俺去啦视频| 3D玉极乐鉴定| 醉缠欢HH无删减版| 欧洲熟妇另类久久久久久| 国产精品密蕾丝视频下载| 桃花视频免费版高清版| 国产学生粉嫩无套进入| 日本japanese18日本护士xxxx| 台湾三级香港三级经典三在线| 国产精品秘?入口免费视频动图| 公交车上把她下面摸出水| 按摩av| 看黄色片的软件| 爽死你个放荡小婬妇打屁股视频| 欧美人妻一区二区三区四区五区| bl被别人玩屁股眼小说| 吉首市| 精品无码久久久久久国产受虐| 草莓视频在线观看地址| 在线观看91香蕉国产免费| 国产成人综合亚洲一区| 中文字幕亚洲综合久久综合第6集 男男GaY?免费网站视频军人 | 日本娇小体内?精XXX在线视频 | 欧洲毛茸茸| 理论片大全免费理伦片| 曰本成A人片日本伦| gayxxxxgay呻吟受日本| 女仆穿白丝裸体吃奶玩乳视频| 三级全黄视频| 中国美女毛片观看|