1. 程式人生 > >系統技術非業餘研究 » 大檔案重定向和管道的效率對比

系統技術非業餘研究 » 大檔案重定向和管道的效率對比

微博上的@拉風_zhang提出了個問題:

@淘寶褚霸 請教個問題,#1. cat huge_dump.sql | mysql -uroot ;#2. mysql -uroot < huge_dump.sql ;#1效率要高,在linux中通過管道傳輸 和 < 這種方式有什麼差別呢?謝謝!#AskBaye#

這個問題挺有意思的,我的第一反應是:

沒比較過,應該是一樣的,一個是cat負責開啟檔案,一個是bash

這種場景在MySQL運維操作裡面應該比較多,所以就花了點時間做了個比較和原理上的分析:
我們先構造場景:
首先準備一個程式b.out來模擬mysql對資料的消耗:

$ cat b.c
#include <stdio.h>
int main(int argc, char *argv[])
{
  char buf[4096];
  while(fread(buf, sizeof(buf), 1, stdin) > 0);
  return 0;
}
$  gcc  -o b.out b.c
$ ls|./b.out 

編譯好再順手我們的程式功能是正確的:純消耗流。

再來寫個systemtap指令碼用來方便觀察程式的行為。

$ cat test.stp
function should_log(){
  return (execname() == "cat" ||
      execname() == "b.out" ||
      execname() == "bash") ;
}
probe syscall.open,
      syscall.close,
      syscall.read,
      syscall.write,
      syscall.pipe,
      syscall.fork,
      syscall.execve,
      syscall.dup,
      syscall.wait4
{
  if (!should_log()) next;
  printf("%s -> %s\n", thread_indent(0), probefunc());
}

probe kernel.function("pipe_read"),
      kernel.function("pipe_readv"),
      kernel.function("pipe_write"),
      kernel.function("pipe_writev")
{
  if (!should_log()) next;
  printf("%s -> %s: file ino %d\n",  thread_indent(0), probefunc(), __file_ino($filp));
}
probe begin { println(":~") }

這個指令碼重點觀察幾個系統呼叫的順序和pipe的讀寫情況,

然後再準備個419M的大檔案huge_dump.sql,在我們幾十G記憶體的機器很容易在記憶體裡放下:

$ sudo dd if=/dev/urandom of=huge_dump.sql bs=4096 count=102400
102400+0 records in
102400+0 records out
419430400 bytes (419 MB) copied, 63.9886 seconds, 6.6 MB/s

因為這個檔案是用bufferio寫的,所以它的內容都cache在pagecahce記憶體裡面,不會涉及到磁碟。

好了,場景齊全了,我們接著來比較下二種情況下的速度:

$ time (cat huge_dump.sql|./b.out)

real    0m0.596s
user    0m0.001s
sys     0m0.919s

$ time (./b.out <huge_dump.sql)

real    0m0.151s
user    0m0.000s
sys     0m0.147s

從數字看出來速度有3倍左右的差別了,第二種明顯快很多。

是不是有點奇怪?好吧我們來從原來上面分析下,還是繼續用資料說話:

這次準備個很小的資料檔案,方便觀察然後在一個視窗執行stap

$ echo hello > huge_dump.sql
$ sudo stap test.stp
:~
     0 bash(26570): -> sys_read
     0 bash(26570): -> sys_read
     0 bash(26570): -> sys_write
     0 bash(26570): -> sys_read
     0 bash(26570): -> sys_write
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_pipe
     0 bash(26570): -> sys_pipe
     0 bash(26570): -> do_fork
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_close
     0 bash(26570): -> do_fork
     0 bash(13775): -> sys_close
     0 bash(13775): -> sys_read
     0 bash(13775): -> pipe_read: file ino 20906911
     0 bash(13775): -> pipe_readv: file ino 20906911
     0 bash(13776): -> sys_close
     0 bash(13776): -> sys_close
     0 bash(13776): -> sys_close
     0 bash(13776): -> do_execve
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_close
     0 bash(13775): -> sys_close
     0 bash(26570): -> sys_wait4
     0 bash(13775): -> sys_close
     0 bash(13775): -> sys_close
     0 b.out(13776): -> sys_close
     0 b.out(13776): -> sys_close
     0 bash(13775): -> do_execve
     0 b.out(13776): -> sys_open
     0 b.out(13776): -> sys_close
     0 b.out(13776): -> sys_open
     0 b.out(13776): -> sys_read
     0 b.out(13776): -> sys_close
     0 cat(13775): -> sys_close
     0 cat(13775): -> sys_close
     0 b.out(13776): -> sys_read
     0 b.out(13776): -> pipe_read: file ino 20906910
     0 b.out(13776): -> pipe_readv: file ino 20906910
     0 cat(13775): -> sys_open
     0 cat(13775): -> sys_close
     0 cat(13775): -> sys_open
     0 cat(13775): -> sys_read
     0 cat(13775): -> sys_close
     0 cat(13775): -> sys_open
     0 cat(13775): -> sys_close
     0 cat(13775): -> sys_open
     0 cat(13775): -> sys_read
     0 cat(13775): -> sys_write
     0 cat(13775): -> pipe_write: file ino 20906910
     0 cat(13775): -> pipe_writev: file ino 20906910
     0 cat(13775): -> sys_read
     0 b.out(13776): -> sys_read
     0 b.out(13776): -> pipe_read: file ino 20906910
     0 b.out(13776): -> pipe_readv: file ino 20906910
     0 cat(13775): -> sys_close
     0 cat(13775): -> sys_close
     0 bash(26570): -> sys_wait4
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_wait4
     0 bash(26570): -> sys_write

stap在收集資料了,我們在另外一個視窗執行情況1管道的情況:

$ cat huge_dump.sql|./b.out

我們從systemtap的日誌可以看出: bash fork了2個程序,然後execve分別執行cat 和 b.out程序, 這二個程序用pipe通訊,資料從由cat從 huge_dump.sql讀出,寫到pipe,然後b.out從pipe讀出處理。

那麼再看下情況二重定向的情況:

$ ./b.out < huge_dump.sql 

stap輸出:
      0 bash(26570): -> sys_read
     0 bash(26570): -> sys_read
     0 bash(26570): -> sys_write
     0 bash(26570): -> sys_read
     0 bash(26570): -> sys_write
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_pipe
     0 bash(26570): -> do_fork
     0 bash(28926): -> sys_close
     0 bash(28926): -> sys_read
     0 bash(28926): -> pipe_read: file ino 20920902
     0 bash(28926): -> pipe_readv: file ino 20920902
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_close
     0 bash(26570): -> sys_wait4
     0 bash(28926): -> sys_close
     0 bash(28926): -> sys_open
     0 bash(28926): -> sys_close
     0 bash(28926): -> do_execve
     0 b.out(28926): -> sys_close
     0 b.out(28926): -> sys_close
     0 b.out(28926): -> sys_open
     0 b.out(28926): -> sys_close
     0 b.out(28926): -> sys_open
     0 b.out(28926): -> sys_read
     0 b.out(28926): -> sys_close
     0 b.out(28926): -> sys_read
     0 b.out(28926): -> sys_read
     0 bash(26570): -> sys_wait4
     0 bash(26570): -> sys_write
     0 bash(26570): -> sys_read

bash fork了一個程序,開啟資料檔案,然後把檔案控制代碼搞到0控制代碼上,這個程序execve執行b.out,然後b.out直接讀取資料。
現在就非常清楚為什麼二種場景速度有3倍的差別:
情況1. 讀二次,寫一次,外加一個程序上下文切換。
情況二:只讀一次。

小結: 越簡單的事情,有時候越有意思!
祝玩得開心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

No related posts.

相關推薦

系統技術業餘研究 » 檔案定向管道效率對比

微博上的@拉風_zhang提出了個問題: @淘寶褚霸 請教個問題,#1. cat huge_dump.sql | mysql -uroot ;#2. mysql -uroot < huge_dump.sql ;#1效率要高,在linux中通過管道傳輸 和 < 這種方式有什麼差別

系統技術業餘研究 » Linux檔案預讀分析以及評估對系統的影響

Linux系統很重要的一個性能提升點就是它的Pagecache, 因為記憶體比IO快太多了,所以大家都想進辦法來利用這個cache。 檔案系統也不例外,為了達到高效能,檔案讀取通常採用預讀來預測使用者的行為,把使用者可能需要的資料預先讀取到cache去,達到高效能的目的。 Linux各個發行版re

系統技術業餘研究 » Erlang節點啟導致的incarnation問題

今天晚上mingchaoyan同學在線上問以下這個問題: 152489 =ERROR REPORT==== 2013-06-28 19:57:53 === 152490 Discarding message {send,<<19 bytes>>} from <0.8

系統技術業餘研究 » iozone檔案系統性能測試工具

IOzone官網: http://www.iozone.org/ IOzone is a filesystem benchmark tool. The benchmark generates and measures a variety of file operations. Iozone has

系統技術業餘研究 » Erlang match_spec引擎介紹應用

match_spec是什麼呢? A “match specification” (match_spec) is an Erlang term describing a small “program” that will try to match something (either the para

系統技術業餘研究 » 區域性性原理在計算機分散式系統中的應用課程PPT

這個課程最主要focus在資料的區域性性原理,從硬體到作業系統到應用程式這樣的順序過來的,對於我們提高核心系統軟體的效能非常有啟發意義. 課件下載點選這裡 修正:由於原連結已經不存在了,特地在這裡放了一份。 以下是教程的介紹: 課程簡介 ___________________________

系統技術業餘研究 » Fio壓測工具io佇列深度理解誤區

Fio 是個強大的IO壓力測試工具,我之前寫過不少fio的使用和實踐,參見 這裡。 隨著塊裝置的發展,特別是SSD盤的出現,裝置的並行度越來越高。利用好這些裝置,有個訣竅就是提高裝置的iodepth, 一把餵給裝置更多的IO請求,讓電梯演算法和裝置有機會來安排合併以及內部並行處理,提高總體效率。

系統技術業餘研究 » qperf測量網路頻寬延遲

我們在做網路伺服器的時候,通常會很關心網路的頻寬和延遲。因為我們的很多協議都是request-reponse協議,延遲決定了最大的QPS,而頻寬決定了最大的負荷。 通常我們知道自己的網絡卡是什麼型號,交換機什麼型號,主機之間的物理距離是多少,理論上是知道頻寬和延遲是多少的。但是現實的情況是,真正的

系統技術業餘研究 » 轉:CPU密集型計算 erlangC 比拼

原文地址:http://pseudelia.wordpress.com/2009/08/23/erlang-native-code-benchmark/ Normalerweise compiliert Erlang Bytecode (heißt das so in Erlang?). Das

系統技術業餘研究 » vanilla_driver最高效的讀檔案行的方法

vanilla_driver是Erlang內建的驅動,用於高效讀取檔案控制代碼或者檔名,官方的文件沒記載. 我來挖掘下: [email protected]:~# cat >>hello.txt hello world CTRL+D [email prot

系統技術業餘研究 » Linux下試驗頁面對映(MAP_HUGETLB)

Linux對大頁面記憶體的引入對減少TLB的失效效果不錯,特別是記憶體大而密集型的程式,比如說在資料庫中的使用。innodb引擎就支援大頁面記憶體,具體使用可參見 這裡。 大頁面更詳細的資料可以參考: Documentation/vm/hugetlbpage.txt 過去使用大頁面記憶體主要透過h

系統技術業餘研究 » Erlang R15最的賣點Native Process

R15最激動人心的東西就是這個Native Process,請參看Rickard Green寫的Future Extensions to the Native Interface:看 這裡 我來blabla下。 做過Erlang規模程式的人都知道有個痛, Erlang的公平排程引起的痛。 舉個例子

系統技術業餘研究 » Linux下如何知道檔案被那個程序寫

晚上朔海同學問: 一個檔案正在被程序寫 我想檢視這個程序 檔案一直在增大 找不到誰在寫 使用lsof也沒找到 這個問題挺有普遍性的,解決方法應該很多,這裡我給大家提個比較直觀的方法。 linux下每個檔案都會在某個塊裝置上存放,當然也都有相應的inode, 那麼透過vfs.write我們就可以知道

系統技術業餘研究

ItPub寫的文章“2017 年度 DB-Engines 資料庫冠軍得主:PostgreSQL 封王!”, 點選 這裡 進一步閱讀 升的最快的幾個資料庫,我簡單的無責任點評: PG資料庫是很老的資料庫,不過這幾年冉冉升起,因為是學院派的,有很好的學術和智力的支援,一直以來在資料庫的體系結構,程式碼

系統技術業餘研究 » MySQL資料庫架構的演化觀察

MySQL資料庫架構的演化觀察 December 14th, 2017 Categories: 資料庫 Tags: mysql

系統技術業餘研究 » inet_dist_connect_options

Erlang 17.5版本引入了inet_dist_{listen,connect}_options,對於結點間的互聯socket可以有更精細的控制,RPC的時候效能可以微調: raimo/inet_tcp_dist-priority-option/OTP-12476: Document ke

系統技術業餘研究 » 推薦工作機會

最後更新時間:2014/11/28 請賜簡歷至:[email protected], 感謝您對加入我們公司有興趣,我們希望能早日和您共事。 以下幾個職位1年內有效,歡迎內部轉崗:
 資深資料工程師 公司:阿里(核心系統資料庫組) 工作地點:杭州(西溪園區) 崗位描述: 分析雲服務產生的海

系統技術業餘研究 » 新的工作研究方向

和大家更新下: 做了將近8年資料庫後,我的工作和研究方向將會延伸到虛擬化和計算相關的雲服務,希望能夠和大家一起進步,Happy New Year! 預祝大家玩得開心! Post Footer automatically generated by wp-posturl plugin for w

系統技術業餘研究 » 叢集引入inet_dist_{listen,connect}_options更精細引數微調

Erlang 17.5版本引入了inet_dist_{listen,connect}_options,對於結點間的互聯socket可以有更精細的控制,RPC的時候效能可以微調: raimo/inet_tcp_dist-priority-option/OTP-12476: Document ke

系統技術業餘研究 » 2017升的最快的幾個資料庫無責任點評

ItPub寫的文章“2017 年度 DB-Engines 資料庫冠軍得主:PostgreSQL 封王!”, 點選 這裡 進一步閱讀 升的最快的幾個資料庫,我簡單的無責任點評: PG資料庫是很老的資料庫,不過這幾年冉冉升起,因為是學院派的,有很好的學術和智力的支援,一直以來在資料庫的體系結構,程式碼