1. 程式人生 > 其它 >春招面試複習:訊息佇列(七)-資料壓縮

春招面試複習:訊息佇列(七)-資料壓縮

技術標籤:面試java演算法

1 資料壓縮意義

Kafka使用資料壓縮,最高可提升約幾十倍吞吐量。資料壓縮不僅可節省儲存空間,還可用於提升網路傳輸效能。這種使用壓縮提升系統性能的方法,不僅在MQ使用,日常開發也可。比如傳輸大量資料或要在磁碟、資料庫中儲存較大資料,這些情況下,都可考慮使用資料壓縮提升效能,還能節省網路頻寬和儲存空間。

2 資料壓縮適用場景

程序間通過網路傳輸資料是不是需要壓縮?

  • 不壓縮直接傳輸耗時: 傳輸未壓縮資料的耗時
  • 使用資料壓縮耗時: 壓縮耗時 + 傳輸壓縮資料耗時 + 解壓耗時
    壓縮快還是不壓縮快呢?
    不好說。影響因素多,比如資料壓縮率、網路頻寬、收發兩端伺服器的繁忙度。

壓縮和解壓的操作都是計算密集型操作。如果你的應用處理業務邏輯就需耗費大量CPU資源,就不太適合再壓縮解壓。

若系統瓶頸是磁碟IO效能,CPU資源又閒,這就非常適合在把資料寫入磁碟前先壓縮。
但若系統讀寫比嚴重失調,要考慮每讀次資料就解壓次是不是划算。

壓縮的本質是資源置換,即時間換空間或CPU資源換儲存資源。

就像木桶理論,每個系統都有效能瓶頸資源,可能磁碟IO、網路頻寬、CPU。
若使用壓縮,能用長板來換些短板,那總體上就能提升效能,這就划算。
若用壓縮後,短板更短,就不划算。

只有通過效能測試,確認資料壓縮可提升系統性能,就需選擇合適壓縮演算法了。

3 壓縮演算法抉擇

壓縮演算法可以分為

  • 有失真壓縮
    主要用來壓縮音視訊,它壓縮之後會丟失資訊
  • 無失真壓縮
    這討論都是無失真壓縮,即資料經過壓縮和解壓過程後,與壓縮前相比100%相同。

資料為什麼可被壓縮呢?各種各樣壓縮演算法又怎麼壓縮資料的?

舉個極端例子:

00000000000000000000

人肉壓縮下:

200

20個字元就被壓縮成4字元,且可無損還原。

常用壓縮演算法:ZIP,GZIP,SNAPPY,LZ4,XZ。
選擇時考慮資料的壓縮率和壓縮耗時。一般壓縮率越高,壓縮耗時越高。

  • 若要高效能,可選擇壓縮速度快的LZ4
  • 要更高壓縮比,考慮GZIP或壓縮率更高的XZ

壓縮樣本對壓縮速度和壓縮比的影響也較大,同樣大小的一段數字和一段新聞的文字,即使用相同壓縮演算法,壓縮率和壓縮時間差異也較大。

所以,有時在選擇壓縮演算法前,用系統樣例業務資料做個測試,幫你找到最合適壓縮演算法。

如果感興趣,可學習最經典的壓縮演算法:哈夫曼編碼。

4 壓縮分段選型

大部分壓縮演算法區別主要是,對資料進行編碼的演算法,壓縮的流程和壓縮包的結構大致一樣。
而在壓縮過程中,你最需要了解的就是如何選擇合適的壓縮分段。

壓縮時,給定的被壓縮資料它必須有確定長度,或是有頭有尾的,不能是個無限資料流,若要對流資料壓縮,必須把流資料劃分成多幀,一幀幀分段壓縮。

主要因為壓縮演算法在壓縮前,一般都需對被壓縮資料從頭到尾掃描:確定如何對資料劃分和編碼。

  • 一般原則:
    重複次數多、佔用空間大的內容,使用盡量短的編碼,這樣壓縮率會更高。

被壓縮資料長度越大,重位元速率更高,壓縮比也越高。
比如這篇文章,可能出現幾十次“壓縮”,將整篇文章壓縮,這詞重複率幾十次,但按照每個自然段來壓縮,每段中這詞重複率只有二三次。顯然全文壓縮壓縮率高於分段壓縮。

分段並非越大越好,超過一定長度後,再增加長度對壓縮率貢獻不大了。
過大的分段長度在解壓時,還有更多解壓浪費。
比如,一個1MB大小的壓縮檔案,即使你只是需要讀其中很短的幾個位元組,也不得不把整個檔案全部解壓縮,造成很大的解壓浪費。

所以要根據業務,選擇合適壓縮分段,在壓縮率、壓縮速度、解壓浪費間找到平衡點。

確定資料劃分和壓縮演算法後,就可壓縮了,壓縮過程就是用編碼替換原始資料。
壓縮後的壓縮包是由這編碼字典和用編碼替換後的資料組成。

這就是資料壓縮過程。解壓時,先讀取編碼字典,然後按字典把壓縮編碼還原成原始資料即可。

5 Kafka 訊息壓縮流程

首先可以配置Kafka是否開啟壓縮,支援配置使用哪種壓縮演算法。
因為不同場景是否需要開啟壓縮,選擇哪種壓縮演算法都不能一概而論。
所以Kafka將選擇權交給使用者。

在開啟壓縮時,Kafka選擇一批訊息一起壓縮,每一個批訊息就是一個壓縮分段。使用者也可以通過引數來控制每批訊息的大小。

在Kafka中,生產者生成一個批訊息發給服務端,在服務端中是不會拆分批訊息的。那按批壓縮,意味在服務端也不用對這批訊息進行解壓,可整批直接儲存,然後整批發給消費者。最後,批訊息由消費者解壓。
在服務端不用解壓,就不會耗費服務端CPU,同時還能獲得壓縮後,佔用傳輸頻寬小,佔用儲存空間小。
使用Kafka時,如果生產者和消費者的CPU不是特別吃緊,開啟壓縮後,可節省網路頻寬和服務端的儲存空間,提升總體的吞吐量,一般都是個不錯的選擇。

Kafka在生產者上,對每批訊息進行壓縮,批訊息在服務端不解壓,消費者在收到訊息之後再進行解壓。Kafka的壓縮和解壓都是在客戶端完成的。

6 RocketMQ 訊息壓縮原始碼

  • 預設壓縮大於4K的訊息(可配置)

壓縮演算法是zip,預設級別5(可配置)

也是客戶端做解壓縮工作,服務端只儲存。

    private boolean tryToCompressMessage(final Message msg) {
        if (msg instanceof MessageBatch) {
            // 當前不支援批量訊息的壓縮
            return false;
        }
        byte[] body = msg.getBody();
        if (body != null) {
            if (body.length >= this.defaultMQProducer.getCompressMsgBodyOverHowmuch()) {
                try {
                    byte[] data = UtilAll.compress(body, zipCompressLevel);
                    if (data != null) {
                        msg.setBody(data);
                        return true;
                    }
                } catch (IOException e) {
                    log.error("tryToCompressMessage exception", e);
                    log.warn(msg.toString());
                }
            }
        }

        return false;
    }

DefaultLitePullConsumerImpl#pullSyncImpl會呼叫PullAPIWrapper#processPullResult,會為壓縮訊息進行解壓縮。
RocketMQ的壓縮機制也是Producer壓縮,Broker傳輸,Consumer解壓縮,
不同的是kaffka的壓縮是基於一批批訊息,對於CPU空閒較多的場景下會有更大的吞吐提升。

7 總結

一直以來,常見演算法都是空間換時間,但在MQ和一些IO密集型應用中還有CPU計資源換網路頻寬/磁碟IO。
資料壓縮本質是CPU資源換儲存資源,或用壓縮解壓的時間換取儲存的空間。

在選擇壓縮演算法的時候,需綜合考慮壓縮時間和壓縮率兩個因素,被壓縮資料的內容也是影響壓縮時間和壓縮率的重要因素。
必要時可先用業務資料做一個壓縮測試,這樣有助於選擇最合適的壓縮演算法。

另外影響壓縮率的重要因素是壓縮分段,需根據業務情況選擇一個合適分段,在保證壓縮率前提下,儘量減少解壓浪費。