天天看點

表格存儲:使用TableStoreWriter進行高并發、高吞吐的資料寫入概述适用場景 架構解析如何使用相關文章

    表格存儲(原ots)的一大特性是能夠支撐海量資料的高并發、高吞吐率的寫入,特别适合日志資料或物聯網場景(例如軌迹追蹤或溯源)資料的寫入和存儲。這些場景的特性是,會在短時間内産生大量的資料需要消化并寫入資料庫,需要資料庫能夠提供高并發、高吞吐率的寫入性能,需要滿足每秒上萬行甚至上百萬行的寫入吞吐率。針對這些場景,我們在存儲層做了很多的優化(本篇文章不贅述),同時在sdk接口層也做了一些優化,專門提供了一個簡單易用、高性能的資料導入接口。

    tablestorewriter是基于java sdk的異步接口,封裝的一層專門用于高并發、高吞吐率資料導入的接口。本篇文章主要會介紹tablestorewriter的适用場景、底層架構以及如何使用。

如果你的應用場景,滿足以下特點,則可以考慮使用tablestorewriter來作為資料寫入的入口:

<b>特點一: 高并發,對吞吐率要求很高</b>

需要高并發的資料寫入,非寫入行的吞吐率要求很高。例如日志場景,需要分布式的采集日志,采集點可能很多;需要在短時間内将這些産生的日志消費掉,導入到資料庫中,衡量導入性能的名額是每秒消費多少mb的日志資料。

<b>特點二:對單條資料的寫入延遲沒有要求</b>

應用場景需要的是高寫入吞吐率,而不是單條資料的寫入延遲。還是拿日志場景舉例,日志場景對寫入的要求是每秒能處理多少條日志,而不在乎一條日志從産生到最終寫入的延遲。這是典型的離線和線上場景的差別,線上場景要求回報是及時的。從延遲的量級上來講,線上場景可能要求資料寫入在毫秒級别,而離線場景可能可以接受資料寫入延遲在百毫秒級别。

為啥tablestorewriter要求應用對單行導入的延遲沒有要求?這與tablestorewriter内部優化寫入吞吐率相關,為了最大化利用存儲層寫入的性能,tablestorewriter内部會做資料緩沖,盡量發送大的資料包,而資料緩沖需要資料從寫入到發送有一個暫緩。

<b>特點三:寫入可異步化(可采用生産者消費者模型)</b>

tablestorewriter為提高寫入吞吐率,做的一個優化即異步化。異步化有很多的好處,包括資料寫入可以更聚集,可以提供更高的寫入并發等。

是以對于應用層,需要能夠接受寫入異步化。異步化代表的意思是,資料寫入的觸發線程,不需要同步的等待該行資料是否寫入成功還是失敗的回報,資料寫入失敗或成功的處理可以被異步的執行。

類似的架構為:生産者将資料寫入一個隊列,而不用管該資料何時被消費,消費者異步的消費資料。

<b>特點四:同一條資料可重複寫入</b>

tablestorewriter無法避免一條資料可能被重複的寫入,重複的原因有很多,例如網絡逾時重傳等。在非事務的寫入模式下,都很難保證一條資料不被重複寫入,而如果帶了事務的寫入,則性能都不會好。tablestorewriter重性能,是以需要應用能接受一條資料被重複的寫入。

日志有其非常典型的特點:

海量:日志的産出代價是比較小的,随着應用規模的增大,日志資料體量會非常大。

要求高吞吐率:對單條日志從産出到寫入的延遲沒有要求,而重視的是消費短時間内産生的大量日志資料的吞吐率。

處理可異步化:日志是業務性比較低的資料,一般不在業務的主線上,通常是離線處理,是以可異步化。

可重複寫入:日志是固化的資料,重複寫入也不會影響資料的正确性。

消息系統例如即時通訊,特點同樣是:

海量(例如寫入放大的群消息等)

要求高吞吐率:對單條消息的延遲不需要很高,可接受百毫秒級别的延遲,但是更注重的是短時間内産生的海量資料的寫入(投遞)速度。

處理可異步化:消息的處理是完全可以被異步化的

可重複寫入:消息通常都會标注唯一的消息id,且消息産生後不會更改,是以重複寫入不會帶來什麼問題。

分布式隊列的應用場景非常廣,被廣泛用在複雜的分布式系統中。它在提供高性能的消息傳遞之外,對架構的好處在于能夠解耦子產品之間的依賴,簡化系統的架構。

若您的應用架構中,也用到了分布式隊列,并且資料的消費者之一是将資料導入到表格存儲資料庫中,那也可以考慮使用tablestorewriter。tablestorewriter自身也是一個生産者消費者模型,與分布式隊列的适用場景有相似之處。

表格存儲:使用TableStoreWriter進行高并發、高吞吐的資料寫入概述适用場景 架構解析如何使用相關文章

圖1 otswriter與sdk的層次關系

    如圖1所示,tablestorewriter是基于sdk層接口之上重新包裝的一層接口,它與tablestore java sdk的關系是:

依賴了sdk提供的asyncclient異步接口

導入資料會使用batchwriterow接口

單行異常重試依賴sdk提供的retrystrategy

表格存儲:使用TableStoreWriter進行高并發、高吞吐的資料寫入概述适用場景 架構解析如何使用相關文章

圖2 otswriter内部架構

    如圖2所示,為tablestorewriter的内部架構。

    如果直接使用tablestore java sdk的接口,可以一樣的完成資料導入的需求,但是tablestorewriter在接口易用性和性能上做了一些優化,包括:

使用異步而非同步接口:旨在為了使用更少的線程但提供更高的并發。

自動資料聚合:在記憶體中使用緩沖隊列,讓一次發給表格存儲的批量寫請求盡量大,提供寫入吞吐率。

采用生産者消費者模式: 比較傳統的,更易于異步化和資料聚集的一種架構。

使用高性能的資料交換隊列:選用disruptor ringbuffer,經過性能測試,采用多生産者單消費者的模型。

屏蔽複雜的batchwriterow請求封裝:通過sdk預檢查,自動過濾髒資料(主鍵格式與表預定義的不符、行大小超限、行列數超限等),避免到了服務端後再抛錯傳回;自動處理請求限制(例如一次批量的行數限制、一次批量的大小限制等);

行級别callback:sdk提供請求級别的callback,tablestorewriter提供行級别的callback,讓業務邏輯專注于處理行資料,完全屏蔽底層的請求單元。

行級别重試:請求級别重試失敗,會根據特定的錯誤碼,轉換為行級别的重試,最大程度保證行的寫入成功率。

初始化一個tablestorewriter需要以下幾個配置參數:

asyncclient:一個提供異步調用的tablestore client,注意由于重試政策是依賴于sdk自身的重試政策,是以若需要定制批量寫資料的重試政策,需要在這個client中配置,如示例所示。

writerconfig:otswriter的相關配置,主要包括:限制項(一次批量寫的行數上限、一次請求的大小限制等)、并發數(異步并發寫入的并發數上限)等。

tablestorecallback&lt;rowchange, consumedcapacity&gt;:處理行級别成功或失敗的callback。

executorservice:用于處理callback調用的executor thread pool。

<code></code>

往tablestorewriter内寫資料非常的簡單,根據相應的請求(rowputchange、rowupdatechange或rowdeletechange)構造不同的rowchange,直接往tablestorewriter内扔即可。

tablestorewriter通過callback來回報行級别的成功或者失敗,若成功,即調用oncomplete函數,若失敗,根據異常的類别,調用對應的onfailed函數。

<a href="http://www.aliyun.com/product/ots">阿裡雲tablestore官方網站</a>

<a href="http://bbs.aliyun.com/">阿裡雲tablestore官方論壇</a>

<a href="https://help.aliyun.com/product/8315004_ots.html">阿裡雲tablestore官方文檔中心</a>

<a href="http://yq.aliyun.com/">阿裡雲雲栖社群</a>

<a href="https://workorder.console.aliyun.com/#/ticket/createindex">阿裡雲工單系統</a>