redis 哨兵 异步_redis 使用历程
redis 使用歷程
為什么使用redis緩存?
答:之前是沒有使用redis的,直接用Java代碼寫類緩存功能,有些系統參數方面也是采用直接查詢數據庫。此中間還出現過一些其他問題,后面才選擇redis。
先說下不使用緩存會造成哪些影響:
1、在項目中,為避免不斷查詢數據庫,給數據庫造成壓力,需要將生效的用戶充值地址加入到緩存中,剛開始直接使用ArrayList,但是在測試階段就發現,在不斷將新的地址加入到ArrayList中,會出現添加異常情況,同時導致應用假死情況,后來經排查發現ArrayList非線程安全,然后采用CopyOnWriteArrayList(該list適合讀多寫少的情況),這個很好的解決了問題。雖然CopyOnWriteArrayList解決了并發問題,但是在性能上不理想,每次有新的地址添加到list中都會創建新的列表,并將之前的列表通過 Arrays.copyOf(elements, len + 1); 效率低下,且如果緩存的用戶地址太多(比如幾萬、十幾萬時),在每次發生新增是會造成內存使用短期飆升的情況。
2、同時在項目中還有些系統配置參數,在業務處理中會根據配置參數執行對應的邏輯(比如:是否允許提現、每日最大提現額度,定時任務是否執行等),但是這些系統參數基本上不怎么變動,在不斷的查詢數據庫也是一種浪費。
3、對一些用戶訪問量大的數據,直接訪問數據庫,在高并發情況下,可能會導致項目掛掉。
4、自己寫的本地緩存方案可能存在一些潛在的未知問題。
基于上述情況,開始加入緩存技術,并就緩存方案進行選型。
緩存方案選型
目前市面上主流的緩存方案有兩種:redis、memcache。我為什么放棄memcache而選擇redis呢?
1、從支持的數據類型方面:memcache只支持簡單數據類型,需要客戶端自己處理復雜對象;而redis支持的類型,除String、List、Hash、Set、SortedSet外,還支持pub/sub(不支持持久化,如果消費者當時不在現場,則消息丟失,可靠的操作還是選擇消息隊列)、Transaction、HyperLogLog(非精確的去重統計,伯努利實驗及拋硬幣)、bloomFilter(避免擊穿)等功能。
2、從持久化方面:memcached不支持持久化,redis支持持久化(可通過aof,rdb)
3、從線程角度:redis是單線程(但單機就可支持10萬的并發量,且不需要考慮上下文切換等問題,如果并發量太大,可以考慮多機部署方案【主從復制、哨兵模式、集群模式等】),memcache多線程。
4、綜上,我選擇redis作為項目的緩存方案。
使用redis常見問題
1、緩存集中到期問題(緩存設置的時候,設置了固定的到期時長,如果同一段時間集中加入緩存,則會存在集中過期的情況,在剛好過期時嗎,如果有大量請求進來,則可能會存在短暫卡頓,或者雪崩現象,甚至導致訪問數據庫癱瘓)
解決方案:
1、在某些基本不怎么變動的緩存,設置永不過期(必要時手動更新)
2、對需要設置過期時間的, 過期時間大小加個隨機數,將集中過期變的分散些,降低緩存雪崩概率。
2、緩存穿透&緩存擊穿
先說【緩存穿透】,指的是請求查詢緩存及數據庫均不存在的數據。比如查詢用戶id(一般都是正數遞增的),你查詢負數或者其他字符串肯定不會存在,且請求會不斷打到db上。避免方案是對請求數據的合法性進行校驗(權限校驗、參數校驗),還有就是采用布隆過濾器(原理是采用bitmap位圖,緩存的key會議bit的方式存入布隆過濾器上, 如果在布隆過濾器上能找到,則可能存在,否則肯定不存在),然后在進行緩存查詢、數據庫查詢。
緩存擊穿:在key失效瞬間(比如過期失效),大量請求打到數據庫上。
3、分布式鎖
說白了就是通過setnx(key不存在則設值)命令向緩存中設值。如果設值成功則獲取鎖,為避免加鎖后忘記釋放,通過expire設值鎖失效時間;若設值不成功,則加鎖失敗。但是有可能在加鎖后,還沒來得及設值過期時間,程序掛掉,需要采用setIfAbsent(K key, V value, long timeout, TimeUnit unit) 記得是這個方法。
但是:雖然解決了鎖過期無法釋放的問題,但設置的過期時間不能保證我當前獲取鎖的線程執行完成了,假如業務線比較長,在鎖過期后還沒有正常執行完成,又有可能引發其他問題。
4、假如在線上環境中有上億個key,如何找出以某些字符串開頭key的值,為什么不能使用keys *?
首先說下為什么不能使用keys * ,因為redis是單線程。使用keys 時會導致其他線程阻塞,導致其他請求進來時需要等待,直到key【且key沒有limit,會全部遍歷】 執行完成,如果剛好在執行key命令時,大量請求進來,那就GG了。推薦方案:采用scan方式,該命令可無阻塞的獲取指定模式的key列表。該命令的缺點是可能會存在一定的重復(為什么會存在重復呢?因為redis底層采用hashMap進行的實現,也就是說數據結構是數組加鏈表,如果在查詢過程中存在擴容或者鎖容時,就會出現重復),需要業務系統進行去重。
5、redis異步消息
可以采用list數據結構進行處理。lpush 加入消息、然后rpop獲取消息,如果list為空,則阻塞。或者rpush加入消息,lpop獲取消息。這樣保證了消息的先進先出;如果lpush、lpop或rpush、rpop則是先進后出。
6、redis延時隊列
可通過sortedSet數據結構,通過zadd添加消息,每次添加時對score自增(建議方案是采用時間戳,但是別神經病調整系統時間,不然就把自己找地埋了吧),消費時使用zrangebyscore(讀取數據后,業務方根據業務邏輯處理)
7、Pipeline操作
redis的管道命令,可以批量將多個請求發送給服務端,中間不需要等待請求的回復,只需要最后一并讀取結果就可以了。但是在集群模式下,不能直接使用Pipeline,否則可能會報錯。
原因:集群模式下,各集群節點是分配了不同的slot槽位,而請求的key在hash及crc16計算后可能存在不同的節點上,所以直接使用會報錯。可以根據redis集群的槽位分配請求,對批量數據進行先計算分配,然后再發起請求。
8、過期策略
定期清理:定期隨機抽取過期的key進行清理
惰性清理:被訪問時,如果發現已過期則清理,且不返回數據給調用方。
9、redis持久化
RDB模式:
原理:是redis會單獨創建(fork)一個與當前進程一模一樣的子進程來進行持久化,這個子線程的所有數據(變量。環境變量,程序程序計數器等)都和原進程一模一樣,會先將數據寫入到一個臨時文件中,待持久化結束了,再用這個臨時文件替換上次持久化好的文件,整個過程中,主進程不進行任何的io操作,這就確保了極高的性能
觸發機制:shutdown時,如果沒有開啟aof,會觸發配置文件中默認的快照配置;執行命令save或者bgsave save是只管保存,其他不管,全部阻塞 bgsave: redis會在后臺異步進行快照操作,同時可以響應客戶端的請求。
AOF
原理:將Reids的操作日志以追加的方式寫入文件,讀操作是不記錄的(配置文件中appendonly默認不開啟)
優勢:優化數據丟失問題,rdb會丟失最后一次快照后的數據,aof丟失不會超過2秒的數據
觸發機制:
no:表示等操作系統進行數據緩存同步到磁盤(快,持久化沒保證) ? always:同步持久化,每次發生數據變更時,立即記錄到磁盤(慢,安全) ? everysec:表示每秒同步一次(默認值,很快,但可能會丟失一秒以內的數據)
auto-aof-rewrite-percentage 100 當AOF文件增長到一定大小的時候Redis能夠調用 bgrewriteaof對日志文件進行重寫 。當AOF文件大小的增長率大于該配置項時自動開啟重寫(這里指超過原大小的100%)
auto-aof-rewrite-min-size 64mb:當AOF文件增長到一定大小的時候Redis能夠調用 bgrewriteaof對日志文件進行重寫 。當AOF文件大小大于該配置項時自動開啟重寫
混合持久化:4.0版本默認關閉,5.0 版本默認開啟。通過aof-use-rdb-preamble配置參數控制,yes則表示開啟,no表示禁用;注意:同時開啟aof跟rdb,aof優先(數據更加全面)
9、同步機制
第一次同步時,主節點做一次bgsave,并同時將后續修改操作記錄到內存buffer,待完成后將RDB文件全量同步到復制節點,復制節點接受完成后將RDB鏡像加載到內存。加載完成后,再通知主節點將期間修改的操作記錄同步到復制節點進行重放就完成了同步過程。后續的增量數據通過AOF日志同步即可,有點類似數據庫的binlog
10、集群方案
1、主從模式
2.6版本之后,slave默認只讀(缺點:主機掛掉后不能更新數據)
2、哨兵模式(高可用)
在master掛掉時,將slave提升為master。中間會有幾秒鐘的不可用狀態,因為在進行選舉。
哨兵原理:
主觀下線:在心跳檢測的定時任務中,如果其他節點超過一定時間沒有回復,小兵節點就會將其進行主管下線
客觀下線:哨兵節點在對主節點進行主管下線后,會聽過sentinel is-master-down-by-addr命令詢問其他哨兵節點該主節點的狀態;如果判斷主節點下線的數量達到一定數值,則對該主節點進行客觀下線
哨兵定時任務:
每10秒通過想主從節點發送info命令獲取最新的主從結構;發現slave節點,確定主從關系
每2秒通過發布訂閱功能獲取其他哨兵節點的信息
沒秒通過向其他節點發送平命令進行心跳檢測,判斷是否下線
哨兵選舉:raft算法(基本思路是先到先得,一般情況誰先完成客觀下線誰就會成為領導者)
新節點選舉:
1、過濾掉不健康的從節點
2、選擇優先級最高的從節點(由replica-priority指定);如果優先級無法區分 3、選擇復制偏移量最大的從節點;如果仍無法區分 4、選擇runid最小的從節點
建議:哨兵節點大于一個(應該是奇數),一方面增加哨兵節點的冗余,冰面哨兵本身成為高可用的瓶頸,另一方面減少對下線的誤判,同時也應該部署在不同的物理機上
3、集群模式(高擴展)
手動搭建步驟:配置文件開啟集群配置;meet個節點;設置slot槽;設置主從;
腳本執行:
5.0之前需要安裝環境并執行redis-trib.rb;
5.0之后可用下面命令執行:
/usr/local/bin/redis-cli --cluster create 192.168.0.104:7000 192.168.0.104:7001 192.168.0.104:7002 192.168.0.104:7003 192.168.0.104:7004 192.168.0.104:7005 --cluster-replicas 1原創不易、轉載請注明來源
集群的擴容與縮容,注意slot分配
總結
以上是生活随笔為你收集整理的redis 哨兵 异步_redis 使用历程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消息称安卓手机厂商将会全球减产 以面对市
- 下一篇: qt 设置串口起始位_【IT专家】Qt: