心智圖資源庫 Redis資料結構知識架構學習
因為redis資料型別有很多,不同的資料型別有相同的元資料要記錄,所以redis會用一個RedisObject結構體來統一記錄這些元資料 當保存Long型別的時候,RedisObject的指標就直接賦值為整數.
編輯於2022-11-14 13:53:00이것은 (III) 저산소증-유도 인자 프롤릴 하이드 록 실라 제 억제제에 대한 마인드 맵이며, 주요 함량은 다음을 포함한다 : 저산소증-유도 인자 프롤릴 하이드 록 실라 제 억제제 (HIF-PHI)는 신장 빈혈의 치료를위한 새로운 소형 분자 경구 약물이다. 1. HIF-PHI 복용량 선택 및 조정. Rosalasstat의 초기 용량, 2. HIF-PHI 사용 중 모니터링, 3. 부작용 및 예방 조치.
이것은 Kuka Industrial Robots의 개발 및 Kuka Industrial Robot의 모션 제어 지침에 대한 마인드 맵입니다. 주요 내용에는 쿠카 산업 로봇의 역사, 쿠카 산업 로봇의 특성, 쿠카 산업 로봇의 응용 분야, 2. 포장 프로세스에서 쿠카 로봇은 빠르고 일관된 포장 작업을 달성하고 포장 효율성을 높이며 인건비를 줄입니다. 2. 인건비 감소 : 자동화는 운영자에 대한 의존성을 줄입니다. 3. 조립 품질 향상 : 정확한 제어는 인간 오류를 줄입니다.
408 컴퓨터 네트워크가 너무 어렵습니까? 두려워하지 마세요! 나는 피를 구토하고 지식 맥락을 명확히하는 데 도움이되는 매우 실용적인 마인드 맵을 분류했습니다. 컨텐츠는 매우 완전합니다. 네트워크 아키텍처에서 응용 프로그램 계층, TCP/IP 프로토콜, 서브넷 디비전 및 기타 핵심 포인트에 이르기까지 원칙을 철저히 이해하는 데 도움이 될 수 있습니다. 📈 명확한 논리 : Mindmas 보물, 당신은 드문 기회가 있습니다. 서둘러! 이 마인드 맵을 사용하여 408 컴퓨터 네트워크의 학습 경로에서 바람과 파도를 타고 성공적으로 해변을 얻으십시오! 도움이 필요한 친구들과 공유해야합니다!
이것은 (III) 저산소증-유도 인자 프롤릴 하이드 록 실라 제 억제제에 대한 마인드 맵이며, 주요 함량은 다음을 포함한다 : 저산소증-유도 인자 프롤릴 하이드 록 실라 제 억제제 (HIF-PHI)는 신장 빈혈의 치료를위한 새로운 소형 분자 경구 약물이다. 1. HIF-PHI 복용량 선택 및 조정. Rosalasstat의 초기 용량, 2. HIF-PHI 사용 중 모니터링, 3. 부작용 및 예방 조치.
이것은 Kuka Industrial Robots의 개발 및 Kuka Industrial Robot의 모션 제어 지침에 대한 마인드 맵입니다. 주요 내용에는 쿠카 산업 로봇의 역사, 쿠카 산업 로봇의 특성, 쿠카 산업 로봇의 응용 분야, 2. 포장 프로세스에서 쿠카 로봇은 빠르고 일관된 포장 작업을 달성하고 포장 효율성을 높이며 인건비를 줄입니다. 2. 인건비 감소 : 자동화는 운영자에 대한 의존성을 줄입니다. 3. 조립 품질 향상 : 정확한 제어는 인간 오류를 줄입니다.
408 컴퓨터 네트워크가 너무 어렵습니까? 두려워하지 마세요! 나는 피를 구토하고 지식 맥락을 명확히하는 데 도움이되는 매우 실용적인 마인드 맵을 분류했습니다. 컨텐츠는 매우 완전합니다. 네트워크 아키텍처에서 응용 프로그램 계층, TCP/IP 프로토콜, 서브넷 디비전 및 기타 핵심 포인트에 이르기까지 원칙을 철저히 이해하는 데 도움이 될 수 있습니다. 📈 명확한 논리 : Mindmas 보물, 당신은 드문 기회가 있습니다. 서둘러! 이 마인드 맵을 사용하여 408 컴퓨터 네트워크의 학습 경로에서 바람과 파도를 타고 성공적으로 해변을 얻으십시오! 도움이 필요한 친구들과 공유해야합니다!
Redis資料結構知識架構學習
快取一致性問題
先更新資料庫,再刪除快取
(1)緩存剛好失效 (2)請求A查詢資料庫,得一個舊值 (3)請求B將新值寫入資料庫 (4)請求B刪除緩存 (5)請求A將查到的舊值寫入快取
以上會發生髒數據
但是只有2,3中 3比2 快, B才會發生先刪除快取,A 用舊值寫緩存
實際上 寫庫操作遠低於讀取操作,所以避免慢 SQL.
先刪快取再寫資料庫
(1)先淘汰緩存 (2)再寫資料庫(這兩步和原來一樣) (3)休眠1秒,再次淘汰緩存
使用非同步雙刪除
基本操作
常見操作
查看個數,長度
是否存在,包含,追加,對該key 或key下的某一域增減
刪除,刪除指定位置,刪除並取得
自由主題
資料類型
Key
刪除,是否存在,查看,按模式匹配(大集合會有性能問題),
Scan迭代所有的key,
對List,set進行排序
從一個redis實例遷移到另一個redis實例
設定,取消過期時間, 取得key的剩餘過期時間
Redis如何淘汰過期的keys Redis keys過期有兩種方式:被動和主動方式。 當一些客戶端嘗試存取它時,key會被發現並主動的過期。 當然,這樣是不夠的,因為有些過期的keys,永遠不會訪問他們。 無論如何,這些keys應該過期,所以定時隨機測試設定keys的過期時間。所有這些過期的keys將會從金鑰空間刪除。 具體就是Redis每秒10次做的事情: 測試隨機的20個keys進行相關過期檢測。 刪除所有已經過期的keys。 如果有多於25%的keys過期,重複步奏1. 這是一個平凡的機率演算法,基本上的假設是,我們的樣本是這個密鑰控件,並且我們不斷重複過期檢測,直到過期的keys的百分百低於25%,這意味著,在任何給定的時刻,最多會清除1/4的過期keys。
Set
Sdiff 取得集合不存在的元素 SDiff a b 相當於a-b
Sdiff Store 將差集儲存到一個key中
求幾個集合的並集, 可儲存到一個key 中
SInter 取交集 SInterStore 將交集寫入到一個key中
List
BLOCK 操作,從佇列頭尾阻塞的取出一個值
可指定從若干個佇列中取得值
當佇列為空,給client 會被阻塞,直到有寫入,可指定逾時時間,逾時後傳回 nil
阻塞操作可以保證公平性
redis 2.4 2.6 不同,同時寫入多個值時如 a,b,c ,因該key被阻塞的client在2.4下,會 收到a, 2.6會收到c
當從server端刪除該值後,假如client在該值被 處理之前掛掉了,那麼該值也就丟了,rabbitmq的消息確認機制可以解決這個問題
可以使用List的阻塞操作結合其他資料型別在同一個交易中的原子操作,為客戶端提供阻塞行為
是否可實現公平的分散式鎖
類似於Java中List提供的操作,新增了LTrim, 截取某一個範圍的值
刪除列表最後一個元素,將其放到另一個列表
自由主題
有序集合
可以對幾個有序集合並集 reduce操作,支援SUM,MIN,MAX
傳回有序集合中某key的排名
可以取得有序集合的某一範圍的值; 也可以指定分數的最小最大值分頁查詢該範圍的集合
迭代集合
Transaction
watch
WATCH指令可以監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),之後的交易就不會執行。監控一直持續到EXEC指令,只要在exec執行之前,該值被修改,該交易就不會被執行,相當於exec時,redis作了檢查
由於WATCH指令的作用只是當被監控的鍵值被修改後阻止之後一個事務的執行,而不能保證其他客戶端不會修改這一鍵值,所以在一般的情況下我們需要在EXEC執行失敗後重新執行整個函數。用循環保證
執行EXEC指令後會取消所有鍵的監控,如果不想執行交易中的指令也可以使用UNWATCH指令來取消監控。在某些業務場景中,watch 之後,我們不一定執行事務操作,
Watch指令是一種樂觀鎖技術,只要是這個鍵值被修改,那麼後邊有效修改都不會生效,通常也可以使用該方式,較少競態條件,當exec返回空集合時,認為該次操作失敗
Exec實際執行交易中的所有指令,會清空watch 指令
Exec命令回復是一個數組,和 命令的執行順序一致
即使事務中有某條/某些命令執行失敗了, 事務佇列中的其他命令仍然會繼續執行 —— Redis 不會停止執行事務中的命令。
事務在執行 EXEC 之前,入隊的命令可能會出錯。比如說,指令可能會產生語法錯誤(參數數量錯誤,參數名錯誤,等等 這種情況下,客戶端會停止執行這個事務
從Mutil指令開始到exec 指令中執行的指令都會被入到交易佇列
Hash
是否存在,新增,刪除,取得所有key,value, 迭代hash集合
遞增hash 某key的值 如果 該key不存在就設定其為0 incre value
自由主題
資料結構坑點
當字串大小需要擴容時,小於1M,都是擴大一倍.大於1M,每次只擴容1M. 最大長度512 M
自增值超過最大值,會報錯
對於容器型資料結構,如果容器不存在就建立,如果元素沒有了,就刪除容器
分散式鎖
單節點方案(非紅鎖)
取得鎖
hash 到一個 cluster 節點
如果不存在,設定 lock path.設定過期時間
加鎖是 value 設定 client id
設定看門狗 watch dog ,定期更新鎖. 可使用延遲隊列實作.
沒有獲取到鎖,可考慮阻塞似等待獲取
解鎖
若不設定過期時間.會導致出現死鎖問題
a) 一旦redis發生主從切換,可能會遺失一些鎖,
和zk 比較
Zookeeper實現的分散式鎖其實有一個缺點,那就是效能上可能並沒有快取服務那麼高。因為每次在建立鎖定和釋放鎖定的過程中,都要動態建立、銷毀瞬時節點來實現鎖定功能。 ZK中建立和刪除節點只能透過Leader伺服器來執行,然後將資料同不到所有的Follower機器上。 並發問題,可能有網路抖動,客戶端和ZK叢集的session連線斷了,zk叢集以為客戶端掛了,就會刪除臨時節點,這時候其他客戶端就可以取得到分散式鎖了
Redis很難實現公平性
redlock
在演算法的分散式版本中,我們假設我們有N個Redis主機。這些節點完全獨立,因此我們不使用複製或任何其他隱式協調系統。我們已經描述瞭如何在單一實例中安全地取得和釋放鎖。我們理所當然地認為演算法將使用此方法在單一實例中獲取和釋放鎖。在我們的範例中,我們設定N = 5,這是一個合理的值,因此我們需要在不同的電腦或虛擬機器上執行5個Redis主伺服器,以確保它們以大多數獨立的方式失敗。 為了取得鎖,客戶端執行以下操作: 1. 它以毫秒為單位取得當前時間。 2. 它嘗試依序取得所有N個實例中的鎖,在所有實例中使用相同的鍵名和隨機值。在步驟2期間,當在每個實例中設定鎖定時,用戶端使用與總鎖定自動釋放時間相比較小的逾時以取得它。例如,如果自動釋放時間是10秒,則超時可以在~5-50毫秒範圍內。這可以防止客戶端長時間保持阻塞狀態,試圖與Redis節點通話失敗:如果執行個體不可用,我們應該盡快嘗試與下一個執行個體通話。 3. 客戶端透過從目前時間中減去在步驟1中獲得的時間戳記來計算獲取鎖定所需的時間。當且僅當客戶端能夠在大多數實例中獲取鎖定時(至少3個)並且獲取鎖定所經過的總時間小於鎖定有效時間,認為鎖定被獲取。 4. 如果獲得了鎖,則其有效時間被認為是初始有效時間減去經過的時間,如步驟3中計算的。 5. 如果客戶端因某種原因(無法鎖定N / 2 1實例或有效時間為負)未能取得鎖定,它將嘗試解鎖所有實例(即使它認為不是能夠鎖定)。
當掛掉一個節點後,不會導致鎖被搶佔的風險
快取
失效
失效時間設定隨機值,避免集體失效
資料結構的實現
應用場景
zset
記錄用戶帖子id 列表.快速顯示
記錄熱榜帖子 ID列表.總熱榜,分類熱榜
用於記錄一對多,且多的一方嚴格不能重複
記錄某個集合,該集合可能是和使用者相關,也可能是與總的系統相關
hash
記錄貼文按讚數,留言數,點擊數.
記錄貼文標題,摘要,作者,封面資訊等.
快取近期的熱貼內容.(貼文內容非常大,不適合從db取)
list
記錄帖子的相關文章清單.根據內容推薦相關帖子
bitmap
用於作為bool數組,或自訂位數組,主要是為了節省內存
HyperLogLog
用於粗略計算去重之後的統計值.
例如網站 UV,需要過濾重複訪問
只能新增和取得總數,不能取得某個值是否存在,或全部元素
蒲隆地
用於去重.取得某個元素是否存在於清單中
如果存在,不一定真的存在 如果不存在,那一定不存在
考慮一定給用戶推薦未訪問過資源
考慮不重複多次使用資源.
要容忍一定的失敗率,即資源可能未被訪問,但是被當成已被訪問過
使用多個 Hash演算法,分別叫key 映射的bit置1.
不存在一定不存在!!!!
只有add和 exist(可查多個)指令
可使用初始參數,設定過濾器,error_rate 是錯誤率,越低容量越大. initial_size 預估總量,要針對實際的場景,設定總量
Redis-cell
專案不大的,維護成本不高的話,可以採用 直接使用 redsi-cell ,否則可以考慮細粒度的控製到每個服務節點去限流,配合相應的負載平衡策略去實現
利用zset,score圈出時間窗口,統計時間窗口內同一個用戶同一個行為出現的次數,如果限流次數太大.可能不適用,例如1s 1000次
CL.THROTTLE test 100 400 60 3
test key 容量100(最大併發) 60s內最多400次. 本次申請3個容量
1: 是否成功,0:成功,1:拒絕 2: 令牌桶的容量,大小為初始值 1 3: 目前令牌桶中可用的令牌 4: 若請求被拒絕,這個值表示多久後才漏斗桶中會重新添加令牌,單位:秒,可以作為重試時間 5: 表示多久後令牌桶中的令牌會存滿
漏斗演算法
特殊的資料結構
壓縮鍊錶
由一個個壓縮鍊錶即數組組成,為了避免普通鍊錶的額外記憶體開銷.
為了盡可能節省記憶體設計出來的雙向鍊錶
儲存字串或整數
在細節上節省內存,對於值的存儲採用了變長的編碼方式
每項會有單獨的位數標記該項的資料長度和類型
hash、list、zset底層資料結構實現
特點
1) 內部表現為資料緊湊排列的一塊連續記憶體數組。
2) 可以模擬雙向鍊錶結構,以O(1)時間複雜度入隊和出隊。
3) 新增刪除操作涉及記憶體重新分配或釋放,增加了操作的複雜度。
4) 讀寫操作涉及複雜的指標移動,最壞時間複雜度為O(n2)。
5) 適合儲存小物件和長度有限的資料。
1)針對效能要求較高的場景使用ziplist,建議長度不要超過1000,每個元素大小控制在512位元組以內
跳躍表
跳表平均支援 O(logN),最壞O(N)複雜度的查找
為什麼不用樹,平衡樹代替跳躍表?
跳躍表的實作很簡單就能達到 O(logN)的級別
快速鍊錶
壓縮鍊錶使用 指標連結起來,變成一個linkedlist
每一個ziplist 預設是8k.(可配)
運維
監控
2)指令平均耗時使用info Commandstats指令獲取,包含每個指令呼叫次數 ,總耗時,平均耗時,單位微秒。
主從
Redis的複製功能分為同步(sync)和命令傳播(command propagate)兩個操作:
同步操作用於將從伺服器的資料庫狀態 更新至主伺服器目前所處的資料庫狀態;
命令傳播操作則用於在主伺服器的資料庫狀態被修改, 導致主從伺服器的資料庫狀態出現不一致時,讓主從 伺服器的資料庫重新回到一致狀態。
讀寫分離
讀寫分離適合大訪問(大到單一redis感覺很慢了),而且寫入操作遠小於讀取操作的情況。
如果讀取請求數量遠超寫請求,導致叢集資料copy成本遠小於讀取請求成本。 同時能一定程度上接受數據的不一致性,那可以做讀寫分離的。
redis cluster
特性
1、所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位協定優化傳輸速度和頻寬。
2.節點的fail是透過叢集中超過半數的節點偵測失效時才生效。
3.客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接叢集所有節點,連接叢集中任何一個可用節點即可。
4.redis-cluster把所有的實體節點映射到[0-16383]slot(不一定是平均分配),cluster 負責維護node<->slot<->value。
每個Redis 節點都需要執行指令,聲明自己負責的 slot
cluster addslots {slot_index1} {slot_index 2} {slot_index 3}
5.Redis集群預分好16384個桶,當需要在 Redis 集群中放置一個 key-value 時,根據 CRC16(key) mod 16384的值,決定將一個key放到哪個桶中。
每個Redis實例都知道其他節點的存在
無法保證強一致性
1.你的客戶端寫給主伺服器節點 B 2.主伺服器節點B向您的客戶端回覆確認。 3.主伺服器節點B將寫入傳播到它的從伺服器B1,B2和B3。
如果在 2步驟之後, 沒有發送從伺服器,此時B 掛掉了,那麼key將丟失(故障期間一定會有key 丟失)
容錯
選舉過程是叢集中所有master參與,如果半數以上master節點與故障節點通訊超過(cluster-node-timeout),認為該節點故障,自動觸發故障轉移操作.
(2):何時整個叢集不可用(cluster_state:fail)? a:如果集群任意master掛掉,且當前master沒有slave.集群進入fail狀態,也可以理解成集群的slot映射[0-16383]不完成時進入fail狀態. b:如果群集超過半數以上master掛掉,無論是否有slave群集進入fail狀態.
當叢集不可用時,所有對叢集的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤
故障轉移
1. 下線的主節點的所有從節點裡面,會進行選舉,選出一個新的主節點。 2. 被選取的從節點會執行 slave no one指令,成為新的主節點。 3. 新的主節點會撤銷所有對已下線主節點的槽指派,並將這些槽指派給自己。 4. 新的主節點向叢集廣播一條pong訊息,這條pong訊息可以讓叢集中的其他節點立即知道這個節點已經由從節點變成了主節點,並且這個主節點已經接管了原本由已下線節點處理的槽。 5.新的主節點開始接受和自己負責處理的槽有關的命令請求,故障轉移操作完成。
主從選舉
1. 當從節點發現自己複製的主節點進入已下線時,從節點(這裡發出請求的從節點可能會有多個)會向集群廣播一條cluster_type_failover_auth_request的訊息,要求有投票權(負責處理槽)的主節點向這個節點進行投票。 2.收到cluster_type_failover_auth_request訊息的主節點,根據自身條件(發起投票節點的current epoch不低於投票節點的current epoch)判斷是否贊成該從節點成為新的主節點,若贊成則傳回一條cluster_type_failover_auth_ack訊息。 3. 從節點接收到cluster_type_failover_auth_ack訊息,會將選票數加1。 4.如果某個從節點的選票大於等於叢集中主節點的一半時(大於等於N/2 1),這個節點就會變成新的主節點。 如果在一個配置週期內,沒有一個從節點獲得足夠的選票,那麼叢集中會進入新的配置週期,並在此進行選舉,知道選出新的主節點為止。
所有從節點都可能徵求意見,自己是否可以成為主(投票的人只投給自己大的節點),超過半數即可(n 1)/2
可能選不出來
局限
1.目前只支援同一個槽上的key的批次操作; 2.目前只支援同一個槽上的key事務; 3.只能使用資料庫0(每個redis實例有16個資料庫,可透過select {index}指令來切換); 4.不能將一個大的key(如hash、list)映射到不同的節點上; 5.目前集群主從複製只支援一層,不支援嵌套樹狀架構;
擴容時
步驟
1.對目標節點發送 cluster setslot {slot_index} importing {source_node_id} 2.對源節點發送 cluster setslot {slot_index} migrating {target_node_id} 3.源節點循環執行 cluster getkeysinslot {slot_index} {count(key個數)} 4.來源節點執行,把key透過管線(pipeline)遷移到目標節點 migrate {target_ip} {target_port} "" 0 {timeout} keys {key1} {key2} {key3} 5.重複3、4步驟 6.向叢集中所有主節點發送通知 cluster setslot {slot_index} node {target_nodeid}
每個節點都知道每個槽對應的 cluster node .
節點在接到命令請求時,查詢是否自己處理,如果是則處理,如果不是,返回move 錯誤, moved錯誤攜帶正確的節點ip和端口號返回給客戶端指引其轉向執行,而且客戶端以後的每一次關於該key都會去moved錯誤提供的節點去執行。
Codis
存取層:存取方式可以是vip或透過java程式碼呼叫jodis,然後連接呼叫不同的codis-proxy位址來實現高可用的LVS和HA功能.
代理層:然後中間層由codis-proxy和zookeeper處理數據走向和分配,通過crc32算法,把key平均分配在不同redis的某一個slot中.實現類似raid0的條帶化,在舊版本的codis中, slot需要手動分配,在codis3.2之後,slot會自動分配,相當方便.
資料層:最後codis-proxy把資料存進真實的redis-server主伺服器上,由於codis的作者黃東旭相當注重資料一致性,不允許有資料延時造成的資料不一致,所以架構從一開始就沒考慮主從讀寫分離.從伺服器僅僅是作為故障切換的冗餘架構,由zookeeper調用redis-sentinel實現故障切換功能.
在Codis中,Codis會把所有的key分成1024個槽,這1024個槽對應的就是Redis的集群,這個在Codis中是會在內存中維護著這1024個槽與Redis實例的映射關係。這個槽是可以配置,可以設定成 2048 或是4096個。看你的Redis的節點數量有多少,偏多的話,可以設定槽多一些。
當Codis的Codis Dashbord 改變槽位的訊息的時候,其他的Codis節點會監聽到ZooKeeper的槽位變化,會及時同步過來。如圖:
zk負責同步槽位資訊.
優先權佇列
sorted set
list
使用多個佇列實作.優先權佇列.不同的優先權任務進入到不同的佇列
同時消費者從隊列中取資料時,支援從多個隊列中取資料,其中有優先順序.
阻塞似
啟動多個消費者就是啟動多個 client取數據
訊息佇列
pubsub
使用
訂閱者可訂閱一個,多個,符合的訂閱 topic
發布者發布某一個主題,和 value
發布主題會被立即轉發到訂閱該主題的消費者,如果沒有消費者該訊息會被丟棄
風險
會存在丟訊息的風險(當宕機,斷網,或網路閃斷遺失封包)
由於該種特性,導致簡單的 pubsub 會存在丟失響應的風險.
數據可靠性的無法保障
無法保證至少一次
擴展不靈活,沒辦法透過多加consumer來加速消費的進度
可以使用多個 channel,監聽多次.
list
list
1、當給定清單內沒有任何元素可供彈出的時候,連線將被 BRPOP 指令阻塞,直到等待逾時或發現可彈出元素為止。 2.當給定多個key參數時,依參數 key 的先後順序依序檢查各個列表,彈出第一個非空列表的尾端元素。 另外,BRPOP 除了彈出元素的位置和 BLPOP 不同之外,其他表現一致。
如果list中沒有任務時, 該連線將會被阻塞 連接的阻塞有一個逾時時間 , 當逾時時間設定為0 , 即可無線等待, 直到彈出訊息
使用 pubsub 也可以通知消費者可以去 list中消費了
適用於 A-B 之間兩個業務之間的訂閱發佈等,當多個業務線意味著不同的消費者時,比較困難
ack實現
維護兩個隊列: pending隊列和doing表(hash表)。
workers定義為ThreadPool。 pending團隊列出隊後,workers分配一個執行緒(單一worker)去處理訊息-給目標訊息append一個當前時間戳記和目前執行緒名稱,將其寫入doing表,然後該worker去消費訊息,完成後自行在doing表擦除資訊。
啟用一個定時任務,每隔一段時間去掃描doing隊列,檢查每隔元素的時間戳,如果超時,則由worker的ThreadPoolExecutor去檢查線程是否存在,如果存在則取消當前任務執行,並把事務rollback。最後把該任務從doing隊列中pop出,再重新push進pending隊列。
可以使用zset 作排序.
避免過度使用 Redis.只用 Redis作最擅長的事情,做不擅長的事情,越做越發現 坑點越多,最後欲罷不能.前期錯誤的設計導致後期故障率高.穩定性差, 改造成本高.等 rabbitmq 並不是很複雜.維運也很簡單,可以跟業務系統混部