摘要:是求兩個有序集合的并集,可以用來合并兩個投票中所有參與的人的排行榜。經過考察技術方案和實現成本,決定采用提供的有序集合,實現投票過程和實時排名的展示,直接讀取緩存,避免了非核心業務對數據庫的突發高并發訪問。
redis是一種提供多種數據類型的開源key-value存儲系統,通常將數據全部存儲在內存中。
redis是目前最受歡迎的key-value存儲系統,是基于內存存儲kv的數據庫,合理的使用redis作為緩存,可以極大的改善系統的性能和服務器請求響應時間。
redis除了基本的kv存儲以外,還實現了哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等數據類型;結合內存和數據結構的特性,在業務功能實現實現過程中,可以更靈活的實現很多特性。
今天介紹的是有序集合,這種數據結構,我們在實際的業務過程中使用了有序集合,并且收獲到一些有價值的經驗。
什么是有序集合在redis提供的數據類型中,有序集合(Sorted Set)和集合(Set),在集合中不能添加重復的元素,相同值的元素只能有一個;有序集合不同于集合的是,它可以給每個元素設置一個double類型的分數,通過這個值,redis為集合中的成員進行從小到大的排序。
在redis中,有序集合的實現,使用的是一種叫skiplist數據結構,這種數據結構可以讓get、set、add和remove等操作的預期時間達到O(log N),具體的原理,有興趣可以自己了解。
有序集合提供了豐富的操作,可以在很多應用場景應用。
zunionstore 是求兩個有序集合的并集,可以用來合并兩個投票中所有參與的人的排行榜。
zinterstore 是求兩個集合的交集,通過它,可以獲得同時參加多個候選人投票的名單列表。
zrevrank 方便的查詢某個元素在有序集合中的位置,也就是投票的排名。
zscore 用來查詢某個元素在集合中的分數
zrevrank 返回某個元素在集合中的位置
zrevrangebyscore 獲取某個分數區間內元素的排行榜
有序集合提供了從小到大和從大到小兩種排行榜,其中有rev的命令,返回的是從大到小的集合。
設計投票游戲之所以會在投票游戲中選用redis,主要考慮高并發的支持,在實際應用的場景中,因為投票的時候可能有很高的并發投票和實時投票結果查詢,如果所有操作都直接操作數據庫,那么會對數據庫造成較大的負載。經過考察技術方案和實現成本,決定采用redis提供的有序集合,實現投票過程和實時排名的展示,直接讀取緩存,避免了非核心業務對數據庫的突發高并發訪問。
投票游戲的用戶故事創建投票的候選人
創建用戶
用戶參加活動,獲得一定數量的投票額度
用戶使用投票額度為候選人投票
候選人查看為自己投票的用戶的計票排名
所有人查看實時的候選人選票排名
游戲流程首先是可以有管理員,創建候選人和用戶,或者候選人和用戶自己注冊,這個取決于具體的場景的需要。本次demo提供的接口是用戶和候選人自己注冊的模式。存儲用戶和候選人信息,最簡單實現可以用redis的字符串類型key/value,本身就是hash,也可以使用redis提供的HASH類型。
創建用戶以后,為用戶分配投票額度是要做的工作,通過redis的字符串類型,INCR實現,可以保證操作的原子性。投票過程同樣在這個數據結構上減去一定的值,但是為了防止并發情況下,用戶使用超過自己擁有的額度,需要設計一個鎖,只有在獲得鎖之后,才能做DECR操作。
投票扣減用戶的額度之后,就可以操作核心數據結構,有序集合。第一步是為特定的候選人增加上獲得的投票,這個是所有候選人的id作為鍵的有序集合,分數就是獲得的總票數;同時在用戶針對這名候選人的投票記錄上,也記錄每個用戶為同一個候選人投票的排名。
實現上面的操作之后,獲得實時投票排名,就是一件很輕松的工作。有序集合提供的操作可以簡單的查詢出各種排名有關的名單。
編碼實現redis的調用設計好游戲流程之后,就可以開始直接動手實現了,下面用redis-cli命令,以偽代碼的形式展示一下競猜的整個流程,可以直接在redis客戶端下查看效果。
redis-cli偽代碼創建用戶和競選的候選人
set voter:1 0 set voter:2 0 set voter:3 0 set elector:1 name set elector:2 name
為用戶分配額度
incrby voter:1 50 incrby voter:2 40 incrby voter:3 60
用戶投票
# voter:1 # 增加總榜單 zincrby elector:total:list 25 elector:1 # 增加競選人榜單 zincrby elector:single:elector:1 25 voter:1 decrby voter:1 25 # voter:2 zincrby elector:total:list 12 elector:1 zincrby elector:single:elector:1 12 voter:2 decrby voter:2 12 # voter:3 zincrby elector:total:list 40 elector:2 zincrby elector:single:elector:2 40 voter:3 decrby voter:3 40
各種榜單
# 總候選人榜單 zrevrange elector:total:list 0 -1 WITHSCORES # 投候選人1的名單 zrevrange elector:single:elector:1 0 -1 WITHSCORES # 創建用戶投票排行 zunionstore voter:total:elector 2 elector:single:elector:1 elector:single:elector:2 # 查看用戶1的排名(返回下標從0開始) zrevrank voter:total:elector voter:1
下圖是運行結果:
node.js代碼查看代碼Node.js實現
最后,我們用node.js實現了一個簡單的后端服務demo,javascript的數據結構和redis SDK比較清晰的展示原生命令的調用效果。demo演示了各種api的調用,可以安裝說明,使用curl調用對應的接口效果。
實現過程中,我們可以看到,如果直接使用命令,其實整個投票過程只需要非常簡單的幾個命令就可以完成。而demo中演示的代碼,相比命令,增加了很多提供接口訪問和sdk調用相關的代碼;如果最后為生產應用編寫一個投票程序,根據業務邏輯的需要和容量規劃,還需要考慮更多的細節,軟件開發本身也是這樣的過程,從一個簡單的想法和創意開始,然后需要考慮更多的現實場景和需求,不斷的在程序中還原出整個構想。
文/liuwill(簡書作者)
原文鏈接:玩轉Redis - 使用有序集合(sorted sets)實現投票游戲
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97999.html
摘要:數據結構之應用之常用命令之應用場景說明本文參考了開發實戰指南,還有實戰自己之前的筆記。我們正式進入主題吧,中種數據結構的使用場景介紹。應用場景土法建索引。此命令會覆蓋哈希表中已存在的域。 數據結構之Redis應用之常用命令之應用場景 說明 1、本文參考了Redis開發實戰指南GitBook,還有《Redis實戰》自己之前的筆記。主體框架來自這里。 2、感謝大佬們的付出,在這里自己只是...
閱讀 1341·2023-04-25 23:42
閱讀 2808·2021-11-19 09:40
閱讀 3520·2021-10-19 11:44
閱讀 3529·2021-10-14 09:42
閱讀 1860·2021-10-13 09:39
閱讀 3821·2021-09-22 15:43
閱讀 665·2019-08-30 15:54
閱讀 1448·2019-08-26 13:32