基於REDIS實現的點贊功能設計思路詳解
06-24
基於REDIS實現的點贊功能設計思路詳解
來自專欄 PHP學習交流,卡卡滴.
前言
點贊其實是一個很有意思的功能。基本的設計思路有大致兩種, 一種自然是用mysql等資料庫直接落地存儲, 另外一種就是利用點贊的業務特徵來扔到redis(或memcache)中, 然後離線刷回mysql等。直接寫入Mysql直接寫入Mysql是最簡單的做法。做兩個表即可,
1、post_like記錄文章被贊的次數,已有多少人贊過這種數據就可以直接從表中查到;2、user_like_post記錄用戶贊過了哪些文章, 當打開文章列表時,顯示的有沒有贊過的數據就在這裡面;缺點1、資料庫讀寫壓力大熱門文章會有很多用戶點贊,甚至是短時間內被大量點贊, 直接操作資料庫從長久來看不是很理想的做法。redis存儲隨後批量刷回資料庫redis主要的特點就是快, 畢竟主要數據都在內存嘛;另外為啥我選擇redis而不是memcache的主要原因在於redis支持更多的數據類型, 例如hash, set, zset等。
下面具體的會用到這幾個類型。優點
1、性能高2、緩解資料庫讀寫壓力其實我更多的在於緩解寫壓力, 真的讀壓力, 通過mysql主從甚至通過加入redis對熱點數據做緩存都可以解決,寫壓力對於前面的方案確實是不大好使。缺點1、開發複雜這個比直接寫mysql的方案要複雜很多, 需要考慮的地方也很多;2、不能保證數據安全性
redis掛掉的時候會丟失數據, 同時不及時同步redis中的數據, 可能會在redis內存置換的時候被淘汰掉;不過對於我們點贊而已, 稍微丟失一點數據問題不大;具體設計
Mysql設計這一塊和寫入寫mysql是一樣的,畢竟是要落地存儲的。所以還是同樣的需要post_like, user_like_post這兩表存儲文章被點贊的個數(等統計), 用戶對那些文章點了贊(取消贊)。這兩表分別通過post_id, user_id進行關聯。redis設計部分:post_set在redis中弄一個set存放所有被點贊的文章
post_user_like_set_{$post_id}對每個post以post_id作為key, 搞一個set存放所有對該post點贊的用戶;post_user_like_{$post_id}{$user_id}將每個用戶對每個post的點贊情況放到一個hash裡面去, hash的欄位就隨意跟進需求來處理就行了。為啥用hash只所以用hash是因為完全可以用hash來存儲一個點贊的對象, 對應資料庫的一行記錄。當然有同學會說用key, value也可以, 將所有的數據序列化(json_encode等)後全部放到value裡面去。 反覆序列化也是一個很大的開銷不是, hash可以很方便的修改某個欄位, 而序列化和反序列化的操作。
post{$post_id}_counter對每個post維護一個計數器, 用來記錄當前在redis中的點贊數,這裡我們只用counter記錄尚未同步到mysql中的點贊數(可以為負), 每次刷回mysql中時將counter中的數據和資料庫已有的贊數相加即可。用戶點贊/取消贊獲取user_id, post_id, 查詢該用戶是否已經點過贊, 已點過則不允許再次點贊,或者設計為前端允許用戶點, 只是後台不重複計算;這裡需要注意的是用戶點贊的記錄可能在資料庫中, 也可能在緩存中, 所以查詢的時候緩存和資料庫都要查詢, 緩存沒有再查詢資料庫。將用戶的點贊/取消贊的情況記錄在redis中, 具體為:
1、寫入post_set
將post_id寫入post_set2、寫入post_user_like_set_{$post_id}將user_id寫入post_user_like_set_{$post_id}3、寫入post_user_like_{$post_id}{$user_id}將用戶點贊數據, 例如贊狀態, post_id, user_id, ctime(操作時間), mtime(修改時間)寫入post_user_like{$post_id}{$user_id}中4、更新post{$post_id}counter更新post{$post_id}counter, 這裡的更新稍晚複雜一點, 需要和前面一樣先獲取當前用戶是否對這個post點過贊如果點過, 並且本次是取消贊, counter減一, 如果沒點過, 本次是點贊, counter加一。如果原來是取消贊的情況, 本次是點贊, counter加一。
同步刷回資料庫循環從post_set中pop出來一個post_id至到空根據{$post_id} , 每次從post_user_like_set{$post_id}中pop出來一個user_id直到空根據post_id, user_id, 直接獲取對應的hash表的內容(post_user_like_{$post_id}{$user_id}將hash表中的數據寫入user_like_post表中將post{$post_id}counter中的數據和post_like中的數據相加, 將結果寫入到post_like表中頁面展示1、查詢用戶點贊情況前面已經說過, 需要同時查詢redis和mysql2、查詢post點贊統計
同樣需要查詢redis中的post{$post_id}_counter和mysql的post_like表, 並將兩者相加得到的結果才是正確的結果總結解決了mysql讀寫的問題但沒有針對用戶量較大的場景考慮分表的設計, 可以考慮針對user_id或者post_id進行分表好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。原文鏈接:http://www.furion.info/808.html
推薦閱讀:
※12 條用於 Linux 的 MySQL/MariaDB 安全最佳實踐
※一觸即發,2017年,資料庫世界的諸神之戰
※mysql的插件顯示
※大家常用哪個MySQL客戶端工具,除了命令行那個mysql之外?
※Spring Boot 連接MySql資料庫