最近在處理系統消息模塊,查閱了不少實踐案例,各有針對性。html
首先站內消息主要包括:我的消息(評論,點贊),系統消息,訂閱消息,私信。git
其中,訂閱區分用戶羣,即系統消息是一個特殊的全部人訂閱的訂閱消息,特色是一對多。github
前三個實時性比較低,最後一個實時性高,離線狀態下是私信,若是雙方在線要轉爲聊天室,特色是一對一。web
那麼,接下來,該選個方案了,SQL or NoSQL?redis
首先,對於我的消息、私信("UserMessage"),一條消息插一句,Mysql跑跑沒問題。sql
對於系統消息或訂閱消息,必然不能夠,假若有10萬用戶,一次性那麼要插入10萬條消息,Mysql必死。數據庫
那麼就是說,要設立一個系統庫("SystemMessage"),每當用戶登陸,就去跑跑系統庫("SystemMessage"),把未讀的系統庫跑到我的庫。json
關於訂閱消息就比較麻煩了,對用戶分組?對消息分組?緩存
關係型數據庫處理集合問題是比較麻煩的,目前想到的結論是創建一個表("RssMessage")存儲消息類型,消息索引。數據結構
下面列了大體的數據庫模型:
看完這個數據庫設計,我也以爲好難受,吐槽前先來想一想爲何吧。
UserSystemRelation表用於記錄用戶讀取到哪一個位置的標記。
能夠看到,UserMessage與SystemMessage表中,title、tid、ctime、type字段冗餘了,好像也不必,
可是從用戶功能上看,當用戶登錄後,查找本身站內消息,必然要用到的有:status,必然要顯示的有:title、ctime,type做爲用戶進入消息面板後,要篩選的方式之一,這樣的話,Mysql就只要跑一個表就能夠完成顯示給用戶的最新站內消息了。
因爲MessageText多是一個大信息通知,用戶查看我的消息時候,並未查看MessageText內容,因此單獨放一張表。
因爲Mongodb是一種文檔型的數據結構,因此,能夠考慮把全部數據轉成json直接塞給Mongodb。
基於用戶的習慣,讀多寫少,大部分時候都是看到消息,刪除、更新比較少,若是數據沒更新直接讀Mongodb,若是數據更新,直接刪除Mongodb
的索引。
這個考慮是在,用戶數量很大的時候,要在"UserSystem"表裏查找到用戶消息比較慢的時候用,相似於吧Mongodb當緩存。
看了Mysql下站內消息的數據庫設計,我也以爲很蛋疼,臨時過渡沒事,可是仍是NoSQL合適。
Redis自帶訂閱與發佈系統,http://redisbook.readthedocs.org/en/latest/feature/pubsub.html
在下圖展現的這個 pubsub_channels 示例中, client2 、 client5 和 client1 就訂閱了 channel1 , 而其餘頻道也分別被別的客戶端所訂閱:
只要是訂閱了相應地頻道,就會收到頻道的消息。
把用戶ID做爲頻道,私信就是反向的頻道訂閱,系統消息就是全部用戶的訂閱,那麼離線的消息呢?
仍是存在系統或我的的哈希表裏,等上線後再去讀取。
在Python中,訂閱發佈消息(Publish)以下:
import redis,time queue = redis.StrictRedis(host='localhost', port=6379, db=0) channel = queue.pubsub() for i in range(100): queue.publish("test", i) time.sleep(0.1)
Python中,訂閱監聽消息(Subcribe)以下:
import redis,time r = redis.StrictRedis(host='localhost', port=6379, db=0) p = r.pubsub() p.subscribe('test') while True: message = p.get_message() if message: print "Subscriber: %s" % message['data']
Redis-py的API能夠看GitHub:https://github.com/andymccurdy/redis-py
這是線上用戶作法。
看過一種作法是創建一個Redis鏈表,存儲登錄用戶,當用戶登錄就直接發送,沒登錄就暫存起來。
這裏的話,能夠用WebSocket實時監聽,按期發送心跳包,若是在線直接返回Redis自帶的訂閱系統。
系統消息創建一個集合:
SADD system:2015-08-03 7 8 9 10 11
第一段標示系統信息,第二段標示日期,後面的數字標示message id。
我的消息創建一個集合:
SADD user:12345:read 1 2 3 4
第一段標示用戶信息集合,第二段標示用戶id,下一段標示消息類型爲已讀,後面的數字標示message id。
關於訂閱消息以下:
SADD rss:xiaocao 12 13 14 15
那麼你就收到小草的訂閱消息,消息ID分別是 12, 13, 14, 15
還有很重要的消息數據存儲,
HMSET message:12 title 標題 content 內容 date 2015-08-03
Python建立數據庫的例子就是:
import redis,time,threading,random pool = redis.ConnectionPool(host='localhost', port=6379, db=1) rs = redis.Redis(connection_pool=pool) rs.sadd("user:123:read", "1", "2") rs.sadd("user:123:unread", "4", "5", "6") rs.sadd("system:2015-08-03", "7", "8", "9", "10", "11") rs.sadd("rss:xiaocao", "12", "13", "14", "15", "11") for i in range(15): rs.hset("message:"+str(i), "title", "title=>"+str(random.uniform(1, 99999))) rs.hset("message:"+str(i), "content","content=>"+str(time.time())) rs.hset("message:"+str(i), "date", str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())))
參考:
-by小草
2015-08-03 01:35:10