1. 程式人生 > 其它 >併發和多執行緒(十五)--AbstractQueuedSynchronizer共享鎖和Condition條件佇列

併發和多執行緒(十五)--AbstractQueuedSynchronizer共享鎖和Condition條件佇列

Kafka是為大資料而生的訊息中介軟體,在資料採集、傳輸、儲存的過程中發揮著舉足輕重的作用。

優點:

  1. 效能卓越,單機寫入TPS約在百萬條/秒,最大的優點,就是吞吐量高。
  2. 時效性:ms級
  3. 可用性:非常高,kafka是分散式的,一個數據多個副本,少數機器宕機,不會丟失資料,不會導致不可用
  4. 消費者採用Pull方式獲取訊息, 訊息有序, 通過控制能夠保證所有訊息被消費且僅被消費一次;
  5. 有優秀的第三方Kafka Web管理介面Kafka-Manager;
  6. 在日誌領域比較成熟,被多家公司和多個開源專案使用;
  7. 功能支援:功能較為簡單,主要支援簡單的MQ功能,在大資料領域的實時計算以及日誌採集被大規模使用。

缺點:

  1. Kafka單機超過64個佇列/分割槽,Load會發生明顯的飆高現象,佇列越多,load越高,傳送訊息響應時間變長;
  2. 使用短輪詢方式,實時性取決於輪詢間隔時間; 消費失敗不支援重試; 支援訊息順序,但是一臺代理宕機後,就會產生訊息亂序
  3. 存在丟訊息可能:在設計層面上就有丟訊息的可能(比如定時刷盤,如果掉電就會丟訊息)。
  4. 錯峰流控:上下游對於事情的處理能力是不同的。比如,Web前端每秒承受上千萬的請求,並不是什麼神奇的事情,只需要加多一點機器,再搭建一些LVS負載均衡裝置和Nginx等即可。但資料庫的處理能力卻十分有限,即使使用SSD加分庫分表,單機的處理能力仍然在萬級。由於成本的考慮,我們不能奢求資料庫的機器數量追上前端。 這種問題同樣存在於系統和系統之間,如簡訊系統可能由於短板效應,速度卡在閘道器上(每秒幾百次請求),跟前端的併發量不是一個數量級。但使用者晚上個半分鐘左右收到簡訊,一般是不會有太大問題的。如果沒有訊息佇列,兩個系統之間通過協商、滑動視窗等複雜的方案也不是說不能實現。但系統複雜性指數級增長,勢必在上游或者下游做儲存,並且要處理定時、擁塞等一系列問題。而且每當有處理能力有差距的時候,都需要單獨開發一套邏輯來維護這套邏輯。所以,利用中間系統轉儲兩個系統的通訊內容,並在下游系統有能力處理這些訊息的時候,再處理這些訊息,是一套相對較通用的方式。

訊息佇列優點:低耦合、可靠投遞、廣播、流量控制、最終一致性等一系列功能,成為非同步RPC的主要手段之一。

分析設計一個訊息佇列時需要考慮到的問題,如RPC、高可用、順序和重複訊息、可靠投遞、消費關係解析等。 當你需要使用訊息佇列時,首先需要考慮它的必要性。可以使用mq的場景有很多,最常用的幾種,是做業務解耦/最終一致性/廣播/錯峰流控等。反之,如果需要強一致性,關注業務邏輯的處理結果,則RPC顯得更為合適。

Kafka是最初由Linkedin公司開發,是一個分散式、分割槽的、多副本的、多訂閱者,基於zookeeper協調的分散式日誌系統(也可以當做MQ系統),

常見可以用於web/nginx日誌、訪問日誌,訊息服務等等,Linkedin於2010年貢獻給了Apache基金會併成為頂級開源專案。

Kakfa具有高吞吐、低延遲等特點,在大資料、日誌收集等應用場景下被廣泛使用。

Kafka部分名詞解釋如下:

  1. Broker:訊息中介軟體處理結點,Kafka服務端,負責訊息的儲存和轉發。一個Kafka節點就是一個broker,多個broker可以組成一個Kafka叢集。
  2. Topic:一類訊息,例如頁面瀏覽日誌、點選日誌等都可以以topic的形式存在,Kafka叢集能夠同時負責多個topic的分發。
  3. Partition:topic物理上的分組,一個topic可以分為多個partition,每個partition是一個有序的佇列。
  4. Segment:partition物理上由多個segment組成,每個Segment存著訊息資訊。
  5. Offset:每個partition都由一系列有序的、不可變的訊息組成,這些訊息被連續的追加到partition中。partition中的每個訊息都有一個連續的序列號叫做offset,用於partition唯一標識一條訊息。
  6. Producer:訊息生產者,負責將產生的訊息傳送到broker。
  7. Consumer:訊息消費者,從broker中拉取訊息進行消費。
  8. Consumer Group:消費者分組,訊息的消費是以組為單位的,每個Consumer必須屬於一個group。partition中的每個訊息只能被組中的一個consumer(執行緒)消費,如果一個訊息可以被多個consumer(執行緒)消費的話,那麼這些consumer必須在不同的組。
  9. Zookeeper:儲存著叢集broker、topic、partition等meta資料;另外,還負責broker故障發現,partition leader選舉,負載均衡等功能

體系結構圖:

Topic

一個topic是對一組訊息的歸納,一個topic可以認為是一類訊息。對每個topic,它被分成多個partition,,每個partition在儲存層面就是append log檔案。也就是說Kafka通過partition對topic做了【日誌分割槽】。

任何釋出到此partition的訊息都會被追加到log檔案的尾部,每條訊息在檔案中的位置稱為offset(偏移量),offset為一個long型的數字,它唯一標記分割槽中的一條訊息。每條訊息都被append到partition中,是順序寫磁碟,因此效率非常高(經驗證,順序寫磁碟效率比隨機寫記憶體還要高,這是Kafka高吞吐率的一個很重要的保證)。連續追加到partition中的訊息是有序的、不可變的。在一個可配置的時間段內,Kafka叢集保留所有釋出的訊息,不管這些訊息有沒有被消費。比如,如果訊息的儲存策略被設定為2天,那麼在一個訊息被髮布的兩天時間內,它都是可以被消費的。之後它將被丟棄以釋放空間。Kafka的效能是和資料量無關的常量級的,所以保留太多的資料並不是問題。

LOG consumer offset

每個consumer唯一需要維護的資料是訊息在【日誌】中的位置,也就是offset。

這個offset由consumer來維護:一般情況下隨著consumer不斷的讀取訊息,offset的值會不斷增加,其實consumer可以以任意的順序讀取訊息,

比如它可以將offset設定成為一箇舊的值來重讀之前的訊息。這使得consumer非常的輕量級:它們可以在不對叢集和其他consumer造成影響的情況下讀取訊息。

使用命令列來'tail'訊息而不會對其他正在消費訊息的consumer造成影響。 將日誌分割槽可以達到以下目的:首先這使得每個日誌的數量不會太大,可以在單個服務上儲存。另外每個分割槽可以單獨釋出和消費,為併發操作topic提供了一種可能。

分散式

每個分割槽在Kafka叢集的若干服務中都有副本,這樣這些持有副本的服務可以共同處理資料和請求,副本數量是可以配置的。副本使Kafka具備了容錯能力。

每個分割槽都由一個伺服器作為"leader",零或若干伺服器作為"followers",leader負責處理訊息的讀和寫,followers則去複製leader。

如果leader 宕機了,followers中的一臺則會自動成為leader。叢集中的每個服務節點都會【同時】扮演兩個角色:作為它所持有的一部分分割槽的leader,同時作為其他分割槽的followers,這樣叢集就會據有較好的負載均衡。

Producer

Producer將訊息釋出到它指定的topic中,並負責決定釋出到哪個分割槽。通常簡單的由負載均衡機制隨機選擇分割槽,但也可以通過特定的分割槽函式選擇分割槽。一般使用的更多的是第二種。 每一條訊息被髮送到broker中,會根據partition規則選擇被儲存到哪一個partition。如果partition規則設定的合理,所有訊息可以均勻分佈到不同的partition裡,這樣就實現了水平擴充套件。(如果一個topic對應一個檔案,那這個檔案所在的機器I/O將會成為這個topic的效能瓶頸,而partition解決了這個問題)。在建立topic時可以'$KAFKA_HOME/config/server.properties'中指定這個partition的數量,當然可以在topic建立之後去修改partition的數量。 在傳送一條訊息時,可以指定這個訊息的key,producer根據這個key和partition機制來判斷這個訊息傳送到哪個partition。partition機制可以通過指定producer的partition.class這一引數來指定,該class必須實現'kafka.producer.Partitioner'介面。

Consumer

釋出訊息通常有兩種模式:佇列模式(queuing)和釋出/訂閱模式(publish-subscribe)。 1)佇列模式:consumers可以同時從服務端讀取訊息,每個訊息只被其中一個consumer讀到; 2)釋出/訂閱模式:訊息被廣播到所有的consumer中,每個consumer都能收到。 Consumers可以加入一個consumer組,在同一個組內共同競爭一個topic,topic中的訊息將被分發到組中的一個成員中。同一組中的consumer可以在不同的程式中,也可以在不同的機器上。如果所有的consumer都在一個組中,都搶一個topic,這就成為了傳統的佇列模式,只有一個會收到訊息,在各consumer中實現負載均衡。如果所有的consumer都在不同的組中,這就成為了釋出/訂閱模式,訊息會被分發到所有的consumer中。更常見的是,每個topic都有若干數量的consumer組,每個組都是一個邏輯上的"訂閱者",為了容錯和更好的穩定性,每個組由若干consumer組成。這其實就是一個釋出/訂閱模式,只不過訂閱者是個組而不是單個consumer。

有序性

相比傳統的訊息系統,Kafka可以很好的保證有序性。傳統的佇列在伺服器上儲存有序的訊息,如果多個consumers同時從這個伺服器消費訊息,伺服器就會以訊息儲存的順序向consumer分發訊息。雖然伺服器按順序釋出訊息,但是訊息是被非同步的分發到各consumer上,所以當訊息到達時可能已經失去了原來的順序,這意味著併發消費將導致順序錯亂。為了避免故障,這樣的訊息系統通常使用"專用consumer"的概念,其實就是隻允許一個消費者消費訊息,當然這就意味著失去了併發性。

Kafka通過分割槽的概念,可以在多個consumer組併發的情況下提供較好的有序性和負載均衡。將每個分割槽分只分發給一個consumer組,這樣一個分割槽就只被這個組的一個consumer消費,就可以順序的消費這個分割槽的訊息。因為有多個分割槽,依然可以在多個consumer組之間進行負載均衡。注意consumer組中consumer的數量不能多於分割槽的數量,也就是有多少分割槽就允許多少併發消費。 Kafka只能保證一個分割槽之內訊息的有序性,在不同的分割槽之間是不可以的,這已經可以滿足大部分應用的需求。如果需要topic中所有訊息的有序性,那就只能讓這個topic只有一個分割槽,當然也就只有一個consumer組消費它。

人生還有意義。那一定是還在找存在的理由