God教程

一、什么是God

God 是用 Ruby 寫的進程監控框架,具有易配置易擴展的優點。用它可以很方便的監控一個軟件的運行狀態,并在特定的條件下殺死或重啟進程,以保證任務的持久性和高可用性。

常見場景

  • 監控一個進程,當它因意味錯誤退出或失去響應時重新啟動它。
  • 監控一個進程,當它耗費的CPU或內存超過特定值時殺死或重新啟動它。

二、God的優缺點

優點:

  • 啟動和控制都使用一個命令: god
  • 可以管理daemon和非daemon進程
  • 可以設置進程的uid、env、dir、log等參數
  • 進程配置文件和supervisord類似,但使用ruby的語法。支持類似monit的,對進程使用資源和各種條件的控制
  • 支持進程配置動態加載功能
  • 支持把多個進程配置拆分成單獨的配置文件,類似include功能
  • 支持通知功能,包括:Webhook、Email、Twitter、Jabber、Campfire等多個接口
  • 根據PID的方式進行監控,GOD可以隨便升級和重啟

缺點

  • 不提供web端和rpc接口
  • log查看stdrr/stdout 功能似乎不能正常work,不過我基本上用不到這個功能
  • linux下采用2種方式檢測進程poll和event。root默認啟用event模式,如果啟動的進程錯誤,它會注冊一個proc_exit事件,但無法響應。

三、安裝

最好的方法是通過rubygems安裝:

 $[sudo] gem install god

四、快速開始

新建一個目錄,然后寫一個簡單的服務器腳本。讓我們給它命名為simple.rb:

新建一個目錄,然后寫一個簡單的服務器腳本。讓我們給它命名為simple.rb:

loop do
  puts 'Hello'
  sleep 1
end

現在我們將寫一個god配置文件,告訴god關于我們的進程。把它和simple.rb放在同一個文件夾,命名為simple.god:

God.watch do |w|
  w.name = "simple"
  w.start = "ruby /full/path/to/simple.rb"
  w.keepalive
end

這是最簡單的god配置文件。
我們以宣布一個God.watch塊開始。
一個watch在god里代表一個我們想要watch和控制的進程。
每個watch必須有一個唯一的名字和一個告訴god怎么啟動進程的命令。
keepalive的聲明告訴god保持這個進程alive。
假如god啟動時這個進程沒有運行,god將會啟動它。假如進程不響應,god就會重新啟動它。

在這個例子里,simple進程在前端運行,所以god會照看該進程,保持跟蹤這個進程的PID。
如果可能,最好要god為我們啟動進程,這樣我們就不必擔心指定和保持跟蹤PID的文件。
后面我們將看見不能在前景運行或者需要指定進程PID的情況下怎樣管理。

為了運行god,我們使用參數-c給它提供一個參數。通過參數-D就可以讓god在前端運行,能讓我們看見發生了什么。

$ god -c path/to/simple.god -D

god可以通過兩種方式來監控你的進程。
第一個和最好的一個是方法是用event。
不是每個系統都支持,但是如果系統支持的話會自動使用event。
通過event,god會立即知道一個進程是否存在。
對那些系統沒有event支持的,god使用polling機制。這個部分的整個輸出如下:

# Events
I [2011-12-10 15:24:34]  INFO: Loading simple.god
I [2011-12-10 15:24:34]  INFO: Syslog enabled.
I [2011-12-10 15:24:34]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-10 15:24:34]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-10 15:24:34]  INFO: simple move 'unmonitored' to 'init'
I [2011-12-10 15:24:34]  INFO: simple moved 'unmonitored' to 'init'
I [2011-12-10 15:24:34]  INFO: simple [trigger] process is not running (ProcessRunning)
I [2011-12-10 15:24:34]  INFO: simple move 'init' to 'start'
I [2011-12-10 15:24:34]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-10 15:24:34]  INFO: simple moved 'init' to 'start'
I [2011-12-10 15:24:34]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:24:34]  INFO: simple move 'start' to 'up'
I [2011-12-10 15:24:34]  INFO: simple registered 'proc_exit' event for pid 23298
I [2011-12-10 15:24:34]  INFO: simple moved 'start' to 'up'

# Polls

I [2011-12-07 09:40:18]  INFO: Loading simple.god
I [2011-12-07 09:40:18]  INFO: Syslog enabled.
I [2011-12-07 09:40:18]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-07 09:40:18]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-07 09:40:18]  INFO: simple move 'unmonitored' to 'up'
I [2011-12-07 09:40:18]  INFO: simple moved 'unmonitored' to 'up'
I [2011-12-07 09:40:18]  INFO: simple [trigger] process is not running (ProcessRunning)
I [2011-12-07 09:40:18]  INFO: simple move 'up' to 'start'
I [2011-12-07 09:40:18]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-07 09:40:19]  INFO: simple moved 'up' to 'up'
I [2011-12-07 09:40:19]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:40:24]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:40:29]  INFO: simple [ok] process is running (ProcessRunning)

你可以看見god啟動了,注意到simple沒有在運行,啟動它,然后每隔5分鐘檢查一下確保simple運行正常。
假如你想看見god的魔力,kill simple的進程。你會發現類似如下的輸出:

# Events
I [2011-12-10 15:33:38]  INFO: simple [trigger] process 23416 exited (ProcessExits)
I [2011-12-10 15:33:38]  INFO: simple move 'up' to 'start'
I [2011-12-10 15:33:38]  INFO: simple deregistered 'proc_exit' event for pid 23416
I [2011-12-10 15:33:38]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-10 15:33:38]  INFO: simple moved 'up' to 'start'
I [2011-12-10 15:33:38]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:33:38]  INFO: simple move 'start' to 'up'
I [2011-12-10 15:33:38]  INFO: simple registered 'proc_exit' event for pid 23601
I [2011-12-10 15:33:38]  INFO: simple moved 'start' to 'up'

# Polls

I [2011-12-07 09:54:59]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:55:04]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:55:09]  INFO: simple [trigger] process is not running (ProcessRunning)
I [2011-12-07 09:55:09]  INFO: simple move 'up' to 'start'
I [2011-12-07 09:55:09]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-07 09:55:09]  INFO: simple moved 'up' to 'up'
I [2011-12-07 09:55:09]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:55:14]  INFO: simple [ok] process is running (ProcessRunning)

保持進程啟動是好的,但是假如能夠保證我們的進程表現良好,當資源超過我們的設置,重新啟動進程將更好。通過添加一點條件,當內存或者CPU超過我們設定的限制,我們能夠容易地讓我們的進程重啟。編輯simple.god配置文件如下:

God.watch do |w|
  w.name = 'simple'
  w.start = "ruby /full/path/to/simple.rb"
  w.keepalive( :memory_max => 150.megabytes,
               :cpu_max => 50.percent)
end

這里我在keepalive命令中使用了 :memory_max 選項。
現在,假如進程的內存用量超過150M, god就會重啟他。
相似地,通過設置 :cpu_max, 假如CPU的使用超過50%,god也會重啟它。
默認這些屬性每隔30秒檢查一次,假如五個條件中滿足三個,則會執行。這防止了進程因為暫時的資源峰值導致重啟。

為了測試這個特性,修改你的simple.rb服務器腳本使得引起內存泄露:

data = ''
loop do
  puts 'Hello'
  100000.times { data << 'x' }
end

按Ctrl-C結束god。注意到你的simple進程依然在運行。
用剛才的方式再次啟動god。
現在代替了啟動simple進程,god監測到simple運行,簡單的切換到up狀態。

# Events
I [2011-12-10 15:36:00]  INFO: Loading simple.god
I [2011-12-10 15:36:00]  INFO: Syslog enabled.
I [2011-12-10 15:36:00]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-10 15:36:00]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-10 15:36:00]  INFO: simple move 'unmonitored' to 'init'
I [2011-12-10 15:36:00]  INFO: simple moved 'unmonitored' to 'init'
I [2011-12-10 15:36:00]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:36:00]  INFO: simple move 'init' to 'up'
I [2011-12-10 15:36:00]  INFO: simple registered 'proc_exit' event for pid 23601
I [2011-12-10 15:36:00]  INFO: simple moved 'init' to 'up'

# Polls

I [2011-12-07 14:50:46]  INFO: Loading simple.god
I [2011-12-07 14:50:46]  INFO: Syslog enabled.
I [2011-12-07 14:50:46]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-07 14:50:47]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-07 14:50:47]  INFO: simple move 'unmonitored' to 'up'
I [2011-12-07 14:50:47]  INFO: simple moved 'unmonitored' to 'up'
I [2011-12-07 14:50:47]  INFO: simple [ok] process is running (ProcessRunning)

為了讓我們的simple服務運行,我們重新啟動simple,這里必須強烈地要求重啟否則新添加的配置不會生效

god restart simple 

通過日志你可以看見god結束了simple進程并重新啟動了:

# Events

I [2011-12-10 15:38:13]  INFO: simple move 'up' to 'restart'
I [2011-12-10 15:38:13]  INFO: simple deregistered 'proc_exit' event for pid 23601
I [2011-12-10 15:38:13]  INFO: simple stop: default lambda killer
I [2011-12-10 15:38:13]  INFO: simple sent SIGTERM
I [2011-12-10 15:38:14]  INFO: simple process stopped
I [2011-12-10 15:38:14]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-10 15:38:14]  INFO: simple moved 'up' to 'restart'
I [2011-12-10 15:38:14]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:38:14]  INFO: simple move 'restart' to 'up'
I [2011-12-10 15:38:14]  INFO: simple registered 'proc_exit' event for pid 23707
I [2011-12-10 15:38:14]  INFO: simple moved 'restart' to 'up'

# Polls

I [2011-12-07 14:51:13]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:51:13]  INFO: simple move 'up' to 'restart'
I [2011-12-07 14:51:13]  INFO: simple stop: default lambda killer
I [2011-12-07 14:51:13]  INFO: simple sent SIGTERM
I [2011-12-07 14:51:14]  INFO: simple process stopped
I [2011-12-07 14:51:14]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-07 14:51:14]  INFO: simple moved 'up' to 'up'
I [2011-12-07 14:51:14]  INFO: simple [ok] process is running (ProcessRunning)

God現在開始報告內存和CPU的使用情況

# Events and Polls

I [2011-12-07 14:54:37]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:37]  INFO: simple [ok] memory within bounds [2032kb] (MemoryUsage)
I [2011-12-07 14:54:37]  INFO: simple [ok] cpu within bounds [0.0%%] (CpuUsage)
I [2011-12-07 14:54:42]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:42]  INFO: simple [ok] memory within bounds [2032kb, 13492kb] (MemoryUsage)
I [2011-12-07 14:54:42]  INFO: simple [ok] cpu within bounds [0.0%%, *99.7%%] (CpuUsage)
I [2011-12-07 14:54:47]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:47]  INFO: simple [ok] memory within bounds [2032kb, 13492kb, 25568kb] (MemoryUsage)
I [2011-12-07 14:54:47]  INFO: simple [ok] cpu within bounds [0.0%%, *99.7%%, *100.0%%] (CpuUsage)
I [2011-12-07 14:54:52]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:52]  INFO: simple [ok] memory within bounds [2032kb, 13492kb, 25568kb, 37556kb] (MemoryUsage)
I [2011-12-07 14:54:52]  INFO: simple [trigger] cpu out of bounds [0.0%%, *99.7%%, *100.0%%, *98.4%%] (CpuUsage)
I [2011-12-07 14:54:52]  INFO: simple move 'up' to 'restart

在最后的一行,你能看見CPU的用量已經超過了50%三次了,
god重新啟動了進程。god會持續地監測simple進程,只要god在運行,進程就會被一直監控。

現在,你結束god之前,讓我們先通過god結束simple服務。在一個新的終端,輸入以下命令:

god stop simple 

如果想停止god,你可以自由地Ctrl-C 退出god 了。

不過這只是個開始。在實際應用中,keepalive 命令是一個方便的方法,使用了可以直接使用的更高級的事務和條件構造。你可以配置許多不同的條件,當CPU或者內存使用太多,磁盤超過下限,當一個指定的URL返回錯誤代碼,等等。另外,你可以寫自己的自定義條件,然后在配置文件里使用它。伴隨著復雜的和可擴展的通知體系,可以控制許多不同的生命周期。

既然你已經知道怎么使用god,讓我們看看god更強大的一面吧。再說一次,最好的學習方法是通過示例。下面這個配置文件是我在gravatar.com保證mongrels運行使用的配置文件。

## 在這里我設置了一個常量,用于整個文件。保持RAILS_ROOT的值是一個常量使得腳本很容易適合其他應用
RAILS_ROOT = "/Users/tom/dev/gravatar2"


## 循環監控  8200 8210 8202 端口
%w{8200 8201 8202}.each do |port|
  God.watch do |w|
    w.name = "gravatar2-mongrel-#{port}"

    ## 使用 mogrel_rails 命令啟動
    w.start = "mogrel_rails start -c #{RAILS_ROOT} -p #{port} \
      -P #{RAILS_ROOT}/log.mogrel.#{port}.pid -d"

    ## 使用 mogrel_rails 命令停止
    w.stop = "morgrel_rails stop -P #{RAILS_ROOT}/log/mogrel.#{port}.pid"
    ##  重啟
    w.restart = "mongrel_rails restart -P #{RAILS_ROOT}/log/mogrel.#{port}.pid"

    w.pid_file = File.join(RAILS_ROOT, "log/mogrel.#{port}.pid")

    ## 假如你正監視的進程是一個后天進程(我的也是),你需要設置pid_file屬性。????
    ## behavio允許你伴隨著start/stop/restart執行額外的命令。
    ## 在我們的例子里,假如進程死了,它會留下PID文件。
    ## 假如下次重新啟動這個程序,就會啟動失敗,提示PID文件已經存在。
    ## 所以啟動程序時,我們想先清除PID文件。內建的clean_pid_file就會清除
    w.behavior(:clean_pid_file)


    ## watch包含由可執行的動作組成的條件應該返回true
    w.start_if do |start|
      start.condition(:process_running) do |c|
        ## 通過用一個識別字符調用condition條件來描述condition,這個例子中是:process_running. 每個條件描述一個poll間隔,這個間隔將覆蓋默認的間隔。這個例子中,我想要每個5秒鐘檢查一次進程,而不是像其他condition一樣用30秒間隔
        c.inteval = 5.seconds
        c.running = false
      end
    end

    ## 和start_if類似,restart_if命令組合condition,
    ## 然后觸發restart。memory_usage條件將會失敗,
    ## 假如指定的進程使用了太多的內存。
    ## 最大允許的內存通過above屬性來指定(你可以用kilobytes, megabytes, 或者gibabytes助手)。
    ## 為了觸發restart需要觸發的次數通過times設置。
    ## 這個可以是一個整數,也可以是一個數組。
    ## 整數意味著它必須連續失敗許多次而數組[x, y]意味著必須y次中失敗x次。
    w.restart_if do |restart|
      restart.condition(:memory_usage) do |c|
       c.above = 150.megabytes
       c.times = [3, 5] # 3 out of 5 intevals
      end

      restart.condition(:cpu_usage) do |c|
        c.above = 50.percent
        c.times = 5
      end
    end

    #lifecycle
    ## 在lifecycle部分中的condition只要進程被監視就一直活動(它們通過狀態的改變活動)。
    ## :flapping condition守護除了god快速開始和重啟你的應用的這些邊緣的狀態的其他情況。
    ## 比如服務器配置變化或者外部服務的不可用都可能造成我得進程不能啟動。
    ## 那樣的話,god將會一直重試啟動我的進程。
    ## :flapping condition提供了兩個水平的放棄不穩定進程。
    ## 假如我翻譯以上的option代碼,那就是:
    ## 假如watch在5分鐘里被啟動或者重啟了5次,然后不再監視它。。。
    ## 然后10分鐘后,再次監視他看看是否只是一個臨時的問題;
    ## 假如進程在兩小時里依然不穩定,然后徹底放棄監視
    ## lifecycle 是一個非常重要的配置,之前聽過架構師說過,God 進程怎么一直在重啟
    ## 肯定就是這里的坑!!!!!!!
    w.lifecycle do |on|
     on.condition(:flapping) do |c|
       c.to_state = [:start, :restart]
       c.times = 5
       c.within = 5.minute
       c.transition = :unmonitored
       c.retry_in = 10.minutes
       c.retry_times = 5
       c.retry_within = 2.hours
     end
    end
   end
  end

五、動態加載文件進入一個已經運行的god

God允許你加載或者重新加載配置文件進入一個已經運行的實例。當你準備這樣做得時候,有幾件事情需要考慮:

  • 已經存在的watch會被新配置文件里的同名的watch覆蓋
  • 所有的路徑必須是絕對路徑或者god運行的相對路徑

將配置文件加載至一個正在運行的god,運行以下命令:

sudo god load path/to/config.god

動態加載的配置文件可以包含任何一個普通的配置文件,然而,全局變量例如God.pid_file_directory塊將可能會被忽視(會在日志里產生一個警告)。

如果把god作為一個后臺進程,只需要把配置文件的路徑傳遞給god(你需要使用sudo假如你在linux使用event或者想要使用setuid/setgid)

sudo god -c /path/to/config.god

當你寫配置文件的時候,在前臺運行god這樣你能看見log消息,可能會很有幫助。你可以:

sudo god -c /path/to/config.god -D

你能啟動、重啟、停止、監測、不監測你的watch用同樣的工具像這樣:

sudo god stop gravatar2-mongrel-8200

六、God 的其他功能

+ 重定向你進程的STDOUT和STDERR
+ 改變進程的UID/GID
+ 設置工作目錄
+ 設置環境變量
+ 使用CHROOT改變文件系統的根目錄
+ Lambda命令
+ 自定義默認的停止運行lambda
+ 加載其他配置文件
+ 為單個watch得到日志文件
+ 通知

轉載,有修改。原文God 使用手冊

參考

God(進程監控)
God進程監控框架
God 使用手冊

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,636評論 25 708
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,898評論 6 342
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,151評論 4 61
  • 原創:liuzesheng 我知道,鉆石本質是什么?就是元素碳。和我們做飯的煤球一個元素。 為什么這樣貴咧?物以稀...
    liuzesheng閱讀 350評論 4 10