天天看點

Java開發項目經理面試題,趕緊收藏!

前言

Mysql的鎖機制确實非常重要,是以在這裡做一個全面的總結整理,便于以後的查閱,也分享給大家。

Mysql的鎖機制還是有點難了解的,是以這篇文章采用圖文結合的方式講解難點,幫助大家了解,講解的主要内容如下圖的腦圖所示,基本涵蓋了Mysql鎖機制的所有知識點。

本文腦圖

Java開發項目經理面試題,趕緊收藏!

思考

前面提到 Kafka 幫我們實作了各個版本的生産者代碼,其實他也可以完全不提供這份代碼,因為核心的隊列的功能已經實作了,這些用戶端的代碼也可以完全交由使用者自己實作。

那麼假如沒有官方代碼,我們又該實作一些什麼功能,有哪些接口,哪些方法,以及如何組織這些代碼呢。帶着這樣的問題我們一起來思考一下!一般對于這種帶有資料流轉的設計,我會從 由誰産生? 什麼資料? 通往哪去? 如何保證通路可靠? 這幾個方面來考慮。

消息自然是通過應用程式構造出來并提供給生産者,生産者首先要知道需要将消息發送到哪個 Broker 的哪個 Topic,以及 Topic 的具體 Partition 。那麼必然需要配置用戶端的 Broker叢集位址 ,需要發送的 Topic 名稱 ,以及 消息的分區政策 ,是指定到具體的分區還是通過某個 key hash 到不同的分區。

知道了消息要通往哪,還需要知道發送的是什麼格式的消息,是字元串還是數字或是被序列化的二進制對象。 消息序列化 将需要消息序列化成位元組數組才友善在網絡上傳輸,是以要配置生産者的消息序列化政策,最好是可以通過傳遞枚舉或者類名的方式自動構造序列化器,便于後續序列化過程的擴充。

消息隊列常常用于多個系統之間的異步調用,那麼這種調用關系就沒有強實時依賴。由于發消息到 Kafka 會産生 網絡 I/O ,相對來說比較耗時,那麼消息發送這一動作除了同步調用, 是否也可以設定為異步,提高生産者的吞吐呢? 。并且大量消息發送場景, 我們可以設定一個視窗,視窗可以是時間次元也可以是消息數量次元,将消息積攢起來批次發送,減少網絡 I/O 次數,提高吞吐量。

最後呢為了保證消息可以最大程度的成功發送到 Broker ,我們還需要一些 失敗重試機制 ,例如失敗後放到重試隊列中,隔一段時間嘗試再次發送。

理清思路

通過上面的分析,我們會有一個大緻的認識,應該會有哪些方法,以及底層的大緻的設計會分為哪幾個部分。但是不夠清楚,不夠明晰。

首先總結一下實作用戶端的幾個要點在于:

  1. 配置 Broker 基礎資訊:叢集位址、Topic、Partition
  2. 消息序列化,通過可擴充的序列化器實作
  3. 消息異步寫入緩沖區,網絡 I/O 線程實作消息發送
  4. 消息發送的失敗重試機制

話不多說,用一張圖畫出各個核心子產品以及他們之間的互動順序:

Java開發項目經理面試題,趕緊收藏!

使用者設定 Kafka 叢集資訊,生産者從 Kafka Broker 上拉取 可用 Kafka 節點、Topic 以及 Partition 對應關系。緩存到生産者成員變量中,如果 Broker 叢集有擴容,或者有機器下線需要重新擷取這些服務資訊。

用戶端根據使用者設定的序列化器,對消息進行序列化,之後異步的将消息寫入到用戶端緩沖區。緩沖區内的消息到達一定的數量或者到達一個時間視窗後,網絡 I/O 線程将消息從緩沖區取走,發送到 Broker 。

以上就是我對于一個 Kafka 生産者實作的思考,接下來看看官方的代碼設計與我們的思路有何差别,他又是為什麼這麼設計。

官方設計

其實經過上面的思考和整理,我們的設計已經非常接近 Kafka 的官方設計了,官方的子產品拆分的更加細緻,功能更加獨立。

核心元件

首先看一眼 KafkaProducer 類中有哪些成員變量,這些變量就是 Producer 的核心元件。

Java開發項目經理面試題,趕緊收藏!

其中核心字段的解釋如下:

clinetId :辨別發送者Id

metric :統計名額

partitioner :分區器作用是決定消息發到哪個分區。有 key 則按照 key 的 hash ,否則使用 roundrobin

key/value Serializer :消息 key/value 序列化器

interceptors :發送之前/後對消息的統一處理

maxRequestSize :可以發送的最大消息,預設值是1M,即影響一個消息 Record 的大小,此值在服務端也是有限制的。

maxBlockTimeMs :buffer滿了或者等待metadata資訊的,逾時的補償機制

accumulator :累積緩沖器

networkClient :包裝的網絡層

sender :網絡 I/O 線程

發送流程

發送一條消息的時候,資料又是怎樣在這些元件之間進行流轉的呢?

Java開發項目經理面試題,趕緊收藏!

Producer調用 send 方法後,在從 Broker 擷取的 Metadata 有效情況下,經過攔截器和序列化後,被分區器放到了一個緩沖區的特定位置,緩沖區由一個 ConcurrentHashMap 構成,key 為主題分區,value 是一個 deque 存放消息緩存塊。從用戶端角度來看如果無需關心發送結果,發送流程就已經結束了。

接下來是獨立的Sender線程負責從緩沖中擷取足量的資料調用 Network Client 封裝層去真正發送資料,這裡使用了 Java8 的 NIO 網絡模型發送資料。

可以看到整個邏輯的關鍵點在于 RecordAccumulator 如何進行消息緩存,一般的成熟架構和中間件中都會有一套自己的記憶體管理機制,比如 Netty 也有一套複雜而又精妙的記憶體管理抽象層,這裡的緩沖區也是一樣的道理,主要需要去看看 Kafka 如何去做記憶體管理。

另外需要關注 Sender 從緩沖裡以什麼樣的邏輯擷取資料,來達到盡量少的網絡互動發送盡量多的資料。還有網絡失敗又是如何保證資料的可靠性的。這個地方也是我們的設計和官方實作的差距,對于網絡 I/O 的精心優化。

目前的篇幅已經比較長了,為了大家友善閱讀了解,本篇主要從和大家一起思考如何設計一個 Kafka Producer 以及官方是如何實作的,我們之間的差距是什麼,更需要關注的點是什麼。通過自己的思考和對比更加能認識到不足學習到新的點!

解,本篇主要從和大家一起思考如何設計一個 Kafka Producer 以及官方是如何實作的,我們之間的差距是什麼,更需要關注的點是什麼。通過自己的思考和對比更加能認識到不足學習到新的點!