您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Schemaless的主要功能是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
Schemaless trigger是一項具有可擴(kuò)展性、容錯性和無損性的技術(shù),監(jiān)聽Schemaless實例中的變更。在行程(trip)流程中起到引擎的作用,從司機按下“結(jié)束行程”并向系統(tǒng)提交費用,直到相應(yīng)數(shù)據(jù)進(jìn)入數(shù)據(jù)庫等待分析。在Schemaless系列的最后一篇中,我們將深入講解Schemaless trigger的功能,以及如何開發(fā)出這個可擴(kuò)展的容錯系統(tǒng)。
簡單來說,在Schemaless數(shù)據(jù)的基本單位被命名為單元(cell)。它是不可變的,一旦寫入,便無法被覆蓋。(在特殊情況下,我們可以刪除舊記錄);單元可以被行鍵(row key)、列名(column name)和引用鍵(ref key)來引用;單元內(nèi)容通過編寫引用鍵更高的新版來執(zhí)行更新,但行鍵和列名保持不變。Schemaless不對其中存儲的數(shù)據(jù)執(zhí)行任何操作(故而命名schemaless)。從Schemaless的觀點來看,它只負(fù)責(zé)存儲JSON對象。
我們來看一下實踐中Schemaless trigger的運作方式。下面的代碼是簡化版的異步計費方式(大寫標(biāo)注Schemaless的列名)。案例Python代碼:
#我們實例化一個客戶端,以便與Schemaless實例通訊 schemaless_client = SchemalessClient(datastore=’mezzanine’) #為BASE列注冊一個bill_rider功能 @trigger(column=’BASE’) def bill_rider(row_key): # row_key是行程的UUID status = schemaless_client.get_cell_latest(row_key, ‘STATUS’) if status.is_completed: #也就是說我們已經(jīng)提交了乘客的賬單 return #否則就嘗試提交賬單 #我們從BASE列拿到了基本行程信息 trip_info = schemaless_client.get_cell_latest(row_key, ‘BASE’) #提交乘客賬單 result = call_to_credit_card_processor_for_billing_trip(trip_info) if result != ‘SUCCESS’: #提交例外,讓Schemaless trigger稍后重試。 raise CouldNotBillRider() #成功提交乘客賬單,寫入Mezzanine schemaless_client.put(row_key, status, body={‘is_completed’: True, ‘result’: result})
在Schemaless實例中,我們在函數(shù)中通過添加decorator@trigger來定義trigger,并指定列。如果指定列的單元中有內(nèi)容,通知Schemaless trigger框架調(diào)用函數(shù)——本例是bill_rider。這里通過BASE中的一個新單元表明行程結(jié)束。觸發(fā)trigger,然后通過函數(shù)來發(fā)送行鍵——本例是行程UUID。如果需要更多數(shù)據(jù),必須從Schemaless實例——本例是從行程存儲Mezzanine中獲取真實數(shù)據(jù)。
bill_rider trigger函數(shù)的信息流見下表(這里是乘客結(jié)賬)。箭頭方向指明調(diào)用方與被調(diào)方,旁邊的數(shù)字指明流程的順序:
首先將行程輸入Mezzanine,Schemaless Trigger框架調(diào)用bill_rider。在調(diào)用時,函數(shù)向行程存儲請求STATUS列的最新信息。本例中is_completed字段不存在,也就是說乘客尚未結(jié)賬。然后獲得BASE列的行程信息,通過函數(shù)調(diào)用信用卡provider來結(jié)賬。在本例中,我們成功用信用卡付費,并返回成功信息到Mezzanine,然后設(shè)置STATUS列的is_completed為True。
Trigger框架確保在每個Schemaless實例中的每個單元至少調(diào)用bill_rider一次。一般來說只觸發(fā)trigger函數(shù)一次,不過在出錯的情況下(無論是trigger功能還是其他功能短暫出錯),都可能需要多次調(diào)用該函數(shù)。也就是說trigger函數(shù)是冪等的,在本例中要檢查單元是否處理完畢。如果答案為是,則返回函數(shù)。
在查看下文中Schemaless如何在流程中提供支持時,要記得這個案例。我們將會解釋Schemaless如何被看作變更日志,并討論與Schemaless相關(guān)的API,分享讓流程支持可擴(kuò)展和可容錯的技術(shù)。
Schemaless包含所有單元,也就是說包含指定行鍵、列keypair的所有版本。由于包含單元的所有歷史版本,除了隨機訪問key-value存儲外,Schemaless還可作為變更日志。事實上它就是一個分區(qū)日志,每個分片都是自己的日志,如下圖:
根據(jù)行鍵(也就是UUID)將每個單元寫入特定的分片。分片中的所有單元都有唯一標(biāo)識符,稱為添加ID。添加ID是一個自動遞增的字段,代表著單元的插入順序(越新的單元,添加ID的數(shù)字越大)。除了添加ID之外,每個單元都有單元寫入的時間(datetime)。在所有分片備份中,單元的添加ID是唯一的,這點對于故障時轉(zhuǎn)移非常重要。
Schemaless的API支持隨機訪問和日志類訪問。隨機訪問API是針對單獨的單元,均由row_key、column_key和ref_key一同定義。
Schemaless還包含這些API端點的批處理版本,這里省略。之前說過的trigger函數(shù)bill_rider就使用這些函數(shù)來獲取并操縱單個單元。
對于日志類訪問API,我們關(guān)心單元的分片數(shù)字與時間戳以及添加ID(合稱位置location):
與隨機訪問API類似,日志訪問API有更多可用的knob,實時從多個分片中抓取單元,不過上面的端點更為重要。位置可以是timestamp或added_id。調(diào)用get_cells_for_shard,除了單元之外,還返回下一個添加ID。例如,如果調(diào)用位置1000的get_cells_for_shards,請求10個單元,返回的下一個位置偏移是1010。
通過日志類訪問API,可以追蹤Schemaless實例,就像可以在系統(tǒng)中追蹤文件一樣(比如tail -f),或者類似最新變更輪詢的事件隊列(比如Kafka)。然后,客戶端持續(xù)追蹤偏移,并將其用在輪詢中。要想引導(dǎo)追蹤程序,需要從第一條開始(比如位置0),或從任何時間,或偏移后。
Schemaless trigger通過使用日志類訪問API完成相同的追蹤,并保持追蹤偏移。輪詢API的好處直接表現(xiàn)在,通過Schemaless trigger讓這個過程具有可擴(kuò)展性與容錯性。通過配置從哪個Schemaless實例、哪一列開始輪詢數(shù)據(jù),將客戶端程序與Schemaless trigger框架鏈接。使用的函數(shù)或回調(diào)與框架中的數(shù)據(jù)流相關(guān),在新單元格插入實例時通過Schemaless trigger或調(diào)用或觸發(fā)。反過來,通過框架在程序所運行的主集群中找到要找的工作進(jìn)程。框架將工作分到可用進(jìn)程中,然后通過將分到故障進(jìn)程的工作分配給其他可用進(jìn)程,巧妙地解決出現(xiàn)故障的進(jìn)程。work分配代表著程序員只用編寫處理程序(比如trigger函數(shù)),并確保它是冪等的。剩下的交給Schemaless trigger來處理。
在這部分中,我們會討論Schemaless trigger如何擴(kuò)展,如何將故障影響最小化。下圖從較高角度展示了其架構(gòu),取自之前的賬單結(jié)算服務(wù):
賬單結(jié)算服務(wù)使用了運行在三臺不同主機上的Schemaless trigger,我們(簡單起見)假設(shè)每個主機只有一個工作進(jìn)程。Schemaless trigger框架區(qū)將分片按工作進(jìn)程區(qū)分開,因此每個工作進(jìn)程只負(fù)責(zé)處理一個特定的分片。注意:工作進(jìn)程1從分片1拉取數(shù)據(jù),工作進(jìn)程2從分片2和分片5拉取數(shù)據(jù),工作進(jìn)程3從分片3和分片4拉取數(shù)據(jù)。一個工作進(jìn)程只處理指定分片的單元,抓取新單元、為這些分片調(diào)用注冊的回調(diào)函數(shù)。一個工作進(jìn)程就是指定的leader,負(fù)責(zé)向工作進(jìn)程分派片區(qū)。如果進(jìn)程掛起,leader將為故障進(jìn)程分配的片區(qū)重新分配給其他進(jìn)程。
在一個分片中,單元都是以寫入順序來觸發(fā)。也就是說如果特定單元的trigger總是由于程序錯誤而出現(xiàn)故障,就會阻礙該片區(qū)的單元處理。為了避免延遲,可以配置Schemaless trigger來標(biāo)記多次出錯的單元,并將它們放在單獨的隊列中。之后,Schemaless trigger就會繼續(xù)下一個單元的處理。如果標(biāo)記單元的數(shù)字超過了特定閾值,trigger就會停止。通常代表著系統(tǒng)錯誤,需要人工修復(fù)。
通過存儲每個片區(qū)中最近一次成功觸發(fā)單元的添加ID,Schemaless trigge繼續(xù)保持追蹤。該框架將這些偏移保存到共享存儲中,比如Zookeeper或Schemaless實例自身,也就是說如果程序重啟,trigger就會繼續(xù)從存儲片區(qū)的存儲偏移開始執(zhí)行。共享存儲也用在meta-info中,比如協(xié)調(diào)選出leader,探知添加或移除的工作進(jìn)程。
Schemaless trigger是為可擴(kuò)展而設(shè)計的。在被追蹤的Schemaless實例中,對于任意客戶端程序,我們能夠添加最多與片區(qū)數(shù)量一致的工作進(jìn)程(通常是4096)。此外,我們能夠在線添加或移除worker,來獨立處理Schemaless實例中其他trigger客戶端的變動負(fù)載。通過在框架中追蹤進(jìn)度,我們可以為要發(fā)送數(shù)據(jù)的Schemaless實例添加盡可能多的客戶端。在服務(wù)器端并沒有邏輯來持續(xù)追蹤客戶端或者將狀態(tài)推送過去。
Schemaless trigger也是容錯的任何進(jìn)程故障都可以不影響系統(tǒng)。
如果一個客戶端worker的進(jìn)程出錯,leader會將這個work重新分配,確保所有片區(qū)都有進(jìn)程。
如果Schemaless trigger節(jié)點上的一個leader出錯,會有新的節(jié)點被選成leader。在leader選舉期間,可以繼續(xù)處理單元,不過work不能執(zhí)行重分配工作,也無法移除和添加進(jìn)程。
如果分片存儲(比如ZooKeeper)出錯,單元進(jìn)程持續(xù)進(jìn)行。不過就像在leader選舉期間一樣,work無法執(zhí)行重分配工作,而在分片存儲出錯時進(jìn)程也無法變更。
最后,在Schemaless實例中,Schemaless trigger框架是不可能出現(xiàn)故障的。任何數(shù)據(jù)庫節(jié)點出錯都沒關(guān)系,因為Schemaless trigger可以從備份讀取。
“Schemaless的主要功能是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。