Schemaless觸發(fā)器
Schemaless的一個重要特性是觸發(fā)器,提供了在Schemaless實例變更時可獲得通知的能力。由于cell是不可變的,以及新的版本是追加的,所以每個cell都代表了一個修改或者一個版本,這允許一個實例的值變更可以像日志一樣查看變化。對于一個給定實例,可以監(jiān)聽這些變化以及觸發(fā)基于這些變化的函數(shù),非常像類似Kafka這種事件總線系統(tǒng)。Schemaless的觸發(fā)器使Schemaless成為一個完美的真實來源的數(shù)據(jù)存儲,因為除了隨機訪問數(shù)據(jù),下游的依賴可以運用觸發(fā)器功能來監(jiān)聽并觸發(fā)任何應用側特定的代碼(與LinkedIn’s的 DataBus類似),進而實現(xiàn)數(shù)據(jù)創(chuàng)建與數(shù)據(jù)處理的解耦。
在其它用例中,Uber在BASE列寫入Mezzanine實例后,使用Schemaless的觸發(fā)器來進行結賬操作。針對上面的例子,當trip_uuid1的BASE列被寫入后,我們的支付服務被BASE列的觸發(fā)器觸發(fā),獲取這個cell,然后嘗試用信用卡支付該行程。無論成功與否,信用卡支付的結果都會回寫如Mezzanine的STATUS列。通過這種方式實現(xiàn)了支付服務于行程創(chuàng)建的解耦,Schemaless扮演了一個異步事件總線的角色。
索引的易用性
最后,Schemaless支持在JSON blob中的字段上定義索引。當這些預定義的用于找到cell的字段與查詢的參數(shù)相匹配時,就會用到索引。索引查詢效率很高,因為索引查詢只需要訪問一個單一的分片來找到需要返回的cell的集合。事實上,查詢還可以更深度的優(yōu)化,因為Schemaless允許非標準化的cell數(shù)據(jù)直接加入索引中。索引中含有非標準化數(shù)據(jù)意味著索引查詢在查詢和取信息操作一起只需要查詢一個分片。事實上,我們通常推薦Schemaless用戶在可能需要的地方都把非標準數(shù)據(jù)加到索引當中,除非只需要直接用row key查詢并取回cell。在某種意義上,這樣一來我們用存儲交換來了快速查詢的性能。
作為Mezzanine的一個例子,我們定義個了一個副索引來查詢指定司機的所有行程。我們將行程的創(chuàng)建時間以及行程發(fā)生的城市非標準話加入到索引中。這樣就可以查詢一個司機在一個城市中一段時間中的所有行程。下面我們給出了driver_partner_index YAML 格式的定義,這是行程數(shù)據(jù)存儲的一部分,定義在BASE列上 (這個例子用標準#符號添加了注釋)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
table: driver_partner_index # Name of the index.
datastore: trips # Name of the associated datastore
column_defs:
– column_key: BASE # From which column to fetch from.
fields: # The fields in the cell to denormalize
– { field: driver_partner_uuid, type: UUID}
– { field: city_uuid, type: UUID}
– { field: trip_created_at, type: datetime}
使用這個索引,通過篩選city_uuid或者trip_created_at,我們能夠找出指定driver_partner_uuid的行程。在這個例子中我們只用到BASE列的中的字段,但是Schemaless支持從多個列中非標準化數(shù)據(jù),相當于上面column_def列表中的多個實例。
像上文提到的Schemaless高效的索引得益于基于分片字段將索引分片。因此一個索引的唯一需求是索引中有一個字段是分片字段(例如上例中最先給出的driver_partner_uuid)。該分片字段決定了索引實體應該在哪個分片寫入或者讀取。原因是我們在查詢索引的時候需要提供分片字段。這意味著在查詢時,我們只需要查詢一個分片來獲取索引實體。關于分片字段有一點需要注意的是要選一個分布好的字段。UUID最佳,其次是city ids,不要選狀態(tài)字段(枚舉值)。
除分片字段外,Schemaless還支持相等、不等以及范圍查詢的過濾器,同時支持只查詢索引字段的一個子集以及根據(jù)索引實體指向的row key獲取特定列或所有列。現(xiàn)在分片字段必須是不可修改的,因此Schemaless只需跟一個分片交互,但是我們正在探尋如何在沒有太大性能開銷的情況下讓他成為可變的。
索引具備最終一致性,無論何時我們寫入一個cell,我也更新這個索引實體,但是這不發(fā)生在同一個事務中。Cell與索引實體通常不在同一個分片上,因此如果我們想要提供一致的索引,就需要在寫入操作中引入 2PC ,這會明顯加大開銷。通過最終一致性的索引,我們避免了這項開銷,但是Schemaless的用戶可能會看到過期的數(shù)據(jù)。多數(shù)情況下cell變化與相關索引變化之間的延遲能控制在20ms之內(nèi)。