【轉】分佈式、高併發、多線程Multithreading

1、分佈式系統

在計算機領域,當單機性能達到瓶頸時,通常有兩種方式解決性能問題,html

  • 一是堆硬件,進一步提高配置;
  • 二是分佈式,水平擴展、垂直拆分。

分佈式系統有不少種:分佈式文件系統、分佈式數據庫、分佈式WebService、分佈式計算等等,java

面向的情景不一樣,但分佈式的思路大體相同,萬法歸一吧!nginx

如下內容主要來自:分佈式系統架構思想web

 

1.一、分佈式系統實現的兩種方式【水平擴展、垂直拆分】

1.1.一、簡單的例子

假設咱們有一臺服務器,它能夠承擔1百萬/秒的請求,這個請求能夠的是:經過http訪問網頁、經過tcp下載文件、jdbc執行sql、RPC調用接口等等方式,如今咱們有一條數據的請求是2百萬/秒,很顯然服務器很難hold住,會各類拒絕訪問,甚至宕機,怎麼辦呢?算法

一臺機器解決不了的問題,那就兩臺。因此咱們加一臺機器,每臺承擔1百萬。若是請求繼續增長呢,兩臺解決不了的問題,那就三臺唄。這種方式咱們稱之爲水平擴展,若是實現請求的平均分配即是負載均衡了。sql

另外一個例子,咱們如今有兩個數據請求,數據190萬,數據280萬,上面那臺機器也hold不住,咱們加一臺機器來負載均衡一下,每臺機器處理45萬數據1和40萬數據2,可是平分太麻煩,不如一臺處理數據1,一臺處理數據2,一樣能解決問題,這種方式咱們稱之爲垂直拆分。數據庫

水平擴展和垂直拆分是分佈式架構的兩種思路,但並非一個二選一的問題,更多的是兼併合用。下面介紹一個實際的場景。這也是許多互聯網的公司架構思路。編程

1.1.二、實際的例子

某些公司的計算機系統非常龐大,天然是一個整的分佈式系統,爲了方便組織管理,公司將整個技術部按業務和平臺拆分爲部門:訂單的、會員的、商家的等等,而每一個部門有本身的web服務器集羣、數據庫服務器集羣,緩存

經過同一個網站訪問的連接可能來自於不一樣的服務器和數據庫,對網站及底層對數據庫的訪問被分配到了不一樣的服務器集羣,這個即是典型的按業務作的垂直拆分,每一個部門的服務器在hold不住時,會有彈性的擴展,這即是水平擴展。服務器

在數據庫層,有些表很是大,數據量在億級,若是隻是純粹的水平的擴展並不必定最好,

若是對錶進行拆分,好比能夠按用戶id進行水平拆表,經過對id取模的方式,將用戶劃分到多張表中,同時這些表也能夠處在不一樣的服務器。

按業務的垂直拆庫 和 按用戶水平拆表 是分佈式數據庫中通用的解決方案。

1.二、負載均衡

前面咱們談到了分佈式來解決性能問題,但其附帶的問題是怎麼分佈,即如何負載均衡。這裏要解決的問題是當客戶端請求時,應該讓它請求分佈式系統中哪一臺服務器,一般的作法是經過一臺中間服務器來給客服端分配目標服務器。

這裏一樣拿兩個不一樣的分佈式系統作說明,

下圖左邊 是分佈式文件系統FastDFS,

下圖右邊 是一個用於分佈式的RPC中間件。

  • FastDFS的一次文件下載請求過程是這樣的

    1. client詢問tracker能夠下載指定文件的storage;

    2. tracker返回一臺可用的storage;

    3. client直接和storage通訊完成文件下載。

其中tracker即是負載均衡服務器,storage是存儲文件和處理上傳下載請求的服務器。

 

  • 而另外一個RPC中間件Hedwig也是相似的

    1. client詢問zookeeper哪臺server能夠執行請求;

    2. zookeeper返回一臺可用server;

    3. client直接與service完成一次RPC。

zookeeper是分佈式系統中一個負載均衡框架,google的chubby的一個開源實現,是Hadoop和Hbase的重要組件。

一樣的在http中,常據說的nginx也是一個負載均衡服務器,它面向的是分佈式web服務器。

1.三、同步問題

分佈式系統中,解決了負載均衡的問題後,另一個問題就是數據的一致性了,這個就須要經過同步來保障。根據不一樣的場景和需求,同步的方式也是有選擇的。

在分佈式文件系統中,好比商品頁面的圖片,若是進行了修改,同步要求並不高,就算有數秒甚至數分鐘的延遲都是能夠接受的,由於通常不會產生損失性的影響,所以能夠簡單的經過文件修改的時間戳,隔必定時間掃描同步一次,能夠犧牲一致性來提升效率。

但銀行中的分佈式數據庫就不同了,一丁點不一樣步就是沒法接受的,甚至能夠經過加鎖等犧牲性能的方式來保障徹底的一致。

在一致性算法中paxos算法是公認的最好的算法,chubby、zookeeper中paxos是它保證一致性的核心。

 

2、高併發

高併發,簡言之:短期,大量請求。

如下內容主要來源於:java系統高併發解決方案(轉載)

----------------------------------------------------------------------------

2.一、併發與分佈

併發反映的是同時有多少許,好比互聯網上的在線直播,可能有幾萬人須要同時訪問服務器,這就是併發。

分佈是將任務分發到不一樣的點上去,通常分佈式最多的就是分佈式計算。經過某種分佈式編程方式,在不一樣的系統上利用各自的CPU,內存等進行計算,將結果聚集至控制中心,進行處理。

  • 高併發也能夠經過分佈式方式解決,好比雲的概念,雲存儲就須要經過分佈式的系統,能夠實現高併發的存儲。這須要取決於需求和容忍度。
  • 對於互聯網這個具體領域,高併發的解決不必定須要經過分佈式系統,能夠經過DNS輪詢,實現服務器負載的分擔。全部的服務器都是同樣的配置,訪問一樣的內容。
  • 對於一些數據庫處理系統,須要快速返回結果,也能夠經過分佈式系統,將計算任務分攤到不一樣的系統上去,加快計算的速度。

2.二、解決高併發的常見經驗

大型網站,好比門戶網站。在面對大量用戶訪問、高併發請求方面,基本的解決方案集中在這樣幾個環節:

  • 使用高性能的服務器
  • 高性能的數據庫
  • 高效率的編程語言
  • 還有高性能的Web容器

以上的幾個方面在必定程度上意味着更大的投入,會常常遇到瓶頸,沒有很好的擴展性,因此還無法根本解決大型網站面臨的高負載和高併發問題。

下面我從低成本、高性能和高擴張性的角度的一些經驗:

  • HTML靜態化
  • 圖片服務器分離
  • 數據庫集羣和庫表散列
  • 緩存
  • 鏡像
  • 負載均衡
  • ......

2.2.一、高併發高負載類網站關注點之數據庫

    首先是數據庫,這是大多數應用所面臨的首個SPOF【single point of failure 單一故障點】。
經常使用的優化措施是M-S(主-從)方式進行同步複製,將查詢和操做和分別在不一樣的服務器上進行操做。

    推薦的是M-M-Slaves方式,2個主Mysql,多個Slaves,須要注意的是,雖然有2個Master,可是同時只有1個是Active,咱們能夠在必定時候切換。之因此用2個M,是保證M不會又成爲系統的SPOF。
Slaves能夠進一步負載均衡,能夠結合LVS,從而將select操做適當的平衡到不一樣的slaves上。
    以上架構能夠抗衡到必定量的負載,可是隨着用戶進一步增長,你的用戶表數據超過1千萬,這時那個M變成了SPOF。你不能任意擴充Slaves,不然複製同步的開銷將直線上升,怎麼辦?個人方法是表分區,從業務層面上進行分區。最簡單的,以用戶數據爲例。根據必定的切分方式,好比id,切分到不一樣的數據庫集羣去。

    全局數據庫用於meta數據的查詢。缺點是每次查詢,會增長一次,好比你要查一個用戶nightsailer,你首先要到全局數據庫羣找到nightsailer對應的cluster id,而後再到指定的cluster找到nightsailer的實際數據。每一個cluster能夠用m-m方式,或者m-m-slaves方式。這是一個能夠擴展的結構,隨着負載的增長,你能夠簡單的增長新的cluster進去。

2.2.二、高併發高負載網站的系統架構之HTML靜態化

    其實你們都知道,效率最高、消耗最小的就是純靜態頁面,因此咱們儘量使咱們的網站上的頁面採用靜態頁面來實現,這個最簡單的方法其實也是最有效的方法。可是對於大量內容而且頻繁更新的網站,咱們沒法所有手動去挨個實現,因而出現了咱們常見的信息發佈系統CMS,像咱們常訪問的各個門戶站點 的新聞頻道,甚至他們的其餘頻道,都是經過信息發佈系統來管理和實現的,信息發佈系統能夠實現最簡單的信息錄入自動生成靜態頁面,還能具有頻道管理、權限 管理、自動抓取等功能,對於一個大型網站來講,擁有一套高效、可管理的CMS是必不可少的。
   同時,html靜態化也是某些緩存策略使用的手段,對於系統中頻繁使用數據庫查詢可是內容更新很小的應用,能夠考慮使用html靜態化來實現,好比論壇 中論壇的公用設置信息,這些信息目前的主流論壇均可以進行後臺管理而且存儲再數據庫中,這些信息其實大量被前臺程序調用,可是更新頻率很小,能夠考慮將這 部份內容進行後臺更新的時候進行靜態化,這樣避免了大量的數據庫訪問請求高併發。

網站HTML靜態化解決方案 
當一個Servlet資源請求到達WEB服務器以後咱們會填充指定的JSP頁面來響應請求:

    HTTP請求---Web服務器---Servlet--業務邏輯處理--訪問數據--填充JSP--響應請求

HTML靜態化以後:

    HTTP請求---Web服務器---Servlet--HTML--響應請求

2.2.三、高併發高負載類網站關注點之緩存、負載均衡、存儲

2.2.四、高併發高負載網站的系統架構之圖片服務器分離 
    你們知道,對於Web 服務器來講,無論是Apache、IIS仍是其餘容器,圖片是最消耗資源的,因而咱們有必要將圖片與頁面進行分離,這是基本上大型網站都會採用的策略,他們都有獨立的圖片服務器,甚至不少臺圖片服務器。這樣的架構能夠下降提供頁面訪問請求的服務器系統壓力,而且能夠保證系統不會由於圖片問題而崩潰。

2.2.五、高併發高負載網站的系統架構之數據庫集羣和庫表散列

    大型網站都有複雜的應用,這些應用必須使用數據庫,那麼在面對大量訪問的時候,數據庫的瓶頸很快就能顯現出來,這時一臺數據庫將很快沒法知足應用,因而咱們須要使用數據庫集羣或者庫表散列。
  
  在數據庫集羣方面,不少數據庫都有本身的解決方案,Oracle、Sybase等都有很好的方案,經常使用的MySQL提供的Master/Slave也是相似的方案,您使用了什麼樣的DB,就參考相應的解決方案來實施便可。
  
   上面提到的數據庫集羣因爲在架構、成本、擴張性方面都會受到所採用DB類型的限制,因而咱們須要從應用程序的角度來考慮改善系統架構,庫表散列是經常使用而且最有效的解決方案。咱們在應用程序中安裝業務和應用或者功能模塊將數據庫進行分離,不一樣的模塊對應不一樣的數據庫或者表,再按照必定的策略對某個頁面或者 功能進行更小的數據庫散列,好比用戶表,按照用戶ID進行表散列,這樣就可以低成本的提高系統的性能而且有很好的擴展性。

------------------------------------------------------------------------------

3、多線程 Multithreading

3.一、Thread 基本概念與特色

多線程(multithreading),是指從軟件或者硬件上實現多個線程併發執行的技術。

具備多線程能力的計算機因有硬件支持而可以在同一時間執行多於一個線程,進而提高總體處理性能。

  • 多線程:指的是這個程序(一個進程)運行時產生了不止一個線程
  • 並行與併發:
    • 並行:多個cpu實例或者多臺機器同時執行一段處理邏輯,是真正的同時。
    • 併發:經過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操做層面不是真正的同時。併發每每在場景中有公用的資源,那麼針對這個公用的資源每每產生瓶頸,咱們會用TPS或者QPS來反應這個系統的處理能力。

3.二、Thread 生命週期

關於Java中線程的生命週期,首先看一下下面這張較爲經典的圖:

上圖中基本上囊括了Java中多線程各重要知識點。掌握了上圖中的各知識點,Java中的多線程也就基本上掌握了。

3.三、Thread五種基本狀態

  • 新建狀態(New):當線程對象對建立後,即進入了新建狀態,如:Thread t = new MyThread();
  • 就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處於就緒狀態的線程,只是說明此線程已經作好了準備,隨時等待CPU調度執行,並非說執行了t.start()此線程當即就會執行;
  • 運行狀態(Running):當CPU開始調度處於就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。注:就     緒狀態是進入到運行狀態的惟一入口,也就是說,線程要想進入運行狀態執行,首先必須處於就緒狀態中;
  • 阻塞狀態(Blocked):處於運行狀態中的線程因爲某種緣由,暫時放棄對CPU的使用權,中止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的緣由不一樣,阻塞狀態又能夠分爲三種:
    • 1.等待阻塞:運行狀態中的線程執行wait()方法,使本線程進入到等待阻塞狀態;
    • 2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(由於鎖被其它線程所佔用),它會進入同步阻塞狀態;
    • 3.其餘阻塞 -- 經過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。
  • 死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。
相關文章
相關標籤/搜索