bit.ly 是一個全球知名的短網址服務商,為網民提供網址和連結縮短服務。Bitly 公司2008年成立於紐約。據說 bitly 每月縮短超過10億個網址用於社交網路分享傳播。2009年5月6日 bit.ly 一度成為 Twitter 預設的短網址,後來被 Twitter 自家的 t.co 取代。今年年初 bitly 運維團隊官方技術部落格發了一篇文章,分享了他們的一些經驗教訓。以下是全文。
我們總是會監控很多指標(比如硬碟利用率、記憶體利用率、負載、ping等等)。除了這些,我們還從運營自家產品系統的過程中吸取了很多經驗教訓,這些經驗教訓幫助我們擴充了在bitly的監控範圍。
下面是我最喜歡的推特之一,來自@DevOps_Borat
開發者的墨菲定律:如果一件事情可能會出現錯誤,那麼這就意味著它已經出錯了,只不過你還沒有發現罷了。
下面是一個我們運營bitly時的監控清單,這些例子的背後故事,有時甚至可以稱為痛苦的經歷,幫助了bitly的成長。
1.叉率 | Fork Rate
我們曾經遇到過這樣一個問題:通過設定options ipv6 disable=1和在/etc/modprobe.conf中的alias ipv6 off,將一臺伺服器的IPv6關閉。不過這可給我們找了一個大麻煩:每次建立一個新的curl物件,modprobe都會被呼叫,並通過檢查net-pf-10來確定IPv6的狀態。這可給伺服器帶來了很大的負擔,最終我們發現了/proc/stat下的程式計數器會以每秒數以百計的速度增長,進而發現了上面說到的那些現象的原因。通常你會希望在一臺流量穩定的機器上的叉率保持在1-10/s。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
#!/bin/bash # Copyright bitly, Aug 2011 # written by Jehiah Czebotar DATAFILE="/var/tmp/nagios_check_forkrate.dat" VALID_INTERVAL=600 OK=0 WARNING=1 CRITICAL=2 UNKNOWN=-1 function usage() { echo "usage: $0 --warn=<int> --critical=<int>" echo "this script checks the rate processes are created" echo "and alerts when it goes above a certain threshold" echo "it saves the value from each run in $DATAFILE" echo "and computes a delta on the next run. It will ignore" echo "any values that are older than --valid-interval=$VALID_INTERVAL (seconds)" echo "warn and critical values are in # of new processes per second" } while [ "$1" != "" ]; do PARAM=`echo $1 | awk -F= '{print $1}'` VALUE=`echo $1 | awk -F= '{print $2}'` case $PARAM in -w | --warn) WARN_THRESHOLD=$VALUE ;; -c | --critical) CRITICAL_THRESHOLD=$VALUE ;; --valid-interval) VALID_INTERVAL=$VALUE ;; -h | --help) usage exit 0; ;; esac shift done if [ -z "$WARN_THRESHOLD" ] || [ -z "$CRITICAL_THRESHOLD" ]; then echo "error: --warn and --critical parameters are required" exit $UNKNOWN fi if [[ $WARN_THRESHOLD -ge $CRITICAL_THRESHOLD ]]; then echo "error: --warn ($WARN_THRESHOLD) can't be greater than --critical ($CRITICAL_THRESHOLD)" exit $UNKNOWN fi NOW=`date +%s` min_valid_ts=$(($NOW - $VALID_INTERVAL)) current_process_count=`awk '/processes/ {print $2}' /proc/stat` if [ ! -f $DATAFILE ]; then mkdir -p $(dirname $DATAFILE) echo -e "$NOW\t$current_process_count" > $DATAFILE echo "Missing $DATAFILE; creating" exit $UNKNOWN fi # now compare this to previous mv $DATAFILE{,.previous} while read ts process_count; do if [[ $ts -lt $min_valid_ts ]]; then continue fi if [[ $ts -ge $NOW ]]; then # we can't use data from the same second continue fi # calculate the rate process_delta=$(($current_process_count - $process_count)) ts_delta=$(($NOW - $ts)) current_fork_rate=`echo "$process_delta / $ts_delta" | bc` echo -e "$ts\t$process_count" >> $DATAFILE done < $DATAFILE.previous echo -e "$NOW\t$current_process_count" >> $DATAFILE echo "fork rate is $current_fork_rate processes/second (based on the last $ts_delta seconds)" if [[ $current_fork_rate -ge $CRITICAL_THRESHOLD ]]; then exit $CRITICAL fi if [[ $current_fork_rate -ge $WARN_THRESHOLD ]]; then exit $WARNING fi exit $OK |
2.流控制包
參考資料。如果你的網路設定中包括流控制包,並且你沒有設定禁止它們,那麼它們有時可能會引起流量丟失。(如果你覺得這聽起來還不夠嚴重,那你也許該檢查下你的腦袋裡都裝了些什麼了)。
1 2 3 4 5 |
$ /usr/sbin/ethtool -S eth0 | grep flow_control rx_flow_control_xon: 0 rx_flow_control_xoff: 0 tx_flow_control_xon: 0 tx_flow_control_xoff: 0 |
注:閱讀這個來更加詳細的瞭解當你使用某些博通網路卡時,這些流控制幀是如何和連結的損耗聯絡在一起的。
3.交換輸入/輸出速率
人們通常會檢查超過某一閾值的交換使用率。不過即便你僅僅只有一小部分記憶體被交換,實際上影響效能的卻是交換輸入/輸出的速率,而不是數量。檢查交換輸入/輸出速率會更直觀。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
#!/bin/bash # Show the rate of swapping (in number of pages) between executions OK=0 WARNING=1 CRITICAL=2 UNKNOWN=-1 EXITFLAG=$OK WARN_THRESHOLD=1 CRITICAL_THRESHOLD=100 IN_DATAFILE="/var/tmp/nagios_check_swap_pages_in.dat" OUT_DATAFILE="/var/tmp/nagios_check_swap_pages_out.dat" VALID_INTERVAL=600 function usage() { echo "usage: $0 --warn=<pages per second in or out> --critical=<pages per second in or out>" echo "Script checks for any swap usage" } while [ "$1" != "" ]; do PARAM=`echo $1 | awk -F= '{print $1}'` VALUE=`echo $1 | awk -F= '{print $2}'` case $PARAM in --warn) WARN_THRESHOLD=$VALUE ;; --critical) CRITICAL_THRESHOLD=$VALUE ;; -h | --help) usage exit 0; ;; esac shift done NOW=`date +%s` min_valid_ts=$(($NOW - $VALID_INTERVAL)) CURRENT_PAGES_SWAPPED_IN=`vmstat -s | grep 'pages swapped in' | awk '{print $1}'` CURRENT_PAGES_SWAPPED_OUT=`vmstat -s | grep 'pages swapped out' | awk '{print $1}'` mkdir -p $(dirname $IN_DATAFILE) if [ ! -f $IN_DATAFILE ]; then echo -e "$NOW\t$CURRENT_PAGES_SWAPPED_IN" > $IN_DATAFILE echo "Missing $IN_DATAFILE; creating" EXITFLAG=$UNKNOWN fi if [ ! -f $OUT_DATAFILE ]; then echo -e "$NOW\t$CURRENT_PAGES_SWAPPED_OUT" > $OUT_DATAFILE echo "Missing $OUT_DATAFILE; creating" EXITFLAG=$UNKNOWN fi if [ $EXITFLAG != $OK ]; then exit $EXITFLAG fi function swap_rate() { local file=$1 local current=$2 local rate=0 mv $file ${file}.previous while read ts swap_count; do if [[ $ts -lt $min_valid_ts ]]; then continue fi if [[ $ts -ge $NOW ]]; then # we can't use data from the same second continue fi # calculate the rate swap_delta=$(($current - $swap_count)) ts_delta=$(($NOW - $ts)) rate=`echo "$swap_delta / $ts_delta" | bc` echo -e "$ts\t$swap_count" >> $file done < ${file}.previous echo -e "$NOW\t$current" >> $file echo $rate } in_rate=`swap_rate $IN_DATAFILE $CURRENT_PAGES_SWAPPED_IN` out_rate=`swap_rate $OUT_DATAFILE $CURRENT_PAGES_SWAPPED_OUT` echo "swap in/out is $in_rate/$out_rate per second" if [[ $in_rate -ge $CRITICAL_THRESHOLD ]] || [[ $out_rate -ge $CRITICAL_THRESHOLD ]]; then exit $CRITICAL fi if [[ $in_rate -ge $WARN_THRESHOLD ]] || [[ $out_rate -ge $WARN_THRESHOLD ]]; then exit $WARNING fi exit $OK |
4.伺服器啟動通知
意外的重啟是生活的一部分。你知道你的伺服器何時重啟了嗎?很多人都不知道。這裡我們會使用一個當系統重啟時會傳送郵件通知的簡單的初始化指令碼。當新增新伺服器的時候,這會很有用。同時,當伺服器出現異常時,能優雅的使人瞭解伺服器狀態的變化,而不是隻提供一個報警。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#!/bin/bash # # ************************************************* # chkconfig: 2345 99 99 # description: notify email address on system boot. # ************************************************* # Installing: # 1) save as /etc/rc.d/init.d/notify # 2) set the desired email address in "MAILADD" variable # 3) chmod a+w /etc/rc.d/init.d/notify # 4) /sbin/chkconfig --level 2345 notify on PATH=/bin:/usr/sbin:/usr/bin SERVER=`hostname` case $1 in start) PUBLIC_IP=`curl --connect-timeout 5 -s icanhazip.com` PUBLIC_IPV6=`curl -6 --connect-timeout 5 -s icanhazip.com` MAILADD=your@email.example mail -s " Boot of $SERVER" $MAILADD <<EOF From: $0 To: $MAILADD $SERVER has booted up. public ip $PUBLIC_IP $PUBLIC_IPV6 If this is news to you, please investigate. `date -u` EOF ;; esac exit 0 |
5.NTP的時鐘偏移
如果這貨不被檢測,是的,你的某臺伺服器也許已經掛了。如果你從未考慮過時鐘偏離,那麼你甚至可能沒有在你的伺服器上跑過ntpd命令。通常來說,有三點可以作為檢查的切入點。1)ntpd是否在執行。2)你的資料中心內的時鐘脈衝相位差。3)你的主時間伺服器和外部之間的時鐘脈衝相位差。
我們使用check_ntp_time來做這個檢查。
6.DNS決議
內部DNS-這是一個你會依賴卻常被忽略掉的、你的構架的隱藏部分。檢查它的切入點如下:
- 1)每個伺服器的本地決議。
- 2)如果你的資料中心有本地DNS伺服器,那麼你應該檢查決議,和查詢的數量。
- 3)檢查你用的每個上行DNS解析器是否可用。
外部DNS-最好能核實你的外部域名解析能正確的和你已經發布的外部域名伺服器對應上。在bitly我們也依靠一些CC頂級域名,而且我們也直接監測這些認證伺服器。(是的,這發生在所有的頂級域名伺服器離線的時候。)
7.SSL過期
因為這種情況發生的如此之少,以至於很多人都忘記了它。修復很簡單,試試更新一下SSL證照吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
define command{ command_name check_ssl_expire command_line $USER1$/check_http --ssl -C 14 -H $ARG1$ } define service{ host_name virtual service_description bitly_com_ssl_expiration use generic-service check_command check_ssl_expire!bitly.com contact_groups email_only normal_check_interval 720 retry_check_interval 10 notification_interval 720 } |
8.DELL伺服器管理器(OMSA)
我們將bitly分別部署在兩個資料中心,一個在DELL的裝置上,另一個是亞馬遜EC2。對於我們的DELL裝置而言,監測OMSA的輸出是十分重要的。它會讓我們留意磁碟陣列的狀態,壞掉的磁碟(可預見性的硬體故障),記憶體問題,能源供應狀態等等。
9.連線限制
你可能在連線限制的情況下執行過例如memcached和mysql這樣的東西,但是當你向外擴充套件應用程式層的時候,你真的監測過你離那些限制到底有多接近嗎?
與此相關的是解決遇到檔案修飾符限制的程式的問題。在實際操作中,我們經常在啟動指令碼中加入ulimit -n 65535來啟動服務以最小化連線限制帶來的影響。我們也可以通過 worker_rlimit_nofile來設定Nginx。
10.負載均衡器的狀態
我們可以設定負載均衡器的健康檢查(health check),這樣我們就可以輕鬆的將某臺伺服器從輪轉中剔除。(假設一個伺服器掛掉了,負載均衡器將會探測到同時停止向這臺伺服器傳送資訊—譯者注)我們發現健康檢查的視覺化十分重要,於是我們基於相同的健康檢查來監控、報警。(如果你使用EC2負載均衡器,你可以通過亞馬遜的API來監測ELB的狀態)
一些碎碎念(這些東西也要監測)
Nginx錯誤日誌,服務重啟(假設遇到錯誤時,會重啟),numa統計,新程式核心轉儲。
結語
以上僅僅是我們保證bitly穩定運營的一些皮毛,如果打動了你,那麼請戳這。