排查效能問題往往比排查功能性的Bug更讓人頭疼,主要有以下幾個原因

  • 很多效能問題只會在高負載的生產環境下出現,在開發過程中很難發現。
  • 功能性出錯時我們通常會丟擲異常,我們可以通過Tracestack很快定位到問題所在程式碼的位置。但對於效能問題,我們很難做這樣的快速定位。
  • 雖然我們有各式各樣的Profiling工具,但適用於對生產環境的並不多。當然這因程式語言而異,Glow伺服器端的技術棧是Python + Gevent,目前為止我們都沒有找到合適的Profiling工具。

對於伺服器端的效能問題,我們常用的方法是寫日誌檔案,例如把每個請求的響應時間都記錄下來,但對海量日誌檔案的儲存,聚合與分析又成了另一個麻煩。常用的解決方案有ElasticSearch + Logstack + Kibana,或是StatsD/CollectD + Graphite等等。在Glow,對於效能監控這樣的通用服務,我們更偏向於選擇雲服務,而不是自己去維護這些系統,這樣我們的精力才能集中在產品研發上。

在對於效能監控類的雲服務做了一些橫向比較後,我們選擇了Datadog,使用一年多,感覺很不錯,所在在這裡分享給大家。

Datadog簡介

Datadog的工作方式是在每一臺需要監控的伺服器上執行它的Agent。Agent不但會收集這臺伺服器的各類基礎效能資料,如CPU使有率,剩餘記憶體空間,剩餘磁碟空間,網路流量等,也可以收集使用者自定義的效能資料,靈活性很好。

Datadog另一個好用的地方在於它與眾多的雲服務和開源專案有整合,我們在實際用的整合有

  • AWS EC2
  • AWS RDS
  • Redis
  • Nginx
  • Slack (用來報警)

下面圖中是我們一臺Redis伺服器的監控面板,除了可以看內建的基本效能資訊外(CPU,記憶體,網路等),也可以實時地看到Redis伺服器的連線數,Key的總數,每秒接收到指令數等,相當實用。 Redis dashbaord

Datadog也可以對各種監控的效能指標設定閾值,當指標超出閾值範圍時,發出警報。我們可以利用它與Slack的整合,直接將警報推送到Slack上。
Slack integration

自定義指標 - Custom metrics

雖說Datadog內建系統監控以及第三方整合都很好用,但它真正強大之處在於可以方便地自定義指標。這些自定義的指標可以是Web server對每個請求的響應時間,或是資料庫中每張表的讀寫請求數,也可以是Job queue裡pending的job數量。因為可以自定義想要收集的資料,所以不會受限於Datadog原生提供的功能,這也是當初我們選擇這個雲服務的主要原因。

Datadog的自定義指標有兩種型別Count和Histogram。Count比較直觀,就是用於記數,用來統計某個事件在一個時間區間內發生了多次次,例如我們可以定義一個page_view

來記錄應用中每個頁面的訪問次數。但在效能監控中,Histogram更為有用,它的每個資料點是一個時間戳加上一個浮點值,所以它不但可以統計某個事件在一個時間區間內發生的次數,也可以統計這些事件所對應的浮點值的平均值,中位數,最大值,最小值等等。如果這聽起來還是比較抽象,一個實際的例子就是記錄伺服器對每個請求的響應時間。用Histogram來記錄,我們就可以方便地得到某個時間段的平均響應時間和最長響應時間,而這兩個資料對於效能監控至關重要。

對傳送到Datadog的每個資料點,我們都可以新增多個tag,這對於之後資料的查詢與分類非常有幫助,比如我們可以根據資料來自哪個microservice,給它們打上不同的tag。在實際使用中,我們會以更細的粒度在資料點上新增tag。

下面是向Datadog傳送自定義指標的Python程式碼示例,其中statsd是Datadog提供的一個類庫。

from statsd import statsd

# send count data
statsd.increment('event.page_view', tags=['app:glow', 'page:home'])

# send histogram data
statsd.histogram('service.response_time', 0.2,  
                 tags=['app:nurture', 'service:user', 'api:get_user_by_id'])

第一個例子我們用statsd.increment來發送Count型別的資料,通過兩個tag,我們告訴Datadog,這次訪問發生在Glow app的Home page上。之後我們可以在多個粒度上統計某段時間內頁面訪問的次數

  • Glow的Home有多少次頁面訪問
  • Glow app有多少次頁面訪問
  • 所有的app總共有多少次頁面訪問

第二個例子我們記錄的是Histogram型別的資料。這裡假設在我們的Nurture應用下,有一個專用於讀寫使用者資料的User service,某次訪問該服務下get_user_by_id這個API的響應時間為0.2秒。通過三個tag,我們之後可以在下面幾個粒度對某段時間內的響應時間進行統計

  • Nurture app的響應時間
  • User service的響應時間
  • User service下get_user_by_id的響應時間

在Datadog上建立Dashboard

當我們把想要監控的資料傳送給Datadog後,下一步就是將統計資料視覺化,這一步可以通過在Datadog上建立Dashboard來完成。雖然Datadog提供了很多種圖表的型別,但最常用的是Time Series和Top List。前者用於顯示某組指標在一段時間內的變化,比如檢視服務響應時間在最近24小時內的變化曲線。後者用於顯示在某段時間內某一指標的排名,比如檢視最近24小時響應時間最長的10個API。

下面看一個簡單的Time Series Graph的例子

Create graph for web server response time

這裡用的自定義指標名為www.resp_time(web響應時間),它是從我們的程式碼裡通過statsd.histogram傳送到Datadog的。from env:prod限定了我們只關心生產環境下的資料,後面的avg by app表示在圖中顯示每個app響應時間的平均值。這裡app,env都是在傳送資料時附加在www.resp_time上的tag。下圖是某段時間內響應時間的變化曲線,那段時間伺服器有些不穩定,雖然平均響應時間在0.2 - 0.4秒之間,但一些時間點上的峰值超過了2秒。其中bryo,emma,kaylee,lexie等等都是我們app的code name。

Web server response time

下面再看一個的Top List的例子

Greate top list for forum response time

上面這例子列出了在生產環境中(env:prod),Forum service下10個響應時間最長的API的URL。並且當響應時間超過0.5時,用紅色背景顯示。

圖表中顯示的資料也可以是若干個指標的數學運算組合。假設我們在程式碼中傳送了應用層快取的Cache hit與Cache miss的Count資料到Datadog,我們就可以建立一個圖表來顯示快取的命中率,也就是cache.hit / (cache.hit + cache.miss)

Create cache hit rate

上圖中acache.hitbcache.miss,然後我們把Graph these queries as設為a / (a + b)

監控與報警

我們不可能每時每刻都關注Datadog上的Dashboard,但當某些服務無法工作或是效能指標異常時,我們希望可以立即被通知到。Datadog的監控報警可以與Slack整合。在發生異常時,Datadog可以把訊息推送到Slack的一個Group裡,這樣所有在這個Group裡的人都能在手機上收到推送通知。

Datadog的監控與報警和配置介面很直觀,基本不需要什麼學習成本。比如在下圖中,我們建立了一個監控web server響應時間的監控,當最近5分鐘內的平均響應時間超過1.0秒時報警

Create monitor

為了保證生產環境的正常運作,我們可能需要建立非常多的監控,這裡有許多的重複勞動(例如,每個app都要對響應時間做監控),純手動操作既低效又容易出錯。幸運的是,Datadog可以通過它的RESTful API來管理監控。這樣配合一些系統配置工具可以更有效地管理這些監控。下面這段Ansible程式碼可以為我們所有的app建立了響應時間的監控,其中dd_monitor是Datadog Monitor的簡寫,也是我們自己編寫的一個Ansible的模組。

- name: Datadog monitor for web request latency
  dd_monitor:
    name: "{{ item }} web request latency"
    type: metric alert
    message: |
      - Take look WWW and Webrpc dashboards on Datadog
      - And then dig into slow request logs on syslog server.
    query: 'avg(last_5m):avg:www.resp_time.avg{app:{{ item }}} by {host} > 1'
  with_items: ['emma', 'kaylee', 'lexie', 'noah']

小結

生產系統的效能監控並不僅僅是為了保證系統的穩定性,也是為了可以持續地改進整體的系統架構。效能調優是任何一個對技術有熱情的團隊都願意做的事情。但很多時候一些技術人員雖熱衷於嘗試新的技術與想法,但卻缺少一種“一切以資料說話”的態度。我的觀點是,沒有明確的量化指標,效能優化就無從談起。也不要輕易地去拿一些網上的benchmark來說話,因為真實的生產環境複雜地多。這篇文章雖然是對Datadog這個工具的介紹,但我想傳達是一種對生產環境的真實效能做全方位量化的態度。從每個API call所用的時間,到各個層級快取的使用頻率與命中率,再到資料庫每張的讀寫頻率與響應時間,這些資料都需要收集,不但要收集,更需要有效地視覺化,讓技術團隊方便實時地分析這些資料,並基於資料來決定未來架構的發展。

擴充套件閱讀