如何設計出高可用、高性能的介面
- 2020 年 3 月 18 日
- 筆記
介面設計怎麼樣才能高可用,高性能?
—————–來自小馬哥的故事
介面設計需要考慮哪些方面
- 介面的命名。
- 請求參數。
- 支援的協議。
- TPS、並發數、響應時長。
- 是否需要白名單。
- 數據存儲。DB選型、快取選型。
- 是否需要依賴於第三方。
- 介面是否拆分。
- 介面是否需要冪等。
- 防刷。
- 介面限流、降級。
- 負載均衡器支援。
- 如何部署。
- 是否需要服務治理。
- 是否存在單點。
- 介面是否資源包、預載入還是內置。
- 是否需要本地快取。
- 是否需要分散式快取、快取穿透怎麼辦。
當我們設計介面,我們或多或少都會有上面列舉的一些考慮,我們只有想的更多才能讓讓我們的介面更加完善,我個人覺得100%完美的介面是不存在,只有適合才是最重要。
介面設計原則
原則一:必須符合Restful,統一返回格式,約定業務層錯誤編碼,每個編碼可以攜帶可選的錯誤資訊。
原則二: 命名必須規範、優雅。
原則三:單一性。
單一性是指介面要做的事情應該是一個比較單一的事情,比如登陸介面,登陸完成應該只是返回登陸成功以後一些用戶資訊即可,但很多人為了減少介面交互,返回一大堆額外的數據。比如有人設計一個用戶列表介面,介面他返回每一條數據都是包含用戶了一大堆跟另外無關的數據,結果一問,原來其他無關的數據是他下一步想要獲取的,想達成數據的懶載入
原則四:可擴展。
介面擴展性,是指設計介面的時候多想想多種情況,多考慮各個方面,其實我覺得單獨將擴展性放在這裡也是不妥的,感覺說的跟單一性有點相反的意思,其實這個不是這個意思,這邊的擴展性是指我們的介面充分考慮客戶端,想想他們是如何調用的,他要怎樣使用我的程式碼,他會如何擴展我的程式碼,不要把過多的工作寫在你的介面裡面,而應該把更多的主動權交給客戶程式設計師。如獲取不同的列表數據介面,我們不可能將每個列表都寫成一個介面。 還有一點,我這裡特別想指出來的是很多開發人員為了省事(姑且只能這麼理解),將介面設計當成只是app頁面展示,這些人將一個頁面展示就用一個介面實現,而不考慮這些數據是不是屬於不同的模組、是不是屬於不同的展示範疇、結果下次視覺一改,整個介面又得重寫,不能復用。
原則五:必須有文檔。
良好的介面設計,離不開清晰的介面文檔表述。文檔表述一定要足夠詳細
原則六:產品心。
為什麼我說要有產品心?因為我覺得很多人忽略了這一點。我來說一下假如開發一個app,如果一開始連個交互文檔給你都沒有的話,你怎麼設計介面?所以我覺得作為一個服務端後台開發人員應該要有產品心,特別是對於交互文檔應該好好理解,因為這些都會對我們的介面設計有很大的影響,我在設計介面的時候就很常發現很多交互文檔根本就走不通,產品沒有考慮到位,交互文檔缺失,這時候作為一個開發要主動推動,完善。
原則七:第三方服務介面數據能快取就快取。
原則八:第三方服務需要做降級。
原則九:建議消除單點。
原則十:介面粒度要小。
原則十一:客戶端能處理的邏輯就不要給服務端處理,減少服務端壓力。
原則十二:資源預載入。
原則十三:不要過度設計。
原則十四:快取盡量不要穿透。
原則十五:介面能快取就快取。
原則十六:思辨大於執行
如何保證介面的高可用、高性能
上面也列舉很多需要考慮和設計的原則,其實還有很多方面,我這邊也不是特別全面。居於上面列舉的這些考慮點,其實這邊說服務是更恰當,能把上面說的點做好,其實介面也是比較可靠,如何設計以及保證介面的高可用和高性能。可以思考一下以下幾個point
高性能:如果我們發現這個介面tps和響應時間沒有達到我們的要求怎麼辦。
- A:數據存儲方面:我們會想資料庫有沒有分庫、分表、有沒有做主從,有沒有讀寫分離、欄位是否有加索引、是否存在慢sql,資料庫引擎是否選用合適、是不是用了事務;其次我們會想到是不是引用了分散式快取、快取key大小是否合適,失效時間是否設置合理,會不會大量快取穿透、有沒有引入本地快取。
- B:業務方面:是否有大量的計算、能否非同步處理。是否需要引入執行緒池或者MQ來非同步處理任務。有沒有必要將介面進行垂直拆分和水平拆分、將介面粒度變小。
- C:其他方面:nginx層面做快取、加機器、用ssd,資源放cdn,多機房部署、資源文件預載入。
高可用:如何保證服務高可用,需要從幾個維度來實現:
- A:消除單點,基於高可用第二位。
- B:能做集群的全部做集群。譬如Redis集群、mysql集群、MongoDB副本集。
- C:能做讀寫分離的都做讀寫分離。
- D:異地多機房部署,接入GSLB
- E:必須有限流、降級機制。
- F:監控。高可用的保證,基於第一位
下圖是從一個基本的請求出發來梳理需要涉及到各個段,以及各個端能做的事情。談談介面服務,但不局限於介面本身。
- 客戶端:資源預載入、限制請求、數據上報。我這邊就拿客戶端來舉個例子。介面服務所依賴的資源包或者一些公共配置預載入在本地,減少介面的交互,通過請求配置文件是否更新,code是否是304等來;介面做一些請求限制,比如搶紅包、搶券等,單位時間內N次點擊只請求一次等;介面失敗數據上報來;這就是客戶端可以做到的對介面有幫助的事情
- GSLB/HttpDNS:多機房部署、流量切換、域名劫持,一般技術和業務比較成熟的公司這一層。
- 資源文件放CDN。
- 負載均衡器:lVS+Nginx是互聯網常用的做負載均衡,可以實現四層/七層負載均衡;這裡除了可以分流、轉發以外,我們用的更多的基於令牌桶限流、快取。
- 本地快取。本地快取能減少我們訪問DB或者分散式快取,本地快取推薦使用guava,guava裡面有很多特性很好用,例如基於令牌桶的限流;當快取失效時只穿透一個請求去訪問後端。
- 執行緒池。
- 模組拆分。將一個項目按功能模組拆分,一個介面也可以按業務粒度進行拆分。
- 數據中心。提供數據支撐,譬如黑名單。
- 資料庫。加索引、分庫、分表、讀寫分離
- 分散式快取。數據分片、拆分大key,並做集群,採用分散式鎖
- MQ。做介面拆分利器,非同步操作。
- 其他服務。限流、防刷以及降級(特別是第三方服務,保證第三方服務down掉不要影響我們自身的服務)。在這裡也需要考慮做第三方數據的快取或者持久化,譬如實名認證、身份證認證等。
- 監控。監控永遠是必須的,能讓你第一時間知道介面服務是否ok
個人小分享
1)介面Restful,統一返回格式,約定業務層錯誤編碼,每個編碼可以攜帶可選的錯誤資訊
在前司,客戶端和服務之間是有統一的數據返回格式,約定各層的編碼,可以通過編碼位數以及編碼就可以看出是那一層出問題,我覺得這對我們定位問題以及維護來說具有莫大的意義,並對異常也進行捕捉,封裝成對應的code,我之前閱讀一些人的程式碼發現其項目根本沒有做這一層,因為簡單而不做我覺得有失所望。
2)採用hybird模式
採用hybird模式涉及到資源預載入的問題,在很多項目裡面都大量使用,譬如前司的生活服務,就採用了hybird模式,先將資源文件(包含圖片、前端頁面)打包放到伺服器並通過版本號進行管理,並通過一個總的配置文件來管理,如果是H5頁面可以進行模板預先設計,down到本地。 配置文件格式:
*文件1* name:xxx url:http:xxxx md5:xxxx *文件2* name:zzz url:http:zzzz md5:zzz
客戶端每次啟動應用或者定時請求總的配置文件,通過http code是否是304判斷是否需要下載這個總的配置文件,如果code是200,那麼下載這個配置,比較那個文件發生變化,並將其下載。這樣的好處:
- 減少介面的交互;
- 資源預載入,節省流量,打開頁面更加流暢,對於服務端來說字需要返回數據json串就行,而不需要其他,減少服務端壓力;
- 方便開發人員,資源管理更加簡潔,比如做活動需要的h5頁面,只需要前端上傳對應的h5資源包到服務端,不需要通過後端開發人員就可以搞定。
雖然這個原理很簡單,但是現在很多app還是沒有做這個,都是通過填寫一個url,載入網頁的方式去打開,體驗性太不友好。
3)客戶端
客戶端跟服務端就是介面請求的關係,很多時候需要要求客戶端做一些數據快取的工作以及一些檢驗工作。在前司已經好幾次給客戶端的同學坑過了,客戶端同學介面亂調用,死循環調用。一次是做一個關於事件提醒的功能,需要每天定時調用調用服務端一個介面,結果客戶端的同學寫了一個bug導致請求每隔一兩秒就調用一次,導致伺服器這邊此介面pv翻了N倍,而且這個bug通過測試同學很難測試出來;還有一次發現服務端一段時間以後UV不見漲,但是PV卻漲的很猛,定位發現是客戶端同學A圖省事在一個方法裡面調用了N個介面,也就是模板方法,因為版本更新,同學B需要做一個新的功能,然後也調用了A同學的介面導致,從而導致PV上升,其實B同學完全不需要調用這麼多介面。這些都是真實案例,所以這裡需要有一個監控介面異常的機制。
4)思辨大於執行
寫到這裡覺得這個非常重要,思辨大於執行,意味著我們不是一股腦就去干,也不是不去干,我們做事情需要思考、辨別;從而讓事情更高效、更好、更有力的執行。介面設計也一樣,需要我們去思辨。
5)本地快取、分散式快取以及非同步
快取在前司主要分為客戶端快取、CDN快取、本地快取(guava)、Redis快取。在MZ早期是介面是採用DB+本地快取的方式提供數據,但這種模式DB壓力大,介面吞吐量小,本地快取多機難一致性、更新不及時問題。為了解決這些問題,引入分散式快取,並通過Task將業務數據刷到Redis,介面只訪問redis,不會訪問DB,及時DB故障也不會影響功能。不同的業務系統系統通過MQ來解耦,多機房不是通過MQ來實現數據的一直。比如,評論,先通過寫Redis,寫MQ來實現數據在多機房同步,再通過task將Redis中評論同步到DB中。
介面設計涉及方方面面,這邊也只談到一個大概,雖然有點泛泛而談,希望此拙文對你有所啟示。
6)資料庫
資料庫分庫分表,一般都是通過userId或者imei或者mac地址來分表,單表數據量控制在500w以內,這需要我們提前估算好數據量,盡量避免數據的遷移。在前司,資料庫一般都是採用mysql+MongoDB兩種,MySQL存儲用戶的用戶數據,MongoDB存儲業務數據,就像閱讀和生活服務裡面的業務數據就存儲在MongoDB裡面。在資料庫這層,我們主要也是通過主從模式、讀寫分離、分庫、分表來實現數據的可用性。
7)業務
業務儘可能拆分、獨立部署、將項目按業務劃分、按功能劃分等。譬如生活服務,我們當時主要拆分成管理後台admin、任務task、活動、web、數據展示模組。
8)數據中心
每個大一點的公司都有數據部門,我們這邊可以通過數據中心的數據分析來達到我們需要的數據。 比如黑名單,推廣效果、活動數據。我們可以通過這些完善我們的介面功能。之前在前司做了個數據處理後非同步載入到Redis來實現數據利用的項目。
本文由 小馬哥 創作,採用 知識共享署名4.0 國際許可協議進行許可 本站文章除註明轉載/出處外,均為本站原創或翻譯,轉載前請務必署名