翻頁技術實現(轉)

原地址http://timyang.net/data/key-list-pagination/

今天討論了一個傳統的問題,問題自己比較簡單,就是針對key-list類型的數據,如何優化方案作到性能與成本的tradeoff。Key-list在用戶類型的產品中很是廣泛,如一個用戶的好友關係 {「uid」:{1,2,3,4,5}},一條微博下面的評論id列表,一個用戶發表的微博id列表等。mysql

根據經驗,在大部分場景下,單個業務的list數據長度99%在1000條如下,但剩下的1%的數據可能多達100萬條,所以在實現方案的時候不能忽視這些超大數據集的問題,這也體現了常說的80%+的時間在優化20%-的功能。sql

List數據訪問模型常見的有兩種方式
1. 扶梯方式
扶梯方式在導航上一般只提供上一頁/下一頁這兩種模式,部分產品甚至不提供上一頁功能,只提供一種「更多/more」的方式,也有下拉自動加載更多的方式,在技術上均可以概括成扶梯方式。緩存

扶梯方式在技術實現上比較簡單及高效,根據當前頁最後一條的偏移日後獲取一頁便可。寫成SQL可能相似服務器

SELECT * FROM LIST_TABLE WHERE id > offset_id LIMIT n;

2. 電梯方式
另一種數據獲取方式在產品上體現成精確的翻頁方式,如1,2,3……n,同時在導航上也能夠由用戶輸入直達n頁。國內大部分場景採用電梯方式,但電梯方式在技術實現上相對成本較高。
在MySQL中,一般提到的b-tree,在存儲引擎實現上,一般都是b+tree,如圖
b+treenosql

從圖中能夠看到,使用電梯方式時候,當用戶指定翻到第n頁時候,並無直接方法尋址到該位置,而是須要從第一樓逐個count,scan到count*page時候,獲取數據才真正開始,因此致使效率不高。而在數據存在新增及刪除的狀況下,偏移量也不能有效的緩存,一個10萬條的list,只要有一條變化,原先的樓層可能會所有發生變化。post

以上描述的場景屬於單機版本,在數據規模較大時候,互聯網系統一般使用分庫的方式來保存,實現方法更爲複雜。
在面向用戶的產品中,數據分片一般會將同一用戶的數據存在相同的分區,以便更有效率的獲取當前用戶的數據。以下圖所示
shard uid性能

但上述方案在常見的場景中存在很大不足,大部分產品用戶只訪問最近產生的數據,歷史的數據只有極小的機率被訪問到,所以同一個區域內部的數據訪問是很是不均勻,如圖中2014年生成的屬於熱數據,2012年之前的屬於冷數據,只有極低的機率被訪問到。所以簡單的解決方案是按時間遠近將數據進行進一步分區,如圖。大數據

shard time

注意在上圖中使用時間方式sharding以後,在一個時間分區內,也須要用前一種方案將數據進行sharding,由於一個時間片區一般也沒法用一臺服務器容納。優化

上面的方案較好的解決了具體場景對於key list訪問性能及成本的tradeoff,可是它存在如下不足ui

  • 數據按時間進行滾動沒法全自動,須要較多人爲介入或干預
  • 數據時間維度須要根據訪問數據及模型進行精巧的設計,沒法簡單重用
  • 爲了實現電梯直達功能,須要增長額外的二級索引,好比2013年某用戶總共有多少條記錄

因爲以上問題,尤爲是二級索引的引入,顯然它不是理想中的key list實現,後文繼續介紹適合長尾翻頁key list設計的一些思路及嘗試。

相關文章
相關標籤/搜索