服務端開發小感

葉劍峰發表於2013-03-24

  從事服務端開發已經有一些日子了,靜下來可以想想和記錄些服務端開發的想法了。

  服務端開發,特別是Web開發,基本上全是處理HTTP請求的處理。根據具體用途分為兩種:Web頁面開發和API介面開發。Web頁面開發也完全可以看成是API介面開發,只是它的兩個主要部分,頁面和ajax請求,一個是返回html,另外一個可以返回html,也可以返回其他格式的而已。API介面開發是針對有客戶端產品而言的。可能是移動裝置,可能是PC應用等。

 應用框架

  應用框架一般使用的是LNMP或者LAMP,基本的框架就是前端N臺Web服務機 + cgi訪問PHP + php訪問mysql。

  PHP可以看成是C寫的一個大型的Web框架,它的優勢在於解釋型,即時修改即時更新。所以線上程式碼更新維護成本極低,加之其為web開發幾乎是專門定製的一些函式,所以適合用於web開發。相較於java開發web服務,動不動就需要重新編譯的痛苦就很知足了。

  web伺服器現在nginx是越來越多使用,nginx比較apache的優勢就在於輕便和靜態頁面的高併發效能。一般拿到裝置先需要考慮下單機可承受的qps大概多少,方法大致就是先只考慮記憶體,計算同時能開啟多少個php-cgi,比如一個4G記憶體的機器,每個php-fpm大概佔用20M記憶體,所以差不多能開啟200個php-cgi程式(一般會留些空餘的),每個程式同一個時間只能跑一個php程式,所以假設每個php程式跑0.1s,1s就能處理10個請求,所以單機qps大概會是2000。當然,一般不會開啟到這麼極致的程度,有幾個原因:

  1 需要考慮到其他程式使用記憶體的情況

  2 考慮到如果一旦全部記憶體都使用完了,是否啟用swap,如果沒有的話,那機器是否就立即當機

  3 還需要考慮到CPU和頻寬的使用情況。CPU對一些比如加解密,視訊轉碼等操作比較耗時,這個時候如果沒有使用佇列,那麼每個請求的時間就會加長。

 檔案伺服器

  一般會要求檔案伺服器和web伺服器分開,分開的意思就是使用不同的域名進行拆分。當然web伺服器也是可以當做檔案伺服器的,但是由於檔案伺服器需要上傳檔案,而上傳檔案是一個非常耗時的工作,即php的一個程式需要停留的時間很長,所以需要將它們分開。一則可以為以後擴充套件檔案伺服器提供便利,二則不會導致檔案服務影響了正常的web服務。

  從檔案伺服器拆分的理由上看,在運營過程中一些比較佔用資源或者特別頻繁呼叫的介面是可以或者應該考慮拆分到不同機器上的。

  Web前端機始終要訪問持久化的資料的,mysql的使用是最為頻繁的。其實所有的web服務說到底都是對資料庫進行增刪改查的操作。說到效能,資料庫的增刪改查操作的效能其實就決定了一切。所以對資料庫的建表,索引的使用對一個網站來說尤為重要。覺得最有用的幾個mysql的技巧有:

  1 覆蓋索引。就是想辦法讓查詢操作只查索引而不去查表的索引建立方法。建立合適的索引和能只在索引就能找到資料的查詢能提高效率。

  2 InnoDB表最好能使用自增鍵,提高插入操作的效率。

  3 string型別的變數的儲存格式,是使用varchar還是char比較好,曾經有個專案表設計從char到varchar之後的資料庫大小差別達到70G和20G的大小…

  4 建表的時候需要考慮下以後的分庫分表,如果是使用分表,什麼是分表鍵?是否需要反向查詢表?

  5 甚至當考慮到資料庫和Web機器的機房分佈,這個設計就更麻煩了...

  mysql的建表環節和需求有很大關係。沒有明確的需求,表設計一定是不正確的。

  資料庫支援有可能還是不足夠的,那麼首先想到的可能就是快取了。快取是使用全域性快取?放在web前端機?需要用什麼hash演算法?用什麼快取?memcache?redis?mysql也有自帶快取,如何查詢才能更好命中這個快取?當資料更新的時候,快取中的資料是否是髒資料?如何更新資料?

 Web頁面開發

  當需要做一個網站的時候,首先要考慮的是使用者量有多少?做一個SNS網站和做一個運營後臺網站完全是兩個不同的概念。

  首先是在頁面壓力上,SNS網站的qps可能幾千上萬,而運營後臺壓力幾乎完全可以不用計算。這個就意味著後端的資料庫支援不同了。SNS網站可能最常呼叫的會是好友關係和個人資訊的介面,這樣的介面是不是需要獨立出來處理?這樣的請求會很多是重複的,是不是考慮使用中介軟體或者快取來減輕對資料庫的直接壓力呢?運營資料一般使用單表就可以解決的。個人覺得運營中統計的需求是最難做的。首先統計並不是任意的統計要求都可以滿足,這個需要和產品討論需求。其次,統計一般需要使用些訪問日誌之類的,可能涉及到許多shell指令碼。

 API開發

  其實相對於Web開發,API開發是屬於被動的。意思就是,由於客戶端可能是手機產品,可能是PC產品。往往都是有釋出和版本的。這個意味著API介面沒法像Web那樣為所欲為隨時更新程式碼。它更多需要考慮到各個版本之間的相容問題。相容問題在很大程度上會變為加法,永遠不會是減法。個人感覺,如果毫無節制地滿足需求,隨著版本越來越多,你的程式碼中會越來越多if else,到最後,你的程式碼就根本無法維護了。然後就會是別人來接手你的工作,踩坑,邊罵邊重構….API開發是最需要依賴測試的。往往只有測試人員才對各個版本的小改動,小特性如數家珍。

 再考慮到非功能配套:

  你可能需要對API呼叫時間進行統計,這樣你才明白你的介面表現如何。

  你的程式碼可能還會用到其他機器上的服務,比如curl一個其他服務,這樣的情況,最好考慮下錯誤處理和日誌記錄。

  對於有金錢交易的介面服務,日誌處理更是必不可少。

  對於一些內部錯誤,最好不需要直接丟擲顯示給使用者,所以需要使用的最好是白名單錯誤機制。

  介面的加密方式,一般最少是需要有個簽名機制的,考慮到加密方法,大致有幾種:對稱加密和非對稱加密。加密的時候就需要考慮到一些情況了,比如手機客戶端的用電量等。

  如果是給手機開發介面,需要考慮流量問題,圖片的規格問題。

  框架永遠是會變的,不說需求的變化,單就使用者量的變化,20w使用者和1000w使用者的框架一定是不一樣的。剛開始的時候你不可能根據1000w的使用者量來設計框架來給20w人用。所以一個好的服務端框架一定是隨著使用者量變化會進行幾次大的變化的。

 後記

  這篇是想到哪寫到哪,寫到這裡發現寫不下去了…總之,web服務開發的技巧和小東西還是很多的。有的坑是需要自己踩過才知道痛的。可愛的是,我還在繼續踩坑中…

  補充下,介面重構幾乎是每個服務端開發人員必須經歷過的。相較於開發一個新系統,介面重構的難度可以說是翻翻,當然這裡的難度也可以理解為難受程度…也會是很鍛鍊人的一個活。對於重構來說,測試尤為重要,如何有個很好的測試集來保證你的重構的正確性是個難度。

相關文章