cassandra的緩存
mysql用得最多了,再就PostgreSQL。
2. Uber實時推送平台是如何打造的
原文:Uber』s Real-Time Push Platform
譯者:LZM
Uber 建立的出行平台每天在處理全球數以百萬計的打車訂單。
實時打車市場是一個十分活躍的市場。一次行程包括多個參與者(乘客、司機),他們需要能在 APP 上實時查看、修改當前旅程的狀態。因此,Uber 需要保證每個參與者和他們的 APP 實時同步相關信息,無論是接車時間、達到時間還是行駛路線和附近的司機。
今天,手機端呈現的功能日益豐富,而這些功能對實時信息同步的需求也逐漸增多。本文將介紹 Uber 工程團隊如何把 Uber 平台信息同步機制從輪詢轉為基於 gRPC 的雙向消息流協議。
在 Uber 後台,一個行程連接了現實世界中的乘客和司機。在行程過程中,這兩個實體需要實時更新後台系統的信息。
我們思考一個場景:乘客發出打車請求,而司機在系統上等待接單。Uber 配對系統在後台自動匹配二者,向司機發送訂單。到此為止,每一方(乘客、司機、後台)應該彼此同步他們的內容。
如果一個新訂單帶來,司機 APP 會每隔幾秒輪詢一次信息以及時更新訂單狀態。與此同時,乘客 APP 也會每隔幾秒輪詢一個信息來查看司機時候接單。
輪詢的頻率由數據改變的速率決定。對於一個大型 APP(例如 Uber APP),這個變化速率從幾秒到幾個小時不等,變化范圍十分寬泛。
80% 的後台 API 請求都是來自客戶端的輪詢請求。激進的輪詢策略能讓 APP 的消息保持最新,但也會導致伺服器資源耗盡。任何輪詢過程中的 bug 都可能頻繁導致後台負載顯著加劇,甚至崩潰。隨著需要動態實時數據的功能的增加,這個方法變得不再可行。
輪詢會導致更快的電池消耗、應用程序延遲和網路級擁塞。這在城市中使用 2G/3G 網路或網路不穩定的地方尤其明顯。在這些地方,應用程序每次嘗試拉取信息時,都會重試多次。
隨著功能增加,開發者們嘗試重載輪詢 API 或重建一個新的 API。在高峰期,APP 同時向多個 API 發送輪詢請求。每個 API 負載數個功能。這些輪詢 API 本質上成為一組分片負載 API。但是,在 API 級別上保持一致性和邏輯分離仍然是一個越來越大的挑戰。
冷啟動問題是其中最具挑戰性的問題之一。每當 APP 啟動,所有功能都希望從後台獲取最新狀態,以渲染用戶界面。這導致多個 API 並發競爭,APP 不能成功渲染出正常界面,直到關鍵組件的消息被返回。在沒有優先順序的情況下,因為所有的 API 都有一些關鍵信息,所以應用載入時間會持續增加。糟糕的網路條件會進一步惡化冷啟動問題。
很明顯,我們需要一個徹頭徹尾的、對消息同步機制的改變。我們開啟了建立一個全新的實時推送平台的旅程。在這個平台上,伺服器可以根據需要向應用程序發送數據。當我們採用這種新架構時,我們發現效率有顯著的改進,同時也解決了不同的問題和挑戰。
接下來,來看看我們對推送平台的幾代改進以及該平台是如何演變的。
雖然使用消息推送是取代輪詢的自然選擇,但在如何構建推送機制上有很多需要考慮的問題。四個主要設計原則如下:
1)從輪詢到推送的簡單遷移
目前存在大量端設備在進行輪詢。新系統必須利用現有的、分配給輪詢 API 的負載和邏輯,而不是完全推倒重來。
2)簡易開發
與開發輪詢 API 相比,開發人員在推送數據方面不應該做截然不同的事情。
3)可靠性
所有消息應該通過網路可靠地發送到客戶的 APP 上,並在發送失敗時重試。
4)高效率
隨著 Uber 在發展中國家的迅速發展,數據使用成本對我們的用戶來說是一個挑戰,對於每天要在 Uber 平台上呆上幾個小時的司機來說尤其如此。新協議必須最小化伺服器和移動應用程序之間的數據傳輸量。
我們將這個消息推送系統命名為 RAMEN (Realtime Asynchronous MEssaging Network,實時非同步消息網路)。
任何時候,實時信息都在變化。消息的生命周期開始於決定生成一條信息的那一刻。微服務 Fireball 用於決定何時推送消息。很大部分決策都由配置文件決定。Fireball 在系統間監聽多種類型的事件,並決定是否推送給該消息涉及的客戶。
例如,當一個司機加單,司機和行程的狀態都會改變,並觸發 Fireball。之後,根據配置文件的內容,Fireball 決定何類消息應該推送給客戶。通常,一個觸發器會向多個用戶發送多個消息。
任何事件都可能被觸發器捕獲,例如一些客戶行為(如發出打車請求、打開 APP)、定時器到期、消息匯流排上的後端業務事件或是地理上的駛出 / 駛入事件。所有這些觸發器都被過濾並轉換為對各種後台 API 的調用。這些 API 需要客戶的上下文信息,如設備定位、設備的操作系統以及 APP 的版本號,來生成一個響應。Fireball 獲取設備上下文 RAMEN 伺服器,並在調用 API 時將它們添加到頭部。
所有來自 Uber APP 的伺服器調用都由我們的 API 網關提供。推送有效負載以同樣的方式生成。一旦 Fireball 決定了推送消息的對象和時間,API 網關就負責決定推送什麼。網關會調用各類域服務來生成正確的推送負載。
網關中的所有 API 在如何生成有效負載方面是相似的。這些 API 分為拉取式和推送式兩種。。拉取式 API 由移動設備調用來執行任何 HTTP 操作。推送 API 由 Fireball 調用,它有一個額外的 「推送」 中間件,可以攔截拉取式 API 的響應,並將其轉發給推送消息系統。
將 API 網關介乎於二者之間有以下好處:
l 拉式和推式 API 共享端設備上的大部分業務邏輯。一個給定的負載可以從拉式 API 無縫切換到推式 API。例如,無論你的 APP 是通過拉式 API 調用拉出一個客戶對象,還是 Fireball 通過推式 API 調用發送一個客戶對象,他們都使用相同的邏輯。
l 網關負責處理大量業務邏輯,如推送消息的速率、路由和消息驗證。
在適當的時候,Fireball 和網關一起生成發送給客戶的推送消息。負責將這些信息傳遞到移動設備的是 「推送消息傳遞系統」。
每條消息推送會根據不同的配置執行,這些配置項包括:
1)優先順序
由於為不同的用例生成了數百個不同的消息負載,因此需要對發送到 APP 的內容進行優先排序。我們將在下一節中看到,我們採用的協議限制在單個連接上發送多個並發負載。此外,接收設備的帶寬是有限的。為了給人一種相對優先順序的感覺,我們將信息大致分為三個不同的優先順序:
l 高優先順序:核心功能數據
l 中優先順序:其他有助於提升客戶體驗的功能數據
l 低優先順序:需要發送的數據規模大且使用頻率不高
優先順序配置用於管理平台的多種行為。例如,連接建立後,消息按照優先順序降序排列在套接字(socket)中。在 RPC 失敗的情況下,通過伺服器端重試,高優先順序消息變得更加可靠,並且支持跨區域復制。
2)存活時間
推送消息是為了改善實時體驗。因此,每個消息都有一個預先定義的生存時間,從幾秒到半個小時不等。消息傳遞系統將消息持久化並在發生錯誤時重試傳遞消息,直到有效值過期為止。
3)去重復
當通過觸發器機制或重傳機制多次生成相同的消息時,此配置項確定是否應該刪除重復的消息推送。對於我們的大多數用例,發送給定類型的最新推送消息足以滿足用戶體驗,這允許我們降低總體數據傳輸速率。
消息推送系統的最後一個組件是實際的有效負載交付服務。該服務維持著與世界各地數百萬 APP 程序的活躍連接,並在它們到達時將有效信息同步。世界各地的移動網路提供了不同級別的可靠性,因此傳輸系統需要足夠魯棒以適應故障。我們的系統保證 「至少一次」 交貨。
為了保證可靠傳輸,我們必須基於 TCP 協議,建立從應用程序到數據中心的持久連接。對於 2015 年的一個應用協議,我們的選擇是使用帶有長輪詢、網路套接字或最終伺服器發送事件 (SSE) 的 HTTP/1.1。
基於各種考慮,如安全性、移動 SDK 的支持和數據大小的影響,我們決定使用 SSE。Uber 已經支持了 HTTP + JSON API 棧,它的簡單性和可操作性使它成為我們當時的選擇。
然而,SSE 是一種單向協議,即數據只能從伺服器發送到應用程序。為了提供之前提到的 「至少一次」 的保障,需要確認和重傳機制以構建到應用程序協議之上的交付協議中。在 SSE 的基礎上,我們定義了一個非常優雅和簡單的協議方案。
客戶端開始接收第一個 HTTP 請求的消息 /ramen/receive?seq=0,在任何新會話開始時序列號為 0。伺服器以 HTTP 200 和 「Content-Type: text/event-stream」 響應客戶端以維護 SSE 連接。接下來,伺服器將按照優先順序降序發送所有掛起的消息並依次遞增序列號。由於底層傳輸協議是 TCP 協議,如果沒有交付帶有 seq#3 的消息,那麼該連接應該已斷開、超時或失敗。
客戶端期望在下一個看到的帶有最大序列號重新連接 (在本例中 seq=2)。這就告訴了伺服器,即使編號 3 寫到了套接字上,它也沒有被正常傳遞。然後伺服器將重新發送相同的消息或以 seq=3 開始的任何更高優先順序的消息。該協議構建了流連接所需的可恢復性,伺服器負責大部分的存儲工作,在客戶端實現起來非常簡單。
為了獲知鏈接是否存活,伺服器每 4 秒會發送一個心跳包,這類數據包大小隻有一個比特。如果超過 7 秒沒有收到來自伺服器的消息或心跳,客戶端會認定服務終端並重新發起鏈接。
在上面的協議中,每當客戶端重新以一個更高的序列號發起連接時,它就充當伺服器刷新舊消息的確認機制。在一個環境良好的網路中,用戶可能會保持連接數分鍾,從而導致伺服器不斷積累舊消息。為了緩解這個問題,應用程序會每 30 秒一次調用 /ramen/ack?seq=N,不管連接質量如何。協議的簡單性允許用許多不同的語言和平台非常快速地編寫客戶端。
在設備上下文存儲上,RAMEN 伺服器在每次建立連接時存儲設備上下文,並將此上下文暴露給 Fireball。每個設備上下文的 id 是用戶及其設備參數對應的唯一哈希值。這允許隔離推送消息,即使用戶在不同的設置下同時使用多個設備或應用程序。
第一代 RAMEN 伺服器使用 Node.js 編寫,並使用 Uber 內部的一致性哈西 / 分片框架 Ringpop。Ringpop 是一個去中心化的分片系統。所有連接都使用用戶的 UUID 進行分片,並使用 Redis 作為持久性數據存儲。
在接下來的一年半時間里,消息推送平台在整個公司得到了廣泛的應用。高峰期時,RAMEN 系統通過維持高達 60 萬個並發數據流連接,每秒向三種不同類型的應用程序推送超過 70000 個 QPS 消息。該系統很快成為伺服器 - 客戶端 API 基礎結構中最重要的部分。
隨著通信量和持久連接的快速增加,我們的技術選擇也需要擴展。基於 Ringpop 的分布式分片是一個非常簡單的架構,不會隨著 ring 中的節點數量的增加而動態擴展。Ringpop 庫使用一種 gossip 協議來評估成員資格。gossip 協議的收斂時間也隨著環的大小增加而增加。
此外,Node.js 是單線程的,並且會有更高級別的事件循環延遲,從而進一步延遲成員信息的收斂。這些問題可能引發拓撲信息不一致,進而導致消息丟失、超時和錯誤。
2017 年初,我們決定重新啟動 RAMEN 協議的伺服器實現,以繼續擴大應用規模。在這次迭代中,我們使用了以下技術:Netty、Apache Zookeeper、Apache Helix、Redis 和 Apache Cassandra。
1)Netty: Netty 是一個用於構建網路伺服器和客戶端的高性能庫。Netty 的 bytebuf 允許零拷貝緩沖區,這使得系統非常高效。
2)Apache ZooKeeper: Apache ZooKeeper 對網路連接進行一致性哈希,可以直接傳輸數據,不需要任何存儲層。但是與分散的拓撲管理不同,我們選擇了 ZooKeeper 的集中共享。ZooKeeper 是一個非常強大的分布式同步和配置管理系統,可以快速檢測連接節點的故障。
3)Apache Helix: Helix 是一個健壯的集群管理框架,運行在 ZooKeeper 之上,允許定義自定義拓撲和重新平衡演算法。它還很好地從核心業務邏輯中抽象出拓撲邏輯。它使用 ZooKeeper 來監控已連接的工作者,並傳播分片狀態信息的變化。它還允許我們編寫一個自定義的 Leader-Follower 拓撲和自定義的漸進再平衡演算法。
4)Redis 和 Apache Cassandra: 當我們為多區域雲架構做准備時,有必要對消息進行正確的復制和存儲。Cassandra 是一個持久的跨區域復制存儲。Redis 被用作 Cassandra 之上的容量緩存,以避免分片系統在部署或故障轉移事件中常見的群發問題。
5)Streamgate: 這個服務在 Netty 上實現了 RAMEN 協議,並擁有所有與處理連接、消息和存儲相關的邏輯。該服務還實現了一個 Apache Helix 參與者來建立與 ZooKeeper 的連接並維護心跳。
6)StreamgateFE (Streamgate Front End): 該服務充當 Apache Helix 的旁觀者,從 ZooKeeper 上偵聽拓撲變化。它實現了反向代理。來自客戶機 (火球、網關或移動應用程序) 的每個請求都使用拓撲信息進行分片,並路由到正確的 Streamgate 工作程序。
7)Helix Controllers: 顧名思義,這是一個 5 節點的獨立服務,單獨負責運行 Apache Helix Controller 進程,是拓撲管理的大腦。無論何時任何 Streamgate 節點啟動或停止,它都會檢測到更改並重新分配分片分區。
在過去的幾年中,我們一直在使用這種架構,並且實現了 99.99% 的伺服器端可靠性。我們推動基礎設施的使用持續增長,支持 iOS、Android 和 Web 平台上的十多種不同類型的應用程序。我們已經使用超過 1.5M 的並發連接來操作這個系統,並且每秒推送超過 250,000 條消息。
伺服器端基礎設施一直保持穩定運行。隨著我們為更多新城市提供各種各樣的網路服務和應用程序,我們的重點將是繼續提高向移動設備消息推送機制的長尾可靠性。我們一直在試驗新協議、開發新方法,以彌合和現實需求的差距。在檢查以往的不足時,我們發現以下方面是導致可靠性下降的原因。
1)缺乏認證
RAMEN 協議在減少數據傳輸進行了優化,僅在每 30 秒或客戶端重新連接時才發送確認消息。這將導致延遲確認,在某些情況下無法確認消息達到,因此很難區分是真正的消息丟失還是確認失敗。
2)連接不穩定
維持客戶端和伺服器的正常連接至關重要。跨不同平台的客戶端實現方式在處理錯誤、超時、後退或應用生命周期事件 (打開或關閉)、網路狀態更改、主機名和數據中心故障轉移等方面有許多細微差別。這導致了不同版本間的性能差異。
3)傳輸限制
由於該協議在 SSE 協議基礎上實現,因此數據傳輸是單向的。但是,許多新的應用程序要求我們啟用雙向消息傳輸機制。沒有實時的往返行程時間測量,確定網路狀況、傳輸速度、緩解線路阻塞都是不可能的。SSE 也是一個基於文本的協議,它限制了我們傳輸二進制有效負載的能力,不需要使用像 base64 這樣的文本編碼,從而獲得更大的有效負載。
2019 年底,我們開始開發下一代 RAMEN 協議以解決上述缺點。經過大量考量,我們選擇在 gRPC 的基礎上進行構建。gRPC 是一個被廣泛採用的 RPC 棧,具有跨多種語言的客戶端和伺服器的標准化實現,對許多不同的 RPC 方法提供了一流的支持,並具有與 QUIC 傳輸層協議的互操作性。
新的、基於 gRPC 的 RAMEN 協議擴展了以前基於 SSE 的協議,有幾個關鍵的區別:
l 確認消息立即通過反向流發送,提高了確認的可靠性,而數據傳輸量幾乎沒有增加。
l 實時確認機制允許我們測量 RTT,了解實時的網路狀況。我們可以區分真正的消息損失和網路損失。
l 在協議之上提供了抽象層,以支持流多路傳輸等功能。它還允許我們試驗應用級網路優先順序和流控制演算法,從而在數據使用和通信延遲方面帶來更高的效率。
l 協議對消息有效負載進行抽象,以支持不同類型的序列化。將來,我們會探索其他序列化方法,但要將 gRPC 保留在傳輸層。
l 不同語言的客戶端實現也讓我們能夠快速支持不同類型的應用程序和設備。
目前,這項開發工作處於 beta 版階段,很快就能上線。
消息推送平台是 Uber 出行體驗的組成部分之一。今天有數百種功能建立在該平台的基礎服務之上。我們總結了消息推送平台在 Uber 出行生態中取得巨大成功的幾個關鍵原因。
1)職能分離
消息觸發、創建和傳遞系統之間明確的職責分離允許我們在業務需求發生變化時將注意力轉移到平台的不同部分。通過將交付組件分離到 Apache Helix 中,數據流的拓撲邏輯和核心業務邏輯被很好的區分開,這允許在完全相同的架構上使用不同的有線協議支持 gRPC。
2)行業標准技術
構建在行業標准技術之上使我們的實現更加魯棒且低成本。上述系統的維護開銷非常小。我們能夠以一個非常高效的團隊規模來傳遞平台的價值。根據我們的經驗,Helix 和 Zookeeper 非常穩定。
我們可以在不同的網路條件下擴展到數百萬用戶的規模,支持數百個功能和幾十個應用程序。該協議的簡單性使其易於擴展和快速迭代。
原文:
https://eng.uber.com/real-time-push-platform/
3. Cassandra怎麼實現查詢「不等於某值」操作
不支持主要是為派或春了性能考慮,比較流行的實踐是在應用端實現,類似你這種做法。用等於來做性能會更好select * from table where status = 1、select * from table where status = 3、select * from table where status = 4,而且也適合來緩存。比如下次你再拿大於2的,就直接取剛才緩存的塵耐3和4就可以了
雖然團嫌看起來有點矬,但用nosql就是有代價的
4. Cassandra中的Primary Key、Partition Key、Clustering Key都是什麼
Cassandra中的Key有如下三種類型
每張表都需要有主鍵。主鍵可以是一個欄位或者多個欄位的組合。每條記錄的主鍵必須唯一。舉個例子
這個數據表的主鍵有多個欄位,稱做復合主鍵。
Cassandra 根據分區鍵,使用一致性哈希演算法,把數據分配到集群的旅凳各個機器上。一個機器可以包含多個分區。 Cassandra 保證同一分區鍵的數據都在一台機器上。通過合理的設置分區鍵,可以信鎮祥讓你的查詢讓盡量少的機器處理,提升查詢的效率
對於單主鍵欄位來說,分區鍵和主鍵是同一個欄位。
對於復合主鍵欄位來說,默認情況下,分區鍵是復合主鍵的第一個欄位。如上例中,分區鍵是 club 欄位
可以通過括弧來將分區鍵指定為多個欄位,如將上面 CQL 的11行修改為
Clustering Keys決定了分區內數據的排序。讓我們再看一下最初的例子
在主鍵中的欄位,除了分區鍵外都是 clustering key 。既然 club 是主鍵,那麼 league name kit_number position goals 是Clustering key。你可以定義 clustering key 中每個欄位的升降序。可以將 kit_number 降序、 goals 升序
排序順序與主鍵中欄位的順序相同。因此,在上面的例子中,數據是按照如下布局的
定義不滑搏同欄位升降序的語法如下(默認為升序)
5. 北大青鳥java培訓:學習Java應該了解的大數據和框架
很多人都在知道,計算機行業的發展是非常迅速的,軟體開發人員想要跟上時代的發展,最重要的就是不斷挑戰自己。
在學習軟體開發的過程,前期學習的知識是遠遠不夠的,需要了解更多的知識,並且挑戰更多的復雜性。
現在學習Java語言不能忽略工具和框架的使用,工具和框架的構建越來越復雜。
很多人不知道學習工具和框架有什麼用?下面遼寧電腦培訓為大傢具或御配體了解Java開發應該了解的大數據工具和框架。
一、MongoDB這是一種最受歡迎的,跨平台的,面向文檔的資料庫。
MongoDB的核心優勢是靈活的文檔模型,高可用性復制集和可擴展的碎片集群。
遼寧java培訓建議可以嘗試以多種方式了解MongoDB,例如MongoDB工具的實時監控,內存使用和頁面錯誤,連接,資料庫操作,復制集等。
二、Elasticsearch主要是能夠為雲構建的分布式RESTful搜索引擎。
Elasticsearch主要是使用在Lucene之中的伺服器,能夠進行分布式多用戶能力的全文搜索引擎,並且還是使用在Java的開發衫指中,這是現在很多企業中使用最流行的搜索引擎。
ElasticSearch不僅是一個全文搜索引擎,而且是一個分布式實時文檔存儲,每個欄位都能夠被索引並且可以被搜索。
它也是一個具有實時分析功能的分布式搜索引擎,java課程發現它還可以擴展到數百個伺服器存儲和處理數PB的數據。
ApacheCassandra是一套開源分布式NoSQL資料庫系統。
集GoogleBigTable的數據模型與AmazonDynamo的完全分布式架構於一身。
於2008開源,此後,由於Cassandra良好的可擴展性,被Digg、Twitter等Web2.0網站所採納,成為了一種流行的分布式結構化數據存儲方案。
四、Redis開源(BSD許可證)內存數據結構存儲,用作資料庫,緩存和消息代理。
Redis是一個開源的,基於日誌的Key-Value資料庫,用ANSIC編寫,支持網路,可以基於內存持久化,並提供多種語言的API。
Redis有三個主要功能,遼寧IT培訓認為可以將它與許多其他競爭對手區分開來:Redis是一個將數據完全存儲在內存中的資料庫,僅使用磁碟用於持久性目的。
6. Apache Cassandra資料庫的優缺點有哪些
Apache Cassandra資料庫的優缺點有哪些?本文將超越眾所周知的一些細節,探討與 Cassandra 相關的不太明顯的細節。您將檢查 Cassandra 數據模型、存儲模式設計、架構,以及與 Cassandra 相關的潛在驚喜。在資料庫歷史文章 「What Goes Around Comes Around」中,Michal Stonebraker 詳細描述了存儲技術是如何隨著時間的推移而發展的。實現關系模型之前,開發人員曾嘗試過其他模型,比如層次圖和有向圖。值得注意的是,基於 SQL 的關系模型(即使到現在也仍然是事實上的標准)已經盛行了大約 30 年。鑒於計算機科學的短暫歷史及其快速發展的步伐,這是一項非凡的成就。關系模型建立已久,以至於許多年來,解決方案架構師很容易為應用程序選擇數據存儲。他們的選擇總是關系資料庫。諸如增加系統、移動設備、擴展的用戶在線狀態、雲計算和多核系統的用戶群之類的開發已經導致產生越來越多的大型系統。Google 和 Amazon 之類的高科技公司都是首批觸及規模問題的公司。他們很快就發現關系資料庫並不足以支持大型系統。為了避免這些挑戰,Google 和 Amazon 提出了兩個可供選擇的解決方案:Big Table 和 Dynamo,他們可以由此放鬆關系數據模型提供的保證,從而實現更高的可擴展性。Eric Brewer 的 「CAP Theorem」後來官方化了這些觀察結果。它宣稱,對於可擴展性系統,一致性、可用性和分區容錯性都是權衡因素,因為根本不可能構建包含所有這些屬性的系統。不久之後,根據 Google 和 Amazon 早期的工作,以及所獲得的對可擴展性系統的理解,計劃創建一種新的存儲系統。這些系統被命名為 「NoSQL」 系統。該名稱最初的意思是 「如果想縮放就不要使用 SQL」,後來被重新定義為 「不只是 SQL」,意思是說,除了基於 SQL 的解決方案外,還有其他的解決方案。有許多 NoSQL 系統,而且每一個系統都緩和或改變了關系模型的某些方面。值得注意的是,沒有一個 NoSQL 解決方案適用於所有的場景。每一個解決方案都優於關系模型,且針對一些用例子集進行了縮放。我的早期文章 「在 Data Storage Haystack 中為您的應用程序尋找正確的數據解決方案」 討論了如何使應用程序需求和 NoSQL 解決方案相匹配。Apache Cassandra是其中一個最早也是最廣泛使用的 NoSQL 解決方案。本文詳細介紹了 Cassandra,並指出了一些首次使用 Cassandra 時不容易發現的細節和復雜之處。Apache CassandraCassandra 是一個 NoSQL 列族 (column family) 實現,使用由 Amazon Dynamo 引入的架構方面的特性來支持 Big Table 數據模型。Cassandra 的一些優勢如下所示:高度可擴展性和高度可用性,沒有單點故障NoSQL 列族實現非常高的寫入吞吐量和良好的讀取吞吐量類似 SQL 的查詢語言(從 0.8 起),並通過二級索引支持搜索可調節的一致性和對復制的支持靈活的模式這些優點很容易讓人們推薦使用 Cassandra,但是,對於開發人員來說,至關重要的一點是要深入探究 Cassandra 的細節和復雜之處,從而掌握該程序的復雜性。 什麼是列?列 有點用詞不當,使用名稱單元格 很可能更容易理解一些。我會堅持使用列,因為這是一種習慣用法。Cassandra 數據模型包括列、行、列族和密鑰空間 (keyspace)。讓我們逐一進行詳細介紹它們。•列:Cassandra 數據模型中最基本的單元,每一個列包括一個名稱、一個值和一個時間戳。在本文的討論中,我們忽略了時間戳,您可以將一個列表示為一個名稱值對(例如 author="Asimov")。•行:用一個名稱標記的列的集合。例如,清單 1 顯示了如何表示一個行: 清單 1. 行的示例"Second Foundation"-> { author="Asimov", publishedDate="..", tag1="sci-fi", tag2="Asimov" }Cassandra 包括許多存儲節點,並且在單個存儲節點內存儲每一個行。在每一行內,Cassandra 總是存儲按照列名稱排序的列。使用這種排序順序,Cassandra 支持切片查詢,在該查詢中,給定了一個行,用戶可以檢索屬於給定的列名稱范圍內的列的子集。例如,范圍 tag0 到 tag9999 內的切片查詢會獲得所有名稱范圍在 tag0 和 tag9999 內的列。•列族:用一個名稱標記的行的集合。清單 2 顯示了樣例數據的可能形式: 清單 2. 列族示例Books->{ "Foundation"->{author="Asimov", publishedDate=".."}, "Second Foundation"->{author="Asimov", publishedDate=".."}, … }人們常說列族就像是關系模型中的一個表格。如下例所示,相似點將不復存在。•密鑰空間:許多列族共同形成的一個組。它只是列族的一個邏輯組合,並為名稱提供獨立的范圍。最後,超級列位於一個列族中,該列族對一個密鑰下的多個列進行分組。正如開發人員不贊成使用超級列一樣,在此,我對此也不作任何討論。Cassandra 與 RDBMS 數據模型根據以上對 Cassandra 數據模型的描述,數據被放入每一個列族的二維 (2D) 空間中。要想在列族中檢索數據,用戶需要兩個密鑰:行名稱和列名稱。從這個意義上來說,盡管還存在多處至關重要的差異,關系模型和 Cassandra 仍然非常相似。•關系列均勻分布在表中的所有行之間。數據項之間通常有明顯的縱向關系,但這種情況並不適用於 Cassandra 列。這就是 Cassandra 使用各個數據項(列)來存儲列名稱的原因。•有了關系模型,2D 數據空間就完整了。2D 空間內的每一個點至少應當擁有存儲在此處的 null 值。另外,這種情況不適用於 Cassandra,Cassandra 可以擁有隻包括少數項的行,而其他行可以擁有數百萬個項。•有了關系模型,就可以對模式進行預定義,而且在運行時不可以更改模式,而 Cassandra 允許用戶在運行時更改模式。•Cassandra 始終存儲數據,這樣就可以根據其名稱對列進行排序。這使得使用切片查詢在列中搜索數據變得很容易,但在行中搜索數據變得很困難,除非您使用的是保序分區程序。•另一個重要差異是,RDMBS 中的列名稱表示與數據有關的元數據,但絕不是數據。而在 Cassandra 中,列名稱可以包括數據。因此,Cassandra 行可以擁有數百萬個列,而關系模型通常只有數十個列。•關系模型使用定義良好的不可變模式來支持復雜的查詢,這些查詢中包括 JOIN 和聚合等。使用關系模型,用戶無需擔心查詢就可定義數據模式。Cassandra 不支持 JOIN 和大多數 SQL 搜索方法。因此,模式必須滿足應用程序的查詢要求。7. 請教Cassandra如何安全關閉的相關推薦
cat pidfile | xargs kill
在cassandra的bin目錄下,有個stop-server的腳本,裡面是用
kill `cat <pidfile>李首`
可見,cassandra的正確關閉彎擾升方法就這個了
如果再想安全一點,那麼可以先用nodetool drain操作,阻止該幾點繼續接收埋老請求,執行成功之後,在執行kill命令,關閉該cassandra節點。
8. 關於NoSQL的思考:為什麼我們要優化存儲的寫性能
比如Cassandra,MongoDB這兩個NoSQL的傑出代表。究其原因,我們可能會想到是因為當前UGC模式已經發展到白熱化,用戶產生內容導致讀寫比已經接近或者說小於1:1。 但是我認為這絕不是個中真實原因。 1. 緩存導致存儲的raw read效率不再重要 真實原因是我們對讀的優化已經做得足夠多了,數據存儲我們使用Memcached,TokyoTyrant/TokyoCabinet等緩存存儲,頁面及文件緩存我們使用squid,nginx proxy_cache等存儲,都可以達到非常好的讀緩存效果,如果數據即時性要求不高,或者說緩存設計合理(讀寫皆緩存),緩存命中率會足夠的高,因此我們無需再過分優化底層存儲的raw read效率。 試想緩存層如果有高達99%以上的命中率,那麼相對於raw read設備,我們的億級的數據讀取請求就輕松的變成百萬級請求,上千並發輕松變成數十並發。當然,這需要我們的緩存層足夠靠譜。比如 nginx proxy_cache 可以多較多,這時候宕掉一台不至於使全部讀請求穿透到底層存儲。至於多了之後purge等操作如何全面的執行,不在本文討論之列。 綜上,raw read效率不需要再提升,因為其需求已經被緩存層大量取改頃慎代。 2. 無法取代的rawwrite功能 看到緩存減輕raw read的工作量,我們可以在想是否有方法可以減輕rawwrite的工作量。答案是不可以的。如果您認為可以。可以留言探討。既然rawwrite的工作量是不可取代的,那麼我們大概可以有兩種方法提升寫操作的性能。 3.1 sharding 通過對數據的分區,我們可以將數據進行分布式的存儲,於是每個結點只會分配到一部分的rawwrite請求。這樣相當於公司員工效率不變,多招了人。但由於結點的增多,其中有結點出問題的效率也大大增加。於是我們不得不做一些replication操作來提供HA方案。 3.2 提升rawwrite效率 如上面的舉例,我們只能選擇提升rawwrite效率來實現總體(核敬包括cache層)更好的讀寫效率。這里通常使用的方法就是將隨機的寫操作在內存中進行序列化,並在一定量後進行順序的flush到磁碟操作。所謂將內存當成硬碟,將硬碟當作磁帶就是這個意思。(可參見我更早的一篇文章:《NoSQL理論之-內存是新的硬碟,硬碟是新的磁帶》)所以我們看到前面說到的很多NoSQL產品著重對乎冊寫操作進行了優化,而對讀性能提升並不明顯,甚至不惜以更慢的讀作為提升寫操作性能的代價。 4. 總結 由於讀性能可以通過設置合理的緩存策略來減少raw read操作的數量。因此不僅對讀寫比不大的情形需要著重進行寫操作的優化,對讀寫比大的情況下,仍舊需要優化寫性能而非讀性能。
9. cassandra 查詢超時
在對某個表做count時出現如下錯誤(在做業務性測試,生產環境請不要簡單粗暴做count操作,耗時還可能不準)
很奇怪,另外一個表應該是跟他相同條數的,都能直接count出來,但是當前表count一直報錯,而且數據還差2兩條(跟ES裡面的數據對比後得知)
在網上可以直接查詢相關問題,結果也出來了很多。其中我給出幾個具有參考性的鏈接
其中第一個鏈接其實已經反映了我這次的問題,但是我第一眼看到這個答案並沒有感覺到確切符合我當前的問題,然後後面看到第二個鏈接時,明白了去哪兒看日誌。
在 cassandra system.log 看到了count產生的日誌,前面後後觀察了很長的日誌,結果會出現如下一些情況
上面是3個有不同於常見日誌的信息,下面是常見的日誌信息
這嘩絕臘個問題曾經以為被定位到問題,但是最終卻發現還是無能為力。這里說下歷程
第一次以為找到緣由
做count 操作操作時,就跟其他讀操作一樣,需要將數據載入到緩存中。數據來源包括 SSTables,tombstone標記,這些數據都放在緩存中。
緩存的大小由cassandra.yaml中的 file_cache_size_in_mb 設置控制。 默認大小為 512 MB
count出問題這張表是因為有一個欄位存了很長的文本內容,count整個表時,將所有數據(完整的每行數據)載入到內存就導致內存不足。
第二次
根據上面的方式解決count超時不久後又發現超時,但這次卻是不同之前說的兩個表。這次沒有再去調配置大小,而是在@玄陵 的指導下 跟蹤了cpu idle 跟磁碟的 %util
在跟蹤的過程中剛好出現 %util 達到 100% , 99% 的情況。然後他認為就是磁碟性能造成的超時。但是我跟蹤了磁碟負載很高的時間剛好是定時任務在往cassandra裡面寫數據。那 %util 高應該是寫入造成的,我在定時任務跑完然後再去執行count 也還是超時,所以我不太認同時磁碟性能造成count超時。當然,我們的確實存在磁碟性能,這個後續需要好好調優
無果
我宏信之前執行count sql 時一直在 datagrip (一種cassandra的可視化管理)中操作。偶然想去cassandra 終端使用cqlsh執行,結果竟然有意外之喜
在cqlsh 首次執行也是超時,但是後面執行就能成功統計。而在datagrip中統計卻一直出現超時錯誤。那這兩個有什麼表現不一樣么
觀察日誌發現:在datagrip做操作時,system.log 會輸出很多(全是查詢的sql語句),而在cqlsh中進行統計時,發現system.log 竟然只有少量的日誌輸出,甚至沒有常見的查詢日誌,也是異常奇怪。目前找不到更多原因亂滑,只能記錄存檔了。
對於這個問題花費了很多力氣,查過緩存不足,tombstone太多,cpu, 硬碟。但最後我更傾向這個操作違反了cassandra的設計,cassandra 是分布式的,記錄是分區存儲。當在做 聚合查詢 時 卻沒有帶where 限制條件,那麼很可能不能得到你預期的結果。count可以對一個數據量小小的table進行,但是數據量稍微大一點,可能就不能這么用了。
對於其他聚合查詢請點擊下面鏈接
解決
如果是業務層需要做count統計,需要根據分區鍵去做count
如果只是觀察數據總條數,建議直接在cqlsh上進行統計(不要使用其他工具),當然這個也依然存在超時的問題。所以這里推薦 一個 非常好的統計工具 brianmhess/cassandra-count
這個工具通過使用numSplits參數拆分令牌范圍,可以減少每個查詢計數的數量並減少超時的可能性。
目前使用下來效果還非常不錯
10. Cassandra實戰 筆記-《Cassandra內部數據存儲結構》
Cassandra的配置文件可以對Cassandra中的數據進行配置。cassandra.yaml 中關於存放數據信息的配置如下:
數據信息一共分為以下3類:
在data目錄下,Cassandra 會將每一個 Keyspace 中的數據存儲在不同的文件目錄下,並且 Keyspace 文件
目錄的名稱與 Keyspace 名稱相同。
假設有兩個 Keyspace,分別為 ks1 和 ks2,但在 data目錄下,將看到3個不同的目錄:ks1,ks2和 system。其中 ks1 和 ks2 用於存儲系統定義的兩個 Keyspace 的數據,另外一個 system 目錄是 Cassandra 系統默認的一個 Keyspace,叫做 system,它用來存儲 Cassandra 系統的相關元數據信息以及 HINT 數據信息。
當 Cassandra 有數據需要更新時,第一個記錄這個更新的地方就是 Commitlog。
Commitlog由如下兩個部分構成:
CommitLog - xxx.log 、 CommitLog - xxx.log.header 。
在 CommitLog - xxx.log 文件灶圓中,保存了每一次更新操作的值。
在 CommitLog - xxx.log.header 文件中,記錄了哪些數據已經從 memtable 中寫入 SSTable 中。
通過log. header文件中記錄的元數據信息, Cassandra 可以及時刪除不必要的Commitlog文件,減少磁碟的佔用量,並在Cassandra重啟時,加快從Commitlog中恢復數據的速度。
Commitlog文件的大小可以在配置文件中指定,默認是128MB。
當一個Commitlog文件大小超過設置的閾值後,將會新建一個Commitlog,並將更新數據寫人這個新的文件中。
Cassandra提供了兩種記錄Commitlog的方式:周期記錄( periodic)和批量記錄( batch)。如果使用周期記錄的方式,需要在配置文件進行如下配置:
Cassandra會每次更新信息將寫人 Commitlog 中,並且每隔一定的時間間隔( commitlog-sync_ period in ms )調用 org apache. cassandra. io. util. BufferedRandomAccessFile. syne() 同步 Commitlog 文件。
如果使用批量記錄的方式,需要在配置文件進行如下配置:
Cassandra會緩存每次更新信息,每隔一定的時間間隔( commitlog sync_ batch _window_in_ ms )調用 org. apache. cassandra. io. util. BuferedRandomAccessFile. syne () 同步Commitlog 文件,最後將之前緩存的更新信息寫人Commitlog中。
如果不允許數據丟失,可以使用周期的方式記錄 Commitlog。圓友如果寫入數據量非常大,同時可以承擔由於機器可能宕機導致的數據丟失的風險,則使用批量記錄的方式記錄 Commitlog。
在實際的使用中,可以根據情況來選用合適的 Commitlog記錄方式。
數據寫入 Commitlog 後,將緩存在 Memtable 中。
Cassandra 中橘辯槐每一個 Memetable 只為一個 ColumnFamily 提供服務。
當下面3個條件中任意個滿足後,會將Memtable中緩存的數據寫入磁碟,形成一個SSTable文件。
上面提到的3個參數都可以在配置文件中進行設置,Cassandra 為每一個ColumnFamily提供單獨的配置。
每當有數據進人 Memtable 中時,會將數據保存到成員變數 ColumnFarmilies 中,並解析這個數據,排除重復或者是已經過期的數據。具體實現如下:
當Cassandra需要將Memtable中緩存的數據寫人磁碟時,會按照內存中Key的順序寫人SSTable中。
使用 Memtable 的優勢在於:將隨機 IO 寫變為順序 IO 寫,降低大量的寫操作對存儲系統的壓力。
Cassandra 中的 Memtable 會緩存客戶端寫入的數據,當Memtable中緩存的某一個ColumnFamily中的數據量( 對應配置文件中的 memtable_ throughput_ in mb 和 memtable_ operations_in_ millions 或者超過上一次生成SSTable的時間(對應配置文件中的 memtable flush_ after_mins )後,Cassandra 會將Memtable中對應的ColumnFamily的數據持久化到磁碟中,生成一個SSTable文件。
如ColumnFamily名稱為Cfl的一個SSTable文件由如下文件組成:
其中,「Cf1」為ColumnFamily的名稱;「e」 為版本的標識(這個標識在0.7之前的版本中是沒有的);「1」代表這是名稱為Cfl的ColumnFamily的第一個SSTable,這個數字會隨著新的SSTable文件的生成不斷增加;「Data」、「Filter」、 「Index"和「Statistics" 分別代表 SSTable 4個不同組成部分,它們的作用各不相同。
在Cassandra中,除了用戶自己定義的 Keyspace 之外,還有一個特殊的 Keyspace :名稱為system的系統表空間。
用戶不能在 Cassandra 中創建名為 system 的 Keyspace,只能由 Cassandra 系統自動創建。系統表空間的主要有以下兩個作用:
如果系統首次啟動,Cassandra 將會自動在data目錄下創建系統表空間,並將系統元數據信息存放在系統表空間中。以後啟動的過程中,Cassandra 將會直接從系統表空間中讀取系統元數據信息。
如果 Cassandra 發現某一個節點宕機,就會將發送給宕機節點的數據以 HINT 的形式發送給另外台 Cassandra 伺服器。接收到 HINT 數據的 Cassandra 伺服器將數據緩存到系統表空間中,當其發現宕機的 Cassandra 恢復後,將緩存 HINT 數據發送給恢復的伺服器,完成數據傳輸後,將緩存的 HINT 數據從系統表空間中刪除。
本章從原理上分析和講解了 Cassandra 的內部數據存儲結構Commitlog、Memtable、SSTable和構成SSTable的4個子文件。了解Cassandra的內部數據存儲構造有利於為基於Cassandra的應用程序設計合理的數據模型,以及找出造成讀寫瓶頸的原因。另外還介紹了Cassandra的系統表空間,了解了整個系統元數據管理的機制。