架構經驗系列文章 - 后端架構 - 架構層面

jopen 10年前發布 | 16K 次閱讀 架構 軟件架構

架構層面:

 

  • 日志集中
  • </ul>

    所謂日志集中就是把程序的所有日志和異常信息的記錄都匯總到一起,在只有一臺服務器的時候我們記錄本地文件問題也不是最大,但是在負載均衡環境下再記錄本地日志的話就出現問題了。在想查看網站日志的時候到哪臺機器去查都不知道,難道有100臺機器就100臺機器逐一遠程連上去看?因此,把這些數據匯總在一起保存對于大型網站系統來說是很必要的,這樣我們就可以直接進行查看、搜索,也很明確可以知道是哪臺機器的業務出了問題。至于這種日志數據是寫到 RDBMS還是NOSQL甚至是搜索引擎這就看需要了,總之避免寫本地的文本文件,否則真的是災難。當然寫一個日志遠遠沒有想的這么簡單:

    1. 為了達到比較好的性能,日志是否先寫本地內存隊列然后定時刷到數據庫中去?
    2. 各種日志混在一起也難以搜索,是否要添加一些搜索字段?比如分模塊?
    3. 如果數據庫不可用的話是不是先寫本地日志以后再匯總過去?
    4. 日志是否易于辨明問題還是看日志怎么記錄,如果日志中只寫錯誤那么記錄了也白記錄,一定要寫清楚這是哪個模塊哪里出現了問題,有條件的話還可以寫上一些參數信息和當前的狀態。
    5. 對于未處理的異常信息不太可能手動去記錄,一般而言很多框架或服務器都會提供一個接口點可以回調我們自己的代碼,在這里我們就可以收集這些未處理異常然后統一記錄,最后把用戶帶到友好的錯誤頁面。不記錄任何一個未處理異常都是可怕的事情,想象一下用戶已經看到了色彩斑斕的頁面,而開發還一無所知,這樣的話這個問題始終會存在,即使用戶投訴了反饋了我們也很難重現。

     

    • 配置集中

    配置集中和日志集中的道理是一樣的,就是統一管理。任何一個系統其實或多或少都會有一些不能在程序中寫死的參數(比如至少的數據庫連接字符串和外部服務地址),一般情況下會寫到配置文件中,這樣存在幾個問題,第一就是在多服務器的負載集群情況下要修改配置需要逐一修改每一臺服務器的配置,第二就是在修改配置還可以需要重啟服務或網站才會生效,第三無法統一管理也無法知道是否所有網站都統一配置了相同參數。解決的辦法還是一樣的就是匯總保存在統一的地方比如保存在數據庫中,然后每一個網站都從數據庫中獲取配置的值,在實現的時候簡單有簡單的做法,復雜有復雜的做法,比如要考慮以下問題:

    1. 參數的值是直接保存強類型的那還是保存字符串在使用的時候轉?甚至說值是支持對象和數組的,而不是簡單類型。
    2. 參數的值不可能每一次獲取都從數據庫取,怎么做緩存,緩存多長時間,值修改了怎么同步回來?
    3. 程序是否允許修改值?還是說程序只是讀取,不允許修改,修改參數的值只能通過數據庫或后臺進行。
    4. 是否是需要根據不同的部署環境、用戶的語言、服務器的IP來設置不同的值。

    不管怎么樣,至少一個最簡單的配置服務,從數據庫中讀取參數值,哪怕讀取后永遠緩存只有重啟服務才能生效,也會比直接從本地配置文件中讀要好很多。示例分享

     

    • 緩存

    緩存這個架構手段實在是太常用了,幾乎所有的人都知道緩存這個設計和性能優化手段。對于一個網站系統來說又有太多的地方可以做緩存,真正能把緩存用好,在合理的地方用緩存,監控緩存的命中率,想辦法提高緩存的命中率其實不是這么容易的,一般來說有這些地方可以做緩存,從上到下:

    1. 瀏覽器和CDN緩存:通過這兩種整頁的緩存可以盡量減少請求打到網站服務器的機會,也就提高了網站服務器的負載能力,當然一般來說靜態的資源比較容易走這種緩存,動態的資源其實也可以走,只不過要能根據訪問的條件做出合適的Key,對于和每一個用戶都獨立的頁面可能要直接進行頁面緩存比較難一點。
    2. 反向代理的緩存:反向代理作為服務器的代理可以進行整頁或是片段頁面的緩存,可以提高直接把請求達到網站服務器的機會提高性能。
    3. 數據的緩存:如果請求真正到了網站服務器,那么我們也不一定要所有的數據都從數據庫中取,可以嘗試把部分數據保存在分布式緩存中。只要Key合理,并且請求有規律那么可以保證比較高的命中率,從而減輕數據庫的壓力,也減輕網站服務器的壓力。
    4. 大塊數據的內存中緩存:對于有一些大塊的數據是無法保存在分布式緩存中的,那么可以直接在網站啟動的時候把這種不太會改變的大塊數據全部加到內存中來,這樣這快數據的訪問效率和計算效率就很高了。

     

    • 分布式緩存

    所謂分布式緩存就是緩存的數據是分布在多個節點上的,好處是一來可以盡量利用服務器的資源,比如一臺服務器可以有1GB內存空閑,找50臺服務器就是 50GB了,如果不用這50臺服務器其實也就是這么多內存空著(一般來說網站服務器使用的內存是相對固定的,主要業務不怎么變化的話,而且諸如 Memcached之類分布式緩存對CPU的使用是很低的,完全可以把Memcached寄居在大內存的Web服務器或是應用服務器上,實現神不知鬼不覺的分布式緩存);第二個好處就是可以減少單點故障帶來的影響,一般來說分布式緩存都有類似于一致性哈希的算法,即使有單點故障的話也只是少部分緩存數據會不命中,損失不是太大。在使用分布式緩存的時候要牢記下面幾點:

    1. 緩存就是緩存,數據是允許排出和丟失的,當成文件系統用的話就錯了。
    2. 分布式緩存的數據是通過網絡存取的,數據傳輸走網絡和本機內存中效率不能比,而且數據需要序列化和反序列化要考慮到性能開銷。
    3. 緩存的Key生成的策略是很關鍵的,Key生成的參數過多的話很可能命中率會幾乎為0,這種緩存做了也白做,因此需要針對分布式緩存的命中率有監控。示例資源

     

    • 隊列

    隊列也是實現高性能架構的一個必不可少的利器,通過把執行時間比較長的任務在隊列中進行排隊,通過限制隊列的最大容納項目數,實現一個抗高壓的能力,并且隊列后端的點也能有一個比較平穩的壓力。隊列說到底也只是一個容器,如果前端的壓力永遠比后端處理能力大的話,隊列總是要爆的,因此隊列也不是萬能。往往對于網站系統即使后端的業務有隊列,前端的頁面如果扛不住高壓力,甚至是驗證碼之類的都刷不出來的話也是沒用的,架構上就是這樣系統中任何一個點都會拖累整站的架構,架構優化針對最薄弱的地方而不是最強的地方。形式上來說隊列有兩種:

    1. 生產者和消費者:生產者生產出來的數據只能被一個消費者消費,也就是任務只能執行一次的。往往這種形式的數據是需要持久化的。
    2. 發布和訂閱:任何一個事件都允許有多個發布者和多個訂閱者,訂閱者訂閱自己感興趣的東西,只要發布者發布了訂閱者感興趣的內容就會傳播到所有的訂閱者。一般來說這種形式的數據可以是允許丟失的不需要持久化的。

     

    • 池技術

    所謂的數據庫連接池,線程池都是池技術的一個應用。池技術說到底就是把創建開銷比較大的對象緩存在池中避免重復創建和銷毀,對象用的時候從池拿出來用,用好了重置后還到池里面別人還可以接著用。比如說數據庫連接池就是避免了頻繁創建代價高的TCP連接,線程池就是避免了頻繁創建代價高的線程。雖然說原理上是這樣,但池其實也有一些算法需要考慮的:

    1. 創建的富裕的對象的回收策略怎么做?
    2. 對象損壞怎么處理?

    一般來說可以參考網上的池實現方式來實現一個通用的池,這樣各種對象都可以進行管理了。

     

    • 分布式文件系統

    分布式文件系統并不是所有網站都必須的,一般小網站會把用戶上傳的圖片直接保存在Web服務器本地,這么做是可以的,但量大了之后會有問題,首先一臺服務器保存不下怎么辦,怎么知道哪個圖片在哪個服務器上?其次讀的請求怎么進行分離,怎么把圖片同步到其它服務器上去。分布式文件系統就是來解決這個問題的,通過把一組服務器當做一個文件系統使得我們的文件資源可以分散保存在多個服務器上并且確保有一定的數據備份。在網站規模不是很大的時候其實可以保存在單臺服務器上,然后使用文件同步工具同步到另一臺服務器,之前再架反向代理解決,數據量再大一定要分布式的話就要上分布式文件系統了。從原理上來說分布式文件系統其實不是很復雜的,但選型的時候也要進行穩定性和性能的考量。有的人是把數據庫保存在數據庫中的,雖然這樣可以實現單點雖然這樣可以實現備份,但這顯然不是很合理的,會極大增加數據庫的壓力。

     

    • 分布式搜索引擎

    如果有站內搜索需求的話就要上搜索引擎了,現在開源的搜索引擎非常多,不過很多都是Lucene的封裝,在選型的時候要根據自己的需求進行選型。所謂分布式也就是如果單點的索引和查詢不能滿足性能容量需求的話就需要分布到多點了。從原理上來說搜索引擎主要還是一個分詞和倒排索引,但是搜索引擎在內容的排序等細節上點還是有很多算法的,除非必要不推薦自己去實現搜索引擎,可以直接針對開源組件進行封裝和改良。搜索引擎做的好其實遠遠不止全文搜索這么簡單,甚至可以根據用戶搜索的內容給予搜索的建議,可以根據用戶搜索的內容進行索引的自完善,還可以根據用戶的搜索結果進行大量的用戶行為分析,為網站的產品進行改良,如果站點具有自己的搜索模塊的話其實有很多事情可以做的。示例資源

     

    • NOSQL

    NOSQL就是非關系型的數據庫,NOSQL不是用來取代關系型數據庫的,之所以NOSQL這么火是因為其性能。從本質上來說,程序就是一組代碼,對于相同的硬件配置來說,程序性能的高低也就取決于實現相同的操作要有多少代碼在CPU中執行一遍,要有多少IO操作要在磁盤上過一遍,往往通用性的東西就會有比較多的計算和IO,往往定制化的東西性能就會比較高。我們說RDBMS性能不高,但是我們也應該看到RDBMS要確保數據的完整性,持久性,要實現通用的功能,要把它的性能和IO達到內存中然后定期刷磁盤的組件來比就不合理了,因此我們要根據業務在合理的地方使用合理的NOSQL,對于資金相關的業務需要事務的業務不太適合NOSQL,對于允許延遲允許數據丟失需要大訪問量的業務比較適合NOSQL。任何一種NOSQL往往都是某個大型公司針對自己的需要定制出來的產品,只有這樣定制化的東西才可能實現高性能,因此市面上才會有這么多NOSQL,那么我們在選擇的時候也要看這個NOSQL針對的應用場景是否就是符合我們業務需要的。另外,NOSQL逼近是一個新新事物,其用戶群不可能有MYSQL或ORACLE這么多,因此我們也不能期望其穩定性能達到非常高的標準,而且NOSQL由于其定制化的特點,在使用的時候不一定都可以通過標準SQL來使用對于學習成本也是我們需要考慮的因素。不管怎么樣在該需要用的時候還是要用,有的應用單靠RDBMS是沒有可能實現這么高性能的,不用NOSQL就是死路一條,用了即使它不穩定還有可能活。

     

    • NOSQL之Mongodb

    Mongodb是一款性能超高的文檔型數據庫,之所以它這么火不僅僅是因為性能高,而且它功能也很全,相比其它NOSQL它幾乎可以實現90%以上的 SQL操作,并且也有豐富的高可用性的配置方式。總結下來Mongodb是一款性能幾倍于傳統RDBMS的最接近于RDBMS功能的NOSQL。對于對性能要求很高,特別是寫數據并發要求很高的應用來說使用Mongodb是比較適合的,比如存業務日志或系統日志。值得一提的是:

    1. Mongodb也不是萬能的,對于超大級別的數據量如果不進行數據分區,那么Mongodb也救不了你,并且不要期望Mongodb的自動Sharding功能能有多好,自動的畢竟沒有手動這么準確,如果你能想到怎么進行數據分片的話還是推薦手動進行。
    2. Mongodb的性能是很好的,但這也是有限度的。只要擁有比較大的內存,那么熱數據可以在內存中保存,讀取性能不會太差,但是數據量達到一定的限度之后,如果你的索引數據都在內存中放不下的話,那么其性能會很差的,其實我們也很容易想到為什么,舉個例子,我們在查字典的時候需要翻索引的,至于字典真正的內容在哪里其實問題不大的,如果一本百科全書即使由100本書構成,只要索引在手里查到了哪一本再去取問題不大,如果這個索引也是由100本書構成,查索引就不能一次性在手里查完還需要翻不同書的話這個性能就會非常差。

     

    • NOSQL之Redis

    Redis于其說是一款NOSQL還不如說是一款緩存組件,在大多數時候把NOSQL當成一個服務端可以做計算的,存儲復雜類型的,又具有一些諸如隊列、管道等小功能的升級版本的Memcached是不錯的。我個人使用Redis的心得是:

    1. Redis不像Memcached,它可以保存多種形式的數據,而不僅僅是一個字符串,這是很有亮點的,意味著我們直接可以在服務端針對大量數據進行一個計算,然后服務端直接返回計算結果,而不是要從緩存中把所有數據都取出來在客戶端進行一番計算然后再保存回緩存中的(這里的客戶端是指使用NOSQL的客戶端,不是瀏覽器),也就是說要用好Redis是要寫一些定制性的代碼的,把我們真正的業務邏輯嵌入到Redis中去,如果只是存KeyValue的話性能不一定比Memcached高多少的。
    2. 一般情況下不建議過多依賴Redis的磁盤VM的,有16GB內存保存32GB的數據是可以的,有16GB的內存用Redis保存1TB的數據那就是用錯 Redis了。NOSQL的產品其實原理上來說都不是特別復雜的,使用NOSQL之前最好熟悉一下它的原理,這樣我們更容易用好NOSQL產品。總之我的觀點還是這樣,由于內存和磁盤性能的巨大差異,如果說能在內存中做大部分事情的話,這個性能就會比較好,如果要來回在內存和磁盤上翻騰的話這個性能也好不到哪里去。示例分享

     

    • NOSQL之HBase

    HBase、Hadoop適合的是超大數據量的存儲和計算,它其實是真正的一個分布式的概念,數據不再能在一個單點上保存了,需要分散到很多機器上,然后計算結果也是分別計算后匯總在一起。對于這套東西我的體會是不要輕易引入:

    1. 除非是億級以上的數據量并且數據的格式比較簡單,否則要考慮是否適合引入,HBase的學習曲線不低的,而且最好是在社區熟悉過一段時間的,否則連用哪套版本的Hadoop什么的都搞不清楚,版本沒用對要么有很多難以解決的BUG要么就是連基本的連通性都搞不起來。
    2. 要想有很好的性能,至少有20臺以上的服務器再來搞HBase,一兩臺機器就算了,還沒到分布式的這個需求。想想也知道所謂通過并行來提高效率首先是你有這么多資源可以把數據并行分散出去,然后同時進行計算匯總才能節約時間,如果根本數據都沒分出去怎么可能節省時間。
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!