Redis場景應用實例

Redis的相關知識點和需要注意的問題我們都已經梳理過了,關鍵還是需要運用到實際的工作中才能達到學以致用,下面我們將整理一個實際應用的場景,并且集合Redis來實現其需求。

目前公司有十萬員工,分成500個部門,公司為員工制定了每日9點前和18點后網上簽到的制度,簽到之后可以及時查看自身簽到狀態(tài),主管可以及時收到下屬員工的簽到狀態(tài),一整天未簽到的員工自動補充曠工

以上為場景;請用java+redis+隊列+mysql實現此功能

分析該需求,首先10w的員工簽到,這個涉及到高并發(fā)的場景,并且主管還需要及時收到下屬員工的簽到狀態(tài),這個需要異步通知的功能,并且一整天未簽到的員工自動補充曠工,這個需要一個定時任務來實現

綜上所述我們?yōu)榱藢崿F其功能最少需要高并發(fā)簽到,異步通知以及定時任務這三個技能,明白了其所需要使用到的技術,下面我們來一個個的剖析,并且實現這樣的功能。

高并發(fā)來實現簽到功能

為了實現高并發(fā),題目中已經給出了我們需要使用redis來實現,這個沒得選,但是我們還是需要分析下是單機版還是Redis集群來實現這樣的功能。

單機還是集群?

10w員工,按照二八定律分析來說大概同時有2w的簽到,也就是寫請求(二八定律真乃神定律,在現實生活中隨處可見),單機版本的Redis大概能支持10w左右的QPS(這個數值有波動,主要跟服務器的性能有關系,內存讀寫速度快的,這個數值還會更大點),所以我們這個單機版的Redis就能實現這樣的功能,如果是員工是100w的話,我們就需要搭建Redis服務集群,最好還是能做到讀寫分離,這樣還能做到橫向擴容。

數據結構很重要??!

一個適用的數據結構能優(yōu)化代碼邏輯,并且減少操作時間復雜度,優(yōu)化服務響應速率,提升客戶使用度,所以數據結構十分的重要。

  1. 首先確定使用redis的數據類型

學過Java的朋友應該都知道Java中的Map的理想操作時間復雜度是O(1),也就是說對于內存來說,訪問任何地址的時間是一樣的,即時間極短,相當于可以同時訪問到所有地址,那么這里redis的hash數據類型和Java的Map是類似的,所以我們選用hash類型來實現所有員工在Redis中的數據存儲

  1. 繼續(xù)優(yōu)化hash的數據結構

看到這里有的朋友可能會考慮,將10w的員工的信息都存放在Redis中,就需要10w個key(map),No,No,不是這樣的!為什么不這樣,我們來分析下。

還是跟Map的類型有關,如果10w個map存儲在redis中,需要消耗一定的內存,并且數據越大,內存查詢的速度也就越慢,所以我們的著眼點應該是按照部門來分別存儲,這樣查詢的時候也可以根據部門來減少查詢到次數,所以我們第一層的數據結構應該是以部門ID+常量+簽到日期為key的map,這樣做的好處有兩個:

  • 每個人都是歸屬部門的,所以先根據部門來縮小查找的范圍,減少查詢遍歷的次數:500+2000=2500,也就是說我們定位一個人最大遍歷2500次就夠了,而如果是直接查詢個人的話,最大可能遍歷10w次。
  • Redis中存放500個map比存放10w個map來的小的多,減少了redis的數據存儲內存的消耗

接著,我們再來分析下value的存儲什么?

我們的需求是員工進行簽到,所以我們的value值中必須要包含是否簽到的相關信息,這里我們還可以擴展下,需求要求是上班前和下班后都進行簽到,需要區(qū)分簽到的類型,所以我們還可以添加一個常量來進行簽到類型區(qū)分,其次是誰簽到的,說到這里,我想這個數據結構已經很清晰了。

是的還是使用hash結構來存放人員的信息,其中key值最好是人員的id,而value值可以是簽到的狀態(tài)

  1. 數據結構的確定
    至此,經過我們的分析,我們確定了Redis中簽到的數據結構,使用Java的數據結構來表達:
    // 外圍的Key是String類型: 主要存放部門的id+常量+簽到日期
    // 外圍的Value是Map類型:主要存放該部門的人員的信息
    // 里層的Key是String類型: 主要存放人員的ID
    // 里層的key也是String類型(這里也可以修改為List類型): 主要存放簽到的狀態(tài)
    Map<String,Map<String,String>>

業(yè)務流程的實現

  1. 初始化數據

既然簽到的map數據結構已經確定了,那么我們該怎么來使用這個數據結構來實現我們的業(yè)務呢?

這里提供一個方案,我們可以提前將部門的map的數據給初始化,有兩個原因:

  • 部門和人員的數據一般變動不大,所以可以先初始化,節(jié)省時間,到時直接從Redis中取就可以了
  • 避免簽到的時候才來生成部門簽到map,主要是為了避免簽到高并發(fā)時,造成數據覆蓋現象,導致簽到數據不正確

這里的部門簽到map(暫時這么稱呼),其有效期應該設置為永遠,避免數據失效!

  1. 簽到

用戶登錄系統(tǒng)后,我們會在redis中生成用戶的基本信息,這里主要是用戶的人員ID和所在部門的ID。

  • 用戶簽到的時候,將個人信息寫入到redis,主要是為了用戶查看其基本信息,包括簽到的狀態(tài)信息
  • 根據員工ID和部門ID到部門簽到map中獲取人員的相關信息,并且更新簽到狀態(tài)。這里最好添加鎖,防止被其他員工取到產生競態(tài),等部門簽到map中的個人簽到狀態(tài)更新成功之后,釋放鎖,并且更新redis中個人信息中的簽到狀態(tài)
  • 將簽到相關信息放入隊列中

上述的簽到流程操作,可以及時的讓用戶查看到自己的簽到情況,即使高并發(fā)的情況下也不影響系統(tǒng)的響應流暢度

  1. 通知主管

用戶簽到之后,就將簽到的信息發(fā)送到隊列,通過隊列來異步通知主管,這里可以使用RabbitMQ來實現消息的發(fā)送通知,主要是考慮RabbitMQ的消息的安全和消息消費失敗后,可以使用死信隊列來實現重發(fā),確保消息的準確和安全性。

  1. 定時數據持久化

開啟一個定時任務,將部門簽到map提取出來,然后循環(huán)遍歷,將人員簽到的信息持久化到數據庫,對于持久化失敗的數據,可以寫入到日志中,展示給相關人員查看。將一整天都未簽到的人員置為曠工。

數據持久化后,可以刪除當天的部門簽到map,同時初始化明天需要用到的部門簽到map

可以是用流程圖展示如下:

[圖片上傳失敗...(image-7d95d9-1561206189155)]

至此,我們的整個業(yè)務流程就很清晰了,對應的代碼實現也就很容易了

總結

在對人員簽到的分析設計已經結束了,不過我們就其中的幾個問題需要討論下

為了實現上述的功能,redis中最小的key值是多少?

我們上面設計中 redis中的key是500個? 那能不能再次縮小呢? 其實是可以的,就是在外面再加一層map,這樣保存到redis中就一個key鍵值了,如果這樣設計的話,那其實沒有什么意義,還是需要查找到對應的部門,再查找到人員,這樣反而增加了一步查詢,還不如不加,而且如果只有一個key值的話,那么用戶簽到的時候需要加鎖,就將這個key添加了鎖,這樣話并發(fā)量就不是很大了,所有的用戶都要等該用戶簽到完成后再進行其拿到,從業(yè)務角度來看就是將10w員工的簽到串行了,我們上面設計的500個key,對不不同部門的人員簽到是不影響的,從業(yè)務角度來說,不同部門是可以同時簽到的,而且不影響數據,提高了效率。

為什么需要吧簽到的信息發(fā)到員工的信息里,還要保存到部門簽到map中?

我們上面的設計中 redis的部門簽到map中已經存放了人員的簽到信息,為什么還要在個人信息中存放簽到信息呢? 主要是為了需求中用戶可以隨時查看自己的簽到狀態(tài)。

這里有的朋友可能就疑問了,部門簽到map中不是已經存在了么,這里主要是為了人員查看的效率考慮的,如果存放在部門簽到map中,那么每次查看一次都需要從部門簽到map中提取出來個人信息才能查看,這樣會影響查看效率。

如果基于redis實現加鎖和釋放鎖功能,如何考慮其中的鎖釋放問題?

加鎖的功能其實也可以由redis來實現,我們可以在簽到時,對這個部門ID+加鎖常量+簽到日期,在redis中新增一個key,如果同部門的其他用戶也來簽到時,先查看是否存在部門ID+加鎖常量+簽到日期的key,如果存在則循環(huán)等待一段時間再請求,相當于給當前簽到用戶添加了鎖,等這個用戶簽到成功后,再刪除這個key。

上面就是簡單的加鎖的功能,這樣需要考慮釋放鎖的問題,如果加鎖成功了,程序在處理業(yè)務時程序異常,沒有正常的釋放鎖,這樣就會造成其他的人員獲取不到鎖,無法進行業(yè)務操作,解決這個問題,我們首先需要考慮不管業(yè)務是否成功,我們都需要釋放鎖,這樣至少不會對其他的人員簽到造成影響。

那么該如何實現這樣能,其實redis能很簡單的實現,就是給這個key添加失效時間,這樣只要到失效時間,這個key就會被刪除,也就相當于釋放了鎖。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容