基於redis的zSet集合做資料快取實現分頁查詢

2021-10-07 07:33:25 字數 4232 閱讀 6741

最近公司要做手機頁面展示新聞文章資料查詢的優化工作,讓我提個優化方案。現狀是目前手機頁面的資料請求系統後台,系統後台然後呼叫其他系統的介面,返回分頁資料到前台展示,這樣一來,使用者每次下拉到頁面底部載入更多資料都要呼叫其他介面,使用者體驗顯然不是很好,那有沒有更好的方案呢?

優化方案:redis正好適合在這種場景下使用,使用者每次下拉到頁面底部,此時從前台頁面到系統後台分頁(假如每次取10條)取資料,可以直接到redis裡取資料,如果redis返回的資料為空或者小於你要取的10條資料,那麼呼叫介面取10條分頁資料放入快取,然後再從快取裡取資料返回到前台。這樣的話,只有當其中乙個使用者第一次查詢的時候會呼叫介面資料存入快取,以後這個使用者或者其他使用者再看這個文章資訊的時候,就是直接從快取裡取資料,就相當快捷,提高使用者體驗。經測試,之前每次呼叫介面在700~800ms左右,現在每次從快取裡取資料,只需要200ms左右,效能顯然提公升很大。

前面只提到下拉到頁面底部載入更多資料時的情況,其實我們當重新整理最新的資料時,這時候該怎麼處理呢?事實上系統後台用到了kafka消費者接收從其他後台實時傳送的文章資料,這裡接收的文章有三種型別:一種是add,就說明這個文章是新增的發布到手機頁面的資料;一種是update,就說明這個文章是要更新已經發布的資料,最後一種是del,就說明這個文章是要從手機頁面刪除的。也就是說,我們一方面可以從介面獲取歷史的資料,另一方面可以實時獲取最新的被傳送來的新增文章資料(或者是要修改和刪除的)。另外補充一點,為了提公升使用者一開啟手機就能快速的看到新聞資訊的體驗度,我們在系統啟動成功後,預設先呼叫介面存入快取10條記錄,這樣,使用者第一次進入手機頁面預設就能先從快取裡取10條新聞資訊。

上面說了那麼多業務,無非是兩點,一:從快取裡獲取分頁資料;二:對快取資料進行增刪改查的操作。而redis定義了5種資料結構,這5種資料結構型別分別為string(字串)、list(列表)、set(集合)、hash(雜湊)和 zset(有序集合)。

zset結構正是我們想要的快取型別,我們把分數score用文章的主鍵news_id,把每個文章的的內容用json字串放入member裡,redis的資料會根據socre也就是news_id自動排序,我們只需要對redis進行新增、刪除的操作就行了(修改可以先刪除再新增)。最後還要考慮redis裡的資料定期刪除的問題,一般來說,設定快取的過期時間即可,但是設定過期時間是針對key來設定,這裡最好的解決方法就是限制快取的資料的個數,當資料的個數超過設定的限制個數之後,就是從score最低的值開始刪除即可。也就是score最低的值,也就是news_id按照自增長的規則,最小的news_id的資料就是比較早的資料,。

補充說明一些zset裡說資料不重複是指:如果新增乙個資料裡的member如果快取裡存在,這個資料的socre和member就會覆蓋快取裡的資料,也就是說score是在資料裡會重複,而member在資料裡是不重複的。      

來一張全部的邏輯圖:

一、kafka新增資料(keynewslist為redis的key值,jm為文章的json資料格式,redisimpnewslistnum是從配置檔案裡取的redis大小的限值)

//建立zset格式的資料,score為news_id的double型,member為每個稿件的資料

double score = double.parsedouble(jm.getstring("news_id"));

redistemplate.opsforzset().removerangebyscore(keynewslist, score,score);

redistemplate.opsforzset().add(keynewslist, jm.tojsonstring(), score);

log.debug("redis從kafka快取首次資料成功score:"+score+",key:"+keynewslist+",member:"+jm.tostring());

//測試

system.out.println("新增之後的個數" + redistemplate.opsforzset().zcard(keynewslist));

//追加邏輯:限制keynewslist的個數

if (stringutils.isnotblank(redisimpnewslistnum))

}system.out.println("刪除之後的個數" + redistemplate.opsforzset().zcard(keynewslist));

二、kafka更新資料

//先刪除後新增

redistemplate.opsforzset().removerangebyscore(keynewslist, score,score);

boolean aboolean= redistemplate.opsforzset().add(keynewslist, jo.tojsonstring(), score);

if (aboolean)

三、kafka刪除資料

//通過score來刪除快取裡的資料

double score = double.parsedouble(data.getstring("news_id"));

redistemplate.opsforzset().removerangebyscore(keynewslist, score,score);

log.debug("kafka刪除資料,直接delete成功,key:" + keynewslist + ",score:" + score);

四、系統首次載入存入快取資料

bspresponse bspres = bspclient.getlist("",

"topmaceco,topcptmkt,topmoney,topfxmkt,topbond,topcom", "1", "100", "","0","");

//string keynewslist = "newslist_redis_*";

string keynewslist = "newslist_redis_impnews";

log.info("redis首頁要聞請求bsp介面狀態:"+bspres.getmessage());

if (bspres.issuccess())

}if (obj != null&& obj.size()>0)

log.info("redis首頁要聞快取:" + redistemplate.opsforzset().reverserange(keynewslist,0,-1));

}} else

五、前台呼叫系統後台

說明:page_news_id是前台傳遞到後台的最小news_id,根據這值,我們可以定位到快取的資料位置,然後開始取多條資料。

舉例:注意在score 在redis裡是double型別

score           member

44390         

44389         

44385         

44378         

44376         

44374         

44373         

44372         

44370         

44369         

44367         

44365         

那麼利用reverserangebyscore(keynewslist,0,pagescore,1,pagesize)方法,取到的資料就會按照score從大到小排序(rangebyscore是按照從小到大排序):

第乙個引數 表示 keynewslist是key,你要從哪個快取取數;

第二第三個引數 表示 0 pagescore 表示從socre範圍最小是0,最大是pagescore;

第四第五個引數 表示 你要從資料下標開始從1取到pagesize,你要取多個。如果從0開始就會把44376這條資料也會取出來,所以要從1開始取。

取出的結果就是如下資料:

44374         

44373         

44372         

44370         

44369         

if(stringutils.isnotblank(page_news_id))

} else

redis 六 redis的zset(有序集合)

相比於set,zset中會有乙個score屬性,用於set的排名。zadd 向zset中新增元素 sorce value zrem 刪除element zscore 獲取score zincrby 增加score zrange 獲取資料,start到end zrank 通過下標獲取排名 127.0....

Redis(七)zset 有序集合

redis 有序集合和集合一樣也是string型別元素的集合,且不允許重複的成員。不同的是每個元素都會關聯乙個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。有序集合的成員是唯一的,但分數 score 卻可以重複。user camellia1 90,camellia...

redis命令之有序集合(zset)

一 常用命令 1 zadd zset nx xx ch incr score member score member nn 表示只新增,不更新 xx 表示只更新,不新增 ch 表示修改返回值,改操作返回新增元素和修改元素的個數。如果命令中有ch,則分數相等的值不會被記錄到返回的個數中 incr 有這...