直播間線上人數或者粉絲查詢
通常對於一些實時線上業務中,比如直播業務中的主播,希望讓主播看到直播間實時線上粉絲數等資料,從而從資料方面提升主播的整體直播體驗。
最簡單的方案就是通過所有線上人數判斷與主播是否構成粉絲關係,每個人進入直播間會產生記錄,根據使用者ID去遍歷主播與使用者的關係表,判斷記錄中is_follow關係是否為1,為1使用者則為主播粉絲,記錄下來,遍歷整張表結束則可以統計出線上粉絲人數。
缺點:對於線上粉絲查詢這一功能而言,是相對實時更新並且主播端請求頻率比較高的操作,如果每次查詢根據每個線上的使用者再去掃描表,即使是掃描從庫也是很耗時,因此是不可取的。而對於主播而言短暫的粉絲數量誤差延遲是可以接受的,所以考慮引入redis進行快取記錄。
也就是記錄線上粉絲功能中涉及到的主要介面
利用redis的不同資料結構記錄線上粉絲。
使用者上線時候,判斷構成粉絲關係,則採用ZADD,將使用者以及線上時間新增集合中,其中live_id是直播間id,用主播id或者直播id區分不同的線上粉絲集合。current_timestamp是進入直播間時間戳。
ZADD "online-fans:live_id" <user_id> <current_timestamp>
通過ZCARD命令檢視集合中的數量,也就是線上粉絲個數
ZCARD 「online-fans:live_id」
通過ZCOUNT 檢視某一時段進入直播間的粉絲。
COUNT "online-fans:live_id" <start_timestamp> <end_timestamp>
使用有序集合能夠同時儲存粉絲的id以及上線時間戳, 但如果只想要記錄線上的id, 而不想要儲存上線時間, 那麼也可以使用集合來代替有序集合進行記錄。
當進入直播間,判斷是否是粉絲, 執行 SADD 命令將它新增到線上記錄中當中:
SADD "online-fans:live_id" <user_id>
通過使用 SISMEMBER 命令, 可以檢查粉絲是否在直播間:
SISMEMBER "online-fans:live_id" <user_id>
統計線上粉絲數則可以通過執行 SCARD 命令來完成:
SCARD "online-fans:live_id"
與有序集合相同的是,都是集合型別,可以進行一些交集和並集的聚合操作,比如交集判斷連續一週都在直播間的粉絲,並集可以檢視一週之內出現在直播間的粉絲等資料。
使用有序集合或者集合能夠儲存具體的線上使用者名稱單, 但是卻在粉絲量線上大的時候需要消耗比較多的記憶體;
bitmap相對來說既能夠獲得線上使用者名稱單, 又可以儘量減少記憶體消耗。Redis 的點陣圖就是一個由二進位制位組成的陣列, 通過將陣列中的每個二進位制位與使用者 ID 進行一一對應, 使用點陣圖可以去記錄每個粉絲是否線上。
當一個使用者進入直播間時,判如果是粉絲,使用 SETBIT 命令, 將這個使用者對應的二進位制位設定為 1
SETBIT "online-fans:live_id <user_id> 1
通過使用 GETBIT 命令去檢查一個二進位制位的值是否為 1 , 判斷粉絲是否線上:
GETBIT "online-fans:live_id" <user_id>
通過 BITCOUNT 命令, 統計出點陣圖中有多少個二進位制位被設定成了1,也即是有多少個粉絲直播間線上:
BITCOUNT "online-fans:live_id"
同樣由於,bitmap是用0,1表示對應的粉絲是否線上,也可以多個記錄的bitmap形成與或非運算,計算多個時段或者多個直播間線上的粉絲數。
綜合實際的情況和要求,採用集合記錄線上粉絲人數。
設定一個集合,具體如下
key = "online-fans:live_id"
value = {user_id1, user_id2, user_id3....}
其中live_id是直播間或者直播場次id,也用主播id定義,集合中記錄使用者的user_id即可
具體操作包括
SADD "online-fans:live_id" <user_id>
EXPIRE "online-fans:live_id" 6*60*60
SREM "online-fans:live_id" <user_id>
DEL "online-fans:live_id" <user_id>
UNLINK "online-fans:live_id" <user_id>
具體的redis刪除集合的命令有兩個,一個是del,一個是unlink,具體的是由於redis在執行命令操作的時候是一般是單執行緒的,因此如果是當線上粉絲人數過多導致集合很大的時候,業務流程中執行del操作,會有延遲。因此可以採用單開一個協程或者執行緒去非同步非阻塞執行del操作或者直接使用unlink命令直接返回刪除結果,讓redis單開一個額外的執行緒去執行刪除操作,不阻塞後端流程。